Title: [184599] trunk
Revision
184599
Author
[email protected]
Date
2015-05-19 15:52:35 -0700 (Tue, 19 May 2015)

Log Message

[Mac] Font lookups are flakey due to caching
https://bugs.webkit.org/show_bug.cgi?id=145180
<rdar://problem/21012406>

Reviewed by Darin Adler.

Source/WebCore:

Font lookups were flakey on Mac due to the cache in fontWithFamily().
The reason is that the "desired family" to "available family" mapping
is sometimes dependent on the desired traits. However, our cache was
only using the "desired family" as key.

This patch now uses a std::pair as key containing both the "desired
family" and the "desired traits" for correctness. I also updated the
cache to use WTF types instead of NS types.

Test: platform/mac/fast/text/font-weights.html

* platform/graphics/mac/FontCacheMac.mm:
(WebCore::desiredFamilyToAvailableFamilyMap):
(WebCore::hasDesiredFamilyToAvailableFamilyMapping):
(WebCore::rememberDesiredFamilyToAvailableFamilyMapping):
(WebCore::fontWithFamily):
(WebCore::invalidateFontCache):
(WebCore::desiredFamilyToAvailableFamilyDictionary): Deleted.

LayoutTests:

* platform/mac/TestExpectations:
Unskip platform/mac/fast/text/font-weights.html as it is no longer
flakey after this change.

* platform/mac/fast/text/font-weights-expected.txt:
Rebaseline the test as the expected results were those based on the
bad caching behavior.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (184598 => 184599)


--- trunk/LayoutTests/ChangeLog	2015-05-19 22:22:51 UTC (rev 184598)
+++ trunk/LayoutTests/ChangeLog	2015-05-19 22:52:35 UTC (rev 184599)
@@ -1,3 +1,19 @@
+2015-05-19  Chris Dumez  <[email protected]>
+
+        [Mac] Font lookups are flakey due to caching
+        https://bugs.webkit.org/show_bug.cgi?id=145180
+        <rdar://problem/21012406>
+
+        Reviewed by Darin Adler.
+
+        * platform/mac/TestExpectations:
+        Unskip platform/mac/fast/text/font-weights.html as it is no longer
+        flakey after this change.
+
+        * platform/mac/fast/text/font-weights-expected.txt:
+        Rebaseline the test as the expected results were those based on the
+        bad caching behavior.
+
 2015-05-19  Brady Eidson  <[email protected]>
 
         X-Frame-Options headers not respected when loading from application cache.

Modified: trunk/LayoutTests/platform/mac/TestExpectations (184598 => 184599)


--- trunk/LayoutTests/platform/mac/TestExpectations	2015-05-19 22:22:51 UTC (rev 184598)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2015-05-19 22:52:35 UTC (rev 184599)
@@ -1262,4 +1262,3 @@
 webkit.org/b/142548 [ Yosemite+ ] editing/selection/extend-by-character-007.html [ Pass ]
 webkit.org/b/141661 [ Yosemite+ ] fast/text/emoji.html [ Pass ]
 
-webkit.org/b/145149 platform/mac/fast/text/font-weights.html [ Pass Failure ]

Modified: trunk/LayoutTests/platform/mac/fast/text/font-weights-expected.txt (184598 => 184599)


--- trunk/LayoutTests/platform/mac/fast/text/font-weights-expected.txt	2015-05-19 22:22:51 UTC (rev 184598)
+++ trunk/LayoutTests/platform/mac/fast/text/font-weights-expected.txt	2015-05-19 22:52:35 UTC (rev 184599)
@@ -451,17 +451,17 @@
         RenderText {#text} at (0,0) size 372x18
           text run at (0,0) width 372: "Font: HelveticaNeue-UltraLightItalic Weight: 100 Style: italic"
       RenderBlock {DIV} at (0,2834) size 769x18
-        RenderText {#text} at (0,0) size 407x18
-          text run at (0,0) width 407: "Font: HelveticaNeue-UltraLightItalic Weight: 200 Style: italic"
+        RenderText {#text} at (0,0) size 372x18
+          text run at (0,0) width 372: "Font: HelveticaNeue-UltraLightItalic Weight: 200 Style: italic"
       RenderBlock {DIV} at (0,2852) size 769x18
-        RenderText {#text} at (0,0) size 407x18
-          text run at (0,0) width 407: "Font: HelveticaNeue-UltraLightItalic Weight: 300 Style: italic"
+        RenderText {#text} at (0,0) size 372x18
+          text run at (0,0) width 372: "Font: HelveticaNeue-UltraLightItalic Weight: 300 Style: italic"
       RenderBlock {DIV} at (0,2870) size 769x18
-        RenderText {#text} at (0,0) size 424x18
-          text run at (0,0) width 424: "Font: HelveticaNeue-UltraLightItalic Weight: 400 Style: italic"
+        RenderText {#text} at (0,0) size 372x18
+          text run at (0,0) width 372: "Font: HelveticaNeue-UltraLightItalic Weight: 400 Style: italic"
       RenderBlock {DIV} at (0,2888) size 769x18
-        RenderText {#text} at (0,0) size 424x18
-          text run at (0,0) width 424: "Font: HelveticaNeue-UltraLightItalic Weight: 500 Style: italic"
+        RenderText {#text} at (0,0) size 372x18
+          text run at (0,0) width 372: "Font: HelveticaNeue-UltraLightItalic Weight: 500 Style: italic"
       RenderBlock {DIV} at (0,2906) size 769x19
         RenderText {#text} at (0,0) size 455x19
           text run at (0,0) width 455: "Font: HelveticaNeue-UltraLightItalic Weight: 600 Style: italic"
@@ -475,8 +475,8 @@
         RenderText {#text} at (0,0) size 455x19
           text run at (0,0) width 455: "Font: HelveticaNeue-UltraLightItalic Weight: 900 Style: italic"
       RenderBlock {DIV} at (0,2982) size 769x18
-        RenderText {#text} at (0,0) size 343x18
-          text run at (0,0) width 343: "Font: HelveticaNeue-LightItalic Weight: 100 Style: italic"
+        RenderText {#text} at (0,0) size 375x18
+          text run at (0,0) width 375: "Font: HelveticaNeue-LightItalic Weight: 100 Style: italic"
       RenderBlock {DIV} at (0,3000) size 769x18
         RenderText {#text} at (0,0) size 375x18
           text run at (0,0) width 375: "Font: HelveticaNeue-LightItalic Weight: 200 Style: italic"
@@ -484,11 +484,11 @@
         RenderText {#text} at (0,0) size 375x18
           text run at (0,0) width 375: "Font: HelveticaNeue-LightItalic Weight: 300 Style: italic"
       RenderBlock {DIV} at (0,3036) size 769x18
-        RenderText {#text} at (0,0) size 390x18
-          text run at (0,0) width 390: "Font: HelveticaNeue-LightItalic Weight: 400 Style: italic"
+        RenderText {#text} at (0,0) size 375x18
+          text run at (0,0) width 375: "Font: HelveticaNeue-LightItalic Weight: 400 Style: italic"
       RenderBlock {DIV} at (0,3054) size 769x18
-        RenderText {#text} at (0,0) size 390x18
-          text run at (0,0) width 390: "Font: HelveticaNeue-LightItalic Weight: 500 Style: italic"
+        RenderText {#text} at (0,0) size 375x18
+          text run at (0,0) width 375: "Font: HelveticaNeue-LightItalic Weight: 500 Style: italic"
       RenderBlock {DIV} at (0,3072) size 769x19
         RenderText {#text} at (0,0) size 418x19
           text run at (0,0) width 418: "Font: HelveticaNeue-LightItalic Weight: 600 Style: italic"
@@ -502,14 +502,14 @@
         RenderText {#text} at (0,0) size 418x19
           text run at (0,0) width 418: "Font: HelveticaNeue-LightItalic Weight: 900 Style: italic"
       RenderBlock {DIV} at (0,3148) size 769x18
-        RenderText {#text} at (0,0) size 313x18
-          text run at (0,0) width 313: "Font: HelveticaNeue-Italic Weight: 100 Style: italic"
+        RenderText {#text} at (0,0) size 355x18
+          text run at (0,0) width 355: "Font: HelveticaNeue-Italic Weight: 100 Style: italic"
       RenderBlock {DIV} at (0,3166) size 769x18
-        RenderText {#text} at (0,0) size 341x18
-          text run at (0,0) width 341: "Font: HelveticaNeue-Italic Weight: 200 Style: italic"
+        RenderText {#text} at (0,0) size 355x18
+          text run at (0,0) width 355: "Font: HelveticaNeue-Italic Weight: 200 Style: italic"
       RenderBlock {DIV} at (0,3184) size 769x18
-        RenderText {#text} at (0,0) size 341x18
-          text run at (0,0) width 341: "Font: HelveticaNeue-Italic Weight: 300 Style: italic"
+        RenderText {#text} at (0,0) size 355x18
+          text run at (0,0) width 355: "Font: HelveticaNeue-Italic Weight: 300 Style: italic"
       RenderBlock {DIV} at (0,3202) size 769x18
         RenderText {#text} at (0,0) size 355x18
           text run at (0,0) width 355: "Font: HelveticaNeue-Italic Weight: 400 Style: italic"

Modified: trunk/Source/WebCore/ChangeLog (184598 => 184599)


--- trunk/Source/WebCore/ChangeLog	2015-05-19 22:22:51 UTC (rev 184598)
+++ trunk/Source/WebCore/ChangeLog	2015-05-19 22:52:35 UTC (rev 184599)
@@ -1,3 +1,30 @@
+2015-05-19  Chris Dumez  <[email protected]>
+
+        [Mac] Font lookups are flakey due to caching
+        https://bugs.webkit.org/show_bug.cgi?id=145180
+        <rdar://problem/21012406>
+
+        Reviewed by Darin Adler.
+
+        Font lookups were flakey on Mac due to the cache in fontWithFamily().
+        The reason is that the "desired family" to "available family" mapping
+        is sometimes dependent on the desired traits. However, our cache was
+        only using the "desired family" as key.
+
+        This patch now uses a std::pair as key containing both the "desired
+        family" and the "desired traits" for correctness. I also updated the
+        cache to use WTF types instead of NS types.
+
+        Test: platform/mac/fast/text/font-weights.html
+
+        * platform/graphics/mac/FontCacheMac.mm:
+        (WebCore::desiredFamilyToAvailableFamilyMap):
+        (WebCore::hasDesiredFamilyToAvailableFamilyMapping):
+        (WebCore::rememberDesiredFamilyToAvailableFamilyMapping):
+        (WebCore::fontWithFamily):
+        (WebCore::invalidateFontCache):
+        (WebCore::desiredFamilyToAvailableFamilyDictionary): Deleted.
+
 2015-05-19  Brady Eidson  <[email protected]>
 
         X-Frame-Options headers not respected when loading from application cache.

Modified: trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm (184598 => 184599)


--- trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm	2015-05-19 22:22:51 UTC (rev 184598)
+++ trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm	2015-05-19 22:52:35 UTC (rev 184599)
@@ -129,31 +129,36 @@
                 FontWeight900Mask));
 }
 
-// Keep a cache for mapping desired font families to font families actually
-// available on the system for performance.
-static NSMutableDictionary* desiredFamilyToAvailableFamilyDictionary()
+#if !ENABLE(PLATFORM_FONT_LOOKUP)
+// Keep a cache for mapping desired font families to font families actually available on the system for performance.
+using AvailableFamilyMap = HashMap<std::pair<AtomicString, NSFontTraitMask>, AtomicString>;
+static AvailableFamilyMap& desiredFamilyToAvailableFamilyMap()
 {
     ASSERT(isMainThread());
-    static NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
-    return dictionary;
+    static NeverDestroyed<AvailableFamilyMap> map;
+    return map;
 }
 
-#if !ENABLE(PLATFORM_FONT_LOOKUP)
-static inline void rememberDesiredFamilyToAvailableFamilyMapping(NSString* desiredFamily, NSString* availableFamily)
+static bool hasDesiredFamilyToAvailableFamilyMapping(const AtomicString& desiredFamily, NSFontTraitMask desiredTraits, NSString*& availableFamily)
 {
-    static const NSUInteger maxCacheSize = 128;
-    NSMutableDictionary *familyMapping = desiredFamilyToAvailableFamilyDictionary();
-    ASSERT([familyMapping count] <= maxCacheSize);
-    if ([familyMapping count] == maxCacheSize) {
-        for (NSString *key in familyMapping) {
-            [familyMapping removeObjectForKey:key];
-            break;
-        }
-    }
-    id value = availableFamily ? availableFamily : [NSNull null];
-    [familyMapping setObject:value forKey:desiredFamily];
+    AtomicString value = desiredFamilyToAvailableFamilyMap().get(std::make_pair(desiredFamily, desiredTraits));
+    availableFamily = value.isEmpty() ? nil : static_cast<NSString*>(value);
+    return !value.isNull();
 }
 
+static inline void rememberDesiredFamilyToAvailableFamilyMapping(const AtomicString& desiredFamily, NSFontTraitMask desiredTraits, NSString* availableFamily)
+{
+    static const unsigned maxCacheSize = 128;
+    auto& familyMapping = desiredFamilyToAvailableFamilyMap();
+    ASSERT(familyMapping.size() <= maxCacheSize);
+    if (familyMapping.size() >= maxCacheSize)
+        familyMapping.remove(familyMapping.begin());
+
+    // Store nil as an emptyAtom to distinguish from missing values (nullAtom).
+    AtomicString value = availableFamily ? AtomicString(availableFamily) : emptyAtom;
+    familyMapping.add(std::make_pair(desiredFamily, desiredTraits), value);
+}
+
 #else
 
 static uint16_t toCoreTextFontWeight(FontWeight fontWeight)
@@ -262,7 +267,6 @@
         return specialCase.value();
 
     NSFontManager *fontManager = [NSFontManager sharedFontManager];
-    NSString *desiredFamily = family;
     NSString *availableFamily;
     int chosenWeight;
     NSFont *font;
@@ -277,20 +281,25 @@
         requestedTraits |= kCTFontItalicTrait;
     if (weight >= FontWeight600)
         requestedTraits |= kCTFontBoldTrait;
+
+    NSString *desiredFamily = family;
     font = CFBridgingRelease(CTFontCreateForCSS((CFStringRef)desiredFamily, toCoreTextFontWeight(weight), requestedTraits, size));
     availableFamily = [font familyName];
     chosenWeight = [fontManager weightOfFont:font];
 
 #else
 
-    id cachedAvailableFamily = [desiredFamilyToAvailableFamilyDictionary() objectForKey:desiredFamily];
-    if (cachedAvailableFamily == [NSNull null]) {
-        // We already know this font is not available.
-        return nil;
+    NSFontTraitMask desiredTraitsForNameMatch = desiredTraits | (weight >= FontWeight600 ? NSBoldFontMask : 0);
+    if (hasDesiredFamilyToAvailableFamilyMapping(family, desiredTraitsForNameMatch, availableFamily)) {
+        if (!availableFamily) {
+            // We already know the desired font family does not map to any available font family.
+            return nil;
+        }
     }
 
-    availableFamily = cachedAvailableFamily;
     if (!availableFamily) {
+        NSString *desiredFamily = family;
+
         // Do a simple case insensitive search for a matching font family.
         // NSFontManager requires exact name matches.
         // This addresses the problem of matching arial to Arial, etc., but perhaps not all the issues.
@@ -302,7 +311,6 @@
         if (!availableFamily) {
             // Match by PostScript name.
             NSFont *nameMatchedFont = nil;
-            NSFontTraitMask desiredTraitsForNameMatch = desiredTraits | (weight >= FontWeight600 ? NSBoldFontMask : 0);
             for (NSString *availableFont in [fontManager availableFonts]) {
                 if ([desiredFamily caseInsensitiveCompare:availableFont] == NSOrderedSame) {
                     nameMatchedFont = [NSFont fontWithName:availableFont size:size];
@@ -322,7 +330,7 @@
             }
         }
 
-        rememberDesiredFamilyToAvailableFamilyMapping(desiredFamily, availableFamily);
+        rememberDesiredFamilyToAvailableFamilyMapping(family, desiredTraitsForNameMatch, availableFamily);
         if (!availableFamily)
             return nil;
     }
@@ -406,7 +414,10 @@
         return;
     }
     FontCache::singleton().invalidate();
-    [desiredFamilyToAvailableFamilyDictionary() removeAllObjects];
+
+#if !ENABLE(PLATFORM_FONT_LOOKUP)
+    desiredFamilyToAvailableFamilyMap().clear();
+#endif
 }
 
 static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to