macOS wxNativeFontInfo changes (#2045)
* adding native font descriptor serialization = v2 * remove common xml prefix from serialized string * Update src/osx/carbon/font.cpp Co-authored-by: VZ <vz-github@zeitlins.org> * Update src/osx/carbon/font.cpp Co-authored-by: VZ <vz-github@zeitlins.org> * static string via accessor * striping off xml preamble unconditionally if we use a different format in the future, we will have to increase our version number * applying italic directly to the font descriptor thus preserving attributes in the native font descriptor which we don’t store explicitly yet * Adding support for preserving font width Although we don’t express this in the public API yet, we try to preserve eg condensed, when changing the font width * Adding reference, bug fix double checked the font weight constants, Co-authored-by: VZ <vz-github@zeitlins.org>
This commit is contained in:
@@ -173,6 +173,7 @@ public:
|
|||||||
|
|
||||||
static CGFloat GetCTWeight( CTFontRef font );
|
static CGFloat GetCTWeight( CTFontRef font );
|
||||||
static CGFloat GetCTWeight( CTFontDescriptorRef font );
|
static CGFloat GetCTWeight( CTFontDescriptorRef font );
|
||||||
|
static CGFloat GetCTwidth( CTFontDescriptorRef font );
|
||||||
static CGFloat GetCTSlant( CTFontDescriptorRef font );
|
static CGFloat GetCTSlant( CTFontDescriptorRef font );
|
||||||
|
|
||||||
CTFontDescriptorRef GetCTFontDescriptor() const;
|
CTFontDescriptorRef GetCTFontDescriptor() const;
|
||||||
@@ -182,6 +183,7 @@ private:
|
|||||||
// attributes for regenerating a CTFontDescriptor, stay close to native values
|
// attributes for regenerating a CTFontDescriptor, stay close to native values
|
||||||
// for better roundtrip fidelity
|
// for better roundtrip fidelity
|
||||||
CGFloat m_ctWeight;
|
CGFloat m_ctWeight;
|
||||||
|
CGFloat m_ctWidth;
|
||||||
wxFontStyle m_style;
|
wxFontStyle m_style;
|
||||||
CGFloat m_ctSize;
|
CGFloat m_ctSize;
|
||||||
wxFontFamily m_family;
|
wxFontFamily m_family;
|
||||||
|
@@ -170,15 +170,15 @@ namespace
|
|||||||
const int kCTWeightsCount = 12;
|
const int kCTWeightsCount = 12;
|
||||||
static CGFloat gCTWeights[kCTWeightsCount] = {
|
static CGFloat gCTWeights[kCTWeightsCount] = {
|
||||||
-1.000, // 0
|
-1.000, // 0
|
||||||
-0.800, // 100
|
-0.800, // 100, NSFontWeightUltraLight
|
||||||
-0.600, // 200
|
-0.600, // 200, NSFontWeightThin
|
||||||
-0.400, // 300
|
-0.400, // 300, NSFontWeightLight
|
||||||
0.000, // 400
|
0.000, // 400, NSFontWeightRegular
|
||||||
0.230, // 500
|
0.230, // 500, NSFontWeightMedium
|
||||||
0.300, // 600
|
0.300, // 600, NSFontWeightSemibold
|
||||||
0.400, // 700
|
0.400, // 700, NSFontWeightBold
|
||||||
0.560, // 800
|
0.560, // 800, NSFontWeightHeavy
|
||||||
0.620, // 900
|
0.620, // 900, NSFontWeightBlack
|
||||||
0.750, // 1000
|
0.750, // 1000
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -746,6 +746,7 @@ void wxNativeFontInfo::Init()
|
|||||||
m_encoding = wxFONTENCODING_UTF8;
|
m_encoding = wxFONTENCODING_UTF8;
|
||||||
|
|
||||||
m_ctWeight = 0.0;
|
m_ctWeight = 0.0;
|
||||||
|
m_ctWidth = 0.0;
|
||||||
m_style = wxFONTSTYLE_NORMAL;
|
m_style = wxFONTSTYLE_NORMAL;
|
||||||
m_ctSize = 0.0;
|
m_ctSize = 0.0;
|
||||||
m_family = wxFONTFAMILY_DEFAULT;
|
m_family = wxFONTFAMILY_DEFAULT;
|
||||||
@@ -765,6 +766,7 @@ void wxNativeFontInfo::Init(const wxNativeFontInfo& info)
|
|||||||
m_encoding = info.m_encoding;
|
m_encoding = info.m_encoding;
|
||||||
|
|
||||||
m_ctWeight = info.m_ctWeight;
|
m_ctWeight = info.m_ctWeight;
|
||||||
|
m_ctWidth = info.m_ctWidth;
|
||||||
m_style = info.m_style;
|
m_style = info.m_style;
|
||||||
m_ctSize = info.m_ctSize;
|
m_ctSize = info.m_ctSize;
|
||||||
m_family = info.m_family;
|
m_family = info.m_family;
|
||||||
@@ -787,6 +789,7 @@ void wxNativeFontInfo::InitFromFontDescriptor(CTFontDescriptorRef desc)
|
|||||||
m_descriptor.reset(wxCFRetain(desc));
|
m_descriptor.reset(wxCFRetain(desc));
|
||||||
|
|
||||||
m_ctWeight = GetCTWeight(desc);
|
m_ctWeight = GetCTWeight(desc);
|
||||||
|
m_ctWidth = GetCTwidth(desc);
|
||||||
m_style = GetCTSlant(desc) > 0.01 ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL;
|
m_style = GetCTSlant(desc) > 0.01 ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL;
|
||||||
wxCFTypeRef(CTFontDescriptorCopyAttribute(desc, kCTFontSizeAttribute)).GetValue(m_ctSize, CGFloat(0.0));
|
wxCFTypeRef(CTFontDescriptorCopyAttribute(desc, kCTFontSizeAttribute)).GetValue(m_ctSize, CGFloat(0.0));
|
||||||
|
|
||||||
@@ -861,6 +864,7 @@ void wxNativeFontInfo::CreateCTFontDescriptor()
|
|||||||
traits.SetValue(kCTFontSymbolicTrait, kCTFontItalicTrait);
|
traits.SetValue(kCTFontSymbolicTrait, kCTFontItalicTrait);
|
||||||
|
|
||||||
traits.SetValue(kCTFontWeightTrait,m_ctWeight);
|
traits.SetValue(kCTFontWeightTrait,m_ctWeight);
|
||||||
|
traits.SetValue(kCTFontWidthTrait,m_ctWidth);
|
||||||
|
|
||||||
attributes.SetValue(kCTFontTraitsAttribute,traits.get());
|
attributes.SetValue(kCTFontTraitsAttribute,traits.get());
|
||||||
attributes.SetValue(kCTFontSizeAttribute, m_ctSize);
|
attributes.SetValue(kCTFontSizeAttribute, m_ctSize);
|
||||||
@@ -925,6 +929,15 @@ CGFloat wxNativeFontInfo::GetCTWeight(CTFontDescriptorRef descr)
|
|||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGFloat wxNativeFontInfo::GetCTwidth(CTFontDescriptorRef descr)
|
||||||
|
{
|
||||||
|
CGFloat weight;
|
||||||
|
CFTypeRef fonttraitstype = CTFontDescriptorCopyAttribute(descr, kCTFontTraitsAttribute);
|
||||||
|
wxCFDictionaryRef traits((CFDictionaryRef)fonttraitstype);
|
||||||
|
traits.GetValue(kCTFontWidthTrait).GetValue(&weight, CGFloat(0.0));
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
CGFloat wxNativeFontInfo::GetCTSlant(CTFontDescriptorRef descr)
|
CGFloat wxNativeFontInfo::GetCTSlant(CTFontDescriptorRef descr)
|
||||||
{
|
{
|
||||||
CGFloat slant;
|
CGFloat slant;
|
||||||
@@ -934,8 +947,18 @@ CGFloat wxNativeFontInfo::GetCTSlant(CTFontDescriptorRef descr)
|
|||||||
return slant;
|
return slant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// recipe taken from
|
||||||
|
// https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/CoreText_Programming/FontOperations/FontOperations.html
|
||||||
|
|
||||||
|
// common prefix of plist serializiation, gets removed and readded
|
||||||
|
|
||||||
|
static const wxString& GetPListPrefix()
|
||||||
|
{
|
||||||
|
static const wxString s_plistPrefix = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC "
|
||||||
|
"\"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
|
||||||
|
return s_plistPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
|
||||||
bool wxNativeFontInfo::FromString(const wxString& s)
|
bool wxNativeFontInfo::FromString(const wxString& s)
|
||||||
{
|
{
|
||||||
double d;
|
double d;
|
||||||
@@ -949,86 +972,151 @@ bool wxNativeFontInfo::FromString(const wxString& s)
|
|||||||
if ( !token.ToLong(&l) )
|
if ( !token.ToLong(&l) )
|
||||||
return false;
|
return false;
|
||||||
version = l;
|
version = l;
|
||||||
//
|
|
||||||
// Ignore the version for now
|
|
||||||
//
|
|
||||||
|
|
||||||
token = tokenizer.GetNextToken();
|
if ( version == 0 || version == 1 )
|
||||||
if ( !token.ToCDouble(&d) )
|
{
|
||||||
return false;
|
token = tokenizer.GetNextToken();
|
||||||
if ( d < 0 || d > FLT_MAX )
|
if ( !token.ToCDouble(&d) )
|
||||||
return false;
|
return false;
|
||||||
|
if ( d < 0 || d > FLT_MAX )
|
||||||
|
return false;
|
||||||
#ifdef __LP64__
|
#ifdef __LP64__
|
||||||
// CGFloat is just double in this case.
|
// CGFloat is just double in this case.
|
||||||
m_ctSize = d;
|
m_ctSize = d;
|
||||||
#else // !__LP64__
|
#else // !__LP64__
|
||||||
m_ctSize = static_cast<CGFloat>(d);
|
m_ctSize = static_cast<CGFloat>(d);
|
||||||
#endif // __LP64__/!__LP64__
|
#endif // __LP64__/!__LP64__
|
||||||
|
|
||||||
token = tokenizer.GetNextToken();
|
token = tokenizer.GetNextToken();
|
||||||
if ( !token.ToLong(&l) )
|
if ( !token.ToLong(&l) )
|
||||||
return false;
|
return false;
|
||||||
m_family = (wxFontFamily)l;
|
m_family = (wxFontFamily)l;
|
||||||
|
|
||||||
token = tokenizer.GetNextToken();
|
token = tokenizer.GetNextToken();
|
||||||
if ( !token.ToLong(&l) )
|
if ( !token.ToLong(&l) )
|
||||||
return false;
|
return false;
|
||||||
m_style = (wxFontStyle)l;
|
m_style = (wxFontStyle)l;
|
||||||
|
|
||||||
token = tokenizer.GetNextToken();
|
token = tokenizer.GetNextToken();
|
||||||
if ( !token.ToLong(&l) )
|
if ( !token.ToLong(&l) )
|
||||||
return false;
|
return false;
|
||||||
m_ctWeight = WXWeightToCT(wxFont::ConvertFromLegacyWeightIfNecessary(l));
|
m_ctWeight = WXWeightToCT(wxFont::ConvertFromLegacyWeightIfNecessary(l));
|
||||||
|
|
||||||
token = tokenizer.GetNextToken();
|
token = tokenizer.GetNextToken();
|
||||||
if ( !token.ToLong(&l) )
|
if ( !token.ToLong(&l) )
|
||||||
return false;
|
return false;
|
||||||
m_underlined = l != 0;
|
m_underlined = l != 0;
|
||||||
|
|
||||||
if ( version == 0L )
|
if ( version == 0L )
|
||||||
{
|
{
|
||||||
m_strikethrough = false;
|
m_strikethrough = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
token = tokenizer.GetNextToken();
|
||||||
|
if ( !token.ToLong(&l) )
|
||||||
|
return false;
|
||||||
|
m_strikethrough = l != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this works correctly via fallback even if this is (backwards compatibility) a font family name
|
||||||
|
SetPostScriptName( tokenizer.GetNextToken() );
|
||||||
|
|
||||||
|
RealizeResource();
|
||||||
|
|
||||||
|
#ifndef __WXMAC__
|
||||||
|
if( !m_familyName )
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
token = tokenizer.GetNextToken();
|
||||||
|
if ( !token.ToLong(&l) )
|
||||||
|
return false;
|
||||||
|
m_encoding = (wxFontEncoding)l;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else if ( version == 2 )
|
||||||
{
|
{
|
||||||
token = tokenizer.GetNextToken();
|
token = tokenizer.GetNextToken();
|
||||||
if ( !token.ToLong(&l) )
|
if ( !token.ToLong(&l) )
|
||||||
return false;
|
return false;
|
||||||
m_strikethrough = l != 0;
|
bool underlined = l != 0;
|
||||||
|
|
||||||
|
token = tokenizer.GetNextToken();
|
||||||
|
if ( !token.ToLong(&l) )
|
||||||
|
return false;
|
||||||
|
bool strikethrough = l != 0;
|
||||||
|
|
||||||
|
token = tokenizer.GetNextToken();
|
||||||
|
if ( !token.ToLong(&l) )
|
||||||
|
return false;
|
||||||
|
wxFontEncoding encoding = (wxFontEncoding)l;
|
||||||
|
|
||||||
|
wxString xml = tokenizer.GetString();
|
||||||
|
xml = GetPListPrefix()+xml;
|
||||||
|
wxCFStringRef plist(xml);
|
||||||
|
wxCFDataRef listData(CFStringCreateExternalRepresentation(kCFAllocatorDefault,plist,kCFStringEncodingUTF8,0));
|
||||||
|
wxCFDictionaryRef attributes((CFDictionaryRef) CFPropertyListCreateWithData(kCFAllocatorDefault, listData, 0, NULL, NULL));
|
||||||
|
CTFontDescriptorRef descriptor = NULL;
|
||||||
|
if (attributes != NULL)
|
||||||
|
descriptor = CTFontDescriptorCreateWithAttributes(attributes);
|
||||||
|
if (descriptor != NULL)
|
||||||
|
{
|
||||||
|
InitFromFontDescriptor(descriptor);
|
||||||
|
m_underlined = underlined;
|
||||||
|
m_strikethrough = strikethrough;
|
||||||
|
m_encoding = encoding;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this works correctly via fallback even if this is (backwards compatibility) a font family name
|
return false;
|
||||||
SetPostScriptName( tokenizer.GetNextToken() );
|
|
||||||
|
|
||||||
RealizeResource();
|
|
||||||
|
|
||||||
#ifndef __WXMAC__
|
|
||||||
if( !m_familyName )
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
token = tokenizer.GetNextToken();
|
|
||||||
if ( !token.ToLong(&l) )
|
|
||||||
return false;
|
|
||||||
m_encoding = (wxFontEncoding)l;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString wxNativeFontInfo::ToString() const
|
wxString wxNativeFontInfo::ToString() const
|
||||||
{
|
{
|
||||||
wxString s;
|
wxString s;
|
||||||
|
|
||||||
s.Printf(wxT("%d;%s;%d;%d;%d;%d;%d;%s;%d"),
|
// version 2 is a streamed property list of the font descriptor as recommended by Apple
|
||||||
1, // version
|
// prefixed by the attributes that are non-native to the native font ref like underline, strikethrough etc.
|
||||||
wxString::FromCDouble(GetFractionalPointSize()),
|
wxCFDictionaryRef attributes(CTFontDescriptorCopyAttributes(GetCTFontDescriptor()));
|
||||||
GetFamily(),
|
|
||||||
(int)GetStyle(),
|
if (attributes != NULL)
|
||||||
GetNumericWeight(),
|
{
|
||||||
GetUnderlined(),
|
CFPropertyListFormat format = kCFPropertyListXMLFormat_v1_0;
|
||||||
GetStrikethrough(),
|
if (CFPropertyListIsValid(attributes, format))
|
||||||
GetPostScriptName().GetData(),
|
{
|
||||||
(int)GetEncoding());
|
wxCFDataRef listData(CFPropertyListCreateData(kCFAllocatorDefault, attributes, format, 0, NULL));
|
||||||
|
wxCFStringRef cfString( CFStringCreateFromExternalRepresentation( kCFAllocatorDefault, listData, kCFStringEncodingUTF8) );
|
||||||
|
wxString xml = cfString.AsString();
|
||||||
|
xml.Replace("\r",wxEmptyString,true);
|
||||||
|
xml.Replace("\t",wxEmptyString,true);
|
||||||
|
xml = xml.Mid(xml.Find("<plist"));
|
||||||
|
|
||||||
|
s.Printf("%d;%d;%d;%d;%s",
|
||||||
|
2, // version
|
||||||
|
GetUnderlined(),
|
||||||
|
GetStrikethrough(),
|
||||||
|
(int)GetEncoding(),
|
||||||
|
xml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( s.empty() )
|
||||||
|
{
|
||||||
|
// fallback to version 1
|
||||||
|
s.Printf(wxT("%d;%s;%d;%d;%d;%d;%d;%s;%d"),
|
||||||
|
1, // version
|
||||||
|
wxString::FromCDouble(GetFractionalPointSize()),
|
||||||
|
GetFamily(),
|
||||||
|
(int)GetStyle(),
|
||||||
|
GetNumericWeight(),
|
||||||
|
GetUnderlined(),
|
||||||
|
GetStrikethrough(),
|
||||||
|
GetPostScriptName().GetData(),
|
||||||
|
(int)GetEncoding());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -1122,7 +1210,13 @@ void wxNativeFontInfo::SetStyle(wxFontStyle style_)
|
|||||||
|
|
||||||
if (formerIsItalic != newIsItalic)
|
if (formerIsItalic != newIsItalic)
|
||||||
{
|
{
|
||||||
Free();
|
if ( m_descriptor )
|
||||||
|
{
|
||||||
|
if ( m_style != wxFONTSTYLE_NORMAL )
|
||||||
|
m_descriptor = CTFontDescriptorCreateCopyWithSymbolicTraits(m_descriptor, kCTFontItalicTrait, kCTFontItalicTrait);
|
||||||
|
else
|
||||||
|
m_descriptor = CTFontDescriptorCreateCopyWithSymbolicTraits(m_descriptor, 0, kCTFontItalicTrait);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user