[OS X] Migrate to CTFontCreateForCharactersWithLanguage from [NSFont findFontLike...
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Aug 2015 04:06:30 +0000 (04:06 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Aug 2015 04:06:30 +0000 (04:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147483

Reviewed by Dean Jackson.

[NSFont findFontLike:forString:withRange:inLanguage] doesn't properly handle its last argument. In
addition, we want to be moving away from NSFont in the first place and on to Core Text. This new
CoreText function correctly handles its language argument, which is required for language-specific
font fallback.

No new tests because there is no behavior change.

* platform/graphics/FontCache.cpp:
(WebCore::FontCache::purgeInactiveFontData):
* platform/graphics/FontCache.h:
(WebCore::FontCache::platformPurgeInactiveFontData):
* platform/graphics/mac/FontCacheMac.mm:
(WebCore::fallbackDedupSet):
(WebCore::FontCache::platformPurgeInactiveFontData):
(WebCore::lookupCTFont):
(WebCore::FontCache::systemFallbackForCharacters):
* platform/spi/cocoa/CoreTextSPI.h:
* platform/spi/mac/NSFontSPI.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@187707 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/FontCache.cpp
Source/WebCore/platform/graphics/FontCache.h
Source/WebCore/platform/graphics/mac/FontCacheMac.mm
Source/WebCore/platform/spi/cocoa/CoreTextSPI.h
Source/WebCore/platform/spi/mac/NSFontSPI.h

index a284bd0..ecc176c 100644 (file)
@@ -1,3 +1,29 @@
+2015-07-31  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [OS X] Migrate to CTFontCreateForCharactersWithLanguage from [NSFont findFontLike:forString:withRange:inLanguage]
+        https://bugs.webkit.org/show_bug.cgi?id=147483
+
+        Reviewed by Dean Jackson.
+
+        [NSFont findFontLike:forString:withRange:inLanguage] doesn't properly handle its last argument. In
+        addition, we want to be moving away from NSFont in the first place and on to Core Text. This new
+        CoreText function correctly handles its language argument, which is required for language-specific
+        font fallback.
+
+        No new tests because there is no behavior change.
+
+        * platform/graphics/FontCache.cpp:
+        (WebCore::FontCache::purgeInactiveFontData):
+        * platform/graphics/FontCache.h:
+        (WebCore::FontCache::platformPurgeInactiveFontData):
+        * platform/graphics/mac/FontCacheMac.mm:
+        (WebCore::fallbackDedupSet):
+        (WebCore::FontCache::platformPurgeInactiveFontData):
+        (WebCore::lookupCTFont):
+        (WebCore::FontCache::systemFallbackForCharacters):
+        * platform/spi/cocoa/CoreTextSPI.h:
+        * platform/spi/mac/NSFontSPI.h:
+
 2015-07-31  Chris Dumez  <cdumez@apple.com>
 
         Drop dummy Timer callbacks
index e8e02eb..a5cdd2e 100644 (file)
@@ -414,6 +414,7 @@ void FontCache::purgeInactiveFontData(unsigned purgeCount)
 {
     pruneUnreferencedEntriesFromFontCascadeCache();
     pruneSystemFallbackFonts();
+    platformPurgeInactiveFontData();
 
 #if PLATFORM(IOS)
     FontLocker fontLocker;
index 4acbe06..ea2a33c 100644 (file)
@@ -150,6 +150,7 @@ public:
     WEBCORE_EXPORT size_t fontCount();
     WEBCORE_EXPORT size_t inactiveFontCount();
     WEBCORE_EXPORT void purgeInactiveFontData(unsigned count = UINT_MAX);
+    void platformPurgeInactiveFontData();
 
 #if PLATFORM(WIN)
     RefPtr<Font> fontFromDescriptionAndLogFont(const FontDescription&, const LOGFONT&, AtomicString& outFontFamilyName);
@@ -184,6 +185,12 @@ private:
     friend class Font;
 };
 
+#if !PLATFORM(MAC)
+inline void FontCache::platformPurgeInactiveFontData()
+{
+}
+#endif
+
 }
 
 #endif
index 385f963..f6ffbbb 100644 (file)
@@ -459,21 +459,53 @@ static bool shouldAutoActivateFontIfNeeded(const AtomicString& family)
     return knownFamilies.get().add(family).isNewEntry;
 }
 
+typedef HashSet<RetainPtr<CTFontRef>, WTF::RetainPtrObjectHash<CTFontRef>, WTF::RetainPtrObjectHashTraits<CTFontRef>> FallbackDedupSet;
+static FallbackDedupSet& fallbackDedupSet()
+{
+    static NeverDestroyed<FallbackDedupSet> dedupSet;
+    return dedupSet.get();
+}
+
+void FontCache::platformPurgeInactiveFontData()
+{
+    // This only has to be consistent throughout an individual layout or paint.
+    fallbackDedupSet().clear();
+}
+
+static inline RetainPtr<CTFontRef> lookupCTFont(CTFontRef font, float fontSize, const UChar* characters, unsigned length)
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED == 1090
+    if (!font) {
+        font = reinterpret_cast<CTFontRef>([NSFont userFontOfSize:fontSize]);
+        bool acceptable = true;
+        
+        RetainPtr<CFCharacterSetRef> characterSet = adoptCF(CTFontCopyCharacterSet(font));
+        for (auto character : StringView(characters, length).codePoints()) {
+            if (!CFCharacterSetIsLongCharacterMember(characterSet.get(), character)) {
+                acceptable = false;
+                break;
+            }
+        }
+        if (acceptable)
+            return font;
+    }
+#endif
+    CFIndex coveredLength = 0;
+    return adoptCF(CTFontCreateForCharactersWithLanguage(font, characters, length, nullptr, &coveredLength));
+}
+
 RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font* originalFontData, bool isPlatformFont, const UChar* characters, unsigned length)
 {
-    UChar32 character;
-    U16_GET(characters, 0, 0, length, character);
     const FontPlatformData& platformData = originalFontData->platformData();
     NSFont *nsFont = platformData.nsFont();
+    RetainPtr<CTFontRef> result = lookupCTFont(platformData.font(), platformData.size(), characters, length);
+    if (!result)
+        return nullptr;
 
-    NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(characters) length:length freeWhenDone:NO];
-    NSFont *substituteFont = [NSFont findFontLike:nsFont forString:string withRange:NSMakeRange(0, [string length]) inLanguage:nil];
-    [string release];
-
-    if (!substituteFont && length == 1)
-        substituteFont = [NSFont findFontLike:nsFont forCharacter:characters[0] inLanguage:nil];
-    if (!substituteFont)
-        return 0;
+    // FontCascade::drawGlyphBuffer() requires that there are no duplicate Font objects which refer to the same thing. This is enforced in
+    // FontCache::fontForPlatformData(), where our equality check is based on hashing the FontPlatformData, whose hash includes the raw CoreText
+    // font pointer.
+    NSFont *substituteFont = reinterpret_cast<NSFont *>(const_cast<__CTFont*>(fallbackDedupSet().add(result).iterator->get()));
 
     // Use the family name from the AppKit-supplied substitute font, requesting the
     // traits, weight, and size we want. One way this does better than the original
@@ -508,6 +540,8 @@ RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& descr
 
     if (traits != substituteFontTraits || weight != substituteFontWeight || !nsFont) {
         if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size]) {
+            UChar32 character;
+            U16_GET(characters, 0, 0, length, character);
             if (!nsFont || (([fontManager traitsOfFont:bestVariation] != substituteFontTraits || [fontManager weightOfFont:bestVariation] != substituteFontWeight)
                 && [[bestVariation coveredCharacterSet] longCharacterIsMember:character]))
                 substituteFont = bestVariation;
index 9b04c2d..8d006a8 100644 (file)
@@ -91,6 +91,7 @@ CTFontDescriptorRef CTFontDescriptorCreateWithAttributesAndOptions(CFDictionaryR
 
 bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef);
 CTFontRef CTFontCreateForCSS(CFStringRef name, uint16_t weight, CTFontSymbolicTraits, CGFloat size);
+CTFontRef CTFontCreateForCharactersWithLanguage(CTFontRef currentFont, const UTF16Char *characters, CFIndex length, CFStringRef language, CFIndex *coveredLength);
 
 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
 extern const CFStringRef kCTUIFontTextStyleShortHeadline;
index a94f66b..f2b9341 100644 (file)
@@ -35,9 +35,6 @@
 #else
 
 @interface NSFont (Private)
-+ (NSFont *)findFontLike:(NSFont *)aFont forCharacter:(UInt32)c inLanguage:(id) language;
-+ (NSFont *)findFontLike:(NSFont *)aFont forString:(NSString *)string withRange:(NSRange)range inLanguage:(id) language;
-
 + (NSFont *)systemFontOfSize:(CGFloat)size weight:(CGFloat)weight;
 @end