Title: [225414] trunk
Revision
225414
Author
[email protected]
Date
2017-12-01 14:13:37 -0800 (Fri, 01 Dec 2017)

Log Message

Free FontFaceSets may include fonts that were never actually added to them
https://bugs.webkit.org/show_bug.cgi?id=180164

Reviewed by Simon Fraser.

Source/WebCore:

There are two circumstances where this can occur:

- If script makes a so-called "free" FontFaceSet, by using "new FontFaceSet". This object is not
associated with the document, and should therefore only include fonts which have been manually
added to it from script. However, today, this object includes preinstalled fonts which have the
same names as any fonts manually added to it. (So, if you manually add "Helvetica", the object
would have two objects - the one you just added and the preinstalled version too).

- For the document's FontFaceSet, the same thing would happen. This one is a little trickier
because the spec is not clear whether or not the document's FontFaceSet should include these
preinstalled fonts. However, running this test in Firefox and Chrome, they both agree that
preinstalled fonts should not be present, so this patch adheres to this behavior.

We can't actually remove the preinstalled fonts from the document's FontFaceSet (because that's
how normal font lookups are performed), but we can filter them out at the point they meet the
_javascript_ API. And, for "free" FontFaceSets, we can avoid adding them in the first place for
performance.

Test: fast/text/font-face-api-preinstalled.html

* css/CSSFontFaceSet.cpp:
(WebCore::CSSFontFaceSet::CSSFontFaceSet):
(WebCore::CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered):
(WebCore::CSSFontFaceSet::addToFacesLookupTable):
(WebCore::CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts):
(WebCore::CSSFontFaceSet::check):
(WebCore::CSSFontFaceSet::matchingFaces): Deleted.
* css/CSSFontFaceSet.h:
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::CSSFontSelector):
* css/FontFaceSet.cpp:
(WebCore::FontFaceSet::load):

LayoutTests:

* fast/text/font-face-api-preinstalled-expected.txt: Added.
* fast/text/font-face-api-preinstalled.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (225413 => 225414)


--- trunk/LayoutTests/ChangeLog	2017-12-01 22:12:01 UTC (rev 225413)
+++ trunk/LayoutTests/ChangeLog	2017-12-01 22:13:37 UTC (rev 225414)
@@ -1,3 +1,13 @@
+2017-12-01  Myles C. Maxfield  <[email protected]>
+
+        Free FontFaceSets may include fonts that were never actually added to them
+        https://bugs.webkit.org/show_bug.cgi?id=180164
+
+        Reviewed by Simon Fraser.
+
+        * fast/text/font-face-api-preinstalled-expected.txt: Added.
+        * fast/text/font-face-api-preinstalled.html: Added.
+
 2017-12-01  Ryan Haddad  <[email protected]>
 
         Update TestExpectations for various editing tests on iOS.

Added: trunk/LayoutTests/fast/text/font-face-api-preinstalled-expected.txt (0 => 225414)


--- trunk/LayoutTests/fast/text/font-face-api-preinstalled-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-api-preinstalled-expected.txt	2017-12-01 22:13:37 UTC (rev 225414)
@@ -0,0 +1,11 @@
+This test makes sure that preinstalled fonts are never returned from the CSS Font Loading API.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS result.length is 0
+PASS result.length is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/text/font-face-api-preinstalled.html (0 => 225414)


--- trunk/LayoutTests/fast/text/font-face-api-preinstalled.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-api-preinstalled.html	2017-12-01 22:13:37 UTC (rev 225414)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+window.jsTestIsAsync = true;
+
+description("This test makes sure that preinstalled fonts are never returned from the CSS Font Loading API.");
+var result;
+
+var fontFaceSet = new FontFaceSet([]);
+var fontFace = new FontFace("Helvetica", "url('../../resources/Ahem.ttf')", {unicodeRange: "U+10FFFF"});
+fontFaceSet.add(fontFace);
+fontFaceSet.load("16px Helvetica", "test").then(function(r) {
+    result = r;
+    shouldBe("result.length", "0");
+}).then(function() {
+    fontFaceSet = document.fonts;
+    fontFaceSet.add(fontFace);
+    return fontFaceSet.load("16px Helvetica", "test")
+}).then(function(r) {
+    result = r;
+    shouldBe("result.length", "0");
+    finishJSTest();
+}, function(result) {
+    testFailed("Load should be successful.");
+});
+</script>
+<script src=""
+</script>
+</div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (225413 => 225414)


--- trunk/Source/WebCore/ChangeLog	2017-12-01 22:12:01 UTC (rev 225413)
+++ trunk/Source/WebCore/ChangeLog	2017-12-01 22:13:37 UTC (rev 225414)
@@ -1,3 +1,43 @@
+2017-12-01  Myles C. Maxfield  <[email protected]>
+
+        Free FontFaceSets may include fonts that were never actually added to them
+        https://bugs.webkit.org/show_bug.cgi?id=180164
+
+        Reviewed by Simon Fraser.
+
+        There are two circumstances where this can occur:
+
+        - If script makes a so-called "free" FontFaceSet, by using "new FontFaceSet". This object is not
+        associated with the document, and should therefore only include fonts which have been manually
+        added to it from script. However, today, this object includes preinstalled fonts which have the
+        same names as any fonts manually added to it. (So, if you manually add "Helvetica", the object
+        would have two objects - the one you just added and the preinstalled version too).
+
+        - For the document's FontFaceSet, the same thing would happen. This one is a little trickier
+        because the spec is not clear whether or not the document's FontFaceSet should include these
+        preinstalled fonts. However, running this test in Firefox and Chrome, they both agree that 
+        preinstalled fonts should not be present, so this patch adheres to this behavior.
+
+        We can't actually remove the preinstalled fonts from the document's FontFaceSet (because that's
+        how normal font lookups are performed), but we can filter them out at the point they meet the
+        _javascript_ API. And, for "free" FontFaceSets, we can avoid adding them in the first place for
+        performance.
+
+        Test: fast/text/font-face-api-preinstalled.html
+
+        * css/CSSFontFaceSet.cpp:
+        (WebCore::CSSFontFaceSet::CSSFontFaceSet):
+        (WebCore::CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered):
+        (WebCore::CSSFontFaceSet::addToFacesLookupTable):
+        (WebCore::CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts):
+        (WebCore::CSSFontFaceSet::check):
+        (WebCore::CSSFontFaceSet::matchingFaces): Deleted.
+        * css/CSSFontFaceSet.h:
+        * css/CSSFontSelector.cpp:
+        (WebCore::CSSFontSelector::CSSFontSelector):
+        * css/FontFaceSet.cpp:
+        (WebCore::FontFaceSet::load):
+
 2017-12-01  Dean Jackson  <[email protected]>
 
         Attempted build fix.

Modified: trunk/Source/WebCore/css/CSSFontFaceSet.cpp (225413 => 225414)


--- trunk/Source/WebCore/css/CSSFontFaceSet.cpp	2017-12-01 22:12:01 UTC (rev 225413)
+++ trunk/Source/WebCore/css/CSSFontFaceSet.cpp	2017-12-01 22:13:37 UTC (rev 225414)
@@ -40,7 +40,8 @@
 
 namespace WebCore {
 
-CSSFontFaceSet::CSSFontFaceSet()
+CSSFontFaceSet::CSSFontFaceSet(CSSFontSelector* owningFontSelector)
+    : m_owningFontSelector(owningFontSelector)
 {
 }
 
@@ -98,6 +99,7 @@
 
 void CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered(const String& familyName)
 {
+    ASSERT(m_owningFontSelector);
     if (m_locallyInstalledFacesLookupTable.contains(familyName))
         return;
 
@@ -164,7 +166,8 @@
         if (addResult.isNewEntry) {
             // m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system.
             // This is by design.
-            ensureLocalFontFacesForFamilyRegistered(familyName);
+            if (m_owningFontSelector)
+                ensureLocalFontFacesForFamilyRegistered(familyName);
             familyFontFaces = { };
         }
 
@@ -328,7 +331,7 @@
     return result;
 }
 
-ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> CSSFontFaceSet::matchingFaces(const String& font, const String& string)
+ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> CSSFontFaceSet::matchingFacesExcludingPreinstalledFonts(const String& font, const String& string)
 {
     auto style = MutableStyleProperties::create();
     auto parseResult = CSSParser::parseValue(style, CSSPropertyFont, font, true, HTMLStandardMode);
@@ -360,6 +363,8 @@
             if (!faces)
                 continue;
             for (auto& constituentFace : faces->constituentFaces()) {
+                if (constituentFace->isLocalFallback())
+                    continue;
                 if (constituentFace->rangesMatchCodePoint(codePoint)) {
                     resultConstituents.add(constituentFace.ptr());
                     found = true;
@@ -380,7 +385,7 @@
 
 ExceptionOr<bool> CSSFontFaceSet::check(const String& font, const String& text)
 {
-    auto matchingFaces = this->matchingFaces(font, text);
+    auto matchingFaces = this->matchingFacesExcludingPreinstalledFonts(font, text);
     if (matchingFaces.hasException())
         return matchingFaces.releaseException();
 

Modified: trunk/Source/WebCore/css/CSSFontFaceSet.h (225413 => 225414)


--- trunk/Source/WebCore/css/CSSFontFaceSet.h	2017-12-01 22:12:01 UTC (rev 225413)
+++ trunk/Source/WebCore/css/CSSFontFaceSet.h	2017-12-01 22:13:37 UTC (rev 225414)
@@ -46,9 +46,9 @@
 
 class CSSFontFaceSet final : public RefCounted<CSSFontFaceSet>, public CSSFontFace::Client {
 public:
-    static Ref<CSSFontFaceSet> create()
+    static Ref<CSSFontFaceSet> create(CSSFontSelector* owningFontSelector = nullptr)
     {
-        return adoptRef(*new CSSFontFaceSet());
+        return adoptRef(*new CSSFontFaceSet(owningFontSelector));
     }
     ~CSSFontFaceSet();
 
@@ -75,7 +75,7 @@
 
     bool hasActiveFontFaces() { return status() == Status::Loading; }
 
-    ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> matchingFaces(const String& font, const String& text);
+    ExceptionOr<Vector<std::reference_wrapper<CSSFontFace>>> matchingFacesExcludingPreinstalledFonts(const String& font, const String& text);
 
     // CSSFontFace::Client needs to be able to be held in a RefPtr.
     void ref() final { RefCounted::ref(); }
@@ -82,7 +82,7 @@
     void deref() final { RefCounted::deref(); }
 
 private:
-    CSSFontFaceSet();
+    CSSFontFaceSet(CSSFontSelector*);
 
     void removeFromFacesLookupTable(const CSSFontFace&, const CSSValueList& familiesToSearchFor);
     void addToFacesLookupTable(CSSFontFace&);
@@ -107,6 +107,7 @@
     size_t m_facesPartitionIndex { 0 }; // All entries in m_faces before this index are CSS-connected.
     Status m_status { Status::Loaded };
     HashSet<CSSFontFaceSetClient*> m_clients;
+    CSSFontSelector* m_owningFontSelector;
     unsigned m_activeCount { 0 };
 };
 

Modified: trunk/Source/WebCore/css/CSSFontSelector.cpp (225413 => 225414)


--- trunk/Source/WebCore/css/CSSFontSelector.cpp	2017-12-01 22:12:01 UTC (rev 225413)
+++ trunk/Source/WebCore/css/CSSFontSelector.cpp	2017-12-01 22:13:37 UTC (rev 225414)
@@ -60,7 +60,7 @@
 
 CSSFontSelector::CSSFontSelector(Document& document)
     : m_document(&document)
-    , m_cssFontFaceSet(CSSFontFaceSet::create())
+    , m_cssFontFaceSet(CSSFontFaceSet::create(this))
     , m_beginLoadingTimer(*this, &CSSFontSelector::beginLoadTimerFired)
     , m_uniqueId(++fontSelectorId)
     , m_version(0)

Modified: trunk/Source/WebCore/css/FontFaceSet.cpp (225413 => 225414)


--- trunk/Source/WebCore/css/FontFaceSet.cpp	2017-12-01 22:12:01 UTC (rev 225413)
+++ trunk/Source/WebCore/css/FontFaceSet.cpp	2017-12-01 22:13:37 UTC (rev 225414)
@@ -125,7 +125,7 @@
 
 void FontFaceSet::load(const String& font, const String& text, LoadPromise&& promise)
 {
-    auto matchingFacesResult = m_backing->matchingFaces(font, text);
+    auto matchingFacesResult = m_backing->matchingFacesExcludingPreinstalledFonts(font, text);
     if (matchingFacesResult.hasException()) {
         promise.reject(matchingFacesResult.releaseException());
         return;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to