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:
Stefan Csomor
2020-09-12 19:29:26 +02:00
committed by GitHub
parent 16ab09208f
commit bc9e7b71e7
2 changed files with 165 additions and 69 deletions

View File

@@ -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;

View File

@@ -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,10 +972,9 @@ 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
//
if ( version == 0 || version == 1 )
{
token = tokenizer.GetNextToken(); token = tokenizer.GetNextToken();
if ( !token.ToCDouble(&d) ) if ( !token.ToCDouble(&d) )
return false; return false;
@@ -1011,14 +1033,78 @@ bool wxNativeFontInfo::FromString(const wxString& s)
if ( !token.ToLong(&l) ) if ( !token.ToLong(&l) )
return false; return false;
m_encoding = (wxFontEncoding)l; m_encoding = (wxFontEncoding)l;
return true; return true;
}
else if ( version == 2 )
{
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
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;
}
}
return false;
} }
wxString wxNativeFontInfo::ToString() const wxString wxNativeFontInfo::ToString() const
{ {
wxString s; wxString s;
// version 2 is a streamed property list of the font descriptor as recommended by Apple
// prefixed by the attributes that are non-native to the native font ref like underline, strikethrough etc.
wxCFDictionaryRef attributes(CTFontDescriptorCopyAttributes(GetCTFontDescriptor()));
if (attributes != NULL)
{
CFPropertyListFormat format = kCFPropertyListXMLFormat_v1_0;
if (CFPropertyListIsValid(attributes, format))
{
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"), s.Printf(wxT("%d;%s;%d;%d;%d;%d;%d;%s;%d"),
1, // version 1, // version
wxString::FromCDouble(GetFractionalPointSize()), wxString::FromCDouble(GetFractionalPointSize()),
@@ -1030,6 +1116,8 @@ wxString wxNativeFontInfo::ToString() const
GetPostScriptName().GetData(), GetPostScriptName().GetData(),
(int)GetEncoding()); (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);
}
} }
} }