<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[174456] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/174456">174456</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2014-10-08 09:20:37 -0700 (Wed, 08 Oct 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Mac] We are spending a lot of time loading fonts when loading weather.com
https://bugs.webkit.org/show_bug.cgi?id=137454

Reviewed by Darin Adler.

We are spending a lot of time loading fonts when loading weather.com:
~4.2% of WebProcess's cpu time in FontCache::getCachedFrontData().
In particular, we are spending a lot of time doing font auto-activation
because we don't have the Open Sans fonts installed and weather.com is
trying to load those.

Before this patch, we were doing font auto-activation ~250 times when
loading weather.com, even though the site is loading ~10 distinct font
families.

This patch adds a cache of font families we already tried to
auto-activate so that we don't try again. This results in ~10 font
auto-activations when loading weather.com instead of 250. It reduces
the amount of time spent in getCachedFrontData() to 62.6ms from 276ms
(4.4x less) when loading weather.com.

No new tests, no behavior change.

* platform/graphics/mac/FontCacheMac.mm:
(WebCore::shouldAutoActivateFontIfNeeded):
(WebCore::FontCache::createFontPlatformData):
* platform/mac/WebFontCache.h:
* platform/mac/WebFontCache.mm:
(+[WebFontCache fontWithFamily:traits:weight:size:shouldAutoActivateIfNeeded:]):
(+[WebFontCache fontWithFamily:traits:weight:size:]):
(+[WebFontCache fontWithFamily:traits:size:]):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsmacFontCacheMacmm">trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmacWebFontCacheh">trunk/Source/WebCore/platform/mac/WebFontCache.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmacWebFontCachemm">trunk/Source/WebCore/platform/mac/WebFontCache.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (174455 => 174456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-10-08 16:18:03 UTC (rev 174455)
+++ trunk/Source/WebCore/ChangeLog        2014-10-08 16:20:37 UTC (rev 174456)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2014-10-08  Christophe Dumez  &lt;cdumez@apple.com&gt;
+
+        [Mac] We are spending a lot of time loading fonts when loading weather.com
+        https://bugs.webkit.org/show_bug.cgi?id=137454
+
+        Reviewed by Darin Adler.
+
+        We are spending a lot of time loading fonts when loading weather.com:
+        ~4.2% of WebProcess's cpu time in FontCache::getCachedFrontData().
+        In particular, we are spending a lot of time doing font auto-activation
+        because we don't have the Open Sans fonts installed and weather.com is
+        trying to load those.
+
+        Before this patch, we were doing font auto-activation ~250 times when
+        loading weather.com, even though the site is loading ~10 distinct font
+        families.
+
+        This patch adds a cache of font families we already tried to
+        auto-activate so that we don't try again. This results in ~10 font
+        auto-activations when loading weather.com instead of 250. It reduces
+        the amount of time spent in getCachedFrontData() to 62.6ms from 276ms
+        (4.4x less) when loading weather.com.
+
+        No new tests, no behavior change.
+
+        * platform/graphics/mac/FontCacheMac.mm:
+        (WebCore::shouldAutoActivateFontIfNeeded):
+        (WebCore::FontCache::createFontPlatformData):
+        * platform/mac/WebFontCache.h:
+        * platform/mac/WebFontCache.mm:
+        (+[WebFontCache fontWithFamily:traits:weight:size:shouldAutoActivateIfNeeded:]):
+        (+[WebFontCache fontWithFamily:traits:weight:size:]):
+        (+[WebFontCache fontWithFamily:traits:size:]):
+
</ins><span class="cx"> 2014-10-08  Darin Adler  &lt;darin@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: underlyingStringIsValid()
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsmacFontCacheMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm (174455 => 174456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm        2014-10-08 16:18:03 UTC (rev 174455)
+++ trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm        2014-10-08 16:20:37 UTC (rev 174456)
</span><span class="lines">@@ -39,9 +39,11 @@
</span><span class="cx"> #import &quot;WebFontCache.h&quot;
</span><span class="cx"> #import &lt;AppKit/AppKit.h&gt;
</span><span class="cx"> #import &lt;wtf/MainThread.h&gt;
</span><ins>+#import &lt;wtf/NeverDestroyed.h&gt;
</ins><span class="cx"> #import &lt;wtf/StdLibExtras.h&gt;
</span><ins>+#import &lt;wtf/Threading.h&gt;
+#import &lt;wtf/text/AtomicStringHash.h&gt;
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> // The &quot;void*&quot; parameter makes the function match the prototype for callbacks from callOnMainThread.
</span><span class="lines">@@ -88,6 +90,25 @@
</span><span class="cx">     return appKitFontWeight &gt;= 7;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool shouldAutoActivateFontIfNeeded(const AtomicString&amp; family)
+{
+#ifndef NDEBUG
+    // This cache is not thread safe so the following assertion is there to
+    // make sure this function is always called from the same thread.
+    static ThreadIdentifier initThreadId = currentThread();
+    ASSERT(currentThread() == initThreadId);
+#endif
+
+    static NeverDestroyed&lt;HashSet&lt;AtomicString&gt;&gt; knownFamilies;
+    static const unsigned maxCacheSize = 128;
+    ASSERT(knownFamilies.get().size() &lt;= maxCacheSize);
+    if (knownFamilies.get().size() == maxCacheSize)
+        knownFamilies.get().remove(knownFamilies.get().begin());
+
+    // Only attempt to auto-activate fonts once for performance reasons.
+    return knownFamilies.get().add(family).isNewEntry;
+}
+
</ins><span class="cx"> PassRefPtr&lt;SimpleFontData&gt; FontCache::systemFallbackForCharacters(const FontDescription&amp; description, const SimpleFontData* originalFontData, bool isPlatformFont, const UChar* characters, int length)
</span><span class="cx"> {
</span><span class="cx">     UChar32 character;
</span><span class="lines">@@ -203,7 +224,7 @@
</span><span class="cx">     NSInteger weight = toAppKitFontWeight(fontDescription.weight());
</span><span class="cx">     float size = fontDescription.computedPixelSize();
</span><span class="cx"> 
</span><del>-    NSFont *nsFont = [WebFontCache fontWithFamily:family traits:traits weight:weight size:size];
</del><ins>+    NSFont *nsFont = [WebFontCache fontWithFamily:family traits:traits weight:weight size:size shouldAutoActivateIfNeeded:shouldAutoActivateFontIfNeeded(family)];
</ins><span class="cx">     if (!nsFont)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacWebFontCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/WebFontCache.h (174455 => 174456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/WebFontCache.h        2014-10-08 16:18:03 UTC (rev 174455)
+++ trunk/Source/WebCore/platform/mac/WebFontCache.h        2014-10-08 16:20:37 UTC (rev 174456)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> // This interface exists so that third party products (like Silk) can patch in to an Obj-C method to manipulate WebKit's font caching/substitution.
</span><span class="cx"> WEBCORE_EXPORT @interface WebFontCache : NSObject
</span><ins>++ (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size shouldAutoActivateIfNeeded:(BOOL)shouldAutoActivateIfNeeded;
</ins><span class="cx"> + (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size;
</span><span class="cx"> + (void)getTraits:(Vector&lt;unsigned&gt;&amp;)traitsMasks inFamily:(NSString *)desiredFamily;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacWebFontCachemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/WebFontCache.mm (174455 => 174456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/WebFontCache.mm        2014-10-08 16:18:03 UTC (rev 174455)
+++ trunk/Source/WebCore/platform/mac/WebFontCache.mm        2014-10-08 16:20:37 UTC (rev 174456)
</span><span class="lines">@@ -276,10 +276,10 @@
</span><span class="cx">     return font;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-+ (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size
</del><ins>++ (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size shouldAutoActivateIfNeeded:(BOOL)shouldAutoActivateIfNeeded
</ins><span class="cx"> {
</span><span class="cx">     NSFont *font = [self internalFontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size];
</span><del>-    if (font)
</del><ins>+    if (font || !shouldAutoActivateIfNeeded)
</ins><span class="cx">         return font;
</span><span class="cx"> 
</span><span class="cx">     // Auto activate the font before looking for it a second time.
</span><span class="lines">@@ -289,10 +289,15 @@
</span><span class="cx">     return [self internalFontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>++ (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits weight:(int)desiredWeight size:(float)size
+{
+    return [self fontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size shouldAutoActivateIfNeeded:YES];
+}
+
</ins><span class="cx"> + (NSFont *)fontWithFamily:(NSString *)desiredFamily traits:(NSFontTraitMask)desiredTraits size:(float)size
</span><span class="cx"> {
</span><span class="cx">     int desiredWeight = (desiredTraits &amp; NSBoldFontMask) ? 9 : 5;
</span><del>-    return [self fontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size];
</del><ins>+    return [self fontWithFamily:desiredFamily traits:desiredTraits weight:desiredWeight size:size shouldAutoActivateIfNeeded:YES];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> @end
</span></span></pre>
</div>
</div>

</body>
</html>