Files
wxWidgets/src/osx/carbon/font.cpp
Vadim Zeitlin 24c83625f6 Remove Mac-specific wxFont ctors and fix strikethrough support
Only accept fractional point sizes and numeric weights via wxFont ctor
using wxFontInfo and avoid having specific ctor/Create() overloads for
the different combinations of font properties: this is not portable (as
these ctors don't exist in the other ports) and unsustainable due to the
very real potential of combinatorial explosion as more properties are
added.

As a side-effect, fix support for stricken-through fonts under Mac,
which was broken, by adding the missing wxFontInfo::IsStrikethrough()
call.
2018-09-17 15:24:41 +02:00

1208 lines
30 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/osx/carbon/font.cpp
// Purpose: wxFont class
// Author: Stefan Csomor
// Modified by:
// Created: 1998-01-01
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#include "wx/font.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/utils.h"
#include "wx/intl.h"
#include "wx/gdicmn.h"
#include "wx/log.h"
#include "wx/math.h"
#endif
#include "wx/fontutil.h"
#include "wx/graphics.h"
#include "wx/settings.h"
#include "wx/tokenzr.h"
#include "wx/osx/private.h"
#include <map>
#include <string>
#define TRACE_CTFONT "ctfont"
class WXDLLEXPORT wxFontRefData : public wxGDIRefData
{
public:
wxFontRefData()
{
Init(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
false, false, wxEmptyString, wxFONTENCODING_DEFAULT);
}
wxFontRefData(float size,
wxFontFamily family,
wxFontStyle style,
int weight,
bool underlined,
bool strikethrough,
const wxString& faceName,
wxFontEncoding encoding)
{
Init(size, family, style, weight, underlined, strikethrough, faceName, encoding);
}
wxFontRefData(const wxFontRefData& data);
wxFontRefData(const wxNativeFontInfo& info)
{
Init();
m_info.Init(info);
}
wxFontRefData(CTFontRef font);
virtual ~wxFontRefData();
float GetFractionalPointSize() const { return m_info.GetFractionalPointSize(); }
wxFontFamily GetFamily() const { return m_info.GetFamily(); }
wxFontStyle GetStyle() const { return m_info.GetStyle(); }
int GetNumericWeight() const { return m_info.GetNumericWeight(); }
bool GetUnderlined() const { return m_info.GetUnderlined(); }
bool GetStrikethrough() const { return m_info.GetStrikethrough(); }
wxString GetFaceName() const { return m_info.GetFaceName(); }
wxFontEncoding GetEncoding() const { return m_info.GetEncoding(); }
bool IsFixedWidth() const;
CTFontRef OSXGetCTFont() const;
CFDictionaryRef OSXGetCTFontAttributes() const;
CGFontRef OSXGetCGFont() const;
const wxNativeFontInfo& GetNativeFontInfo() const;
void SetFractionalPointSize(float size)
{
if (GetFractionalPointSize() != size)
{
m_info.SetFractionalPointSize(size);
Free();
}
}
void SetFamily(wxFontFamily family)
{
if (m_info.GetFamily() != family)
{
m_info.SetFamily(family);
Free();
}
}
void SetStyle(wxFontStyle style)
{
if (m_info.GetStyle() != style)
{
m_info.SetStyle(style);
Free();
}
}
void SetNumericWeight(int weight)
{
if (m_info.GetNumericWeight() != weight)
{
m_info.SetNumericWeight(weight);
Free();
}
}
void SetStrikethrough(bool s)
{
if (m_info.GetStrikethrough() != s)
{
m_info.SetStrikethrough(s);
Free();
}
}
void SetUnderlined(bool u)
{
if (m_info.GetUnderlined() != u)
{
m_info.SetUnderlined(u);
Free();
}
}
void SetFaceName(const wxString& facename)
{
if (m_info.GetFaceName() != facename)
{
m_info.SetFaceName(facename);
Free();
}
}
void SetEncoding(wxFontEncoding encoding)
{
if (m_info.GetEncoding() != encoding)
{
m_info.SetEncoding(encoding);
Free();
}
}
void Free();
void Alloc();
protected:
// common part of all ctors
void Init();
void Init(float size,
wxFontFamily family,
wxFontStyle style,
int weight,
bool underlined,
bool strikethrough,
const wxString& faceName,
wxFontEncoding encoding);
void SetFont(CTFontRef font);
void AllocIfNeeded() const;
wxCFRef<CTFontRef> m_ctFont;
wxCFMutableDictionaryRef m_ctFontAttributes;
wxCFRef<CGFontRef> m_cgFont;
wxNativeFontInfo m_info;
};
// ============================================================================
// implementation
// ============================================================================
wxStringToStringHashMap gs_FontFamilyToPSName;
namespace
{
const int kCTWeightsCount = 12;
static CGFloat gCTWeights[kCTWeightsCount] = {
-1.000, // 0
-0.800, // 100
-0.600, // 200
-0.400, // 300
0.000, // 400
0.230, // 500
0.300, // 600
0.400, // 700
0.560, // 800
0.620, // 900
0.750, // 1000
};
int CTWeightToWX(CGFloat weight)
{
for (int i = 0; i < kCTWeightsCount; ++i)
{
if ( (weight - gCTWeights[i]) < (gCTWeights[i+1]-weight) )
return i * 100;
}
return 1000;
}
CGFloat WXWeightToCT(int w)
{
if (w < 0)
w = 0;
else if (w > 1000)
w = 1000;
return gCTWeights[w / 100];
}
wxString FamilyToFaceName(wxFontFamily family)
{
wxString faceName;
switch (family)
{
case wxFONTFAMILY_DEFAULT:
faceName = wxT("Lucida Grande");
break;
case wxFONTFAMILY_SCRIPT:
case wxFONTFAMILY_ROMAN:
case wxFONTFAMILY_DECORATIVE:
faceName = wxT("Times");
break;
case wxFONTFAMILY_SWISS:
faceName = wxT("Helvetica");
break;
case wxFONTFAMILY_MODERN:
case wxFONTFAMILY_TELETYPE:
faceName = wxT("Courier");
break;
default:
faceName = wxT("Times");
break;
}
return faceName;
}
} // anonymous namespace
// ----------------------------------------------------------------------------
// wxFontRefData
// ----------------------------------------------------------------------------
#define M_FONTDATA ((wxFontRefData*)m_refData)
wxFontRefData::wxFontRefData(const wxFontRefData& data)
: wxGDIRefData()
{
Init();
m_info = data.m_info;
m_ctFont = data.m_ctFont;
m_ctFontAttributes = data.m_ctFontAttributes;
m_cgFont = data.m_cgFont;
}
void wxFontRefData::Init()
{
m_info.Init();
}
void wxFontRefData::Init(float size,
wxFontFamily family,
wxFontStyle style,
int weight,
bool underlined,
bool strikethrough,
const wxString& faceName,
wxFontEncoding encoding)
{
m_info.Init();
if ( !faceName.empty() )
SetFaceName(faceName);
else
SetFamily(family);
SetFractionalPointSize(size < 0 ? wxNORMAL_FONT->GetFractionalPointSize() : size);
SetNumericWeight(weight);
SetStyle(style);
SetUnderlined(underlined);
SetStrikethrough(strikethrough);
SetEncoding(encoding);
}
wxFontRefData::~wxFontRefData()
{
Free();
}
void wxFontRefData::Free()
{
m_ctFont.reset();
m_ctFontAttributes.reset();
m_cgFont.reset();
}
wxFontRefData::wxFontRefData(CTFontRef font)
{
Init();
SetFont(font);
m_info.InitFromFont(font);
}
void wxFontRefData::SetFont(CTFontRef font)
{
m_ctFont.reset(wxCFRetain(font));
wxCFMutableDictionaryRef dict;
dict.SetValue(kCTFontAttributeName, m_ctFont.get());
dict.SetValue(kCTForegroundColorFromContextAttributeName, kCFBooleanTrue);
m_ctFontAttributes = dict;
}
static const CGAffineTransform kSlantTransform = CGAffineTransformMake(1, 0, tan(wxDegToRad(11)), 1, 0, 0);
namespace
{
struct CachedFontEntry
{
CachedFontEntry()
{
used = false;
}
wxCFRef<CTFontRef> font;
wxCFMutableDictionaryRef fontAttributes;
wxCFRef<CGFontRef> cgFont;
bool used;
};
} // anonymous namespace
void wxFontRefData::AllocIfNeeded() const
{
if (!m_ctFont)
const_cast<wxFontRefData *>(this)->Alloc();
}
void wxFontRefData::Alloc()
{
wxCHECK_RET(m_info.GetPointSize() > 0, wxT("Point size should not be zero."));
// use font caching, we cache a font with a certain size and a font with just any size for faster creation
wxString lookupnameNoSize = wxString::Format("%s_%d_%d", m_info.GetFamilyName(), (int)m_info.GetStyle(), m_info.GetNumericWeight());
wxString lookupnameWithSize = wxString::Format("%s_%d_%d_%.2f", m_info.GetFamilyName(), (int)m_info.GetStyle(), m_info.GetNumericWeight(), m_info.GetFractionalPointSize());
static std::map<wxString, CachedFontEntry> fontcache;
CachedFontEntry& entryWithSize = fontcache[lookupnameWithSize];
if (entryWithSize.used)
{
m_ctFont = entryWithSize.font;
m_ctFontAttributes = entryWithSize.fontAttributes;
}
else
{
CachedFontEntry& entryNoSize = fontcache[lookupnameNoSize];
if ( entryNoSize.used )
{
m_ctFont = CTFontCreateCopyWithAttributes(entryNoSize.font, m_info.GetPointSize(), NULL, NULL);
m_ctFontAttributes = entryNoSize.fontAttributes.CreateCopy();
m_ctFontAttributes.SetValue(kCTFontAttributeName,m_ctFont.get());
m_cgFont = CTFontCopyGraphicsFont(m_ctFont, NULL);
entryWithSize.font = m_ctFont;
entryWithSize.cgFont = m_cgFont;
entryWithSize.cgFont = m_cgFont;
entryWithSize.fontAttributes = m_ctFontAttributes;
entryWithSize.used = true;
}
else
{
// emulate slant if necessary, the font descriptor itself carries that information,
// while the weight can only be determined properly from the generated font itself
const CGAffineTransform* remainingTransform = NULL;
if ( m_info.GetStyle() != wxFONTSTYLE_NORMAL && m_info.GetCTSlant(m_info.GetCTFontDescriptor()) < 0.01 )
remainingTransform = &kSlantTransform;
wxCFRef<CTFontRef> font = CTFontCreateWithFontDescriptor(m_info.GetCTFontDescriptor(), m_info.GetPointSize(), remainingTransform);
// emulate weigth if necessary
int difference = m_info.GetNumericWeight() - CTWeightToWX(wxNativeFontInfo::GetCTWeight(font));
SetFont(font);
if ( difference != 0 )
{
if ( difference > 0 )
{
// TODO: find better heuristics to determine target stroke width
CGFloat width = 0;
width = -1.0 * (1 + (difference / 100));
m_ctFontAttributes.SetValue(kCTStrokeWidthAttributeName, width);
}
else
{
// we cannot emulate lighter fonts
}
}
m_cgFont = CTFontCopyGraphicsFont(m_ctFont, NULL);
entryWithSize.font = m_ctFont;
entryWithSize.cgFont = m_cgFont;
entryWithSize.fontAttributes = m_ctFontAttributes;
entryWithSize.used = true;
entryNoSize.font = m_ctFont;
entryNoSize.fontAttributes = m_ctFontAttributes;
// no reason to copy cgFont as will have to be regenerated anyway
entryNoSize.used = true;
}
}
m_cgFont.reset(CTFontCopyGraphicsFont(m_ctFont, NULL));
}
bool wxFontRefData::IsFixedWidth() const
{
CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(m_ctFont);
return (traits & kCTFontMonoSpaceTrait) != 0;
}
CTFontRef wxFontRefData::OSXGetCTFont() const
{
AllocIfNeeded();
return m_ctFont;
}
CFDictionaryRef wxFontRefData::OSXGetCTFontAttributes() const
{
AllocIfNeeded();
return m_ctFontAttributes;
}
CGFontRef wxFontRefData::OSXGetCGFont() const
{
AllocIfNeeded();
return m_cgFont;
}
const wxNativeFontInfo& wxFontRefData::GetNativeFontInfo() const
{
AllocIfNeeded();
return m_info;
}
// ----------------------------------------------------------------------------
// wxFont
// ----------------------------------------------------------------------------
bool wxFont::Create(const wxNativeFontInfo& info)
{
UnRef();
m_refData = new wxFontRefData(info);
RealizeResource();
return true;
}
wxFont::wxFont(wxOSXSystemFont font)
{
wxASSERT(font != wxOSX_SYSTEM_FONT_NONE);
CTFontUIFontType uifont = kCTFontSystemFontType;
switch (font)
{
case wxOSX_SYSTEM_FONT_NORMAL:
uifont = kCTFontSystemFontType;
break;
case wxOSX_SYSTEM_FONT_BOLD:
uifont = kCTFontEmphasizedSystemFontType;
break;
case wxOSX_SYSTEM_FONT_SMALL:
uifont = kCTFontSmallSystemFontType;
break;
case wxOSX_SYSTEM_FONT_SMALL_BOLD:
uifont = kCTFontSmallEmphasizedSystemFontType;
break;
case wxOSX_SYSTEM_FONT_MINI:
uifont = kCTFontMiniSystemFontType;
break;
case wxOSX_SYSTEM_FONT_MINI_BOLD:
uifont = kCTFontMiniEmphasizedSystemFontType;
break;
case wxOSX_SYSTEM_FONT_LABELS:
uifont = kCTFontLabelFontType;
break;
case wxOSX_SYSTEM_FONT_VIEWS:
uifont = kCTFontViewsFontType;
break;
default:
break;
}
wxCFRef<CTFontRef> ctfont(CTFontCreateUIFontForLanguage(uifont, 0.0, NULL));
m_refData = new wxFontRefData(ctfont);
}
wxFont::wxFont(WX_NSFont nsfont)
{
m_refData = new wxFontRefData((CTFontRef)nsfont);
}
wxFont::wxFont(CTFontRef font)
{
m_refData = new wxFontRefData(font);
}
wxFont::wxFont(const wxString& fontdesc)
{
wxNativeFontInfo info;
if (info.FromString(fontdesc))
(void)Create(info);
}
wxFont::wxFont(const wxFontInfo& info)
{
m_refData = new wxFontRefData
(
info.GetFractionalPointSize(),
info.GetFamily(),
info.GetStyle(),
info.GetNumericWeight(),
info.IsUnderlined(),
info.IsStrikethrough(),
info.GetFaceName(),
info.GetEncoding()
);
if ( info.IsUsingSizeInPixels() )
SetPixelSize(info.GetPixelSize());
}
wxFont::wxFont(int size,
int family,
int style,
int weight,
bool underlined,
const wxString& face,
wxFontEncoding encoding)
{
(void)Create(size, (wxFontFamily)family, (wxFontStyle)style,
(wxFontWeight)weight, underlined, face, encoding);
}
bool wxFont::Create(int pointSize,
wxFontFamily family,
wxFontStyle style,
wxFontWeight weight,
bool underlined,
const wxString& faceName,
wxFontEncoding encoding)
{
AccountForCompatValues(pointSize, style, weight);
m_refData = new wxFontRefData
(
wxFontInfo::ToFloatPointSize(pointSize),
family, style,
GetNumericWeightOf(weight),
underlined, false, faceName, encoding
);
return true;
}
wxFont::~wxFont()
{
}
void wxFont::DoSetNativeFontInfo(const wxNativeFontInfo& info)
{
UnRef();
m_refData = new wxFontRefData(info);
}
bool wxFont::RealizeResource()
{
return OSXGetCTFont();
}
void wxFont::SetEncoding(wxFontEncoding encoding)
{
AllocExclusive();
M_FONTDATA->SetEncoding(encoding);
}
wxGDIRefData* wxFont::CreateGDIRefData() const
{
return new wxFontRefData;
}
wxGDIRefData* wxFont::CloneGDIRefData(const wxGDIRefData* data) const
{
return new wxFontRefData(*static_cast<const wxFontRefData*>(data));
}
void wxFont::SetFractionalPointSize(float pointSize)
{
AllocExclusive();
M_FONTDATA->SetFractionalPointSize(pointSize);
}
void wxFont::SetFamily(wxFontFamily family)
{
AllocExclusive();
M_FONTDATA->SetFamily(family);
}
void wxFont::SetStyle(wxFontStyle style)
{
AllocExclusive();
M_FONTDATA->SetStyle(style);
}
void wxFont::SetNumericWeight(int weight)
{
AllocExclusive();
M_FONTDATA->SetNumericWeight(weight);
}
bool wxFont::SetFaceName(const wxString& faceName)
{
AllocExclusive();
M_FONTDATA->SetFaceName(faceName);
return wxFontBase::SetFaceName(faceName);
}
void wxFont::SetUnderlined(bool underlined)
{
AllocExclusive();
M_FONTDATA->SetUnderlined(underlined);
}
void wxFont::SetStrikethrough(bool strikethrough)
{
AllocExclusive();
M_FONTDATA->SetStrikethrough(strikethrough);
}
// ----------------------------------------------------------------------------
// accessors
// ----------------------------------------------------------------------------
// TODO: insert checks everywhere for M_FONTDATA == NULL!
float wxFont::GetFractionalPointSize() const
{
wxCHECK_MSG(IsOk(), 0, wxT("invalid font"));
return M_FONTDATA->GetFractionalPointSize();
}
wxSize wxFont::GetPixelSize() const
{
#if wxUSE_GRAPHICS_CONTEXT
// TODO: consider caching the value
wxGraphicsContext* dc = wxGraphicsContext::CreateFromNative((CGContextRef)NULL);
dc->SetFont(*(wxFont*)this, *wxBLACK);
wxDouble width, height = 0;
dc->GetTextExtent(wxT("g"), &width, &height, NULL, NULL);
delete dc;
return wxSize((int)width, (int)height);
#else
return wxFontBase::GetPixelSize();
#endif
}
bool wxFont::IsFixedWidth() const
{
wxCHECK_MSG(IsOk(), false, wxT("invalid font"));
// cast away constness otherwise lazy font resolution is not possible
const_cast<wxFont*>(this)->RealizeResource();
return M_FONTDATA->IsFixedWidth();
}
wxFontFamily wxFont::DoGetFamily() const
{
return M_FONTDATA->GetFamily();
}
wxFontStyle wxFont::GetStyle() const
{
wxCHECK_MSG(IsOk(), wxFONTSTYLE_MAX, wxT("invalid font"));
return M_FONTDATA->GetStyle();
}
int wxFont::GetNumericWeight() const
{
wxCHECK_MSG(IsOk(), wxFONTWEIGHT_MAX, wxT("invalid font"));
return M_FONTDATA->GetNumericWeight();
}
bool wxFont::GetUnderlined() const
{
wxCHECK_MSG(IsOk(), false, wxT("invalid font"));
return M_FONTDATA->GetUnderlined();
}
bool wxFont::GetStrikethrough() const
{
wxCHECK_MSG(IsOk(), false, wxT("invalid font"));
return M_FONTDATA->GetStrikethrough();
}
wxString wxFont::GetFaceName() const
{
wxCHECK_MSG(IsOk(), wxEmptyString, wxT("invalid font"));
return M_FONTDATA->GetFaceName();
}
wxFontEncoding wxFont::GetEncoding() const
{
wxCHECK_MSG(IsOk(), wxFONTENCODING_DEFAULT, wxT("invalid font"));
return M_FONTDATA->GetEncoding();
}
CTFontRef wxFont::OSXGetCTFont() const
{
wxCHECK_MSG(IsOk(), 0, wxT("invalid font"));
return M_FONTDATA->OSXGetCTFont();
}
CFDictionaryRef wxFont::OSXGetCTFontAttributes() const
{
wxCHECK_MSG(IsOk(), 0, wxT("invalid font"));
return M_FONTDATA->OSXGetCTFontAttributes();
}
#if wxOSX_USE_COCOA_OR_CARBON
CGFontRef wxFont::OSXGetCGFont() const
{
wxCHECK_MSG(IsOk(), 0, wxT("invalid font"));
return M_FONTDATA->OSXGetCGFont();
}
#endif
const wxNativeFontInfo* wxFont::GetNativeFontInfo() const
{
return IsOk() ? &(M_FONTDATA->GetNativeFontInfo()) : NULL;
}
// ----------------------------------------------------------------------------
// wxNativeFontInfo
// ----------------------------------------------------------------------------
/* from Core Text Manual Common Operations */
void wxNativeFontInfo::Init()
{
m_descriptor.reset();
m_underlined = false;
m_strikethrough = false;
m_encoding = wxFONTENCODING_UTF8;
m_ctWeight = 0.0;
m_style = wxFONTSTYLE_NORMAL;
m_ctSize = 0.0;
m_family = wxFONTFAMILY_DEFAULT;
m_styleName.clear();
m_familyName.clear();
}
void wxNativeFontInfo::Init(const wxNativeFontInfo& info)
{
Init();
m_descriptor = info.m_descriptor;
m_underlined = info.m_underlined;
m_strikethrough = info.m_strikethrough;
m_encoding = info.m_encoding;
m_ctWeight = info.m_ctWeight;
m_style = info.m_style;
m_ctSize = info.m_ctSize;
m_family = info.m_family;
m_styleName = info.m_styleName;
m_familyName = info.m_familyName;
}
void wxNativeFontInfo::InitFromFont(CTFontRef font)
{
Init();
InitFromFontDescriptor(CTFontCopyFontDescriptor(font) );
}
void wxNativeFontInfo::InitFromFontDescriptor(CTFontDescriptorRef desc)
{
Init();
m_descriptor.reset(wxCFRetain(desc));
m_ctWeight = GetCTWeight(desc);
m_style = GetCTSlant(desc) > 0.01 ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL;
wxCFTypeRef(CTFontDescriptorCopyAttribute(desc, kCTFontSizeAttribute)).GetValue(m_ctSize, CGFloat(0.0));
// determine approximate family
CTFontSymbolicTraits symbolicTraits;
wxCFDictionaryRef traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute));
traits.GetValue(kCTFontSymbolicTrait).GetValue((int32_t*)&symbolicTraits, 0);
m_family = wxFONTFAMILY_DEFAULT;
if (symbolicTraits & kCTFontTraitMonoSpace)
m_family = wxFONTFAMILY_TELETYPE;
else
{
uint32_t stylisticClass = symbolicTraits & kCTFontTraitClassMask;
if (stylisticClass == kCTFontSansSerifClass)
m_family = wxFONTFAMILY_SWISS;
else if (stylisticClass == kCTFontScriptsClass)
m_family = wxFONTFAMILY_SCRIPT;
else if (stylisticClass == kCTFontOrnamentalsClass)
m_family = wxFONTFAMILY_DECORATIVE;
else if (stylisticClass == kCTFontSymbolicClass)
m_family = wxFONTFAMILY_DECORATIVE;
else
m_family = wxFONTFAMILY_ROMAN;
}
wxCFTypeRef(CTFontDescriptorCopyAttribute(desc, kCTFontStyleNameAttribute)).GetValue(m_styleName);
wxCFTypeRef(CTFontDescriptorCopyAttribute(desc, kCTFontFamilyNameAttribute)).GetValue(m_familyName);
}
void wxNativeFontInfo::Free()
{
m_descriptor.reset();
}
CTFontDescriptorRef wxNativeFontInfo::GetCTFontDescriptor() const
{
if ( !m_descriptor )
const_cast<wxNativeFontInfo *>(this)->CreateCTFontDescriptor();
return m_descriptor;
}
void wxNativeFontInfo::CreateCTFontDescriptor()
{
CTFontDescriptorRef descriptor = NULL;
wxCFMutableDictionaryRef attributes;
// build all attributes that define our font.
wxString fontfamilyname = m_familyName;
if ( fontfamilyname.empty() )
fontfamilyname = FamilyToFaceName(m_family);
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, wxCFStringRef(fontfamilyname));
wxCFMutableDictionaryRef traits;
if ( m_style != wxFONTSTYLE_NORMAL )
traits.SetValue(kCTFontSymbolicTrait, kCTFontItalicTrait);
traits.SetValue(kCTFontWeightTrait,m_ctWeight);
attributes.SetValue(kCTFontTraitsAttribute,traits.get());
attributes.SetValue(kCTFontSizeAttribute, m_ctSize);
// Create the font descriptor with our attributes
descriptor = CTFontDescriptorCreateWithAttributes(attributes);
wxASSERT(descriptor != NULL);
m_descriptor = descriptor;
}
// Core Text Helpers
CGFloat wxNativeFontInfo::GetCTWeight(CTFontRef font)
{
CGFloat weight;
CFTypeRef fonttraitstype = CTFontCopyAttribute(font, kCTFontTraitsAttribute);
wxCFDictionaryRef traits((CFDictionaryRef)fonttraitstype);
traits.GetValue(kCTFontWeightTrait).GetValue(&weight, CGFloat(0.0));
return weight;
}
CGFloat wxNativeFontInfo::GetCTWeight(CTFontDescriptorRef descr)
{
CGFloat weight;
CFTypeRef fonttraitstype = CTFontDescriptorCopyAttribute(descr, kCTFontTraitsAttribute);
wxCFDictionaryRef traits((CFDictionaryRef)fonttraitstype);
traits.GetValue(kCTFontWeightTrait).GetValue(&weight, CGFloat(0.0));
return weight;
}
CGFloat wxNativeFontInfo::GetCTSlant(CTFontDescriptorRef descr)
{
CGFloat slant;
CFTypeRef fonttraitstype = CTFontDescriptorCopyAttribute(descr, kCTFontTraitsAttribute);
wxCFDictionaryRef traits((CFDictionaryRef)fonttraitstype);
traits.GetValue(kCTFontSlantTrait).GetValue(&slant, CGFloat(0.0));
return slant;
}
//
bool wxNativeFontInfo::FromString(const wxString& s)
{
long l, version;
Init();
wxStringTokenizer tokenizer(s, wxT(";"));
wxString token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
version = l;
//
// Ignore the version for now
//
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
m_ctSize = (int)l;
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
m_family = (wxFontFamily)l;
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
m_style = (wxFontStyle)l;
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
m_ctWeight = WXWeightToCT(l);
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
m_underlined = l != 0;
if ( version == 0L )
{
m_strikethrough = false;
}
else
{
token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) )
return false;
m_strikethrough = l != 0;
}
m_familyName = tokenizer.GetNextToken();
#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 s;
s.Printf(wxT("%d;%d;%d;%d;%d;%d;%d;%s;%d"),
1, // version
GetPointSize(),
GetFamily(),
(int)GetStyle(),
(int)GetWeight(),
GetUnderlined(),
GetStrikethrough(),
GetFaceName().GetData(),
(int)GetEncoding());
return s;
}
float wxNativeFontInfo::GetFractionalPointSize() const
{
return m_ctSize;
}
wxFontStyle wxNativeFontInfo::GetStyle() const
{
return m_style;
}
int wxNativeFontInfo::GetNumericWeight() const
{
return CTWeightToWX(m_ctWeight /* GetCTWeight(m_descriptor)*/);
}
bool wxNativeFontInfo::GetUnderlined() const
{
return m_underlined;
}
wxString wxNativeFontInfo::GetFamilyName() const
{
return m_familyName;
}
wxString wxNativeFontInfo::GetStyleName() const
{
return m_styleName;
}
wxString wxNativeFontInfo::GetFaceName() const
{
#if wxDEBUG_LEVEL >= 2
// for debugging: show all different font names
wxCFRef<CTFontRef> font = CTFontCreateWithFontDescriptor(m_descriptor, 12, NULL);
wxString familyname;
wxCFTypeRef(CTFontDescriptorCopyAttribute(m_descriptor, kCTFontFamilyNameAttribute)).GetValue(familyname);
wxLogTrace(TRACE_CTFONT,"FontFamilyName: %s",familyname.c_str());
wxString name;
wxCFTypeRef(CTFontDescriptorCopyAttribute(m_descriptor, kCTFontNameAttribute)).GetValue(name);
wxLogTrace(TRACE_CTFONT,"FontName: %s",name.c_str());
wxString psname;
wxCFTypeRef(CTFontCopyPostScriptName(font)).GetValue(psname);
wxLogTrace(TRACE_CTFONT,"PostScriptName: %s",psname.c_str());
wxString fullname;
wxCFTypeRef(CTFontCopyFullName(font)).GetValue(fullname);
wxLogTrace(TRACE_CTFONT,"FullName: %s",fullname.c_str());
wxString display;
wxCFTypeRef(CTFontDescriptorCopyAttribute(m_descriptor, kCTFontDisplayNameAttribute)).GetValue(display);
wxLogTrace(TRACE_CTFONT,"DisplayName: %s",display.c_str());
wxString style;
wxCFTypeRef(CTFontDescriptorCopyAttribute(m_descriptor, kCTFontStyleNameAttribute)).GetValue(style);
wxLogTrace(TRACE_CTFONT,"StyleName: %s",style.c_str());
#endif
return m_familyName;
}
wxFontFamily wxNativeFontInfo::GetFamily() const
{
return m_family;
}
wxFontEncoding wxNativeFontInfo::GetEncoding() const
{
return m_encoding;
}
bool wxNativeFontInfo::GetStrikethrough() const
{
return m_strikethrough;
}
// changing the font descriptor
void wxNativeFontInfo::SetFractionalPointSize(float pointsize)
{
if (GetFractionalPointSize() != pointsize)
{
m_ctSize = pointsize;
if ( m_descriptor)
{
wxCFMutableDictionaryRef attributes;
attributes.SetValue(kCTFontSizeAttribute, wxCFNumberRef((CGFloat)pointsize));
m_descriptor.reset(CTFontDescriptorCreateCopyWithAttributes(m_descriptor, attributes));
}
}
}
void wxNativeFontInfo::SetStyle(wxFontStyle style_)
{
bool formerIsItalic = GetStyle() != wxFONTSTYLE_NORMAL;
bool newIsItalic = style_ != wxFONTSTYLE_NORMAL;
m_style = style_;
if (formerIsItalic != newIsItalic)
{
Free();
}
}
void wxNativeFontInfo::SetNumericWeight(int weight)
{
int formerWeight = GetNumericWeight();
if (formerWeight != weight)
{
Free();
m_ctWeight = WXWeightToCT(weight);
}
}
void wxNativeFontInfo::SetUnderlined(bool underlined)
{
m_underlined = underlined;
}
bool wxNativeFontInfo::SetFaceName(const wxString& facename)
{
if (GetFaceName() != facename)
{
Free();
m_familyName = facename;
}
return true;
}
void wxNativeFontInfo::SetFamily(wxFontFamily family)
{
Free();
m_familyName.clear();
m_family = family;
}
void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding)
{
wxUnusedVar(encoding);
}
void wxNativeFontInfo::SetStrikethrough(bool strikethrough)
{
m_strikethrough = strikethrough;
}
void wxNativeFontInfo::UpdateNamesMap(const wxString& familyName, CTFontDescriptorRef descr)
{
if (gs_FontFamilyToPSName.find(familyName) == gs_FontFamilyToPSName.end())
{
wxCFStringRef psName((CFStringRef)CTFontDescriptorCopyAttribute(descr, kCTFontNameAttribute));
gs_FontFamilyToPSName[familyName] = psName.AsString();
}
}
void wxNativeFontInfo::UpdateNamesMap(const wxString& familyName, CTFontRef font)
{
if (gs_FontFamilyToPSName.find(familyName) == gs_FontFamilyToPSName.end())
{
wxCFRef<CTFontDescriptorRef> descr(CTFontCopyFontDescriptor(font));
UpdateNamesMap(familyName, descr);
}
}