Smart pointers will clean up the resources automatically, there is no need to call Free() manually from the dtor.
1152 lines
28 KiB
C++
1152 lines
28 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(const wxFontInfo& info = wxFontInfo());
|
|
|
|
wxFontRefData(const wxFontRefData& data);
|
|
|
|
wxFontRefData(const wxNativeFontInfo& info)
|
|
: m_info(info)
|
|
{
|
|
}
|
|
|
|
wxFontRefData(CTFontRef font);
|
|
|
|
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:
|
|
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()
|
|
{
|
|
m_info = data.m_info;
|
|
m_ctFont = data.m_ctFont;
|
|
m_ctFontAttributes = data.m_ctFontAttributes;
|
|
m_cgFont = data.m_cgFont;
|
|
}
|
|
|
|
wxFontRefData::wxFontRefData(const wxFontInfo& info)
|
|
{
|
|
m_info.Init();
|
|
|
|
const wxString& faceName = info.GetFaceName();
|
|
if ( !faceName.empty() )
|
|
SetFaceName(faceName);
|
|
else
|
|
SetFamily(info.GetFamily());
|
|
|
|
m_info.SetSizeOrDefault(info.GetFractionalPointSize());
|
|
SetNumericWeight(info.GetNumericWeight());
|
|
SetStyle(info.GetStyle());
|
|
SetUnderlined(info.IsUnderlined());
|
|
SetStrikethrough(info.IsStrikethrough());
|
|
SetEncoding(info.GetEncoding());
|
|
}
|
|
|
|
void wxFontRefData::Free()
|
|
{
|
|
m_ctFont.reset();
|
|
m_ctFontAttributes.reset();
|
|
m_cgFont.reset();
|
|
}
|
|
|
|
wxFontRefData::wxFontRefData(CTFontRef font)
|
|
{
|
|
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);
|
|
|
|
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(pointSize).
|
|
Family(family).
|
|
Style(style).
|
|
Weight(GetNumericWeightOf(weight)).
|
|
Underlined(underlined).
|
|
FaceName(faceName).
|
|
Encoding(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);
|
|
}
|
|
}
|
|
|
|
|