[Cocoa] Expand system-ui to include every item in the Core Text cascade list
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Jun 2017 00:56:44 +0000 (00:56 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Jun 2017 00:56:44 +0000 (00:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173043
<rdar://problem/21125708>

Reviewed by Simon Fraser.

Source/WebCore:

The concept of the system font on Cocoa platforms represents the entire Core Text cascade list.
However, previously, WebKit only represented system-ui by pulling out the first item in the Core
Text cascade list. Instead, we should make all text rendered with "system-ui" match what the
platform would natively render.

Previously, we walked through the strings in the font-family property and looked them up one by
one. However, now we want to abstract this idea of a font family to possibly hold a
CTFontDescriptorRef instead of a string. This way, we expand a font-family list of ["fontA",
"system-ui", "fontB"] to ["fontA", ... a bunch of CTFontDescriptorRefs ..., "FontB"]. We can
then modify the consumer of this object to have two codepaths: the old string-based codepath,
and a new, platform-specific codepath which simply embeds the CTFontDesriptorRefs inside a Font
object.

We don't want to simply pull out the family name from each item in the Core Text fallback list
because that is a lossy translation. There is more information in these font descriptors which
cannot be represented by CSS. Therefore, we must keep the descriptors alive and add the new
codepath for them.

We also don't want to run the CSS font matching algorithm on each member of the Core Text
fallback list because it may yield different results from Core Text's font matching algorithm.
Our goal is to draw text as closely as possible to the system APIs. If we ran it, we may find
a font which is closer to the requested traits, but it would look out of place on the system.

This new codepath is only enabled on macOS High Sierra and iOS 11, because enabling it on all
operating systems would make fixing https://bugs.webkit.org/show_bug.cgi?id=173300 impossible.

Tests: fast/text/system-font-fallback-emoji.html
       fast/text/system-font-fallback.html
       fast/text/system-font-zero-size.html

* WebCore.xcodeproj/project.pbxproj:
* page/MemoryRelease.cpp:
(WebCore::releaseNoncriticalMemory):
* platform/graphics/FontCascadeFonts.cpp:
(WebCore::realizeNextFallback): The consumer of our new data type. Now uses WTF::visit().
(WebCore::FontCascadeFonts::realizeFallbackRangesAt): Now that the number of items to test
against the current character is larger than the number of strings in the font-family list,
we need to update the existing code to use the correct value.
* platform/graphics/FontDescription.cpp: Default implementation for non-Cocoa ports.
(WebCore::FontDescription::invalidateCaches):
(WebCore::FontCascadeDescription::effectiveFamilyCount):
(WebCore::FontCascadeDescription::effectiveFamilyAt):
* platform/graphics/FontDescription.h: Our new data type is a Variant of AtomicString and a
platform-specific class. Cocoa uses a class that holds a CTFontDescriptorRef and other ports
use an empty non-constructable class.
* platform/graphics/FontFamilySpecificationNull.h: Added. The empty non-constructable
class.
(WebCore::FontFamilySpecificationNull::fontRanges):
* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::fontCacheRegisteredFontsChangedNotificationCallback):
(WebCore::FontCache::platformInit): Changing the system language will change the system font
fallback list, so we need to listen to this notification. This also matters for
FontCache::systemFallbackForCharacters(), so we should build off the same callback we are
already using for font installation.
(WebCore::invalidateFontCache):
* platform/graphics/cocoa/FontDescriptionCocoa.cpp: Added. The platform-specific creation of
our CTFontDescriptorRefs. We hold them cached in a SystemFontDatabase.
(WebCore::SystemFontDatabase::CoreTextCascadeListParameters::CoreTextCascadeListParameters):
(WebCore::SystemFontDatabase::CoreTextCascadeListParameters::isHashTableDeletedValue):
(WebCore::SystemFontDatabase::CoreTextCascadeListParameters::operator==):
(WebCore::SystemFontDatabase::CoreTextCascadeListParameters::hash):
(WebCore::SystemFontDatabase::singleton):
(WebCore::SystemFontDatabase::systemFontCascadeList):
(WebCore::SystemFontDatabase::clear):
(WebCore::SystemFontDatabase::SystemFontDatabase):
(WebCore::SystemFontDatabase::applyWeightAndItalics):
(WebCore::SystemFontDatabase::removeCascadeList):
(WebCore::SystemFontDatabase::computeCascadeList):
(WebCore::SystemFontDatabase::CoreTextCascadeListParametersHash::hash):
(WebCore::SystemFontDatabase::CoreTextCascadeListParametersHash::equal):
(WebCore::isSystemFontString):
(WebCore::systemFontParameters):
(WebCore::FontDescription::invalidateCaches):
(WebCore::FontCascadeDescription::effectiveFamilyCount): We don't store the result of this
because it would probably be a bad idea to increase the size of every single FontCascade just
in case it might ask for the system font. Most fonts never mention system-ui. Because it's so
rare, we can just recalculate the result of this as necessary. This shouldn't be slow because
the results are cached.
(WebCore::FontCascadeDescription::effectiveFamilyAt):
* platform/graphics/cocoa/FontFamilySpecificationCoreText.cpp: Added.
(WebCore::FontFamilySpecificationCoreText::fontRanges): Create a FontRanges from a
CTFontDescriptorRef.
* platform/graphics/cocoa/FontFamilySpecificationCoreText.h: Added.
(WebCore::FontFamilySpecificationCoreText::FontFamilySpecificationCoreText):
* platform/graphics/ios/FontCacheIOS.mm:
(WebCore::platformFontWithFamilySpecialCase):
* platform/graphics/mac/FontCacheMac.mm:
(WebCore::platformFontWithFamilySpecialCase):

LayoutTests:

* fast/text/system-font-fallback-emoji-expected.txt: Added.
* fast/text/system-font-fallback-emoji.html: Added.
* fast/text/system-font-fallback-expected.html: Added.
* fast/text/system-font-fallback.html: Added.
* fast/text/system-font-zero-size-expected.txt: Added.
* fast/text/system-font-zero-size.html: Added.
* platform/ios/TestExpectations:
* platform/mac/TestExpectations:
* platform/mac/fast/text/international/system-language/system-font-punctuation-expected.png: Added.

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text/system-font-fallback-emoji-expected.txt [new file with mode: 0644]
LayoutTests/fast/text/system-font-fallback-emoji.html [new file with mode: 0644]
LayoutTests/fast/text/system-font-fallback-expected.html [new file with mode: 0644]
LayoutTests/fast/text/system-font-fallback.html [new file with mode: 0644]
LayoutTests/fast/text/system-font-zero-size-expected.txt [new file with mode: 0644]
LayoutTests/fast/text/system-font-zero-size.html [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
LayoutTests/platform/mac/TestExpectations
LayoutTests/platform/mac/fast/text/international/system-language/system-font-punctuation-expected.png [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/page/MemoryRelease.cpp
Source/WebCore/platform/graphics/FontCascadeFonts.cpp
Source/WebCore/platform/graphics/FontDescription.cpp
Source/WebCore/platform/graphics/FontDescription.h
Source/WebCore/platform/graphics/FontFamilySpecificationNull.h [new file with mode: 0644]
Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
Source/WebCore/platform/graphics/cocoa/FontDescriptionCocoa.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/cocoa/FontFamilySpecificationCoreText.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/cocoa/FontFamilySpecificationCoreText.h [new file with mode: 0644]
Source/WebCore/platform/graphics/ios/FontCacheIOS.mm
Source/WebCore/platform/graphics/mac/FontCacheMac.mm

index 70fd10b..780cc86 100644 (file)
@@ -1,3 +1,21 @@
+2017-06-15  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] Expand system-ui to include every item in the Core Text cascade list
+        https://bugs.webkit.org/show_bug.cgi?id=173043
+        <rdar://problem/21125708>
+
+        Reviewed by Simon Fraser.
+
+        * fast/text/system-font-fallback-emoji-expected.txt: Added.
+        * fast/text/system-font-fallback-emoji.html: Added.
+        * fast/text/system-font-fallback-expected.html: Added.
+        * fast/text/system-font-fallback.html: Added.
+        * fast/text/system-font-zero-size-expected.txt: Added.
+        * fast/text/system-font-zero-size.html: Added.
+        * platform/ios/TestExpectations:
+        * platform/mac/TestExpectations:
+        * platform/mac/fast/text/international/system-language/system-font-punctuation-expected.png: Added.
+
 2017-06-15  Matt Lewis  <jlewis3@apple.com>
 
         Marked webrtc/video-unmute.html as flaky.
diff --git a/LayoutTests/fast/text/system-font-fallback-emoji-expected.txt b/LayoutTests/fast/text/system-font-fallback-emoji-expected.txt
new file mode 100644 (file)
index 0000000..56f2e86
--- /dev/null
@@ -0,0 +1,12 @@
+This test makes sure that the system font draws emoji correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS systemFontTarget.offsetWidth is not 100
+PASS appleColorEmojiTarget.offsetWidth is 100
+PASS successfullyParsed is true
+
+TEST COMPLETE
+😊
+😊
diff --git a/LayoutTests/fast/text/system-font-fallback-emoji.html b/LayoutTests/fast/text/system-font-fallback-emoji.html
new file mode 100644 (file)
index 0000000..05bad52
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="font-size: 100px;">
+<div><span id="systemFontTarget" style="font-family: 'system-ui', 'AppleColorEmoji';">😊</span></div>
+<div><span id="appleColorEmojiTarget" style="font-family: 'AppleColorEmoji';">😊</span></div>
+</div>
+<script>
+description("This test makes sure that the system font draws emoji correctly.");
+var systemFontTarget = document.getElementById("systemFontTarget");
+var appleColorEmojiTarget = document.getElementById("appleColorEmojiTarget");
+shouldNotBe("systemFontTarget.offsetWidth", "100");
+shouldBe("appleColorEmojiTarget.offsetWidth", "100");
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/system-font-fallback-expected.html b/LayoutTests/fast/text/system-font-fallback-expected.html
new file mode 100644 (file)
index 0000000..38d79e2
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+This test makes sure that "system-ui" is expanded to every item in the platform fallback list. The test passes if all the lines below are rendered in the same font and identical.
+<div style="font-size: 100px;">
+<div style="font-family: 'Thonburi';">&#xE01;&#xE02;&#xE03;&#xE04;&#xE05;&#xE06;&#xE07;</div>
+<div style="font-family: 'Thonburi';">&#xE01;&#xE02;&#xE03;&#xE04;&#xE05;&#xE06;&#xE07;</div>
+<div style="font-family: 'Thonburi';">&#xE01;&#xE02;&#xE03;&#xE04;&#xE05;&#xE06;&#xE07;</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/system-font-fallback.html b/LayoutTests/fast/text/system-font-fallback.html
new file mode 100644 (file)
index 0000000..e769554
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+This test makes sure that "system-ui" is expanded to every item in the platform fallback list. The test passes if all the lines below are rendered in the same font and identical.
+<div style="font-size: 100px;">
+<div style="font-family: 'system-ui'            ;">&#xE01;&#xE02;&#xE03;&#xE04;&#xE05;&#xE06;&#xE07;</div>
+<div style="font-family: 'system-ui', 'Thonburi';">&#xE01;&#xE02;&#xE03;&#xE04;&#xE05;&#xE06;&#xE07;</div>
+<div style="font-family: 'system-ui', 'Ayuthaya';">&#xE01;&#xE02;&#xE03;&#xE04;&#xE05;&#xE06;&#xE07;</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/system-font-zero-size-expected.txt b/LayoutTests/fast/text/system-font-zero-size-expected.txt
new file mode 100644 (file)
index 0000000..afc798c
--- /dev/null
@@ -0,0 +1,4 @@
+This test makes sure that using the system font at 0px size doesn't crash. The test passes if there is no crash.
+Hello
+Hello
+Hello
diff --git a/LayoutTests/fast/text/system-font-zero-size.html b/LayoutTests/fast/text/system-font-zero-size.html
new file mode 100644 (file)
index 0000000..f7e9208
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+</head>
+<body>
+This test makes sure that using the system font at 0px size doesn't crash. The test passes if there is no crash.
+<div style="font: 0px 'system-ui';">Hello</div>
+<div style="font: 0px 'Times'; font-synthesis: none; font-weight: 0; font-stretch: 0%; font-style: italic;">Hello</div>
+<div style="font: 0px 'Times'; font-synthesis: none; font-weight: 0; font-stretch: 0%;">Hello</div>
+</body>
+</html>
index a36f7b6..a90b1da 100644 (file)
@@ -2837,3 +2837,6 @@ webkit.org/b/172610 media/ios/autoplay-only-in-main-document.html [ Skip ]
 webkit.org/b/172672 fast/events/before-unload-returnValue.html [ Skip ]
 
 webkit.org/b/168239 [ Release ] fast/css/target-fragment-match.html [ Pass Failure ]
+
+webkit.org/b/173328 fast/text/system-font-fallback-emoji.html [ Failure ]
+webkit.org/b/173328 fast/text/system-font-fallback.html [ ImageOnlyFailure ]
index 3cdce48..649ce34 100644 (file)
@@ -1595,3 +1595,6 @@ media/modern-media-controls/media-documents/media-document-video-ios-sizing.html
 webkit.org/b/170907 [ Debug ] imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/hkdf.worker.html [ Pass Failure Timeout ]
 
 webkit.org/b/172255 imported/w3c/web-platform-tests/html/browsers/windows/browsing-context.html [ Pass Failure ]
+
+webkit.org/b/173328 [ ElCapitan Sierra ] fast/text/system-font-fallback-emoji.html [ Failure ]
+webkit.org/b/173328 [ ElCapitan Sierra ] fast/text/system-font-fallback.html [ ImageOnlyFailure ]
diff --git a/LayoutTests/platform/mac/fast/text/international/system-language/system-font-punctuation-expected.png b/LayoutTests/platform/mac/fast/text/international/system-language/system-font-punctuation-expected.png
new file mode 100644 (file)
index 0000000..a313b1c
Binary files /dev/null and b/LayoutTests/platform/mac/fast/text/international/system-language/system-font-punctuation-expected.png differ
index 5407874..a7907d2 100644 (file)
@@ -1,3 +1,100 @@
+2017-06-15  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [Cocoa] Expand system-ui to include every item in the Core Text cascade list
+        https://bugs.webkit.org/show_bug.cgi?id=173043
+        <rdar://problem/21125708>
+
+        Reviewed by Simon Fraser.
+
+        The concept of the system font on Cocoa platforms represents the entire Core Text cascade list.
+        However, previously, WebKit only represented system-ui by pulling out the first item in the Core
+        Text cascade list. Instead, we should make all text rendered with "system-ui" match what the
+        platform would natively render.
+
+        Previously, we walked through the strings in the font-family property and looked them up one by
+        one. However, now we want to abstract this idea of a font family to possibly hold a
+        CTFontDescriptorRef instead of a string. This way, we expand a font-family list of ["fontA",
+        "system-ui", "fontB"] to ["fontA", ... a bunch of CTFontDescriptorRefs ..., "FontB"]. We can
+        then modify the consumer of this object to have two codepaths: the old string-based codepath,
+        and a new, platform-specific codepath which simply embeds the CTFontDesriptorRefs inside a Font
+        object.
+
+        We don't want to simply pull out the family name from each item in the Core Text fallback list
+        because that is a lossy translation. There is more information in these font descriptors which
+        cannot be represented by CSS. Therefore, we must keep the descriptors alive and add the new
+        codepath for them.
+
+        We also don't want to run the CSS font matching algorithm on each member of the Core Text
+        fallback list because it may yield different results from Core Text's font matching algorithm.
+        Our goal is to draw text as closely as possible to the system APIs. If we ran it, we may find
+        a font which is closer to the requested traits, but it would look out of place on the system.
+
+        This new codepath is only enabled on macOS High Sierra and iOS 11, because enabling it on all
+        operating systems would make fixing https://bugs.webkit.org/show_bug.cgi?id=173300 impossible.
+
+        Tests: fast/text/system-font-fallback-emoji.html
+               fast/text/system-font-fallback.html
+               fast/text/system-font-zero-size.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/MemoryRelease.cpp:
+        (WebCore::releaseNoncriticalMemory):
+        * platform/graphics/FontCascadeFonts.cpp:
+        (WebCore::realizeNextFallback): The consumer of our new data type. Now uses WTF::visit().
+        (WebCore::FontCascadeFonts::realizeFallbackRangesAt): Now that the number of items to test
+        against the current character is larger than the number of strings in the font-family list,
+        we need to update the existing code to use the correct value.
+        * platform/graphics/FontDescription.cpp: Default implementation for non-Cocoa ports.
+        (WebCore::FontDescription::invalidateCaches):
+        (WebCore::FontCascadeDescription::effectiveFamilyCount):
+        (WebCore::FontCascadeDescription::effectiveFamilyAt):
+        * platform/graphics/FontDescription.h: Our new data type is a Variant of AtomicString and a
+        platform-specific class. Cocoa uses a class that holds a CTFontDescriptorRef and other ports
+        use an empty non-constructable class.
+        * platform/graphics/FontFamilySpecificationNull.h: Added. The empty non-constructable
+        class.
+        (WebCore::FontFamilySpecificationNull::fontRanges):
+        * platform/graphics/cocoa/FontCacheCoreText.cpp:
+        (WebCore::fontCacheRegisteredFontsChangedNotificationCallback):
+        (WebCore::FontCache::platformInit): Changing the system language will change the system font
+        fallback list, so we need to listen to this notification. This also matters for
+        FontCache::systemFallbackForCharacters(), so we should build off the same callback we are
+        already using for font installation.
+        (WebCore::invalidateFontCache):
+        * platform/graphics/cocoa/FontDescriptionCocoa.cpp: Added. The platform-specific creation of
+        our CTFontDescriptorRefs. We hold them cached in a SystemFontDatabase.
+        (WebCore::SystemFontDatabase::CoreTextCascadeListParameters::CoreTextCascadeListParameters):
+        (WebCore::SystemFontDatabase::CoreTextCascadeListParameters::isHashTableDeletedValue):
+        (WebCore::SystemFontDatabase::CoreTextCascadeListParameters::operator==):
+        (WebCore::SystemFontDatabase::CoreTextCascadeListParameters::hash):
+        (WebCore::SystemFontDatabase::singleton):
+        (WebCore::SystemFontDatabase::systemFontCascadeList):
+        (WebCore::SystemFontDatabase::clear):
+        (WebCore::SystemFontDatabase::SystemFontDatabase):
+        (WebCore::SystemFontDatabase::applyWeightAndItalics):
+        (WebCore::SystemFontDatabase::removeCascadeList):
+        (WebCore::SystemFontDatabase::computeCascadeList):
+        (WebCore::SystemFontDatabase::CoreTextCascadeListParametersHash::hash):
+        (WebCore::SystemFontDatabase::CoreTextCascadeListParametersHash::equal):
+        (WebCore::isSystemFontString):
+        (WebCore::systemFontParameters):
+        (WebCore::FontDescription::invalidateCaches):
+        (WebCore::FontCascadeDescription::effectiveFamilyCount): We don't store the result of this
+        because it would probably be a bad idea to increase the size of every single FontCascade just
+        in case it might ask for the system font. Most fonts never mention system-ui. Because it's so
+        rare, we can just recalculate the result of this as necessary. This shouldn't be slow because
+        the results are cached.
+        (WebCore::FontCascadeDescription::effectiveFamilyAt):
+        * platform/graphics/cocoa/FontFamilySpecificationCoreText.cpp: Added.
+        (WebCore::FontFamilySpecificationCoreText::fontRanges): Create a FontRanges from a
+        CTFontDescriptorRef.
+        * platform/graphics/cocoa/FontFamilySpecificationCoreText.h: Added.
+        (WebCore::FontFamilySpecificationCoreText::FontFamilySpecificationCoreText):
+        * platform/graphics/ios/FontCacheIOS.mm:
+        (WebCore::platformFontWithFamilySpecialCase):
+        * platform/graphics/mac/FontCacheMac.mm:
+        (WebCore::platformFontWithFamilySpecialCase):
+
 2017-06-15  David Kilzer  <ddkilzer@apple.com>
 
         Revert: [iOS] Generate a simulated crash when the WebThread starts in MobileSafari
index 497dcb5..d3b5034 100644 (file)
                1C0939EA1A13E12900B788E5 /* CachedSVGFont.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C0939E81A13E12900B788E5 /* CachedSVGFont.cpp */; };
                1C0939EB1A13E12900B788E5 /* CachedSVGFont.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0939E91A13E12900B788E5 /* CachedSVGFont.h */; };
                1C09D0591E31C6A900725F18 /* libPAL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C09D0501E31C32900725F18 /* libPAL.a */; };
+               1C12AC2A1EE778AE0079E0A0 /* FontFamilySpecificationCoreText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C12AC281EE778AE0079E0A0 /* FontFamilySpecificationCoreText.cpp */; };
+               1C12AC2B1EE778AE0079E0A0 /* FontFamilySpecificationCoreText.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C12AC291EE778AE0079E0A0 /* FontFamilySpecificationCoreText.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               1C12AC2D1EE779950079E0A0 /* FontDescriptionCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C12AC2C1EE779950079E0A0 /* FontDescriptionCocoa.cpp */; };
                1C18DA58181AF6A500C4EF22 /* TextPainter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */; };
                1C18DA59181AF6A500C4EF22 /* TextPainter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C18DA57181AF6A500C4EF22 /* TextPainter.h */; };
                1C21E57C183ED1FF001C289D /* IOSurfacePool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C21E57A183ED1FF001C289D /* IOSurfacePool.cpp */; };
                1C0939E81A13E12900B788E5 /* CachedSVGFont.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedSVGFont.cpp; sourceTree = "<group>"; };
                1C0939E91A13E12900B788E5 /* CachedSVGFont.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedSVGFont.h; sourceTree = "<group>"; };
                1C09D04B1E31C32800725F18 /* PAL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = PAL.xcodeproj; path = PAL/PAL.xcodeproj; sourceTree = "<group>"; };
+               1C12AC281EE778AE0079E0A0 /* FontFamilySpecificationCoreText.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FontFamilySpecificationCoreText.cpp; sourceTree = "<group>"; };
+               1C12AC291EE778AE0079E0A0 /* FontFamilySpecificationCoreText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FontFamilySpecificationCoreText.h; sourceTree = "<group>"; };
+               1C12AC2C1EE779950079E0A0 /* FontDescriptionCocoa.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FontDescriptionCocoa.cpp; sourceTree = "<group>"; };
                1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextPainter.cpp; sourceTree = "<group>"; };
                1C18DA57181AF6A500C4EF22 /* TextPainter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPainter.h; sourceTree = "<group>"; };
                1C21E57A183ED1FF001C289D /* IOSurfacePool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IOSurfacePool.cpp; sourceTree = "<group>"; };
                                CD5D27751E8318E000D80A3D /* WebCoreDecompressionSession.mm */,
                                316BDB8A1E6E153000DE0D5A /* WebGPULayer.h */,
                                316BDB891E6E153000DE0D5A /* WebGPULayer.mm */,
+                               1C12AC281EE778AE0079E0A0 /* FontFamilySpecificationCoreText.cpp */,
+                               1C12AC291EE778AE0079E0A0 /* FontFamilySpecificationCoreText.h */,
+                               1C12AC2C1EE779950079E0A0 /* FontDescriptionCocoa.cpp */,
                        );
                        path = cocoa;
                        sourceTree = "<group>";
                                262391361A648CEE007251A3 /* ContentExtensionsDebugging.h in Headers */,
                                51FB67DC1AE6B82F00D06C5A /* ContentExtensionStyleSheet.h in Headers */,
                                A149786F1ABAF33800CEF7E4 /* ContentFilter.h in Headers */,
+                               1C12AC2B1EE778AE0079E0A0 /* FontFamilySpecificationCoreText.h in Headers */,
                                A14090FD1AA51E480091191A /* ContentFilterUnblockHandler.h in Headers */,
                                97C471DC12F925BD0086354B /* ContentSecurityPolicy.h in Headers */,
                                CE799FA41C6A503A0097B518 /* ContentSecurityPolicyDirective.h in Headers */,
                                4A6E9FC713C17D570046A7F8 /* FontTaggedSettings.cpp in Sources */,
                                1C3249111C6D6A3B007EDB32 /* FontVariantBuilder.cpp in Sources */,
                                4A0DA2FE129B241900AB61E1 /* FormAssociatedElement.cpp in Sources */,
+                               1C12AC2A1EE778AE0079E0A0 /* FontFamilySpecificationCoreText.cpp in Sources */,
                                D05CED290A40BB2C00C5AF38 /* FormatBlockCommand.cpp in Sources */,
                                7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */,
                                F50664F7157F52DC00AC226F /* FormController.cpp in Sources */,
                                CDCA98EB18B2C8EB00C12FF9 /* LegacyCDMPrivateMediaPlayer.cpp in Sources */,
                                CDE8B5F01A69778B00B4B66A /* LegacyCDMSessionClearKey.cpp in Sources */,
                                E4C3B1FC0F0E4170009693F6 /* LegacyTileCache.mm in Sources */,
+                               1C12AC2D1EE779950079E0A0 /* FontDescriptionCocoa.cpp in Sources */,
                                E4B65A5A132FAAF90070E7BE /* LegacyTileGrid.mm in Sources */,
                                E424A3A01330DF1E00CF6DC9 /* LegacyTileGridTile.mm in Sources */,
                                E4B65A5E132FADB60070E7BE /* LegacyTileLayer.mm in Sources */,
index 8108f65..795dec8 100644 (file)
@@ -60,6 +60,7 @@ static void releaseNoncriticalMemory()
     RenderTheme::singleton().purgeCaches();
 
     FontCache::singleton().purgeInactiveFontData();
+    FontDescription::invalidateCaches();
 
     clearWidthCaches();
 
index 286798e..84afbc1 100644 (file)
@@ -138,20 +138,28 @@ bool FontCascadeFonts::isLoadingCustomFonts() const
 
 static FontRanges realizeNextFallback(const FontCascadeDescription& description, unsigned& index, FontSelector* fontSelector)
 {
-    ASSERT(index < description.familyCount());
+    ASSERT(index < description.effectiveFamilyCount());
 
     auto& fontCache = FontCache::singleton();
-    while (index < description.familyCount()) {
-        const AtomicString& family = description.familyAt(index++);
-        if (family.isEmpty())
-            continue;
-        if (fontSelector) {
-            auto ranges = fontSelector->fontRangesForFamily(description, family);
-            if (!ranges.isNull())
-                return ranges;
-        }
-        if (auto font = fontCache.fontForFamily(description, family))
-            return FontRanges(WTFMove(font));
+    while (index < description.effectiveFamilyCount()) {
+        auto visitor = WTF::makeVisitor([&](const AtomicString& family) -> FontRanges {
+            if (family.isEmpty())
+                return FontRanges();
+            if (fontSelector) {
+                auto ranges = fontSelector->fontRangesForFamily(description, family);
+                if (!ranges.isNull())
+                    return ranges;
+            }
+            if (auto font = fontCache.fontForFamily(description, family))
+                return FontRanges(WTFMove(font));
+            return FontRanges();
+        }, [&](const FontFamilyPlatformSpecification& fontFamilySpecification) -> FontRanges {
+            return fontFamilySpecification.fontRanges(description);
+        });
+        const auto& currentFamily = description.effectiveFamilyAt(index++);
+        auto ranges = WTF::visit(visitor, currentFamily);
+        if (!ranges.isNull())
+            return ranges;
     }
     // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform.
     // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the
@@ -183,13 +191,13 @@ const FontRanges& FontCascadeFonts::realizeFallbackRangesAt(const FontCascadeDes
         return fontRanges;
     }
 
-    if (m_lastRealizedFallbackIndex < description.familyCount())
+    if (m_lastRealizedFallbackIndex < description.effectiveFamilyCount())
         fontRanges = realizeNextFallback(description, m_lastRealizedFallbackIndex, m_fontSelector.get());
 
     if (fontRanges.isNull() && m_fontSelector) {
-        ASSERT(m_lastRealizedFallbackIndex >= description.familyCount());
+        ASSERT(m_lastRealizedFallbackIndex >= description.effectiveFamilyCount());
 
-        unsigned fontSelectorFallbackIndex = m_lastRealizedFallbackIndex - description.familyCount();
+        unsigned fontSelectorFallbackIndex = m_lastRealizedFallbackIndex - description.effectiveFamilyCount();
         if (fontSelectorFallbackIndex == m_fontSelector->fallbackFontCount())
             return fontRanges;
         ++m_lastRealizedFallbackIndex;
index 2c9eea5..3a94d8d 100644 (file)
@@ -97,6 +97,22 @@ FontCascadeDescription::FontCascadeDescription()
 {
 }
 
+#if !USE_PLATFORM_SYSTEM_FALLBACK_LIST
+void FontDescription::invalidateCaches()
+{
+}
+    
+unsigned FontCascadeDescription::effectiveFamilyCount() const
+{
+    return familyCount();
+}
+
+FontFamilySpecification FontCascadeDescription::effectiveFamilyAt(unsigned i) const
+{
+    return familyAt(i);
+}
+#endif
+
 FontSelectionValue FontCascadeDescription::lighterWeight(FontSelectionValue weight)
 {
     if (weight < FontSelectionValue(100))
index e28cbbc..693e992 100644 (file)
 #include <unicode/uscript.h>
 #include <wtf/MathExtras.h>
 #include <wtf/RefCountedArray.h>
+#include <wtf/Variant.h>
+
+#if PLATFORM(COCOA)
+#include "FontFamilySpecificationCoreText.h"
+#else
+#include "FontFamilySpecificationNull.h"
+#endif
 
 namespace WebCore {
 
+#if PLATFORM(COCOA)
+typedef FontFamilySpecificationCoreText FontFamilyPlatformSpecification;
+#else
+typedef FontFamilySpecificationNull FontFamilyPlatformSpecification;
+#endif
+
+#define USE_PLATFORM_SYSTEM_FALLBACK_LIST ((PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300))
+
+typedef Variant<AtomicString, FontFamilyPlatformSpecification> FontFamilySpecification;
+
 using namespace WebKitFontFamilyNames;
 
 class FontDescription {
@@ -132,6 +149,8 @@ public:
     void setOpticalSizing(FontOpticalSizing sizing) { m_opticalSizing = static_cast<unsigned>(sizing); }
     void setFontStyleAxis(FontStyleAxis axis) { m_fontStyleAxis = axis == FontStyleAxis::ital; }
 
+    static void invalidateCaches();
+
 private:
     // FIXME: Investigate moving these into their own object on the heap (to save memory).
     FontFeatureSettings m_featureSettings;
@@ -212,6 +231,9 @@ public:
     const AtomicString& firstFamily() const { return familyAt(0); }
     const AtomicString& familyAt(unsigned i) const { return m_families[i]; }
     const RefCountedArray<AtomicString>& families() const { return m_families; }
+    
+    unsigned effectiveFamilyCount() const;
+    FontFamilySpecification effectiveFamilyAt(unsigned) const;
 
     float specifiedSize() const { return m_specifiedSize; }
     bool isAbsoluteSize() const { return m_isAbsoluteSize; }
diff --git a/Source/WebCore/platform/graphics/FontFamilySpecificationNull.h b/Source/WebCore/platform/graphics/FontFamilySpecificationNull.h
new file mode 100644 (file)
index 0000000..89db226
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "FontSelector.h"
+
+namespace WebCore {
+
+class FontFamilySpecificationNull {
+public:
+    FontFamilySpecificationNull() = delete;
+    
+    FontRanges fontRanges(const FontDescription&) const
+    {
+        ASSERT_NOT_REACHED();
+        return FontRanges();
+    }
+};
+
+}
+
index 13e12e9..8b03058 100644 (file)
@@ -710,17 +710,25 @@ static float stretchFromCoreTextTraits(CFDictionaryRef traits)
 
 static void invalidateFontCache();
 
-static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef)
+static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void *, CFDictionaryRef)
 {
     ASSERT_UNUSED(observer, observer == &FontCache::singleton());
-    ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification));
 
     invalidateFontCache();
 }
 
 void FontCache::platformInit()
 {
-    CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately);
+    CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, &fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
+
+#if PLATFORM(MAC)
+    CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
+    const CFStringRef notificationName = kCFLocaleCurrentLocaleDidChangeNotification;
+#else
+    CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter();
+    const CFStringRef notificationName = CFSTR("com.apple.language.changed");
+#endif
+    CFNotificationCenterAddObserver(center, this, &fontCacheRegisteredFontsChangedNotificationCallback, notificationName, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
 }
 
 Vector<String> FontCache::systemFontFamilies()
@@ -1167,6 +1175,8 @@ static void invalidateFontCache()
         return;
     }
 
+    FontDescription::invalidateCaches();
+
     FontDatabase::singleton().clear();
 
     FontCache::singleton().invalidate();
diff --git a/Source/WebCore/platform/graphics/cocoa/FontDescriptionCocoa.cpp b/Source/WebCore/platform/graphics/cocoa/FontDescriptionCocoa.cpp
new file mode 100644 (file)
index 0000000..4f399f3
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontDescription.h"
+
+#include "CoreTextSPI.h"
+#include "FontFamilySpecificationCoreText.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashTraits.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/AtomicStringHash.h>
+
+#if USE_PLATFORM_SYSTEM_FALLBACK_LIST
+
+namespace WebCore {
+
+class SystemFontDatabase {
+public:
+    struct CoreTextCascadeListParameters {
+        CoreTextCascadeListParameters()
+        {
+        }
+        
+        CoreTextCascadeListParameters(WTF::HashTableDeletedValueType)
+            : locale(WTF::HashTableDeletedValue)
+        {
+        }
+        
+        bool isHashTableDeletedValue() const
+        {
+            return locale.isHashTableDeletedValue();
+        }
+        
+        bool operator==(const CoreTextCascadeListParameters& other) const
+        {
+            return locale == other.locale
+                && weight == other.weight
+                && size == other.size
+                && italic == other.italic;
+        }
+        
+        unsigned hash() const
+        {
+            IntegerHasher hasher;
+            hasher.add(locale.isNull() ? 0 : locale.existingHash());
+            hasher.add(weight);
+            hasher.add(size);
+            hasher.add(italic);
+            return hasher.hash();
+        }
+    
+        AtomicString locale;
+        CGFloat weight { 0 };
+        float size { 0 };
+        bool italic { false };
+    };
+    
+    static SystemFontDatabase& singleton()
+    {
+        static NeverDestroyed<SystemFontDatabase> database = SystemFontDatabase();
+        return database.get();
+    }
+    
+    Vector<RetainPtr<CTFontDescriptorRef>> systemFontCascadeList(const CoreTextCascadeListParameters& parameters)
+    {
+        auto createSystemFont = [&] {
+            auto localeString = parameters.locale.string().createCFString();
+            return std::make_pair(localeString, adoptCF(CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, parameters.size, localeString.get())));
+        };
+        
+        // Avoid adding an empty value to the hash map
+        if (!parameters.size) {
+            auto systemFont = createSystemFont().second;
+            auto descriptor = adoptCF(CTFontCopyFontDescriptor(systemFont.get()));
+            return { removeCascadeList(descriptor.get()) };
+        }
+        
+        return m_systemFontCache.ensure(parameters, [&] {
+            RetainPtr<CFStringRef> localeString;
+            RetainPtr<CTFontRef> systemFont;
+            std::tie(localeString, systemFont) = createSystemFont();
+            systemFont = applyWeightAndItalics(systemFont.get(), parameters.weight, parameters.italic, parameters.size);
+            return computeCascadeList(systemFont.get(), localeString.get());
+        }).iterator->value;
+    }
+    
+    void clear()
+    {
+        m_systemFontCache.clear();
+    }
+    
+private:
+    SystemFontDatabase()
+    {
+    }
+
+    static RetainPtr<CTFontRef> applyWeightAndItalics(CTFontRef font, CGFloat weight, bool italic, float size)
+    {
+        auto weightNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight));
+        const float systemFontItalicSlope = 0.07;
+        float italicsRawNumber = italic ? systemFontItalicSlope : 0;
+        auto italicsNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &italicsRawNumber));
+        CFTypeRef traitsKeys[] = { kCTFontWeightTrait, kCTFontSlantTrait, kCTFontUIFontDesignTrait };
+        CFTypeRef traitsValues[] = { weightNumber.get(), italicsNumber.get(), kCFBooleanTrue };
+        auto traitsDictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, traitsKeys, traitsValues, WTF_ARRAY_LENGTH(traitsKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+        CFTypeRef modificationKeys[] = { kCTFontTraitsAttribute };
+        CFTypeRef modificationValues[] = { traitsDictionary.get() };
+        auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, modificationKeys, modificationValues, WTF_ARRAY_LENGTH(modificationKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+        auto modification = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
+        return adoptCF(CTFontCreateCopyWithAttributes(font, size, nullptr, modification.get()));
+    }
+    
+    static RetainPtr<CTFontDescriptorRef> removeCascadeList(CTFontDescriptorRef fontDescriptor)
+    {
+        auto emptyArray = adoptCF(CFArrayCreate(kCFAllocatorDefault, nullptr, 0, &kCFTypeArrayCallBacks));
+        CFTypeRef fallbackDictionaryKeys[] = { kCTFontCascadeListAttribute };
+        CFTypeRef fallbackDictionaryValues[] = { emptyArray.get() };
+        auto fallbackDictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, fallbackDictionaryKeys, fallbackDictionaryValues, WTF_ARRAY_LENGTH(fallbackDictionaryKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+        auto modifiedFontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithAttributes(fontDescriptor, fallbackDictionary.get()));
+        return modifiedFontDescriptor;
+    }
+    
+    static Vector<RetainPtr<CTFontDescriptorRef>> computeCascadeList(CTFontRef font, CFStringRef locale)
+    {
+        CFTypeRef arrayValues[] = { locale };
+        auto localeArray = adoptCF(CFArrayCreate(kCFAllocatorDefault, arrayValues, WTF_ARRAY_LENGTH(arrayValues), &kCFTypeArrayCallBacks));
+        auto cascadeList = adoptCF(CTFontCopyDefaultCascadeListForLanguages(font, localeArray.get()));
+        Vector<RetainPtr<CTFontDescriptorRef>> result;
+        // WebKit handles the cascade list, and WebKit 2's IPC code doesn't know how to serialize Core Text's cascade list.
+        result.append(removeCascadeList(adoptCF(CTFontCopyFontDescriptor(font)).get()));
+        CFIndex arrayLength = CFArrayGetCount(cascadeList.get());
+        for (CFIndex i = 0; i < arrayLength; ++i)
+            result.append(static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(cascadeList.get(), i)));
+        return result;
+    }
+    
+    struct CoreTextCascadeListParametersHash : WTF::PairHash<AtomicString, float> {
+        static unsigned hash(const CoreTextCascadeListParameters& parameters)
+        {
+            return parameters.hash();
+        }
+        static bool equal(const CoreTextCascadeListParameters& a, const CoreTextCascadeListParameters& b)
+        {
+            return a == b;
+        }
+        static const bool safeToCompareToEmptyOrDeleted = true;
+    };
+    
+    HashMap<CoreTextCascadeListParameters, Vector<RetainPtr<CTFontDescriptorRef>>, CoreTextCascadeListParametersHash, SimpleClassHashTraits<CoreTextCascadeListParameters>> m_systemFontCache;
+};
+
+static inline bool isSystemFontString(const AtomicString& string)
+{
+    return equalLettersIgnoringASCIICase(string, "-webkit-system-font")
+        || equalLettersIgnoringASCIICase(string, "-apple-system")
+        || equalLettersIgnoringASCIICase(string, "-apple-system-font")
+        || equalLettersIgnoringASCIICase(string, "system-ui");
+}
+
+static inline SystemFontDatabase::CoreTextCascadeListParameters systemFontParameters(const FontCascadeDescription& description)
+{
+    SystemFontDatabase::CoreTextCascadeListParameters result;
+    result.locale = description.locale();
+    result.size = description.computedSize();
+    result.italic = isItalic(description.italic());
+    
+    auto weight = description.weight();
+    if (weight < FontSelectionValue(150))
+        result.weight = kCTFontWeightUltraLight;
+    else if (weight < FontSelectionValue(250))
+        result.weight = kCTFontWeightThin;
+    else if (weight < FontSelectionValue(350))
+        result.weight = kCTFontWeightLight;
+    else if (weight < FontSelectionValue(450))
+        result.weight = kCTFontWeightRegular;
+    else if (weight < FontSelectionValue(550))
+        result.weight = kCTFontWeightMedium;
+    else if (weight < FontSelectionValue(650))
+        result.weight = kCTFontWeightSemibold;
+    else if (weight < FontSelectionValue(750))
+        result.weight = kCTFontWeightBold;
+    else if (weight < FontSelectionValue(850))
+        result.weight = kCTFontWeightHeavy;
+    else
+        result.weight = kCTFontWeightBlack;
+        
+    return result;
+}
+
+void FontDescription::invalidateCaches()
+{
+    SystemFontDatabase::singleton().clear();
+}
+
+unsigned FontCascadeDescription::effectiveFamilyCount() const
+{
+    // FIXME: Move all the other system font keywords from platformFontWithFamilySpecialCase() to here.
+    unsigned result = 0;
+    for (unsigned i = 0; i < familyCount(); ++i) {
+        const auto& cssFamily = familyAt(i);
+        if (isSystemFontString(cssFamily))
+            result += SystemFontDatabase::singleton().systemFontCascadeList(systemFontParameters(*this)).size();
+        else
+            ++result;
+    }
+    return result;
+}
+
+FontFamilySpecification FontCascadeDescription::effectiveFamilyAt(unsigned index) const
+{
+    for (unsigned i = 0; i < familyCount(); ++i) {
+        const auto& cssFamily = familyAt(i);
+        if (isSystemFontString(cssFamily)) {
+            auto cascadeList = SystemFontDatabase::singleton().systemFontCascadeList(systemFontParameters(*this));
+            if (index < cascadeList.size())
+                return FontFamilySpecification(cascadeList[index].get());
+            index -= cascadeList.size();
+        } else if (!index)
+            return cssFamily;
+        else
+            --index;
+    }
+    ASSERT_NOT_REACHED();
+    return nullAtom;
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/cocoa/FontFamilySpecificationCoreText.cpp b/Source/WebCore/platform/graphics/cocoa/FontFamilySpecificationCoreText.cpp
new file mode 100644 (file)
index 0000000..217b5e3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontFamilySpecificationCoreText.h"
+
+#include "FontCache.h"
+
+namespace WebCore {
+
+FontRanges FontFamilySpecificationCoreText::fontRanges(const FontDescription& fontDescription) const
+{
+    auto size = fontDescription.computedSize();
+    
+    auto font = adoptCF(CTFontCreateWithFontDescriptor(m_fontDescriptor.get(), size, nullptr));
+
+    font = preparePlatformFont(font.get(), fontDescription, nullptr, nullptr, { }, fontDescription.computedSize());
+    
+    bool syntheticBold, syntheticOblique;
+    std::tie(syntheticBold, syntheticOblique) = computeNecessarySynthesis(font.get(), fontDescription).boldObliquePair();
+    
+    FontPlatformData fontPlatformData(font.get(), size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant(), fontDescription.textRenderingMode());
+    
+    return FontRanges(FontCache::singleton().fontForPlatformData(fontPlatformData));
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/cocoa/FontFamilySpecificationCoreText.h b/Source/WebCore/platform/graphics/cocoa/FontFamilySpecificationCoreText.h
new file mode 100644 (file)
index 0000000..e10bff8
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "FontSelector.h"
+#include <CoreText/CoreText.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+class FontFamilySpecificationCoreText {
+public:
+    FontFamilySpecificationCoreText(CTFontDescriptorRef fontDescriptor)
+        : m_fontDescriptor(fontDescriptor)
+    {
+    }
+    
+    FontRanges fontRanges(const FontDescription&) const;
+
+private:
+    RetainPtr<CTFontDescriptorRef> m_fontDescriptor;
+};
+
+}
index 74eadf1..9c0ae05 100644 (file)
@@ -80,6 +80,7 @@ Ref<Font> FontCache::lastResortFallbackFont(const FontDescription& fontDescripti
     return *fontForFamily(fontDescription, AtomicString(".PhoneFallback", AtomicString::ConstructFromLiteral));
 }
 
+#if !USE_PLATFORM_SYSTEM_FALLBACK_LIST
 static RetainPtr<CTFontDescriptorRef> baseSystemFontDescriptor(FontSelectionValue weight, bool bold, float size)
 {
     CTFontUIFontType fontType = kCTFontUIFontSystem;
@@ -142,6 +143,7 @@ static RetainPtr<CTFontDescriptorRef> systemFontDescriptor(FontSelectionValue we
     return fontDescriptor;
 #endif
 }
+#endif
 
 RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& family, FontSelectionRequest request, float size)
 {
@@ -156,7 +158,11 @@ RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& famil
     }
 
     if (equalLettersIgnoringASCIICase(family, "-webkit-system-font") || equalLettersIgnoringASCIICase(family, "-apple-system") || equalLettersIgnoringASCIICase(family, "-apple-system-font") || equalLettersIgnoringASCIICase(family, "system-ui")) {
+#if !USE_PLATFORM_SYSTEM_FALLBACK_LIST
         return adoptCF(CTFontCreateWithFontDescriptor(systemFontDescriptor(request.weight, isFontWeightBold(request.weight), isItalic(request.slope), size).get(), size, nullptr));
+#else
+        ASSERT_NOT_REACHED();
+#endif
     }
 
     if (equalLettersIgnoringASCIICase(family, "-apple-system-monospaced-numbers")) {
index f0779b0..2c33d45 100644 (file)
@@ -54,6 +54,7 @@ namespace WebCore {
 
 #if PLATFORM(MAC)
 
+#if !USE_PLATFORM_SYSTEM_FALLBACK_LIST
 static CGFloat toNSFontWeight(FontSelectionValue fontWeight)
 {
     if (fontWeight < FontSelectionValue(150))
@@ -74,10 +75,12 @@ static CGFloat toNSFontWeight(FontSelectionValue fontWeight)
         return NSFontWeightHeavy;
     return NSFontWeightBlack;
 }
+#endif
 
 RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& family, FontSelectionRequest request, float size)
 {
     if (equalLettersIgnoringASCIICase(family, "-webkit-system-font") || equalLettersIgnoringASCIICase(family, "-apple-system") || equalLettersIgnoringASCIICase(family, "-apple-system-font") || equalLettersIgnoringASCIICase(family, "system-ui")) {
+#if !USE_PLATFORM_SYSTEM_FALLBACK_LIST
         RetainPtr<CTFontRef> result = toCTFont([NSFont systemFontOfSize:size weight:toNSFontWeight(request.weight)]);
         if (isItalic(request.slope)) {
             CTFontSymbolicTraits desiredTraits = kCTFontItalicTrait;
@@ -87,6 +90,10 @@ RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& famil
                 result = italicizedFont;
         }
         return result;
+#else
+        UNUSED_PARAM(request);
+        ASSERT_NOT_REACHED();
+#endif
     }
 
     if (equalLettersIgnoringASCIICase(family, "-apple-system-monospaced-numbers")) {