<!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>[187707] 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/187707">187707</a></dd>
<dt>Author</dt> <dd>mmaxfield@apple.com</dd>
<dt>Date</dt> <dd>2015-07-31 21:06:30 -0700 (Fri, 31 Jul 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsFontCachecpp">trunk/Source/WebCore/platform/graphics/FontCache.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsFontCacheh">trunk/Source/WebCore/platform/graphics/FontCache.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsmacFontCacheMacmm">trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformspicocoaCoreTextSPIh">trunk/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h</a></li>
<li><a href="#trunkSourceWebCoreplatformspimacNSFontSPIh">trunk/Source/WebCore/platform/spi/mac/NSFontSPI.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (187706 => 187707)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-08-01 03:41:07 UTC (rev 187706)
+++ trunk/Source/WebCore/ChangeLog        2015-08-01 04:06:30 UTC (rev 187707)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2015-07-31  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        [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:
+
</ins><span class="cx"> 2015-07-31  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Drop dummy Timer callbacks
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsFontCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/FontCache.cpp (187706 => 187707)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/FontCache.cpp        2015-08-01 03:41:07 UTC (rev 187706)
+++ trunk/Source/WebCore/platform/graphics/FontCache.cpp        2015-08-01 04:06:30 UTC (rev 187707)
</span><span class="lines">@@ -414,6 +414,7 @@
</span><span class="cx"> {
</span><span class="cx">     pruneUnreferencedEntriesFromFontCascadeCache();
</span><span class="cx">     pruneSystemFallbackFonts();
</span><ins>+    platformPurgeInactiveFontData();
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     FontLocker fontLocker;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsFontCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/FontCache.h (187706 => 187707)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/FontCache.h        2015-08-01 03:41:07 UTC (rev 187706)
+++ trunk/Source/WebCore/platform/graphics/FontCache.h        2015-08-01 04:06:30 UTC (rev 187707)
</span><span class="lines">@@ -150,6 +150,7 @@
</span><span class="cx">     WEBCORE_EXPORT size_t fontCount();
</span><span class="cx">     WEBCORE_EXPORT size_t inactiveFontCount();
</span><span class="cx">     WEBCORE_EXPORT void purgeInactiveFontData(unsigned count = UINT_MAX);
</span><ins>+    void platformPurgeInactiveFontData();
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(WIN)
</span><span class="cx">     RefPtr&lt;Font&gt; fontFromDescriptionAndLogFont(const FontDescription&amp;, const LOGFONT&amp;, AtomicString&amp; outFontFamilyName);
</span><span class="lines">@@ -184,6 +185,12 @@
</span><span class="cx">     friend class Font;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+#if !PLATFORM(MAC)
+inline void FontCache::platformPurgeInactiveFontData()
+{
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+}
+
</ins><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsmacFontCacheMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm (187706 => 187707)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm        2015-08-01 03:41:07 UTC (rev 187706)
+++ trunk/Source/WebCore/platform/graphics/mac/FontCacheMac.mm        2015-08-01 04:06:30 UTC (rev 187707)
</span><span class="lines">@@ -459,22 +459,54 @@
</span><span class="cx">     return knownFamilies.get().add(family).isNewEntry;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+typedef HashSet&lt;RetainPtr&lt;CTFontRef&gt;, WTF::RetainPtrObjectHash&lt;CTFontRef&gt;, WTF::RetainPtrObjectHashTraits&lt;CTFontRef&gt;&gt; FallbackDedupSet;
+static FallbackDedupSet&amp; fallbackDedupSet()
+{
+    static NeverDestroyed&lt;FallbackDedupSet&gt; dedupSet;
+    return dedupSet.get();
+}
+
+void FontCache::platformPurgeInactiveFontData()
+{
+    // This only has to be consistent throughout an individual layout or paint.
+    fallbackDedupSet().clear();
+}
+
+static inline RetainPtr&lt;CTFontRef&gt; lookupCTFont(CTFontRef font, float fontSize, const UChar* characters, unsigned length)
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED == 1090
+    if (!font) {
+        font = reinterpret_cast&lt;CTFontRef&gt;([NSFont userFontOfSize:fontSize]);
+        bool acceptable = true;
+        
+        RetainPtr&lt;CFCharacterSetRef&gt; 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, &amp;coveredLength));
+}
+
</ins><span class="cx"> RefPtr&lt;Font&gt; FontCache::systemFallbackForCharacters(const FontDescription&amp; description, const Font* originalFontData, bool isPlatformFont, const UChar* characters, unsigned length)
</span><span class="cx"> {
</span><del>-    UChar32 character;
-    U16_GET(characters, 0, 0, length, character);
</del><span class="cx">     const FontPlatformData&amp; platformData = originalFontData-&gt;platformData();
</span><span class="cx">     NSFont *nsFont = platformData.nsFont();
</span><ins>+    RetainPtr&lt;CTFontRef&gt; result = lookupCTFont(platformData.font(), platformData.size(), characters, length);
+    if (!result)
+        return nullptr;
</ins><span class="cx"> 
</span><del>-    NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast&lt;UChar*&gt;(characters) length:length freeWhenDone:NO];
-    NSFont *substituteFont = [NSFont findFontLike:nsFont forString:string withRange:NSMakeRange(0, [string length]) inLanguage:nil];
-    [string release];
</del><ins>+    // 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&lt;NSFont *&gt;(const_cast&lt;__CTFont*&gt;(fallbackDedupSet().add(result).iterator-&gt;get()));
</ins><span class="cx"> 
</span><del>-    if (!substituteFont &amp;&amp; length == 1)
-        substituteFont = [NSFont findFontLike:nsFont forCharacter:characters[0] inLanguage:nil];
-    if (!substituteFont)
-        return 0;
-
</del><span class="cx">     // Use the family name from the AppKit-supplied substitute font, requesting the
</span><span class="cx">     // traits, weight, and size we want. One way this does better than the original
</span><span class="cx">     // AppKit request is that it takes synthetic bold and oblique into account.
</span><span class="lines">@@ -508,6 +540,8 @@
</span><span class="cx"> 
</span><span class="cx">     if (traits != substituteFontTraits || weight != substituteFontWeight || !nsFont) {
</span><span class="cx">         if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size]) {
</span><ins>+            UChar32 character;
+            U16_GET(characters, 0, 0, length, character);
</ins><span class="cx">             if (!nsFont || (([fontManager traitsOfFont:bestVariation] != substituteFontTraits || [fontManager weightOfFont:bestVariation] != substituteFontWeight)
</span><span class="cx">                 &amp;&amp; [[bestVariation coveredCharacterSet] longCharacterIsMember:character]))
</span><span class="cx">                 substituteFont = bestVariation;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformspicocoaCoreTextSPIh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h (187706 => 187707)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h        2015-08-01 03:41:07 UTC (rev 187706)
+++ trunk/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h        2015-08-01 04:06:30 UTC (rev 187707)
</span><span class="lines">@@ -91,6 +91,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef);
</span><span class="cx"> CTFontRef CTFontCreateForCSS(CFStringRef name, uint16_t weight, CTFontSymbolicTraits, CGFloat size);
</span><ins>+CTFontRef CTFontCreateForCharactersWithLanguage(CTFontRef currentFont, const UTF16Char *characters, CFIndex length, CFStringRef language, CFIndex *coveredLength);
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101000
</span><span class="cx"> extern const CFStringRef kCTUIFontTextStyleShortHeadline;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformspimacNSFontSPIh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/spi/mac/NSFontSPI.h (187706 => 187707)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/spi/mac/NSFontSPI.h        2015-08-01 03:41:07 UTC (rev 187706)
+++ trunk/Source/WebCore/platform/spi/mac/NSFontSPI.h        2015-08-01 04:06:30 UTC (rev 187707)
</span><span class="lines">@@ -35,9 +35,6 @@
</span><span class="cx"> #else
</span><span class="cx"> 
</span><span class="cx"> @interface NSFont (Private)
</span><del>-+ (NSFont *)findFontLike:(NSFont *)aFont forCharacter:(UInt32)c inLanguage:(id) language;
-+ (NSFont *)findFontLike:(NSFont *)aFont forString:(NSString *)string withRange:(NSRange)range inLanguage:(id) language;
-
</del><span class="cx"> + (NSFont *)systemFontOfSize:(CGFloat)size weight:(CGFloat)weight;
</span><span class="cx"> @end
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>