From 68d0ea9dfb4b04e45413b2e11ecce6e54ca5ce10 Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 10 Sep 2024 19:21:20 +0100 Subject: [PATCH] Fonts: Avoid calling deprecated CTFontManagerRegisterGraphicsFont The main reason for removing this call is that this function is deprecated, and is no longer needed now that we keep our own cache of CTFonts that have been loaded from memory, and now that we no longer use CoreText text layouts. This also appears to fix an issue with garbled text which was occasionally seen when different versions of the same font were available, e.g. because differing versions of the font were simultaneously embedded as BinaryData and installed on the system. --- .../juce_graphics/native/juce_Fonts_mac.mm | 132 +++++++++++++----- 1 file changed, 97 insertions(+), 35 deletions(-) diff --git a/modules/juce_graphics/native/juce_Fonts_mac.mm b/modules/juce_graphics/native/juce_Fonts_mac.mm index f0f3ab58d4..15e06729be 100644 --- a/modules/juce_graphics/native/juce_Fonts_mac.mm +++ b/modules/juce_graphics/native/juce_Fonts_mac.mm @@ -51,21 +51,56 @@ class CoreTextTypeface final : public Typeface void add (CTFontRef ref) { const std::scoped_lock lock { mutex }; - CFUniquePtr cgFont { CTFontCopyGraphicsFont (ref, nullptr) }; - - if (CTFontManagerRegisterGraphicsFont (cgFont.get(), nullptr)) - map.emplace (ref, std::move (cgFont)); + set.emplace (addOwner (ref)); } void remove (CTFontRef ref) { const std::scoped_lock lock { mutex }; + set.erase (addOwner (ref)); + } - if (const auto iter = map.find (ref); iter != map.end()) + CFUniquePtr findMatch (const String& fontName, const String& fontStyle) const + { + const std::scoped_lock lock { mutex }; + + for (auto& item : set) { - CTFontManagerUnregisterGraphicsFont (iter->second.get(), nullptr); - map.erase (iter); + const auto keyAsString = [&] (auto key) + { + return String::fromCFString (CFUniquePtr { CTFontCopyName (item.get(), key) }.get()); + }; + + const auto family = keyAsString (kCTFontFamilyNameKey); + const auto style = keyAsString (kCTFontStyleNameKey); + + if (fontName == family && (style.isEmpty() || fontStyle.equalsIgnoreCase (style))) + return addOwner (item.get()); } + + return nullptr; + } + + std::vector> findAllStylesForFamily (const String& fontName) const + { + const std::scoped_lock lock { mutex }; + + std::vector> result; + + for (auto& item : set) + { + const auto keyAsString = [&] (auto key) + { + return String::fromCFString (CFUniquePtr { CTFontCopyName (item.get(), key) }.get()); + }; + + const auto family = keyAsString (kCTFontFamilyNameKey); + + if (fontName == family) + result.emplace_back (addOwner (item.get())); + } + + return result; } std::set getRegisteredFamilies() const @@ -73,9 +108,9 @@ class CoreTextTypeface final : public Typeface const std::scoped_lock lock { mutex }; std::set result; - for (const auto& item : map) + for (const auto& item : set) { - const CFUniquePtr family { CTFontCopyName (item.first, kCTFontFamilyNameKey) }; + const CFUniquePtr family { CTFontCopyName (item.get(), kCTFontFamilyNameKey) }; result.insert (String::fromCFString (family.get())); } @@ -83,7 +118,13 @@ class CoreTextTypeface final : public Typeface } private: - std::map> map; + static CFUniquePtr addOwner (CTFontRef reference) + { + CFRetain (reference); + return CFUniquePtr { reference }; + } + + std::set> set; mutable std::mutex mutex; }; @@ -94,35 +135,41 @@ class CoreTextTypeface final : public Typeface public: static Typeface::Ptr from (const Font& font) { - CFUniquePtr cfFontFamily (FontStyleHelpers::getConcreteFamilyName (font).toCFString()); + auto ctFont = [&]() -> CFUniquePtr + { + if (auto f = getRegistered().findMatch (font.getTypefaceName(), font.getTypefaceStyle())) + return f; - if (cfFontFamily == nullptr) - return {}; + CFUniquePtr cfFontFamily (FontStyleHelpers::getConcreteFamilyName (font).toCFString()); - CFUniquePtr cfFontStyle (findBestAvailableStyle (font).toCFString()); + if (cfFontFamily == nullptr) + return {}; - if (cfFontStyle == nullptr) - return {}; + CFUniquePtr cfFontStyle (findBestAvailableStyle (font).toCFString()); - CFStringRef keys[] { kCTFontFamilyNameAttribute, kCTFontStyleNameAttribute }; - CFTypeRef values[] { cfFontFamily.get(), cfFontStyle.get() }; + if (cfFontStyle == nullptr) + return {}; - CFUniquePtr fontDescAttributes (CFDictionaryCreate (nullptr, - (const void**) &keys, - (const void**) &values, - numElementsInArray (keys), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); + CFStringRef keys[] { kCTFontFamilyNameAttribute, kCTFontStyleNameAttribute }; + CFTypeRef values[] { cfFontFamily.get(), cfFontStyle.get() }; - if (fontDescAttributes == nullptr) - return {}; + CFUniquePtr fontDescAttributes (CFDictionaryCreate (nullptr, + (const void**) &keys, + (const void**) &values, + numElementsInArray (keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); - CFUniquePtr ctFontDescRef (CTFontDescriptorCreateWithAttributes (fontDescAttributes.get())); + if (fontDescAttributes == nullptr) + return {}; - if (ctFontDescRef == nullptr) - return {}; + CFUniquePtr ctFontDescRef (CTFontDescriptorCreateWithAttributes (fontDescAttributes.get())); - CFUniquePtr ctFont { CTFontCreateWithFontDescriptor (ctFontDescRef.get(), 1, nullptr) }; + if (ctFontDescRef == nullptr) + return {}; + + return CFUniquePtr { CTFontCreateWithFontDescriptor (ctFontDescRef.get(), 1, nullptr) }; + }(); if (ctFont == nullptr) return {}; @@ -231,6 +278,11 @@ public: return getRegistered().getRegisteredFamilies(); } + static std::vector> findRegisteredStylesForFamily (const String& family) + { + return getRegistered().findAllStylesForFamily (family); + } + ~CoreTextTypeface() override { getRegistered().remove (ctFont.get()); @@ -330,8 +382,6 @@ StringArray Font::findAllTypefaceNames() { StringArray names; - // The collection returned from CTFontCollectionCreateFromAvailableFonts doesn't include fonts registered by - // CTFontManagerRegisterGraphicsFont on iOS, so we need to keep track of registered fonts ourselves. auto nameSet = CoreTextTypeface::getRegisteredFamilies(); CFUniquePtr fontCollectionRef (CTFontCollectionCreateFromAvailableFonts (nullptr)); @@ -356,7 +406,14 @@ StringArray Font::findAllTypefaceStyles (const String& family) if (FontStyleHelpers::isPlaceholderFamilyName (family)) return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); - StringArray results; + std::set results; + + for (const auto& font : CoreTextTypeface::findRegisteredStylesForFamily (family)) + { + const CFUniquePtr descriptor (CTFontCopyFontDescriptor (font.get())); + const CFUniquePtr cfsFontStyle ((CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(), kCTFontStyleNameAttribute)); + results.insert (String::fromCFString (cfsFontStyle.get())); + } CFUniquePtr cfsFontFamily (family.toCFString()); CFStringRef keys[] { kCTFontFamilyNameAttribute }; @@ -376,11 +433,16 @@ StringArray Font::findAllTypefaceStyles (const String& family) { auto ctFontDescriptorRef = (CTFontDescriptorRef) CFArrayGetValueAtIndex (fontDescriptorArray.get(), i); CFUniquePtr cfsFontStyle ((CFStringRef) CTFontDescriptorCopyAttribute (ctFontDescriptorRef, kCTFontStyleNameAttribute)); - results.add (String::fromCFString (cfsFontStyle.get())); + results.insert (String::fromCFString (cfsFontStyle.get())); } } - return results; + StringArray stringArray; + + for (const auto& result : results) + stringArray.add (result); + + return stringArray; } struct DefaultFontNames