Title: [175292] branches/safari-600.3-branch/Source/WebCore

Diff

Modified: branches/safari-600.3-branch/Source/WebCore/ChangeLog (175291 => 175292)


--- branches/safari-600.3-branch/Source/WebCore/ChangeLog	2014-10-29 00:29:58 UTC (rev 175291)
+++ branches/safari-600.3-branch/Source/WebCore/ChangeLog	2014-10-29 00:32:16 UTC (rev 175292)
@@ -1,5 +1,51 @@
 2014-10-28  Dana Burkart  <dburk...@apple.com>
 
+        Merge r174516. <rdar://problem/18640864>
+
+    2014-10-09  Chris Dumez  <cdu...@apple.com>
+    
+            [Mac] Spending too much time mapping desired font families to available ones
+            https://bugs.webkit.org/show_bug.cgi?id=137539
+    
+            Reviewed by Darin Adler.
+    
+            While profiling the load of weather.com, I noticed that we are spending
+            quite a bit of time trying to map the font family requested to a font
+            that is available on the system. The process involves:
+            1. Doing a linear search of all the installed font families and do a
+               case-insensitive string comparison for each of them until we find a
+               match,
+            2. Then, if we don't find a match, do another linear search of the
+               fonts' postscript names this time and do again a case-insensitive
+               string comparison for each of them.
+    
+            This process is costly and the fonts requested by weather.com are not
+            available, causing us to do 2 linear searches and a lot of string
+            comparisons (accounting for ~2% of the WebProcess CPU time for the page
+            load). As a result, we end up spending ~90ms in
+            internalFontWithFamily() when loading weather.com.
+    
+            This patch introduces a cache for the mapping between desired font
+            families and available font families. This cuts the time spent in
+            internalFontWithFamily() in half (~45ms). The cache gets invalidated
+            when fonts are installed / uninstalled on the system so we don't break
+            that scenario. The cache is also limited in size to avoid using too
+            much memory.
+    
+            No new tests, but manual testing making sure the cache gets invalidated
+            when installing a font on the system.
+    
+            * platform/graphics/mac/FontCacheMac.mm:
+            (WebCore::invalidateFontCache):
+            * platform/mac/WebFontCache.h:
+            * platform/mac/WebFontCache.mm:
+            (desiredFamilyToAvailableFamilyDictionary):
+            (rememberDesiredFamilyToAvailableFamilyMapping):
+            (+[WebFontCache internalFontWithFamily:traits:weight:size:]):
+            (+[WebFontCache invalidate]):
+    
+2014-10-28  Dana Burkart  <dburk...@apple.com>
+
         Merge r174457. <rdar://problem/18640864>
 
     2014-10-08  Chris Dumez  <cdu...@apple.com>

Modified: branches/safari-600.3-branch/Source/WebCore/platform/graphics/mac/FontCacheMac.mm (175291 => 175292)


--- branches/safari-600.3-branch/Source/WebCore/platform/graphics/mac/FontCacheMac.mm	2014-10-29 00:29:58 UTC (rev 175291)
+++ branches/safari-600.3-branch/Source/WebCore/platform/graphics/mac/FontCacheMac.mm	2014-10-29 00:32:16 UTC (rev 175292)
@@ -54,6 +54,7 @@
         return;
     }
     fontCache().invalidate();
+    [WebFontCache invalidate];
 }
 
 static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef)

Modified: branches/safari-600.3-branch/Source/WebCore/platform/mac/WebFontCache.h (175291 => 175292)


--- branches/safari-600.3-branch/Source/WebCore/platform/mac/WebFontCache.h	2014-10-29 00:29:58 UTC (rev 175291)
+++ branches/safari-600.3-branch/Source/WebCore/platform/mac/WebFontCache.h	2014-10-29 00:32:16 UTC (rev 175292)
@@ -32,6 +32,7 @@
 + (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size shouldAutoActivateIfNeeded:(BOOL)shouldAutoActivateIfNeeded;
 + (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size;
 + (void)getTraits:(Vector<unsigned>&)traitsMasks inFamily:(NSString *)desiredFamily;
++ (void)invalidate;
 
 // This older version of the interface is relied upon by some clients. WebCore doesn't use it.
 + (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits size:(float)size;

Modified: branches/safari-600.3-branch/Source/WebCore/platform/mac/WebFontCache.mm (175291 => 175292)


--- branches/safari-600.3-branch/Source/WebCore/platform/mac/WebFontCache.mm	2014-10-29 00:29:58 UTC (rev 175291)
+++ branches/safari-600.3-branch/Source/WebCore/platform/mac/WebFontCache.mm	2014-10-29 00:32:16 UTC (rev 175292)
@@ -35,6 +35,7 @@
 #import <AppKit/AppKit.h>
 #import <Foundation/Foundation.h>
 #import <math.h>
+#import <wtf/MainThread.h>
 
 using namespace WebCore;
 
@@ -115,6 +116,30 @@
                                    FontWeight900Mask));
 }
 
+// Keep a cache for mapping desired font families to font families actually
+// available on the system for performance.
+static NSMutableDictionary* desiredFamilyToAvailableFamilyDictionary()
+{
+    ASSERT(isMainThread());
+    static NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
+    return dictionary;
+}
+
+static inline void rememberDesiredFamilyToAvailableFamilyMapping(NSString* desiredFamily, 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];
+}
+
 @implementation WebFontCache
 
 + (void)getTraits:(Vector<unsigned>&)traitsMasks inFamily:(NSString *)desiredFamily
@@ -160,48 +185,55 @@
 // we then do a search based on the family names of the installed fonts.
 + (NSFont *)internalFontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size
 {
-
     if (stringIsCaseInsensitiveEqualToString(desiredFamily, @"-webkit-system-font")
         || stringIsCaseInsensitiveEqualToString(desiredFamily, @"-apple-system-font")) {
         // We ignore italic for system font.
         return (desiredWeight >= 7) ? [NSFont boldSystemFontOfSize:size] : [NSFont systemFontOfSize:size];
     }
 
-    NSFontManager *fontManager = [NSFontManager sharedFontManager];
-
-    // 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.
-    NSEnumerator *e = [[fontManager availableFontFamilies] objectEnumerator];
-    NSString *availableFamily;
-    while ((availableFamily = [e nextObject])) {
-        if ([desiredFamily caseInsensitiveCompare:availableFamily] == NSOrderedSame)
-            break;
+    id cachedAvailableFamily = [desiredFamilyToAvailableFamilyDictionary() objectForKey:desiredFamily];
+    if (cachedAvailableFamily == [NSNull null]) {
+        // We already know this font is not available.
+        return nil;
     }
 
+    NSFontManager *fontManager = [NSFontManager sharedFontManager];
+    NSString *availableFamily = cachedAvailableFamily;
     if (!availableFamily) {
-        // Match by PostScript name.
-        NSEnumerator *availableFonts = [[fontManager availableFonts] objectEnumerator];
-        NSString *availableFont;
-        NSFont *nameMatchedFont = nil;
-        NSFontTraitMask desiredTraitsForNameMatch = desiredTraits | (desiredWeight >= 7 ? NSBoldFontMask : 0);
-        while ((availableFont = [availableFonts nextObject])) {
-            if ([desiredFamily caseInsensitiveCompare:availableFont] == NSOrderedSame) {
-                nameMatchedFont = [NSFont fontWithName:availableFont size:size];
+        // 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.
+        for (availableFamily in [fontManager availableFontFamilies]) {
+            if ([desiredFamily caseInsensitiveCompare:availableFamily] == NSOrderedSame)
+                break;
+        }
 
-                // Special case Osaka-Mono.  According to <rdar://problem/3999467>, we need to 
-                // treat Osaka-Mono as fixed pitch.
-                if ([desiredFamily caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame && desiredTraitsForNameMatch == 0)
-                    return nameMatchedFont;
+        if (!availableFamily) {
+            // Match by PostScript name.
+            NSFont *nameMatchedFont = nil;
+            NSFontTraitMask desiredTraitsForNameMatch = desiredTraits | (desiredWeight >= 7 ? NSBoldFontMask : 0);
+            for (NSString *availableFont in [fontManager availableFonts]) {
+                if ([desiredFamily caseInsensitiveCompare:availableFont] == NSOrderedSame) {
+                    nameMatchedFont = [NSFont fontWithName:availableFont size:size];
 
-                NSFontTraitMask traits = [fontManager traitsOfFont:nameMatchedFont];
-                if ((traits & desiredTraitsForNameMatch) == desiredTraitsForNameMatch)
-                    return [fontManager convertFont:nameMatchedFont toHaveTrait:desiredTraitsForNameMatch];
+                    // Special case Osaka-Mono. According to <rdar://problem/3999467>, we need to
+                    // treat Osaka-Mono as fixed pitch.
+                    if ([desiredFamily caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame && !desiredTraitsForNameMatch)
+                        return nameMatchedFont;
 
-                availableFamily = [nameMatchedFont familyName];
-                break;
+                    NSFontTraitMask traits = [fontManager traitsOfFont:nameMatchedFont];
+                    if ((traits & desiredTraitsForNameMatch) == desiredTraitsForNameMatch)
+                        return [fontManager convertFont:nameMatchedFont toHaveTrait:desiredTraitsForNameMatch];
+
+                    availableFamily = [nameMatchedFont familyName];
+                    break;
+                }
             }
         }
+
+        rememberDesiredFamilyToAvailableFamilyMapping(desiredFamily, availableFamily);
+        if (!availableFamily)
+            return nil;
     }
 
     // Found a family, now figure out what weight and traits to use.
@@ -300,4 +332,8 @@
     return [self fontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size shouldAutoActivateIfNeeded:YES];
 }
 
++ (void)invalidate
+{
+    [desiredFamilyToAvailableFamilyDictionary() removeAllObjects];
+}
 @end
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to