They will be also needed in wxFontInfo soon, so move them there and use these functions from both wxFont and wxNativeFontInfo, as they can depend on wxFontInfo but not the other way round. No real changes.
1200 lines
29 KiB
C++
1200 lines
29 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,
|
|
wxFontWeight 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,
|
|
wxFontWeight 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,
|
|
wxFontWeight 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(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(float pointSize,
|
|
wxFontFamily family,
|
|
wxFontStyle style,
|
|
wxFontWeight weight,
|
|
bool underlined,
|
|
const wxString& faceName,
|
|
wxFontEncoding encoding)
|
|
{
|
|
UnRef();
|
|
|
|
m_refData = new wxFontRefData(pointSize, family, style, weight,
|
|
underlined, false, faceName, encoding);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxFont::Create(int pointSize,
|
|
wxFontFamily family,
|
|
wxFontStyle style,
|
|
wxFontWeight weight,
|
|
bool underlined,
|
|
const wxString& faceName,
|
|
wxFontEncoding encoding)
|
|
{
|
|
AccountForCompatValues(pointSize, style, weight);
|
|
|
|
return Create(wxFontInfo::ToFloatPointSize(pointSize),
|
|
family, style, weight, underlined, faceName, encoding);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|