From 27047eb338a3040cc23318c786857cd1f3f4ebd5 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 27 Aug 2021 00:04:42 +0200 Subject: [PATCH 1/2] Cache system fonts in wxOSX Call CTFontCreateUIFontForLanguage() only once for every CTFontUIFontType value and cache the results, as it is expensive to do it every time wxSystemSettings::GetFont() is called. Closes #19191. This commit is best viewed ignoring whitespace-only changes. --- src/osx/carbon/font.cpp | 145 ++++++++++++++++++++++++++++++---------- 1 file changed, 109 insertions(+), 36 deletions(-) diff --git a/src/osx/carbon/font.cpp b/src/osx/carbon/font.cpp index 6102d0a815..2e0a063396 100644 --- a/src/osx/carbon/font.cpp +++ b/src/osx/carbon/font.cpp @@ -19,6 +19,7 @@ #include "wx/gdicmn.h" #include "wx/log.h" #include "wx/math.h" +#include "wx/module.h" #endif #include "wx/fontutil.h" @@ -29,6 +30,7 @@ #include "wx/osx/private.h" #include "wx/osx/private/available.h" +#include #include #include @@ -440,44 +442,115 @@ bool wxFont::Create(const wxNativeFontInfo& info) return true; } +// Module maintaining and, most importantly, cleaning up, a cache wxFontRefData +// objects corresponding to the system fonts, as recreating them every time is +// too expensive. +class wxOSXSystemFontsCacheModule : public wxModule +{ +public: + wxOSXSystemFontsCacheModule() { } + + bool OnInit() wxOVERRIDE + { + for ( auto& p: ms_systemFontsCache ) + p = nullptr; + + return true; + } + + void OnExit() wxOVERRIDE + { + for ( auto& p: ms_systemFontsCache ) + { + if ( p ) + { + p->DecRef(); + p = nullptr; + } + } + } + + // The returned pointer must be DecRef()'d by caller if non-null. + static wxFontRefData* Get(wxOSXSystemFont font) + { + wxCHECK(font != wxOSX_SYSTEM_FONT_NONE, nullptr); + + wxFontRefData*& cached = ms_systemFontsCache[font - 1]; + if ( !cached ) + { + CTFontUIFontType uifont; + switch (font) + { + // This case is unreachable because of the precondition check + // above and is only present to avoid -Wswitch warnings. + case wxOSX_SYSTEM_FONT_NONE: + wxFALLTHROUGH; + + 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; + case wxOSX_SYSTEM_FONT_FIXED: + uifont = kCTFontUIFontUserFixedPitch; + break; + + // Remember to update Cache array size when adding new cases to + // this switch statement! + } + wxCFRef ctfont(CTFontCreateUIFontForLanguage(uifont, 0.0, NULL)); + cached = new wxFontRefData(ctfont); + } + + cached->IncRef(); + + return cached; + } + +private: + // This relies on wxOSX_SYSTEM_FONT_FIXED being the last element of enum, + // which should rename true until a new enum element is added, at which + // stage we should get a warning about the missing case in the switch above + // and the size of this array will need to be modified when adding the new + // case. + // + // Notice that we don't need "+ 1" here because we never cache the font for + // wxOSX_SYSTEM_FONT_NONE which should be never used, so we use the index + // of "enum value - 1" in the cache. + using Cache = std::array; + + // Cache owns the pointers, i.e. calls DecRef() on them when it's destroyed. + static Cache ms_systemFontsCache; + + wxDECLARE_DYNAMIC_CLASS(wxOSXSystemFontsCacheModule); +}; + +wxIMPLEMENT_DYNAMIC_CLASS(wxOSXSystemFontsCacheModule, wxModule); + +wxOSXSystemFontsCacheModule::Cache wxOSXSystemFontsCacheModule::ms_systemFontsCache; + 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; - case wxOSX_SYSTEM_FONT_FIXED: - uifont = kCTFontUIFontUserFixedPitch; - break; - default: - break; - } - wxCFRef ctfont(CTFontCreateUIFontForLanguage(uifont, 0.0, NULL)); - m_refData = new wxFontRefData(ctfont); + m_refData = wxOSXSystemFontsCacheModule::Get(font); } #if wxOSX_USE_COCOA From 046fde85804824b68d2b9525b3b7cabc7a0f708b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 27 Aug 2021 00:08:18 +0200 Subject: [PATCH 2/2] Use non-deprecated CTFontUIFontType constants Use "new" (available since 10.5, for most part) values of the enum instead of the deprecated ones, which are still defined, but might not be in the future. No real changes. --- src/osx/carbon/font.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/osx/carbon/font.cpp b/src/osx/carbon/font.cpp index 2e0a063396..4535b3c9e6 100644 --- a/src/osx/carbon/font.cpp +++ b/src/osx/carbon/font.cpp @@ -487,28 +487,28 @@ public: wxFALLTHROUGH; case wxOSX_SYSTEM_FONT_NORMAL: - uifont = kCTFontSystemFontType; + uifont = kCTFontUIFontSystem; break; case wxOSX_SYSTEM_FONT_BOLD: - uifont = kCTFontEmphasizedSystemFontType; + uifont = kCTFontUIFontEmphasizedSystem; break; case wxOSX_SYSTEM_FONT_SMALL: - uifont = kCTFontSmallSystemFontType; + uifont = kCTFontUIFontSmallSystem; break; case wxOSX_SYSTEM_FONT_SMALL_BOLD: - uifont = kCTFontSmallEmphasizedSystemFontType; + uifont = kCTFontUIFontSmallEmphasizedSystem; break; case wxOSX_SYSTEM_FONT_MINI: - uifont = kCTFontMiniSystemFontType; + uifont = kCTFontUIFontMiniSystem; break; case wxOSX_SYSTEM_FONT_MINI_BOLD: - uifont = kCTFontMiniEmphasizedSystemFontType; + uifont = kCTFontUIFontMiniEmphasizedSystem; break; case wxOSX_SYSTEM_FONT_LABELS: - uifont = kCTFontLabelFontType; + uifont = kCTFontUIFontLabel; break; case wxOSX_SYSTEM_FONT_VIEWS: - uifont = kCTFontViewsFontType; + uifont = kCTFontUIFontViews; break; case wxOSX_SYSTEM_FONT_FIXED: uifont = kCTFontUIFontUserFixedPitch;