Title: [196954] trunk
Revision
196954
Author
[email protected]
Date
2016-02-22 13:40:02 -0800 (Mon, 22 Feb 2016)

Log Message

[Font Loading] Split CSSFontSelector into a FontFaceSet implementation and the rest of the class
https://bugs.webkit.org/show_bug.cgi?id=153347

Reviewed by Antti Koivisto.

Source/WebCore:

This patch implements the document.fonts _javascript_ object. It does so by briding the
already-existing FontFaceSet _javascript_ object with the CSSFontSelector WebCore object.
CSSFontSelector used to hold internal objects for each @font-face object in the
Document. These objects have been moved into CSSFontFaceSet, so CSSFontSelector simply
just owns an instance of a CSSFontFaceSet.

The lifetime of the FontFace and FontFaceSet objects is a little interesting: because
all the ownership references are inside the WebCore CSSFontFace{,Set} objects, the
higher-level _javascript_ FontFace{,Set} objects are held through a WeakPtr. This means
that if all the references to these higher-level objects go away, and you re-query the
document for its FontFace objects, you may get a new object (albeit with the same
state as a previous object). However, this won't occur if there are any references to
the old object, which means it is almost not observable.

This patch doesn't implement the relationship between the CSSOM and the FontFace
objects. Changing one should result in a change in the other, but that will be
implemented in a forthcoming patch.

This patch also doesn't alter the lifetime of the CSSFontSelector, which means that all
the Document's fonts may be destroyed and recreated from CSS. There are a few things
which can trigger this. A subsequent patch will make the CSSFontSelector outlive the
Document.

This patch does implement (and test) the ability to add a new FontFace to the Document
to cause a relayout, as well as changing properties of existing FontFace objects already
in the Document to cause a relayout.

Test: fast/text/font-face-set-document.html

* Modules/fetch/FetchHeaders.cpp:
(WebCore::FetchHeaders::Iterator::next): Pass an extra argument.
* Modules/fetch/FetchHeaders.h:
* bindings/js/JSKeyValueIterator.h: The ExecState is necessary to build an external
wrapper from an existing CSSFontFace object.
(WebCore::JSKeyValueIterator<JSWrapper>::next):
* css/CSSFontFace.cpp:
(WebCore::CSSFontFace::appendSources): Moved from CSSFontSelector.
(WebCore::CSSFontFace::CSSFontFace):
(WebCore::CSSFontFace::notifyClientsOfFontPropertyChange):
(WebCore::CSSFontFace::setFamilies):
(WebCore::CSSFontFace::calculateStyle): Shared code between CSSFontFaceSet and
CSSFontFace.
(WebCore::CSSFontFace::setStyle): Update to use calculateStyle().
(WebCore::CSSFontFace::calculateWeight): Ditto.
(WebCore::CSSFontFace::setWeight): Update to use caculateWeight().
(WebCore::CSSFontFace::setUnicodeRange): Notify clients.
(WebCore::CSSFontFace::setVariantLigatures): Ditto.
(WebCore::CSSFontFace::setVariantPosition): Ditto.
(WebCore::CSSFontFace::setVariantCaps): Ditto.
(WebCore::CSSFontFace::setVariantNumeric): Ditto.
(WebCore::CSSFontFace::setVariantAlternates): Ditto.
(WebCore::CSSFontFace::setVariantEastAsian): Ditto.
(WebCore::CSSFontFace::setFeatureSettings): Ditto.
(WebCore::CSSFontFace::removeClient):
(WebCore::CSSFontFace::wrapper): Build a new wrapper if one doesn't already
exist. Note that this requires an ExecState to create a promise.
(WebCore::CSSFontFace::setStatus):
(WebCore::CSSFontFace::fontLoaded):
(WebCore::CSSFontFace::pump):
(WebCore::CSSFontFace::font):
* css/CSSFontFace.h:
* css/CSSFontFaceSet.cpp:
(WebCore::CSSFontFaceSet::CSSFontFaceSet): Moved code from CSSFontSelector.
(WebCore::CSSFontFaceSet::~CSSFontFaceSet):
(WebCore::CSSFontFaceSet::addClient): This object can now have multiple
clients.
(WebCore::CSSFontFaceSet::removeClient):
(WebCore::CSSFontFaceSet::incrementActiveCount): Update for multiple clients.
(WebCore::CSSFontFaceSet::decrementActiveCount): Ditto.
(WebCore::CSSFontFaceSet::hasFace):
(WebCore::CSSFontFaceSet::registerLocalFontFacesForFamily): Moved from
CSSFontSelector.
(WebCore::CSSFontFaceSet::familyNameFromPrimitive): Ditto.
(WebCore::CSSFontFaceSet::addToFacesLookupTable): This helper function can
be used when a property of a FontFace is changed.
(WebCore::CSSFontFaceSet::add): Update to use addToFacesLookupTable().
(WebCore::CSSFontFaceSet::removeFromFacesLookupTable): Same as
addToFacesLookupTable().
(WebCore::CSSFontFaceSet::remove): Update to use removeFromFacesLookupTable().
(WebCore::CSSFontFaceSet::clear):
(WebCore::CSSFontFaceSet::operator[]):
(WebCore::computeFontTraitsMask): Moved from CSSFontSelector.
(WebCore::CSSFontFaceSet::matchingFaces): Update to use new data structures.
(WebCore::FontFaceComparator::FontFaceComparator): Moved from
CSSFontSelector.
(WebCore::FontFaceComparator::operator()):
(WebCore::CSSFontFaceSet::getFontFace): Update to use new data structures.
(WebCore::CSSFontFaceSet::fontStateChanged): Update to use multiple clients.
(WebCore::CSSFontFaceSet::fontPropertyChanged): We must update our internal
data structure if the family name changed.
(WebCore::extractFamilies): Deleted.
(WebCore::familiesIntersect): Deleted.
(WebCore::CSSFontFaceSet::load): Deleted.
(WebCore::CSSFontFaceSet::stateChanged): Deleted.
* css/CSSFontFaceSet.h: Now needs to be RefCounted. New data structures are
taken from CSSFontSelector.
(WebCore::CSSFontFaceSetClient::faceFinished):
(WebCore::CSSFontFaceSetClient::fontModified):
(WebCore::CSSFontFaceSetClient::startedLoading):
(WebCore::CSSFontFaceSetClient::completedLoading):
* css/CSSFontFaceSource.h:
* css/CSSFontSelector.cpp: Move code into CSSFontFaceSet.
(WebCore::CSSFontSelector::CSSFontSelector):
(WebCore::CSSFontSelector::~CSSFontSelector):
(WebCore::CSSFontSelector::fontFaceSet):
(WebCore::CSSFontSelector::isEmpty):
(WebCore::CSSFontSelector::addFontFaceRule):
(WebCore::CSSFontSelector::fontModified):
(WebCore::CSSFontSelector::fontRangesForFamily):
(WebCore::CSSFontSelector::clearDocument):
(WebCore::CSSFontSelector::appendSources): Deleted.
(WebCore::CSSFontSelector::familyNameFromPrimitive): Deleted.
(WebCore::CSSFontSelector::registerLocalFontFacesForFamily): Deleted.
(WebCore::FontFaceComparator::FontFaceComparator): Deleted.
(WebCore::FontFaceComparator::operator()): Deleted.
(WebCore::CSSFontSelector::getFontFace): Deleted.
* css/CSSFontSelector.h:
* css/CSSSegmentedFontFace.cpp:
(WebCore::CSSSegmentedFontFace::CSSSegmentedFontFace):
* css/CSSSegmentedFontFace.h:
* css/FontFace.cpp:
(WebCore::FontFace::create):
(WebCore::FontFace::FontFace):
(WebCore::FontFace::createWeakPtr):
(WebCore::FontFace::fontStateChanged):
(WebCore::FontFace::stateChanged): Deleted.
* css/FontFace.h:
* css/FontFaceSet.cpp:
(WebCore::FontFaceSet::create):
(WebCore::FontFaceSet::FontFaceSet):
(WebCore::FontFaceSet::~FontFaceSet):
(WebCore::FontFaceSet::Iterator::next):
(WebCore::FontFaceSet::has):
(WebCore::FontFaceSet::size):
(WebCore::FontFaceSet::add):
(WebCore::FontFaceSet::remove):
(WebCore::FontFaceSet::clear):
(WebCore::FontFaceSet::load):
(WebCore::FontFaceSet::check):
(WebCore::FontFaceSet::status):
(WebCore::FontFaceSet::canSuspendForDocumentSuspension):
(WebCore::FontFaceSet::faceFinished):
* css/FontFaceSet.h:
* css/FontFaceSet.idl:
* dom/Document.cpp:
(WebCore::Document::fonts):
* dom/Document.h:
* dom/Document.idl:
* svg/SVGFontFaceElement.h:

LayoutTests:

* fast/text/font-face-_javascript_.html:
* fast/text/font-face-set-document-expected.txt: Added.
* fast/text/font-face-set-document.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (196953 => 196954)


--- trunk/LayoutTests/ChangeLog	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/LayoutTests/ChangeLog	2016-02-22 21:40:02 UTC (rev 196954)
@@ -1,3 +1,14 @@
+2016-02-22  Myles C. Maxfield  <[email protected]>
+
+        [Font Loading] Split CSSFontSelector into a FontFaceSet implementation and the rest of the class
+        https://bugs.webkit.org/show_bug.cgi?id=153347
+
+        Reviewed by Antti Koivisto.
+
+        * fast/text/font-face-_javascript_.html:
+        * fast/text/font-face-set-document-expected.txt: Added.
+        * fast/text/font-face-set-document.html: Added.
+
 2016-02-22  Konstantin Tokarev  <[email protected]>
 
         [JSC shell] Don't put empty arguments array to VM.

Modified: trunk/LayoutTests/fast/text/font-face-_javascript_.html (196953 => 196954)


--- trunk/LayoutTests/fast/text/font-face-_javascript_.html	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/LayoutTests/fast/text/font-face-_javascript_.html	2016-02-22 21:40:02 UTC (rev 196954)
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<html>
 <head>
 <script src=""
 </head>

Added: trunk/LayoutTests/fast/text/font-face-set-document-expected.txt (0 => 196954)


--- trunk/LayoutTests/fast/text/font-face-set-document-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-set-document-expected.txt	2016-02-22 21:40:02 UTC (rev 196954)
@@ -0,0 +1,24 @@
+PASS document.fonts.size is 2
+PASS object.done is false
+PASS object.value.family is "MyFont1"
+PASS object.done is false
+PASS object.value.family is "MyFont2"
+PASS object.done is true
+PASS fontFaceSet.size is 2
+PASS object.done is false
+PASS object.value.family is "MyFont1"
+PASS object.done is false
+PASS object.value.family is "MyFont2"
+PASS object.done is true
+PASS document.getElementById("testElement").offsetWidth is not originalWidth
+PASS document.getElementById("testElement").offsetWidth is originalWidth
+PASS object.length is 2
+PASS object[0].family is "MyFont3"
+PASS object[1].family is "MyFont3"
+PASS document.getElementById("testElement").offsetWidth is not originalWidth
+PASS document.getElementById("testElement").offsetWidth is originalWidth
+PASS successfullyParsed is true
+
+TEST COMPLETE
+On Load Executed.
+l

Added: trunk/LayoutTests/fast/text/font-face-set-document.html (0 => 196954)


--- trunk/LayoutTests/fast/text/font-face-set-document.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-set-document.html	2016-02-22 21:40:02 UTC (rev 196954)
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style id="styleElement">
+@font-face {
+    font-family: "MyFont1";
+    src: url("../../resources/Ahem.ttf") format("truetype");
+}
+@font-face {
+    font-family: "MyFont2";
+    src: url("../../resources/Ahem.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+<div id="onLoadElement"></div>
+<span id="testElement" style="font: 50px AppliedFont">l</span>
+<script>
+window._onload_ = function() {
+    document.getElementById("onLoadElement").innerText = "On Load Executed.";
+}
+var originalWidth = document.getElementById("testElement").offsetWidth;
+
+shouldBe("document.fonts.size", "2");
+var iterator = document.fonts.keys();
+var object = iterator.next();
+shouldBeFalse("object.done");
+shouldBeEqualToString("object.value.family", "MyFont1");
+object = iterator.next();
+shouldBeFalse("object.done");
+shouldBeEqualToString("object.value.family", "MyFont2");
+object = iterator.next();
+shouldBeTrue("object.done");
+
+var fontFaceSet = new FontFaceSet([]);
+fontFaceSet.add(new FontFace("MyFont2", "url(\"asdf\")", {}));
+fontFaceSet.add(document.fonts.keys().next().value);
+shouldBe("fontFaceSet.size", "2");
+iterator = fontFaceSet.keys();
+object = iterator.next();
+shouldBeFalse("object.done");
+shouldBeEqualToString("object.value.family", "MyFont1");
+object = iterator.next();
+shouldBeFalse("object.done");
+shouldBeEqualToString("object.value.family", "MyFont2");
+object = iterator.next();
+shouldBeTrue("object.done");
+
+iterator = undefined;
+object = undefined;
+
+self.jsTestIsAsync = true;
+function startLoading() {
+    var appliedFont = undefined;
+    document.fonts.keys().next().value.load().then(function() {
+        return document.fonts.keys().next().value.loaded;
+    }, function() {
+        testFailed("Loading should succeed.");
+        finishJSTest();
+    }).then(function() {
+        document.fonts.keys().next().value.family = "AppliedFont";
+        shouldNotBe("document.getElementById(\"testElement\").offsetWidth", "originalWidth");
+        document.fonts.keys().next().value.family = "MyFont1";
+        shouldBe("document.getElementById(\"testElement\").offsetWidth", "originalWidth");
+        document.fonts.add(new FontFace("MyFont3", "url(\"../../resources/Ahem.otf\")", {}));
+        return document.fonts.load("MyFont3");
+    }, function() {
+        testFailed("The same promise should not fail and then succeed.");
+        finishJSTest();
+    }).then(function() {
+        testFailed("Should not be able to parse as a font: property.");
+        finishJSTest();
+    }, function() {
+        document.fonts.add(new FontFace("MyFont3", "url(\"../../resources/Ahem.ttf\")", {'variant': 'small-caps'}));
+        return document.fonts.load("50px MyFont3");
+    }).then(function(x) {
+        object = x;
+        shouldBe("object.length", "2");
+        shouldBeEqualToString("object[0].family", "MyFont3");
+        shouldBeEqualToString("object[1].family", "MyFont3");
+        object = undefined;
+        appliedFont = new FontFace("AppliedFont", "url(\"../../resources/Ahem.otf\")", {});
+        document.fonts.add(appliedFont);
+        return appliedFont.loaded;
+    }, function() {
+        testFailed("Loading should succeed.");
+        finishJSTest();
+    }).then(function(x) {
+        shouldNotBe("document.getElementById(\"testElement\").offsetWidth", "originalWidth");
+        document.fonts.delete(appliedFont);
+        shouldBe("document.getElementById(\"testElement\").offsetWidth", "originalWidth");
+        finishJSTest();
+    }, function() {
+        testFailed("Loading should succeed.");
+        finishJSTest();
+    });
+}
+if (window.GCController)
+    window.GCController.collect();
+startLoading();
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (196953 => 196954)


--- trunk/Source/WebCore/ChangeLog	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/ChangeLog	2016-02-22 21:40:02 UTC (rev 196954)
@@ -1,3 +1,160 @@
+2016-02-22  Myles C. Maxfield  <[email protected]>
+
+        [Font Loading] Split CSSFontSelector into a FontFaceSet implementation and the rest of the class
+        https://bugs.webkit.org/show_bug.cgi?id=153347
+
+        Reviewed by Antti Koivisto.
+
+        This patch implements the document.fonts _javascript_ object. It does so by briding the
+        already-existing FontFaceSet _javascript_ object with the CSSFontSelector WebCore object.
+        CSSFontSelector used to hold internal objects for each @font-face object in the
+        Document. These objects have been moved into CSSFontFaceSet, so CSSFontSelector simply
+        just owns an instance of a CSSFontFaceSet.
+
+        The lifetime of the FontFace and FontFaceSet objects is a little interesting: because
+        all the ownership references are inside the WebCore CSSFontFace{,Set} objects, the
+        higher-level _javascript_ FontFace{,Set} objects are held through a WeakPtr. This means
+        that if all the references to these higher-level objects go away, and you re-query the
+        document for its FontFace objects, you may get a new object (albeit with the same
+        state as a previous object). However, this won't occur if there are any references to
+        the old object, which means it is almost not observable.
+
+        This patch doesn't implement the relationship between the CSSOM and the FontFace
+        objects. Changing one should result in a change in the other, but that will be
+        implemented in a forthcoming patch.
+
+        This patch also doesn't alter the lifetime of the CSSFontSelector, which means that all
+        the Document's fonts may be destroyed and recreated from CSS. There are a few things
+        which can trigger this. A subsequent patch will make the CSSFontSelector outlive the
+        Document.
+
+        This patch does implement (and test) the ability to add a new FontFace to the Document
+        to cause a relayout, as well as changing properties of existing FontFace objects already
+        in the Document to cause a relayout.
+
+        Test: fast/text/font-face-set-document.html
+
+        * Modules/fetch/FetchHeaders.cpp:
+        (WebCore::FetchHeaders::Iterator::next): Pass an extra argument.
+        * Modules/fetch/FetchHeaders.h:
+        * bindings/js/JSKeyValueIterator.h: The ExecState is necessary to build an external
+        wrapper from an existing CSSFontFace object.
+        (WebCore::JSKeyValueIterator<JSWrapper>::next):
+        * css/CSSFontFace.cpp:
+        (WebCore::CSSFontFace::appendSources): Moved from CSSFontSelector.
+        (WebCore::CSSFontFace::CSSFontFace):
+        (WebCore::CSSFontFace::notifyClientsOfFontPropertyChange):
+        (WebCore::CSSFontFace::setFamilies):
+        (WebCore::CSSFontFace::calculateStyle): Shared code between CSSFontFaceSet and
+        CSSFontFace.
+        (WebCore::CSSFontFace::setStyle): Update to use calculateStyle().
+        (WebCore::CSSFontFace::calculateWeight): Ditto.
+        (WebCore::CSSFontFace::setWeight): Update to use caculateWeight().
+        (WebCore::CSSFontFace::setUnicodeRange): Notify clients.
+        (WebCore::CSSFontFace::setVariantLigatures): Ditto.
+        (WebCore::CSSFontFace::setVariantPosition): Ditto.
+        (WebCore::CSSFontFace::setVariantCaps): Ditto.
+        (WebCore::CSSFontFace::setVariantNumeric): Ditto.
+        (WebCore::CSSFontFace::setVariantAlternates): Ditto.
+        (WebCore::CSSFontFace::setVariantEastAsian): Ditto.
+        (WebCore::CSSFontFace::setFeatureSettings): Ditto.
+        (WebCore::CSSFontFace::removeClient):
+        (WebCore::CSSFontFace::wrapper): Build a new wrapper if one doesn't already
+        exist. Note that this requires an ExecState to create a promise.
+        (WebCore::CSSFontFace::setStatus):
+        (WebCore::CSSFontFace::fontLoaded):
+        (WebCore::CSSFontFace::pump):
+        (WebCore::CSSFontFace::font):
+        * css/CSSFontFace.h:
+        * css/CSSFontFaceSet.cpp:
+        (WebCore::CSSFontFaceSet::CSSFontFaceSet): Moved code from CSSFontSelector.
+        (WebCore::CSSFontFaceSet::~CSSFontFaceSet):
+        (WebCore::CSSFontFaceSet::addClient): This object can now have multiple
+        clients.
+        (WebCore::CSSFontFaceSet::removeClient):
+        (WebCore::CSSFontFaceSet::incrementActiveCount): Update for multiple clients.
+        (WebCore::CSSFontFaceSet::decrementActiveCount): Ditto.
+        (WebCore::CSSFontFaceSet::hasFace):
+        (WebCore::CSSFontFaceSet::registerLocalFontFacesForFamily): Moved from
+        CSSFontSelector.
+        (WebCore::CSSFontFaceSet::familyNameFromPrimitive): Ditto.
+        (WebCore::CSSFontFaceSet::addToFacesLookupTable): This helper function can
+        be used when a property of a FontFace is changed.
+        (WebCore::CSSFontFaceSet::add): Update to use addToFacesLookupTable().
+        (WebCore::CSSFontFaceSet::removeFromFacesLookupTable): Same as
+        addToFacesLookupTable().
+        (WebCore::CSSFontFaceSet::remove): Update to use removeFromFacesLookupTable().
+        (WebCore::CSSFontFaceSet::clear):
+        (WebCore::CSSFontFaceSet::operator[]):
+        (WebCore::computeFontTraitsMask): Moved from CSSFontSelector.
+        (WebCore::CSSFontFaceSet::matchingFaces): Update to use new data structures.
+        (WebCore::FontFaceComparator::FontFaceComparator): Moved from
+        CSSFontSelector.
+        (WebCore::FontFaceComparator::operator()):
+        (WebCore::CSSFontFaceSet::getFontFace): Update to use new data structures.
+        (WebCore::CSSFontFaceSet::fontStateChanged): Update to use multiple clients.
+        (WebCore::CSSFontFaceSet::fontPropertyChanged): We must update our internal
+        data structure if the family name changed.
+        (WebCore::extractFamilies): Deleted.
+        (WebCore::familiesIntersect): Deleted.
+        (WebCore::CSSFontFaceSet::load): Deleted.
+        (WebCore::CSSFontFaceSet::stateChanged): Deleted.
+        * css/CSSFontFaceSet.h: Now needs to be RefCounted. New data structures are
+        taken from CSSFontSelector.
+        (WebCore::CSSFontFaceSetClient::faceFinished):
+        (WebCore::CSSFontFaceSetClient::fontModified):
+        (WebCore::CSSFontFaceSetClient::startedLoading):
+        (WebCore::CSSFontFaceSetClient::completedLoading):
+        * css/CSSFontFaceSource.h:
+        * css/CSSFontSelector.cpp: Move code into CSSFontFaceSet.
+        (WebCore::CSSFontSelector::CSSFontSelector):
+        (WebCore::CSSFontSelector::~CSSFontSelector):
+        (WebCore::CSSFontSelector::fontFaceSet):
+        (WebCore::CSSFontSelector::isEmpty):
+        (WebCore::CSSFontSelector::addFontFaceRule):
+        (WebCore::CSSFontSelector::fontModified):
+        (WebCore::CSSFontSelector::fontRangesForFamily):
+        (WebCore::CSSFontSelector::clearDocument):
+        (WebCore::CSSFontSelector::appendSources): Deleted.
+        (WebCore::CSSFontSelector::familyNameFromPrimitive): Deleted.
+        (WebCore::CSSFontSelector::registerLocalFontFacesForFamily): Deleted.
+        (WebCore::FontFaceComparator::FontFaceComparator): Deleted.
+        (WebCore::FontFaceComparator::operator()): Deleted.
+        (WebCore::CSSFontSelector::getFontFace): Deleted.
+        * css/CSSFontSelector.h:
+        * css/CSSSegmentedFontFace.cpp:
+        (WebCore::CSSSegmentedFontFace::CSSSegmentedFontFace):
+        * css/CSSSegmentedFontFace.h:
+        * css/FontFace.cpp:
+        (WebCore::FontFace::create):
+        (WebCore::FontFace::FontFace):
+        (WebCore::FontFace::createWeakPtr):
+        (WebCore::FontFace::fontStateChanged):
+        (WebCore::FontFace::stateChanged): Deleted.
+        * css/FontFace.h:
+        * css/FontFaceSet.cpp:
+        (WebCore::FontFaceSet::create):
+        (WebCore::FontFaceSet::FontFaceSet):
+        (WebCore::FontFaceSet::~FontFaceSet):
+        (WebCore::FontFaceSet::Iterator::next):
+        (WebCore::FontFaceSet::has):
+        (WebCore::FontFaceSet::size):
+        (WebCore::FontFaceSet::add):
+        (WebCore::FontFaceSet::remove):
+        (WebCore::FontFaceSet::clear):
+        (WebCore::FontFaceSet::load):
+        (WebCore::FontFaceSet::check):
+        (WebCore::FontFaceSet::status):
+        (WebCore::FontFaceSet::canSuspendForDocumentSuspension):
+        (WebCore::FontFaceSet::faceFinished):
+        * css/FontFaceSet.h:
+        * css/FontFaceSet.idl:
+        * dom/Document.cpp:
+        (WebCore::Document::fonts):
+        * dom/Document.h:
+        * dom/Document.idl:
+        * svg/SVGFontFaceElement.h:
+
 2016-02-22  Konstantin Tokarev  <[email protected]>
 
         [cmake] Moved library setup code to WEBKIT_FRAMEWORK macro.

Modified: trunk/Source/WebCore/Modules/fetch/FetchHeaders.cpp (196953 => 196954)


--- trunk/Source/WebCore/Modules/fetch/FetchHeaders.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/Modules/fetch/FetchHeaders.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -179,7 +179,7 @@
     }
 }
 
-bool FetchHeaders::Iterator::next(String& nextKey, String& nextValue)
+bool FetchHeaders::Iterator::next(JSC::ExecState&, String& nextKey, String& nextValue)
 {
     while (m_currentIndex < m_keys.size()) {
         auto& key = m_keys[m_currentIndex++];

Modified: trunk/Source/WebCore/Modules/fetch/FetchHeaders.h (196953 => 196954)


--- trunk/Source/WebCore/Modules/fetch/FetchHeaders.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/Modules/fetch/FetchHeaders.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -33,6 +33,10 @@
 
 #include "HTTPHeaderMap.h"
 
+namespace JSC {
+class ExecState;
+}
+
 namespace WebCore {
 
 typedef int ExceptionCode;
@@ -65,7 +69,7 @@
     class Iterator {
     public:
         explicit Iterator(FetchHeaders&);
-        bool next(String& nextKey, String& nextValue);
+        bool next(JSC::ExecState&, String& nextKey, String& nextValue);
 
     private:
         Ref<FetchHeaders> m_headers;

Modified: trunk/Source/WebCore/bindings/js/JSKeyValueIterator.h (196953 => 196954)


--- trunk/Source/WebCore/bindings/js/JSKeyValueIterator.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/bindings/js/JSKeyValueIterator.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -129,7 +129,7 @@
     typename JSWrapper::IteratorKey nextKey;
     typename JSWrapper::IteratorValue nextValue;
     auto iterator = wrapper->wrapped().createIterator();
-    while (!iterator.next(nextKey, nextValue)) {
+    while (!iterator.next(state, nextKey, nextValue)) {
         JSC::MarkedArgumentBuffer arguments;
         arguments.append(toJS(&state, wrapper->globalObject(), nextValue));
         arguments.append(toJS(&state, wrapper->globalObject(), nextKey));
@@ -153,7 +153,7 @@
 {
     typename JSWrapper::IteratorKey nextKey;
     typename JSWrapper::IteratorValue nextValue;
-    if (m_iterator.next(nextKey, nextValue)) {
+    if (m_iterator.next(state, nextKey, nextValue)) {
         value = JSC::jsUndefined();
         return true;
     }

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (196953 => 196954)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-02-22 21:40:02 UTC (rev 196954)
@@ -4039,6 +4039,7 @@
     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
     return "${svgNativeType}*" if $svgNativeType;
     return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
+    return "RefPtr<FontFace>" if $type eq "FontFace";
     return "RefPtr<${type}>" if $codeGenerator->IsTypedArrayType($type) and not $type eq "ArrayBuffer";
     return $nativeType{$type} if exists $nativeType{$type};
 

Modified: trunk/Source/WebCore/css/CSSFontFace.cpp (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontFace.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontFace.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -27,6 +27,7 @@
 #include "CSSFontFace.h"
 
 #include "CSSFontFaceSource.h"
+#include "CSSFontFaceSrcValue.h"
 #include "CSSFontFamily.h"
 #include "CSSFontFeatureValue.h"
 #include "CSSFontSelector.h"
@@ -38,16 +39,48 @@
 #include "Document.h"
 #include "Font.h"
 #include "FontDescription.h"
-#include "FontLoader.h"
+#include "FontFace.h"
 #include "FontVariantBuilder.h"
 #include "RuntimeEnabledFeatures.h"
+#include "Settings.h"
 #include "StyleProperties.h"
+#include "StyleRule.h"
 
 namespace WebCore {
 
-CSSFontFace::CSSFontFace(CSSFontSelector& fontSelector, FontFace* wrapper, bool isLocalFallback)
+void CSSFontFace::appendSources(CSSFontFace& fontFace, CSSValueList& srcList, Document* document, bool isInitiatingElementInUserAgentShadowTree)
+{
+    for (auto& src : srcList) {
+        // An item in the list either specifies a string (local font name) or a URL (remote font to download).
+        CSSFontFaceSrcValue& item = downcast<CSSFontFaceSrcValue>(src.get());
+        std::unique_ptr<CSSFontFaceSource> source;
+        SVGFontFaceElement* fontFaceElement = nullptr;
+        bool foundSVGFont = false;
+
+#if ENABLE(SVG_FONTS)
+        foundSVGFont = item.isSVGFontFaceSrc() || item.svgFontFaceElement();
+        fontFaceElement = item.svgFontFaceElement();
+#endif
+        if (!item.isLocal()) {
+            Settings* settings = document ? document->settings() : nullptr;
+            bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
+            if (allowDownloading && item.isSupportedFormat() && document) {
+                if (CachedFont* cachedFont = item.cachedFont(document, foundSVGFont, isInitiatingElementInUserAgentShadowTree))
+                    source = std::make_unique<CSSFontFaceSource>(fontFace, item.resource(), cachedFont);
+            }
+        } else
+            source = std::make_unique<CSSFontFaceSource>(fontFace, item.resource(), nullptr, fontFaceElement);
+
+        if (source)
+            fontFace.adoptSource(WTFMove(source));
+    }
+    fontFace.sourcesPopulated();
+}
+
+CSSFontFace::CSSFontFace(CSSFontSelector* fontSelector, StyleRuleFontFace* cssConnection, FontFace* wrapper, bool isLocalFallback)
     : m_fontSelector(fontSelector)
-    , m_wrapper(wrapper)
+    , m_cssConnection(cssConnection)
+    , m_wrapper(wrapper ? wrapper->createWeakPtr() : WeakPtr<FontFace>())
     , m_isLocalFallback(isLocalFallback)
 {
 }
@@ -56,6 +89,15 @@
 {
 }
 
+void CSSFontFace::notifyClientsOfFontPropertyChange()
+{
+    auto clientsCopy = m_clients;
+    for (auto* client : clientsCopy) {
+        if (m_clients.contains(client))
+            client->fontPropertyChanged(*this);
+    }
+}
+
 bool CSSFontFace::setFamilies(CSSValue& family)
 {
     if (!is<CSSValueList>(family))
@@ -65,80 +107,96 @@
     if (!familyList.length())
         return false;
 
+    RefPtr<CSSValueList> oldFamilies = m_families;
     m_families = &familyList;
+
+    auto clientsCopy = m_clients;
+    for (auto* client : clientsCopy) {
+        if (m_clients.contains(client))
+            client->fontPropertyChanged(*this, oldFamilies.get());
+    }
+
     return true;
 }
 
-bool CSSFontFace::setStyle(CSSValue& style)
+Optional<FontTraitsMask> CSSFontFace::calculateStyleMask(CSSValue& style)
 {
     if (!is<CSSPrimitiveValue>(style))
-        return false;
+        return Nullopt;
 
-    unsigned styleMask = 0;
     switch (downcast<CSSPrimitiveValue>(style).getValueID()) {
     case CSSValueNormal:
-        styleMask = FontStyleNormalMask;
-        break;
+        return FontStyleNormalMask;
     case CSSValueItalic:
     case CSSValueOblique:
-        styleMask = FontStyleItalicMask;
-        break;
+        return FontStyleItalicMask;
     default:
-        styleMask = FontStyleNormalMask;
-        break;
+        return FontStyleNormalMask;
     }
 
-    m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontStyleMask)) | styleMask);
-    return true;
+    return FontStyleNormalMask;
 }
 
-bool CSSFontFace::setWeight(CSSValue& weight)
+bool CSSFontFace::setStyle(CSSValue& style)
 {
+    if (auto mask = calculateStyleMask(style)) {
+        m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontStyleMask)) | mask.value());
+
+        notifyClientsOfFontPropertyChange();
+
+        return true;
+    }
+    return false;
+}
+
+Optional<FontTraitsMask> CSSFontFace::calculateWeightMask(CSSValue& weight)
+{
     if (!is<CSSPrimitiveValue>(weight))
-        return false;
+        return Nullopt;
 
-    unsigned weightMask = 0;
     switch (downcast<CSSPrimitiveValue>(weight).getValueID()) {
     case CSSValueBold:
     case CSSValueBolder:
     case CSSValue700:
-        weightMask = FontWeight700Mask;
-        break;
+        return FontWeight700Mask;
     case CSSValueNormal:
     case CSSValue400:
-        weightMask = FontWeight400Mask;
-        break;
+        return FontWeight400Mask;
     case CSSValue900:
-        weightMask = FontWeight900Mask;
-        break;
+        return FontWeight900Mask;
     case CSSValue800:
-        weightMask = FontWeight800Mask;
-        break;
+        return FontWeight800Mask;
     case CSSValue600:
-        weightMask = FontWeight600Mask;
-        break;
+        return FontWeight600Mask;
     case CSSValue500:
-        weightMask = FontWeight500Mask;
-        break;
+        return FontWeight500Mask;
     case CSSValue300:
-        weightMask = FontWeight300Mask;
-        break;
+        return FontWeight300Mask;
     case CSSValueLighter:
     case CSSValue200:
-        weightMask = FontWeight200Mask;
-        break;
+        return FontWeight200Mask;
     case CSSValue100:
-        weightMask = FontWeight100Mask;
-        break;
+        return FontWeight100Mask;
     default:
-        weightMask = FontWeight400Mask;
-        break;
+        return FontWeight400Mask;
     }
 
-    m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontWeightMask)) | weightMask);
-    return true;
+    return FontWeight400Mask;
 }
 
+bool CSSFontFace::setWeight(CSSValue& weight)
+{
+    if (auto mask = calculateWeightMask(weight)) {
+        m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontWeightMask)) | mask.value());
+
+        notifyClientsOfFontPropertyChange();
+
+        return true;
+    }
+
+    return false;
+}
+
 bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
 {
     if (!is<CSSValueList>(unicodeRange))
@@ -150,6 +208,9 @@
         CSSUnicodeRangeValue& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
         m_ranges.append(UnicodeRange(range.from(), range.to()));
     }
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -160,6 +221,9 @@
     m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
     m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
     m_variantSettings.contextualAlternates = ligatures.contextualAlternates;
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -168,6 +232,9 @@
     if (!is<CSSPrimitiveValue>(variantPosition))
         return false;
     m_variantSettings.position = downcast<CSSPrimitiveValue>(variantPosition);
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -176,6 +243,9 @@
     if (!is<CSSPrimitiveValue>(variantCaps))
         return false;
     m_variantSettings.caps = downcast<CSSPrimitiveValue>(variantCaps);
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -187,6 +257,9 @@
     m_variantSettings.numericFraction = numeric.fraction;
     m_variantSettings.numericOrdinal = numeric.ordinal;
     m_variantSettings.numericSlashedZero = numeric.slashedZero;
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -195,6 +268,9 @@
     if (!is<CSSPrimitiveValue>(variantAlternates))
         return false;
     m_variantSettings.alternates = downcast<CSSPrimitiveValue>(variantAlternates);
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -204,6 +280,9 @@
     m_variantSettings.eastAsianVariant = eastAsian.variant;
     m_variantSettings.eastAsianWidth = eastAsian.width;
     m_variantSettings.eastAsianRuby = eastAsian.ruby;
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -218,6 +297,9 @@
         CSSFontFeatureValue& feature = downcast<CSSFontFeatureValue>(rangeValue.get());
         m_featureSettings.insert(FontFeature(feature.tag(), feature.value()));
     }
+
+    notifyClientsOfFontPropertyChange();
+
     return true;
 }
 
@@ -237,9 +319,39 @@
 
 void CSSFontFace::removeClient(Client& client)
 {
+    ASSERT(m_clients.contains(&client));
     m_clients.remove(&client);
 }
 
+Ref<FontFace> CSSFontFace::wrapper(JSC::ExecState& execState)
+{
+    if (m_wrapper)
+        return Ref<FontFace>(*m_wrapper.get());
+
+    Ref<FontFace> wrapper = FontFace::create(execState, *this);
+    switch (m_status) {
+    case Status::Pending:
+        break;
+    case Status::Loading:
+        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+        break;
+    case Status::TimedOut:
+        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+        wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
+        break;
+    case Status::Success:
+        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+        wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
+        break;
+    case Status::Failure:
+        wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+        wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
+        break;
+    }
+    m_wrapper = wrapper->createWeakPtr();
+    return wrapper;
+}
+
 void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
 {
     m_sources.append(WTFMove(source));
@@ -268,8 +380,8 @@
         break;
     }
 
-    for (auto& client : m_clients)
-        client->stateChanged(*this, m_status, newStatus);
+    for (auto* client : m_clients)
+        client->fontStateChanged(*this, m_status, newStatus);
 
     m_status = newStatus;
 }
@@ -282,9 +394,10 @@
     if (m_sourcesPopulated)
         pump();
 
+    ASSERT(m_fontSelector);
     m_fontSelector->fontLoaded();
 
-    for (auto& client : m_clients)
+    for (auto* client : m_clients)
         client->fontLoaded(*this);
 }
 
@@ -296,9 +409,10 @@
 
         if (source->status() == CSSFontFaceSource::Status::Pending) {
             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
+            ASSERT(m_fontSelector);
             if (m_status == Status::Pending)
                 setStatus(Status::Loading);
-            source->load(m_fontSelector.get());
+            source->load(*m_fontSelector);
         }
 
         switch (source->status()) {
@@ -345,8 +459,10 @@
     size_t startIndex = pump();
     for (size_t i = startIndex; i < m_sources.size(); ++i) {
         auto& source = m_sources[i];
-        if (source->status() == CSSFontFaceSource::Status::Pending)
-            source->load(m_fontSelector.get());
+        if (source->status() == CSSFontFaceSource::Status::Pending) {
+            ASSERT(m_fontSelector);
+            source->load(*m_fontSelector);
+        }
 
         switch (source->status()) {
         case CSSFontFaceSource::Status::Pending:

Modified: trunk/Source/WebCore/css/CSSFontFace.h (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontFace.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontFace.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -27,7 +27,6 @@
 #define CSSFontFace_h
 
 #include "CSSFontFaceRule.h"
-#include "CSSFontFaceSource.h"
 #include "FontFeatureSettings.h"
 #include "TextFlags.h"
 #include <memory>
@@ -36,22 +35,29 @@
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
 
+namespace JSC {
+class ExecState;
+}
+
 namespace WebCore {
 
+class CSSFontFaceSource;
+class CSSFontSelector;
 class CSSSegmentedFontFace;
 class CSSValue;
 class CSSValueList;
+class Document;
 class FontDescription;
 class Font;
 class FontFace;
 
-// FIXME: This class does not need to be reference counted.
 class CSSFontFace final : public RefCounted<CSSFontFace> {
 public:
-    static Ref<CSSFontFace> create(CSSFontSelector& fontSelector, FontFace* wrapper = nullptr, bool isLocalFallback = false)
+    static Ref<CSSFontFace> create(CSSFontSelector* fontSelector, StyleRuleFontFace* cssConnection = nullptr, FontFace* wrapper = nullptr, bool isLocalFallback = false)
     {
-        return adoptRef(*new CSSFontFace(fontSelector, wrapper, isLocalFallback));
+        return adoptRef(*new CSSFontFace(fontSelector, cssConnection, wrapper, isLocalFallback));
     }
     virtual ~CSSFontFace();
 
@@ -78,7 +84,11 @@
     void setTraitsMask(FontTraitsMask traitsMask) { m_traitsMask = traitsMask; }
     bool isLocalFallback() const { return m_isLocalFallback; }
     Status status() const { return m_status; }
+    StyleRuleFontFace* cssConnection() const { return m_cssConnection.get(); }
 
+    static Optional<FontTraitsMask> calculateStyleMask(CSSValue& style);
+    static Optional<FontTraitsMask> calculateWeightMask(CSSValue& weight);
+
     class Client;
     void addClient(Client&);
     void removeClient(Client&);
@@ -93,11 +103,14 @@
     void load();
     RefPtr<Font> font(const FontDescription&, bool syntheticBold, bool syntheticItalic);
 
+    static void appendSources(CSSFontFace&, CSSValueList&, Document*, bool isInitiatingElementInUserAgentShadowTree);
+
     class Client {
     public:
         virtual ~Client() { }
         virtual void fontLoaded(CSSFontFace&) { };
-        virtual void stateChanged(CSSFontFace&, Status oldState, Status newState) { UNUSED_PARAM(oldState); UNUSED_PARAM(newState); };
+        virtual void fontStateChanged(CSSFontFace&, Status oldState, Status newState) { UNUSED_PARAM(oldState); UNUSED_PARAM(newState); };
+        virtual void fontPropertyChanged(CSSFontFace&, CSSValueList* oldFamilies = nullptr) { UNUSED_PARAM(oldFamilies); };
     };
 
     // Pending => Loading  => TimedOut
@@ -132,27 +145,30 @@
         UChar32 m_to;
     };
 
-    FontFace* wrapper() const { return m_wrapper; }
+    // We don't guarantee that the FontFace wrapper will be the same every time you ask for it.
+    Ref<FontFace> wrapper(JSC::ExecState&);
 
 #if ENABLE(SVG_FONTS)
     bool hasSVGFontFaceSource() const;
 #endif
 
 private:
-    CSSFontFace(CSSFontSelector&, FontFace*, bool isLocalFallback);
+    CSSFontFace(CSSFontSelector*, StyleRuleFontFace*, FontFace*, bool isLocalFallback);
 
     size_t pump();
     void setStatus(Status);
+    void notifyClientsOfFontPropertyChange();
 
     RefPtr<CSSValueList> m_families;
     FontTraitsMask m_traitsMask { static_cast<FontTraitsMask>(FontStyleNormalMask | FontWeight400Mask) };
     Vector<UnicodeRange> m_ranges;
-    HashSet<Client*> m_clients;
-    Ref<CSSFontSelector> m_fontSelector;
-    FontFace* m_wrapper;
     FontFeatureSettings m_featureSettings;
     FontVariantSettings m_variantSettings;
     Vector<std::unique_ptr<CSSFontFaceSource>> m_sources;
+    RefPtr<CSSFontSelector> m_fontSelector;
+    RefPtr<StyleRuleFontFace> m_cssConnection;
+    HashSet<Client*> m_clients;
+    WeakPtr<FontFace> m_wrapper;
     Status m_status { Status::Pending };
     bool m_isLocalFallback { false };
     bool m_sourcesPopulated { false };

Modified: trunk/Source/WebCore/css/CSSFontFaceSet.cpp (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontFaceSet.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontFaceSet.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -26,17 +26,20 @@
 #include "config.h"
 #include "CSSFontFaceSet.h"
 
+#include "CSSFontFaceSource.h"
 #include "CSSFontFamily.h"
 #include "CSSFontSelector.h"
 #include "CSSParser.h"
 #include "CSSPrimitiveValue.h"
+#include "CSSSegmentedFontFace.h"
 #include "CSSValueList.h"
+#include "CSSValuePool.h"
+#include "FontCache.h"
 #include "StyleProperties.h"
 
 namespace WebCore {
 
-CSSFontFaceSet::CSSFontFaceSet(CSSFontFaceSetClient& client)
-    : m_client(client)
+CSSFontFaceSet::CSSFontFaceSet()
 {
 }
 
@@ -44,14 +47,31 @@
 {
     for (auto& face : m_faces)
         face->removeClient(*this);
+
+    for (auto& pair : m_locallyInstalledFacesLookupTable) {
+        for (auto& face : pair.value)
+            face->removeClient(*this);
+    }
 }
 
+void CSSFontFaceSet::addClient(CSSFontFaceSetClient& client)
+{
+    m_clients.add(&client);
+}
+
+void CSSFontFaceSet::removeClient(CSSFontFaceSetClient& client)
+{
+    ASSERT(m_clients.contains(&client));
+    m_clients.remove(&client);
+}
+
 void CSSFontFaceSet::incrementActiveCount()
 {
     ++m_activeCount;
     if (m_activeCount == 1) {
         m_status = Status::Loading;
-        m_client.startedLoading();
+        for (auto* client : m_clients)
+            client->startedLoading();
     }
 }
 
@@ -60,7 +80,8 @@
     --m_activeCount;
     if (!m_activeCount) {
         m_status = Status::Loaded;
-        m_client.completedLoading();
+        for (auto* client : m_clients)
+            client->completedLoading();
     }
 }
 
@@ -70,23 +91,141 @@
         if (myFace.ptr() == &face)
             return true;
     }
+
     return false;
 }
 
+void CSSFontFaceSet::registerLocalFontFacesForFamily(const String& familyName)
+{
+    ASSERT(!m_locallyInstalledFacesLookupTable.contains(familyName));
+
+    Vector<FontTraitsMask> traitsMasks = FontCache::singleton().getTraitsInFamily(familyName);
+    if (traitsMasks.isEmpty())
+        return;
+
+    Vector<Ref<CSSFontFace>> faces;
+    for (auto mask : traitsMasks) {
+        Ref<CSSFontFace> face = CSSFontFace::create(nullptr, nullptr, nullptr, true);
+        
+        Ref<CSSValueList> familyList = CSSValueList::createCommaSeparated();
+        familyList->append(CSSValuePool::singleton().createFontFamilyValue(familyName));
+        face->setFamilies(familyList.get());
+        face->setTraitsMask(mask);
+        face->adoptSource(std::make_unique<CSSFontFaceSource>(face.get(), familyName));
+        ASSERT(!face->allSourcesFailed());
+        faces.append(WTFMove(face));
+    }
+    m_locallyInstalledFacesLookupTable.add(familyName, WTFMove(faces));
+}
+
+String CSSFontFaceSet::familyNameFromPrimitive(const CSSPrimitiveValue& value)
+{
+    if (value.isFontFamily())
+        return value.fontFamily().familyName;
+    if (!value.isValueID())
+        return { };
+
+    // We need to use the raw text for all the generic family types, since @font-face is a way of actually
+    // defining what font to use for those types.
+    switch (value.getValueID()) {
+    case CSSValueSerif:
+        return serifFamily;
+    case CSSValueSansSerif:
+        return sansSerifFamily;
+    case CSSValueCursive:
+        return cursiveFamily;
+    case CSSValueFantasy:
+        return fantasyFamily;
+    case CSSValueMonospace:
+        return monospaceFamily;
+    case CSSValueWebkitPictograph:
+        return pictographFamily;
+    default:
+        return { };
+    }
+}
+
+void CSSFontFaceSet::addToFacesLookupTable(CSSFontFace& face)
+{
+    if (!face.families())
+        return;
+
+    for (auto& item : *face.families()) {
+        String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
+        if (familyName.isEmpty())
+            continue;
+
+        auto addResult = m_facesLookupTable.add(familyName, Vector<Ref<CSSFontFace>>());
+        auto& familyFontFaces = addResult.iterator->value;
+        if (addResult.isNewEntry) {
+            // m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system.
+            // This is by design.
+            registerLocalFontFacesForFamily(familyName);
+            familyFontFaces = { };
+        }
+
+        familyFontFaces.append(face);
+    }
+}
+
 void CSSFontFaceSet::add(CSSFontFace& face)
 {
     ASSERT(!hasFace(face));
 
-    m_faces.append(face);
+    for (auto* client : m_clients)
+        client->fontModified();
+
     face.addClient(*this);
+    m_cache.clear();
+
+    if (face.cssConnection())
+        m_faces.insert(m_facesPartitionIndex++, face);
+    else
+        m_faces.append(face);
+
+    addToFacesLookupTable(face);
+
     if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
         incrementActiveCount();
 }
 
+void CSSFontFaceSet::removeFromFacesLookupTable(const CSSFontFace& face, const CSSValueList& familiesToSearchFor)
+{
+    for (auto& item : familiesToSearchFor) {
+        String familyName = CSSFontFaceSet::familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
+        if (familyName.isEmpty())
+            continue;
+
+        auto iterator = m_facesLookupTable.find(familyName);
+        ASSERT(iterator != m_facesLookupTable.end());
+        bool found = false;
+        for (size_t i = 0; i < iterator->value.size(); ++i) {
+            if (iterator->value[i].ptr() == &face) {
+                found = true;
+                iterator->value.remove(i);
+                break;
+            }
+        }
+        ASSERT_UNUSED(found, found);
+        if (!iterator->value.size())
+            m_facesLookupTable.remove(iterator);
+    }
+}
+
 void CSSFontFaceSet::remove(const CSSFontFace& face)
 {
+    m_cache.clear();
+
+    for (auto* client : m_clients)
+        client->fontModified();
+
+    if (face.families())
+        removeFromFacesLookupTable(face, *face.families());
+
     for (size_t i = 0; i < m_faces.size(); ++i) {
         if (m_faces[i].ptr() == &face) {
+            if (i < m_facesPartitionIndex)
+                --m_facesPartitionIndex;
             m_faces[i]->removeClient(*this);
             m_faces.remove(i);
             if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
@@ -97,30 +236,43 @@
     ASSERT_NOT_REACHED();
 }
 
-static HashSet<String> extractFamilies(const CSSValueList& list)
+void CSSFontFaceSet::clear()
 {
-    HashSet<String> result;
-    for (auto& family : list) {
-        const CSSPrimitiveValue& primitive = downcast<CSSPrimitiveValue>(family.get());
-        if (!primitive.isFontFamily())
-            continue;
-        result.add(primitive.fontFamily().familyName);
-    }
-    return result;
+    m_faces.clear();
+    m_facesLookupTable.clear();
+    m_locallyInstalledFacesLookupTable.clear();
+    m_cache.clear();
 }
 
-static bool familiesIntersect(const CSSFontFace& face, const CSSValueList& request)
+CSSFontFace& CSSFontFaceSet::operator[](size_t i)
 {
-    if (!face.families())
-        return false;
+    ASSERT(i < faceCount());
+    return m_faces[i];
+}
 
-    HashSet<String> faceFamilies = extractFamilies(*face.families());
-    HashSet<String> requestFamilies = extractFamilies(request);
-    for (auto& family1 : faceFamilies) {
-        if (requestFamilies.contains(family1))
-            return true;
-    }
-    return false;
+static Optional<FontTraitsMask> computeFontTraitsMask(MutableStyleProperties& style)
+{
+    RefPtr<CSSValue> styleValue = style.getPropertyCSSValue(CSSPropertyFontStyle).get();
+    if (!styleValue)
+        styleValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
+
+    FontTraitsMask styleMask;
+    if (auto styleMaskOptional = CSSFontFace::calculateStyleMask(*styleValue))
+        styleMask = styleMaskOptional.value();
+    else
+        return Nullopt;
+
+    RefPtr<CSSValue> weightValue = style.getPropertyCSSValue(CSSPropertyFontWeight).get();
+    if (!weightValue)
+        weightValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
+
+    FontTraitsMask weightMask;
+    if (auto weightMaskOptional = CSSFontFace::calculateWeightMask(*weightValue))
+        weightMask = weightMaskOptional.value();
+    else
+        return Nullopt;
+
+    return static_cast<FontTraitsMask>(static_cast<unsigned>(styleMask) | static_cast<unsigned>(weightMask));
 }
 
 Vector<std::reference_wrapper<CSSFontFace>> CSSFontFaceSet::matchingFaces(const String& font, const String&, ExceptionCode& ec)
@@ -132,14 +284,15 @@
         ec = SYNTAX_ERR;
         return result;
     }
-    bool desiredStyleIsNormal = true;
-    if (RefPtr<CSSValue> desiredStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) {
-        if (!is<CSSPrimitiveValue>(*desiredStyle)) {
-            ec = SYNTAX_ERR;
-            return result;
-        }
-        desiredStyleIsNormal = downcast<CSSPrimitiveValue>(*desiredStyle).getValueID() == CSSValueNormal;
+
+    FontTraitsMask fontTraitsMask;
+    if (auto maskOptional = computeFontTraitsMask(style.get()))
+        fontTraitsMask = maskOptional.value();
+    else {
+        ec = SYNTAX_ERR;
+        return result;
     }
+
     RefPtr<CSSValue> family = style->getPropertyCSSValue(CSSPropertyFontFamily);
     if (!is<CSSValueList>(family.get())) {
         ec = SYNTAX_ERR;
@@ -147,23 +300,23 @@
     }
     CSSValueList& familyList = downcast<CSSValueList>(*family);
 
-    // Match CSSFontSelector::getFontFace()
-    for (auto& face : m_faces) {
-        if (!familiesIntersect(face, familyList) || (desiredStyleIsNormal && !(face->traitsMask() & FontStyleNormalMask)))
+    HashSet<AtomicString> uniqueFamilies;
+    for (auto& family : familyList) {
+        const CSSPrimitiveValue& primitive = downcast<CSSPrimitiveValue>(family.get());
+        if (!primitive.isFontFamily())
             continue;
-        result.append(face.get());
+        uniqueFamilies.add(primitive.fontFamily().familyName);
     }
-    return result;
-}
 
-void CSSFontFaceSet::load(const String& font, const String& text, ExceptionCode& ec)
-{
-    auto matchingFaces = this->matchingFaces(font, text, ec);
-    if (ec)
-        return;
+    for (auto& family : uniqueFamilies) {
+        CSSSegmentedFontFace* faces = getFontFace(fontTraitsMask, family);
+        if (!faces)
+            continue;
+        for (auto& constituentFace : faces->constituentFaces())
+            result.append(constituentFace.get());
+    }
 
-    for (auto& face : matchingFaces)
-        face.get().load();
+    return result;
 }
 
 bool CSSFontFaceSet::check(const String& font, const String& text, ExceptionCode& ec)
@@ -179,8 +332,110 @@
     return true;
 }
 
-void CSSFontFaceSet::stateChanged(CSSFontFace& face, CSSFontFace::Status oldState, CSSFontFace::Status newState)
+static bool fontFaceComparator(FontTraitsMask desiredTraitsMaskForComparison, const CSSFontFace& first, const CSSFontFace& second)
 {
+    FontTraitsMask firstTraitsMask = first.traitsMask();
+    FontTraitsMask secondTraitsMask = second.traitsMask();
+
+    bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
+    bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
+
+    if (firstHasDesiredStyle != secondHasDesiredStyle)
+        return firstHasDesiredStyle;
+
+    if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) {
+        // Prefer a font that has indicated that it can only support italics to a font that claims to support
+        // all styles. The specialized font is more likely to be the one the author wants used.
+        bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
+        bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
+        if (firstRequiresItalics != secondRequiresItalics)
+            return firstRequiresItalics;
+    }
+
+    if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
+        return false;
+    if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
+        return true;
+
+    // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says :
+    //   - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found.
+    //   - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found.
+    //   - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used.
+    //   - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used.
+
+    static const unsigned fallbackRuleSets = 9;
+    static const unsigned rulesPerSet = 8;
+    static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
+        { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
+        { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
+        { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
+        { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
+        { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
+        { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
+        { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
+        { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
+        { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
+    };
+
+    unsigned ruleSetIndex = 0;
+    for (; !(desiredTraitsMaskForComparison & (1 << (FontWeight100Bit + ruleSetIndex))); ruleSetIndex++) { }
+
+    const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
+    for (unsigned i = 0; i < rulesPerSet; ++i) {
+        if (secondTraitsMask & weightFallbackRule[i])
+            return false;
+        if (firstTraitsMask & weightFallbackRule[i])
+            return true;
+    }
+
+    return false;
+}
+
+CSSSegmentedFontFace* CSSFontFaceSet::getFontFace(FontTraitsMask traitsMask, const AtomicString& family)
+{
+    auto iterator = m_facesLookupTable.find(family);
+    if (iterator == m_facesLookupTable.end())
+        return nullptr;
+    auto& familyFontFaces = iterator->value;
+
+    auto& segmentedFontFaceCache = m_cache.add(family, HashMap<unsigned, std::unique_ptr<CSSSegmentedFontFace>>()).iterator->value;
+
+    auto& face = segmentedFontFaceCache.add(traitsMask, nullptr).iterator->value;
+    if (face)
+        return face.get();
+
+    face = std::make_unique<CSSSegmentedFontFace>();
+
+    Vector<std::reference_wrapper<CSSFontFace>, 32> candidateFontFaces;
+    for (int i = familyFontFaces.size() - 1; i >= 0; --i) {
+        CSSFontFace& candidate = familyFontFaces[i];
+        unsigned candidateTraitsMask = candidate.traitsMask();
+        if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
+            continue;
+        candidateFontFaces.append(candidate);
+    }
+
+    auto localIterator = m_locallyInstalledFacesLookupTable.find(family);
+    if (localIterator != m_locallyInstalledFacesLookupTable.end()) {
+        for (auto& candidate : localIterator->value) {
+            unsigned candidateTraitsMask = candidate->traitsMask();
+            if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
+                continue;
+            candidateFontFaces.append(candidate);
+        }
+    }
+
+    std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [traitsMask](const CSSFontFace& first, const CSSFontFace& second) {
+        return fontFaceComparator(traitsMask, first, second);
+    });
+    for (auto& candidate : candidateFontFaces)
+        face->appendFontFace(candidate.get());
+
+    return face.get();
+}
+
+void CSSFontFaceSet::fontStateChanged(CSSFontFace& face, CSSFontFace::Status oldState, CSSFontFace::Status newState)
+{
     ASSERT(hasFace(face));
     if (oldState == CSSFontFace::Status::Pending) {
         ASSERT(newState == CSSFontFace::Status::Loading);
@@ -188,9 +443,23 @@
     }
     if (newState == CSSFontFace::Status::Success || newState == CSSFontFace::Status::Failure) {
         ASSERT(oldState == CSSFontFace::Status::Loading || oldState == CSSFontFace::Status::TimedOut);
-        m_client.faceFinished(face, newState);
+        for (auto* client : m_clients)
+            client->faceFinished(face, newState);
         decrementActiveCount();
     }
 }
 
+void CSSFontFaceSet::fontPropertyChanged(CSSFontFace& face, CSSValueList* oldFamilies)
+{
+    m_cache.clear();
+
+    if (oldFamilies) {
+        removeFromFacesLookupTable(face, *oldFamilies);
+        addToFacesLookupTable(face);
+    }
+
+    for (auto* client : m_clients)
+        client->fontModified();
 }
+
+}

Modified: trunk/Source/WebCore/css/CSSFontFaceSet.h (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontFaceSet.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontFaceSet.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -27,34 +27,46 @@
 #define CSSFontFaceSet_h
 
 #include "CSSFontFace.h"
+#include <wtf/HashMap.h>
 #include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
 
 namespace WebCore {
 
+class CSSPrimitiveValue;
 class FontFaceSet;
 
 class CSSFontFaceSetClient {
 public:
     virtual ~CSSFontFaceSetClient() { }
-    virtual void faceFinished(CSSFontFace&, CSSFontFace::Status) = 0;
-    virtual void startedLoading() = 0;
-    virtual void completedLoading() = 0;
+    virtual void faceFinished(CSSFontFace&, CSSFontFace::Status) { };
+    virtual void fontModified() { };
+    virtual void startedLoading() { };
+    virtual void completedLoading() { };
 };
 
-class CSSFontFaceSet final : public CSSFontFace::Client {
+class CSSFontFaceSet final : public RefCounted<CSSFontFaceSet>, public CSSFontFace::Client {
 public:
-    CSSFontFaceSet(CSSFontFaceSetClient&);
+    static Ref<CSSFontFaceSet> create()
+    {
+        return adoptRef(*new CSSFontFaceSet());
+    }
     ~CSSFontFaceSet();
 
+    void addClient(CSSFontFaceSetClient&);
+    void removeClient(CSSFontFaceSetClient&);
+
     bool hasFace(const CSSFontFace&) const;
     size_t faceCount() const { return m_faces.size(); }
     void add(CSSFontFace&);
     void remove(const CSSFontFace&);
-    const CSSFontFace& operator[](size_t i) const { return m_faces[i]; }
+    void clear();
+    CSSFontFace& operator[](size_t i);
 
-    void load(const String& font, const String& text, ExceptionCode&);
     bool check(const String& font, const String& text, ExceptionCode&);
 
+    CSSSegmentedFontFace* getFontFace(FontTraitsMask, const AtomicString& family);
+
     enum class Status {
         Loading,
         Loaded
@@ -64,14 +76,29 @@
     Vector<std::reference_wrapper<CSSFontFace>> matchingFaces(const String& font, const String& text, ExceptionCode&);
 
 private:
+    CSSFontFaceSet();
+
+    void removeFromFacesLookupTable(const CSSFontFace&, const CSSValueList& familiesToSearchFor);
+    void addToFacesLookupTable(CSSFontFace&);
+
     void incrementActiveCount();
     void decrementActiveCount();
 
-    virtual void stateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) override;
+    virtual void fontStateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) override;
+    virtual void fontPropertyChanged(CSSFontFace&, CSSValueList* oldFamilies = nullptr) override;
 
-    Vector<Ref<CSSFontFace>> m_faces;
+    void registerLocalFontFacesForFamily(const String&);
+
+    static String familyNameFromPrimitive(const CSSPrimitiveValue&);
+
+    // m_faces should hold all the same fonts as the ones inside inside m_facesLookupTable.
+    Vector<Ref<CSSFontFace>> m_faces; // We should investigate moving m_faces to FontFaceSet and making it reference FontFaces. This may clean up the font loading design.
+    HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_facesLookupTable;
+    HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_locallyInstalledFacesLookupTable;
+    HashMap<String, HashMap<unsigned, std::unique_ptr<CSSSegmentedFontFace>>, ASCIICaseInsensitiveHash> m_cache;
+    size_t m_facesPartitionIndex { 0 }; // All entries in m_faces before this index are CSS-connected.
     Status m_status { Status::Loaded };
-    CSSFontFaceSetClient& m_client;
+    HashSet<CSSFontFaceSetClient*> m_clients;
     unsigned m_activeCount { 0 };
 };
 

Modified: trunk/Source/WebCore/css/CSSFontFaceSource.h (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontFaceSource.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontFaceSource.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -45,6 +45,8 @@
 class CSSFontFaceSource final : public CachedFontClient {
     WTF_MAKE_FAST_ALLOCATED;
 public:
+    CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CachedFont* = nullptr, SVGFontFaceElement* = nullptr);
+    virtual ~CSSFontFaceSource();
 
     //                      => Success
     //                    //
@@ -57,10 +59,6 @@
         Success,
         Failure
     };
-
-    CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CachedFont* = nullptr, SVGFontFaceElement* = nullptr);
-    virtual ~CSSFontFaceSource();
-
     Status status() const { return m_status; }
 
     const AtomicString& familyNameOrURI() const { return m_familyNameOrURI; }

Modified: trunk/Source/WebCore/css/CSSFontSelector.cpp (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontSelector.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontSelector.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -31,7 +31,6 @@
 #include "CSSFontFace.h"
 #include "CSSFontFaceRule.h"
 #include "CSSFontFaceSource.h"
-#include "CSSFontFaceSrcValue.h"
 #include "CSSFontFamily.h"
 #include "CSSFontFeatureValue.h"
 #include "CSSPrimitiveValue.h"
@@ -46,6 +45,7 @@
 #include "Document.h"
 #include "Font.h"
 #include "FontCache.h"
+#include "FontFaceSet.h"
 #include "FontVariantBuilder.h"
 #include "Frame.h"
 #include "FrameLoader.h"
@@ -65,6 +65,7 @@
 
 CSSFontSelector::CSSFontSelector(Document& document)
     : m_document(&document)
+    , m_cssFontFaceSet(CSSFontFaceSet::create())
     , m_beginLoadingTimer(*this, &CSSFontSelector::beginLoadTimerFired)
     , m_uniqueId(++fontSelectorId)
     , m_version(0)
@@ -75,99 +76,32 @@
 
     ASSERT(m_document);
     FontCache::singleton().addClient(*this);
+    m_cssFontFaceSet->addClient(*this);
 }
 
 CSSFontSelector::~CSSFontSelector()
 {
     clearDocument();
+    m_cssFontFaceSet->removeClient(*this);
     FontCache::singleton().removeClient(*this);
 }
 
-bool CSSFontSelector::isEmpty() const
+FontFaceSet& CSSFontSelector::fontFaceSet()
 {
-    return m_fonts.isEmpty();
-}
-
-void CSSFontSelector::appendSources(CSSFontFace& fontFace, CSSValueList& srcList, Document* document, bool isInitiatingElementInUserAgentShadowTree)
-{
-    for (auto& src : srcList) {
-        // An item in the list either specifies a string (local font name) or a URL (remote font to download).
-        CSSFontFaceSrcValue& item = downcast<CSSFontFaceSrcValue>(src.get());
-        std::unique_ptr<CSSFontFaceSource> source;
-        SVGFontFaceElement* fontFaceElement = nullptr;
-        bool foundSVGFont = false;
-
-#if ENABLE(SVG_FONTS)
-        foundSVGFont = item.isSVGFontFaceSrc() || item.svgFontFaceElement();
-        fontFaceElement = item.svgFontFaceElement();
-#endif
-        if (!item.isLocal()) {
-            Settings* settings = document ? document->settings() : nullptr;
-            bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
-            if (allowDownloading && item.isSupportedFormat() && document) {
-                if (CachedFont* cachedFont = item.cachedFont(document, foundSVGFont, isInitiatingElementInUserAgentShadowTree))
-                    source = std::make_unique<CSSFontFaceSource>(fontFace, item.resource(), cachedFont);
-            }
-        } else
-            source = std::make_unique<CSSFontFaceSource>(fontFace, item.resource(), nullptr, fontFaceElement);
-
-        if (source)
-            fontFace.adoptSource(WTFMove(source));
+    if (!m_fontFaceSet) {
+        ASSERT(m_document);
+        m_fontFaceSet = FontFaceSet::create(*m_document, m_cssFontFaceSet.get());
     }
-    fontFace.sourcesPopulated();
-}
 
-String CSSFontSelector::familyNameFromPrimitive(const CSSPrimitiveValue& value)
-{
-    if (value.isFontFamily())
-        return value.fontFamily().familyName;
-    if (!value.isValueID())
-        return { };
-
-    // We need to use the raw text for all the generic family types, since @font-face is a way of actually
-    // defining what font to use for those types.
-    switch (value.getValueID()) {
-    case CSSValueSerif:
-        return serifFamily;
-    case CSSValueSansSerif:
-        return sansSerifFamily;
-    case CSSValueCursive:
-        return cursiveFamily;
-    case CSSValueFantasy:
-        return fantasyFamily;
-    case CSSValueMonospace:
-        return monospaceFamily;
-    case CSSValueWebkitPictograph:
-        return pictographFamily;
-    default:
-        return { };
-    }
+    return *m_fontFaceSet;
 }
 
-void CSSFontSelector::registerLocalFontFacesForFamily(const String& familyName)
+bool CSSFontSelector::isEmpty() const
 {
-    ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
-
-    Vector<FontTraitsMask> traitsMasks = FontCache::singleton().getTraitsInFamily(familyName);
-    if (traitsMasks.isEmpty())
-        return;
-
-    Vector<Ref<CSSFontFace>> faces = { };
-    for (auto mask : traitsMasks) {
-        Ref<CSSFontFace> face = CSSFontFace::create(*this, nullptr, true);
-        
-        RefPtr<CSSValueList> familyList = CSSValueList::createCommaSeparated();
-        familyList->append(CSSValuePool::singleton().createFontFamilyValue(familyName));
-        face->setFamilies(*familyList);
-        face->setTraitsMask(mask);
-        face->adoptSource(std::make_unique<CSSFontFaceSource>(face.get(), familyName));
-        ASSERT(!face->allSourcesFailed());
-        faces.append(WTFMove(face));
-    }
-    m_locallyInstalledFontFaces.add(familyName, WTFMove(faces));
+    return !m_cssFontFaceSet->faceCount();
 }
 
-void CSSFontSelector::addFontFaceRule(const StyleRuleFontFace& fontFaceRule, bool isInitiatingElementInUserAgentShadowTree)
+void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isInitiatingElementInUserAgentShadowTree)
 {
     const StyleProperties& style = fontFaceRule.properties();
     RefPtr<CSSValue> fontFamily = style.getPropertyCSSValue(CSSPropertyFontFamily);
@@ -201,7 +135,8 @@
     if (!srcList.length())
         return;
 
-    Ref<CSSFontFace> fontFace = CSSFontFace::create(*this);
+    m_creatingFont = true;
+    Ref<CSSFontFace> fontFace = CSSFontFace::create(this, &fontFaceRule);
 
     if (!fontFace->setFamilies(*fontFamily))
         return;
@@ -226,26 +161,13 @@
     if (featureSettings && !fontFace->setFeatureSettings(*featureSettings))
         return;
 
-    appendSources(fontFace, srcList, m_document, isInitiatingElementInUserAgentShadowTree);
+    CSSFontFace::appendSources(fontFace, srcList, m_document, isInitiatingElementInUserAgentShadowTree);
     if (fontFace->allSourcesFailed())
         return;
 
-    for (auto& item : familyList) {
-        String familyName = familyNameFromPrimitive(downcast<CSSPrimitiveValue>(item.get()));
-        if (familyName.isEmpty())
-            continue;
-
-        auto addResult = m_fontFaces.add(familyName, Vector<Ref<CSSFontFace>>());
-        auto& familyFontFaces = addResult.iterator->value;
-        if (addResult.isNewEntry) {
-            registerLocalFontFacesForFamily(familyName);
-            familyFontFaces = { };
-        }
-
-        familyFontFaces.append(fontFace.copyRef());
-        
-        ++m_version;
-    }
+    m_cssFontFaceSet->add(fontFace.get());
+    m_creatingFont = false;
+    ++m_version;
 }
 
 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient& client)
@@ -273,6 +195,12 @@
     dispatchInvalidationCallbacks();
 }
 
+void CSSFontSelector::fontModified()
+{
+    if (!m_creatingFont)
+        dispatchInvalidationCallbacks();
+}
+
 void CSSFontSelector::fontCacheInvalidated()
 {
     dispatchInvalidationCallbacks();
@@ -304,84 +232,13 @@
     return familyName;
 }
 
-class FontFaceComparator {
-public:
-    FontFaceComparator(FontTraitsMask desiredTraitsMaskForComparison)
-        : m_desiredTraitsMaskForComparison(desiredTraitsMaskForComparison)
-    {
-        ASSERT_WITH_SECURITY_IMPLICATION(m_desiredTraitsMaskForComparison & FontWeightMask);
-    }
-
-    bool operator()(const CSSFontFace& first, const CSSFontFace& second)
-    {
-        FontTraitsMask firstTraitsMask = first.traitsMask();
-        FontTraitsMask secondTraitsMask = second.traitsMask();
-
-        bool firstHasDesiredStyle = firstTraitsMask & m_desiredTraitsMaskForComparison & FontStyleMask;
-        bool secondHasDesiredStyle = secondTraitsMask & m_desiredTraitsMaskForComparison & FontStyleMask;
-
-        if (firstHasDesiredStyle != secondHasDesiredStyle)
-            return firstHasDesiredStyle;
-
-        if ((m_desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) {
-            // Prefer a font that has indicated that it can only support italics to a font that claims to support
-            // all styles. The specialized font is more likely to be the one the author wants used.
-            bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
-            bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
-            if (firstRequiresItalics != secondRequiresItalics)
-                return firstRequiresItalics;
-        }
-
-        if (secondTraitsMask & m_desiredTraitsMaskForComparison & FontWeightMask)
-            return false;
-        if (firstTraitsMask & m_desiredTraitsMaskForComparison & FontWeightMask)
-            return true;
-
-        // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says :
-        //   - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found.
-        //   - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found.
-        //   - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used.
-        //   - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used.
-
-        static const unsigned fallbackRuleSets = 9;
-        static const unsigned rulesPerSet = 8;
-        static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
-            { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
-            { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
-            { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
-            { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
-            { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
-            { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
-            { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
-            { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
-            { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
-        };
-
-        unsigned ruleSetIndex = 0;
-        for (; !(m_desiredTraitsMaskForComparison & (1 << (FontWeight100Bit + ruleSetIndex))); ruleSetIndex++) { }
-
-        const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
-        for (unsigned i = 0; i < rulesPerSet; ++i) {
-            if (secondTraitsMask & weightFallbackRule[i])
-                return false;
-            if (firstTraitsMask & weightFallbackRule[i])
-                return true;
-        }
-
-        return false;
-    }
-
-private:
-    FontTraitsMask m_desiredTraitsMaskForComparison;
-};
-
 FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescription, const AtomicString& familyName)
 {
     // FIXME: The spec (and Firefox) says user specified generic families (sans-serif etc.) should be resolved before the @font-face lookup too.
     bool resolveGenericFamilyFirst = familyName == standardFamily;
 
     AtomicString familyForLookup = resolveGenericFamilyFirst ? resolveGenericFamily(m_document, fontDescription, familyName) : familyName;
-    CSSSegmentedFontFace* face = getFontFace(fontDescription, familyForLookup);
+    CSSSegmentedFontFace* face = m_cssFontFaceSet->getFontFace(fontDescription.traitsMask(), familyForLookup);
     if (!face) {
         if (!resolveGenericFamilyFirst)
             familyForLookup = resolveGenericFamily(m_document, fontDescription, familyName);
@@ -391,49 +248,6 @@
     return face->fontRanges(fontDescription);
 }
 
-CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& family)
-{
-    auto iterator = m_fontFaces.find(family);
-    if (iterator == m_fontFaces.end())
-        return nullptr;
-    auto& familyFontFaces = iterator->value;
-
-    auto& segmentedFontFaceCache = m_fonts.add(family, HashMap<unsigned, std::unique_ptr<CSSSegmentedFontFace>>()).iterator->value;
-
-    FontTraitsMask traitsMask = fontDescription.traitsMask();
-
-    auto& face = segmentedFontFaceCache.add(traitsMask, nullptr).iterator->value;
-    if (face)
-        return face.get();
-
-    face = std::make_unique<CSSSegmentedFontFace>(*this);
-
-    Vector<std::reference_wrapper<CSSFontFace>, 32> candidateFontFaces;
-    for (int i = familyFontFaces.size() - 1; i >= 0; --i) {
-        CSSFontFace& candidate = familyFontFaces[i];
-        unsigned candidateTraitsMask = candidate.traitsMask();
-        if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
-            continue;
-        candidateFontFaces.append(candidate);
-    }
-
-    auto localIterator = m_locallyInstalledFontFaces.find(family);
-    if (localIterator != m_locallyInstalledFontFaces.end()) {
-        for (auto& candidate : localIterator->value) {
-            unsigned candidateTraitsMask = candidate->traitsMask();
-            if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
-                continue;
-            candidateFontFaces.append(candidate);
-        }
-    }
-
-    std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), FontFaceComparator(traitsMask));
-    for (auto& candidate : candidateFontFaces)
-        face->appendFontFace(candidate.get());
-
-    return face.get();
-}
-
 void CSSFontSelector::clearDocument()
 {
     if (!m_document) {
@@ -454,9 +268,7 @@
     m_document = nullptr;
 
     // FIXME: This object should outlive the Document.
-    m_fontFaces.clear();
-    m_locallyInstalledFontFaces.clear();
-    m_fonts.clear();
+    m_cssFontFaceSet->clear();
     m_clients.clear();
 }
 

Modified: trunk/Source/WebCore/css/CSSFontSelector.h (196953 => 196954)


--- trunk/Source/WebCore/css/CSSFontSelector.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSFontSelector.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -27,6 +27,7 @@
 #define CSSFontSelector_h
 
 #include "CSSFontFace.h"
+#include "CSSFontFaceSet.h"
 #include "CachedResourceHandle.h"
 #include "Font.h"
 #include "FontSelector.h"
@@ -48,7 +49,7 @@
 class Document;
 class StyleRuleFontFace;
 
-class CSSFontSelector final : public FontSelector {
+class CSSFontSelector final : public FontSelector, public CSSFontFaceSetClient {
 public:
     static Ref<CSSFontSelector> create(Document& document)
     {
@@ -62,12 +63,10 @@
     virtual FontRanges fontRangesForFamily(const FontDescription&, const AtomicString&) override;
     virtual size_t fallbackFontCount() override;
     virtual RefPtr<Font> fallbackFontAt(const FontDescription&, size_t) override;
-    CSSSegmentedFontFace* getFontFace(const FontDescription&, const AtomicString& family);
 
     void clearDocument();
 
-    static void appendSources(CSSFontFace&, CSSValueList&, Document*, bool isInitiatingElementInUserAgentShadowTree);
-    void addFontFaceRule(const StyleRuleFontFace&, bool isInitiatingElementInUserAgentShadowTree);
+    void addFontFaceRule(StyleRuleFontFace&, bool isInitiatingElementInUserAgentShadowTree);
 
     void fontLoaded();
     virtual void fontCacheInvalidated() override;
@@ -81,21 +80,20 @@
 
     void beginLoadingFontSoon(CachedFont*);
 
-    static String familyNameFromPrimitive(const CSSPrimitiveValue&);
+    FontFaceSet& fontFaceSet();
 
 private:
     explicit CSSFontSelector(Document&);
 
     void dispatchInvalidationCallbacks();
 
+    virtual void fontModified() override;
+
     void beginLoadTimerFired();
 
-    void registerLocalFontFacesForFamily(const String&);
-
     Document* m_document;
-    HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_fontFaces;
-    HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_locallyInstalledFontFaces;
-    HashMap<String, HashMap<unsigned, std::unique_ptr<CSSSegmentedFontFace>>, ASCIICaseInsensitiveHash> m_fonts;
+    RefPtr<FontFaceSet> m_fontFaceSet;
+    Ref<CSSFontFaceSet> m_cssFontFaceSet;
     HashSet<FontSelectorClient*> m_clients;
 
     Vector<CachedResourceHandle<CachedFont>> m_fontsToBeginLoading;
@@ -103,6 +101,7 @@
 
     unsigned m_uniqueId;
     unsigned m_version;
+    bool m_creatingFont { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp (196953 => 196954)


--- trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -37,8 +37,7 @@
 
 namespace WebCore {
 
-CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector& fontSelector)
-    : m_fontSelector(fontSelector)
+CSSSegmentedFontFace::CSSSegmentedFontFace()
 {
 }
 

Modified: trunk/Source/WebCore/css/CSSSegmentedFontFace.h (196953 => 196954)


--- trunk/Source/WebCore/css/CSSSegmentedFontFace.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/CSSSegmentedFontFace.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -42,19 +42,18 @@
 class CSSSegmentedFontFace final : public CSSFontFace::Client {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    CSSSegmentedFontFace(CSSFontSelector&);
+    CSSSegmentedFontFace();
     ~CSSSegmentedFontFace();
 
-    CSSFontSelector& fontSelector() const { return m_fontSelector; }
-
     void appendFontFace(Ref<CSSFontFace>&&);
 
     FontRanges fontRanges(const FontDescription&);
 
+    Vector<Ref<CSSFontFace>, 1>& constituentFaces() { return m_fontFaces; }
+
 private:
     virtual void fontLoaded(CSSFontFace&) override;
 
-    CSSFontSelector& m_fontSelector;
     HashMap<FontDescriptionKey, FontRanges, FontDescriptionKeyHash, WTF::SimpleClassHashTraits<FontDescriptionKey>> m_cache;
     Vector<Ref<CSSFontFace>, 1> m_fontFaces;
 };

Modified: trunk/Source/WebCore/css/FontFace.cpp (196953 => 196954)


--- trunk/Source/WebCore/css/FontFace.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/FontFace.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -75,7 +75,7 @@
         auto value = FontFace::parseString(sourceString, CSSPropertySrc);
         if (is<CSSValueList>(value.get())) {
             CSSValueList& srcList = downcast<CSSValueList>(*value);
-            CSSFontSelector::appendSources(result->backing(), srcList, &downcast<Document>(context), false);
+            CSSFontFace::appendSources(result->backing(), srcList, &downcast<Document>(context), false);
         } else {
             ec = SYNTAX_ERR;
             return nullptr;
@@ -110,18 +110,37 @@
     return result.ptr();
 }
 
+Ref<FontFace> FontFace::create(JSC::ExecState& execState, CSSFontFace& face)
+{
+    return adoptRef(*new FontFace(execState, face));
+}
+
 FontFace::FontFace(JSC::ExecState& execState, CSSFontSelector& fontSelector)
-    : m_backing(CSSFontFace::create(fontSelector, this))
+    : m_weakPtrFactory(this)
+    , m_backing(CSSFontFace::create(&fontSelector, nullptr, this))
     , m_promise(createPromise(execState))
 {
     m_backing->addClient(*this);
 }
 
+FontFace::FontFace(JSC::ExecState& execState, CSSFontFace& face)
+    : m_weakPtrFactory(this)
+    , m_backing(face)
+    , m_promise(createPromise(execState))
+{
+    m_backing->addClient(*this);
+}
+
 FontFace::~FontFace()
 {
     m_backing->removeClient(*this);
 }
 
+WeakPtr<FontFace> FontFace::createWeakPtr() const
+{
+    return m_weakPtrFactory.createWeakPtr();
+}
+
 RefPtr<CSSValue> FontFace::parseString(const String& string, CSSPropertyID propertyID)
 {
     Ref<MutableStyleProperties> style = MutableStyleProperties::create();
@@ -317,18 +336,25 @@
     return String("error", String::ConstructFromLiteral);
 }
 
-void FontFace::stateChanged(CSSFontFace& face, CSSFontFace::Status, CSSFontFace::Status newState)
+void FontFace::fontStateChanged(CSSFontFace& face, CSSFontFace::Status, CSSFontFace::Status newState)
 {
     ASSERT_UNUSED(face, &face == m_backing.ptr());
     switch (newState) {
+    case CSSFontFace::Status::Loading:
+        // We still need to resolve promises when loading completes, even if all references to use have fallen out of scope.
+        ref();
+        break;
     case CSSFontFace::Status::TimedOut:
         rejectPromise(NETWORK_ERR);
+        deref();
         return;
     case CSSFontFace::Status::Success:
         fulfillPromise();
+        deref();
         return;
     case CSSFontFace::Status::Failure:
         rejectPromise(NETWORK_ERR);
+        deref();
         return;
     default:
         return;

Modified: trunk/Source/WebCore/css/FontFace.h (196953 => 196954)


--- trunk/Source/WebCore/css/FontFace.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/FontFace.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -33,6 +33,7 @@
 #include "JSDOMPromise.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 namespace Deprecated {
@@ -48,6 +49,7 @@
 class FontFace final : public RefCounted<FontFace>, public CSSFontFace::Client {
 public:
     static RefPtr<FontFace> create(JSC::ExecState&, ScriptExecutionContext&, const String& family, const Deprecated::ScriptValue& source, const Dictionary& descriptors, ExceptionCode&);
+    static Ref<FontFace> create(JSC::ExecState&, CSSFontFace&);
     virtual ~FontFace();
 
     void setFamily(const String&, ExceptionCode&);
@@ -76,14 +78,18 @@
 
     static RefPtr<CSSValue> parseString(const String&, CSSPropertyID);
 
+    virtual void fontStateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) override;
+
+    WeakPtr<FontFace> createWeakPtr() const;
+
 private:
     FontFace(JSC::ExecState&, CSSFontSelector&);
+    FontFace(JSC::ExecState&, CSSFontFace&);
 
-    virtual void stateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) override;
-
     void fulfillPromise();
     void rejectPromise(ExceptionCode);
 
+    WeakPtrFactory<FontFace> m_weakPtrFactory;
     Ref<CSSFontFace> m_backing;
     Promise m_promise;
 };

Modified: trunk/Source/WebCore/css/FontFaceSet.cpp (196953 => 196954)


--- trunk/Source/WebCore/css/FontFaceSet.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/FontFaceSet.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -42,17 +42,39 @@
     return FontFaceSet::Promise(DeferredWrapper(&exec, &globalObject, JSC::JSPromiseDeferred::create(&exec, &globalObject)));
 }
 
-FontFaceSet::FontFaceSet(JSC::ExecState& execState, Document& document, const Vector<RefPtr<FontFace>>& initialFaces)
+Ref<FontFaceSet> FontFaceSet::create(Document& document, const Vector<RefPtr<FontFace>>& initialFaces)
+{
+    Ref<FontFaceSet> result = adoptRef(*new FontFaceSet(document, initialFaces));
+    result->suspendIfNeeded();
+    return result;
+}
+
+Ref<FontFaceSet> FontFaceSet::create(Document& document, CSSFontFaceSet& backing)
+{
+    Ref<FontFaceSet> result = adoptRef(*new FontFaceSet(document, backing));
+    result->suspendIfNeeded();
+    return result;
+}
+
+FontFaceSet::FontFaceSet(Document& document, const Vector<RefPtr<FontFace>>& initialFaces)
     : ActiveDOMObject(&document)
-    , m_backing(*this)
-    , m_promise(createPromise(execState))
+    , m_backing(CSSFontFaceSet::create())
 {
+    m_backing->addClient(*this);
     for (auto& face : initialFaces)
         add(face.get());
 }
 
+FontFaceSet::FontFaceSet(Document& document, CSSFontFaceSet& backing)
+    : ActiveDOMObject(&document)
+    , m_backing(backing)
+{
+    m_backing->addClient(*this);
+}
+
 FontFaceSet::~FontFaceSet()
 {
+    m_backing->removeClient(*this);
 }
 
 FontFaceSet::Iterator::Iterator(FontFaceSet& set)
@@ -60,11 +82,11 @@
 {
 }
 
-bool FontFaceSet::Iterator::next(FontFace*& key, FontFace*& value)
+bool FontFaceSet::Iterator::next(JSC::ExecState& execState, RefPtr<FontFace>& key, RefPtr<FontFace>& value)
 {
     if (m_index == m_target->size())
         return true;
-    key = m_target->m_backing[m_index++].wrapper();
+    key = m_target->backing()[m_index++].wrapper(execState);
     value = key;
     return false;
 }
@@ -78,45 +100,45 @@
 {
 }
 
-bool FontFaceSet::has(FontFace* face) const
+bool FontFaceSet::has(RefPtr<WebCore::FontFace> face) const
 {
     if (!face)
         return false;
-    return m_backing.hasFace(face->backing());
+    return m_backing->hasFace(face->backing());
 }
 
 size_t FontFaceSet::size() const
 {
-    return m_backing.faceCount();
+    return m_backing->faceCount();
 }
 
-FontFaceSet& FontFaceSet::add(FontFace* face)
+FontFaceSet& FontFaceSet::add(RefPtr<WebCore::FontFace> face)
 {
-    if (face && !m_backing.hasFace(face->backing()))
-        m_backing.add(face->backing());
+    if (face && !m_backing->hasFace(face->backing()))
+        m_backing->add(face->backing());
     return *this;
 }
 
-bool FontFaceSet::remove(FontFace* face)
+bool FontFaceSet::remove(RefPtr<WebCore::FontFace> face)
 {
     if (!face)
         return false;
 
-    bool result = m_backing.hasFace(face->backing());
+    bool result = m_backing->hasFace(face->backing());
     if (result)
-        m_backing.remove(face->backing());
+        m_backing->remove(face->backing());
     return result;
 }
 
 void FontFaceSet::clear()
 {
-    while (m_backing.faceCount())
-        m_backing.remove(m_backing[0]);
+    while (m_backing->faceCount())
+        m_backing->remove(m_backing.get()[0]);
 }
 
-void FontFaceSet::load(const String& font, const String& text, DeferredWrapper&& promise, ExceptionCode& ec)
+void FontFaceSet::load(JSC::ExecState& execState, const String& font, const String& text, DeferredWrapper&& promise, ExceptionCode& ec)
 {
-    auto matchingFaces = m_backing.matchingFaces(font, text, ec);
+    auto matchingFaces = m_backing->matchingFaces(font, text, ec);
     if (ec)
         return;
 
@@ -139,11 +161,11 @@
     }
 
     for (auto& face : matchingFaces) {
-        pendingPromise->faces.append(face.get().wrapper());
+        pendingPromise->faces.append(face.get().wrapper(execState));
         if (face.get().status() == CSSFontFace::Status::Success)
             continue;
         waiting = true;
-        auto& vector = m_pendingPromises.add(RefPtr<FontFace>(face.get().wrapper()), Vector<Ref<PendingPromise>>()).iterator->value;
+        auto& vector = m_pendingPromises.add(RefPtr<CSSFontFace>(&face.get()), Vector<Ref<PendingPromise>>()).iterator->value;
         vector.append(pendingPromise.copyRef());
     }
 
@@ -153,14 +175,14 @@
 
 bool FontFaceSet::check(const String& family, const String& text, ExceptionCode& ec)
 {
-    return m_backing.check(family, text, ec);
+    return m_backing->check(family, text, ec);
 }
 
 auto FontFaceSet::promise(JSC::ExecState& execState) -> Promise&
 {
     if (!m_promise) {
         m_promise = createPromise(execState);
-        if (m_backing.status() == CSSFontFaceSet::Status::Loaded)
+        if (m_backing->status() == CSSFontFaceSet::Status::Loaded)
             fulfillPromise();
     }
     return m_promise.value();
@@ -168,7 +190,7 @@
     
 String FontFaceSet::status() const
 {
-    switch (m_backing.status()) {
+    switch (m_backing->status()) {
     case CSSFontFaceSet::Status::Loading:
         return String("loading", String::ConstructFromLiteral);
     case CSSFontFaceSet::Status::Loaded:
@@ -180,7 +202,7 @@
 
 bool FontFaceSet::canSuspendForDocumentSuspension() const
 {
-    return m_backing.status() == CSSFontFaceSet::Status::Loaded;
+    return m_backing->status() == CSSFontFaceSet::Status::Loaded;
 }
 
 void FontFaceSet::startedLoading()
@@ -209,7 +231,7 @@
 
 void FontFaceSet::faceFinished(CSSFontFace& face, CSSFontFace::Status newStatus)
 {
-    auto iterator = m_pendingPromises.find(face.wrapper());
+    auto iterator = m_pendingPromises.find(&face);
     if (iterator == m_pendingPromises.end())
         return;
 

Modified: trunk/Source/WebCore/css/FontFaceSet.h (196953 => 196954)


--- trunk/Source/WebCore/css/FontFaceSet.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/FontFaceSet.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -38,6 +38,10 @@
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
+namespace JSC {
+class ExecState;
+}
+
 namespace WebCore {
 
 class Document;
@@ -45,22 +49,18 @@
 
 class FontFaceSet final : public RefCounted<FontFaceSet>, public CSSFontFaceSetClient, public EventTargetWithInlineData, public ActiveDOMObject {
 public:
-    static Ref<FontFaceSet> create(JSC::ExecState& execState, Document& document, const Vector<RefPtr<FontFace>>& initialFaces)
-    {
-        Ref<FontFaceSet> result = adoptRef(*new FontFaceSet(execState, document, initialFaces));
-        result->suspendIfNeeded();
-        return result;
-    }
+    static Ref<FontFaceSet> create(Document&, const Vector<RefPtr<FontFace>>& initialFaces);
+    static Ref<FontFaceSet> create(Document&, CSSFontFaceSet& backing);
     virtual ~FontFaceSet();
 
-    bool has(FontFace*) const;
+    bool has(RefPtr<WebCore::FontFace>) const;
     size_t size() const;
-    FontFaceSet& add(FontFace*);
-    bool remove(FontFace*);
+    FontFaceSet& add(RefPtr<WebCore::FontFace>);
+    bool remove(RefPtr<WebCore::FontFace>);
     void clear();
 
-    void load(const String& font, DeferredWrapper&& promise, ExceptionCode& ec) { load(font, String(" ", String::ConstructFromLiteral), WTFMove(promise), ec); }
-    void load(const String& font, const String& text, DeferredWrapper&& promise, ExceptionCode&);
+    void load(JSC::ExecState& execState, const String& font, DeferredWrapper&& promise, ExceptionCode& ec) { load(execState, font, String(" ", String::ConstructFromLiteral), WTFMove(promise), ec); }
+    void load(JSC::ExecState&, const String& font, const String& text, DeferredWrapper&& promise, ExceptionCode&);
     bool check(const String& font, ExceptionCode& ec) { return check(font, String(" ", String::ConstructFromLiteral), ec); }
     bool check(const String& font, const String& text, ExceptionCode&);
 
@@ -69,14 +69,16 @@
     typedef DOMPromise<FontFaceSet&, DOMCoreException&> Promise;
     Promise& promise(JSC::ExecState&);
 
+    CSSFontFaceSet& backing() { return m_backing; }
+
     class Iterator {
     public:
         explicit Iterator(FontFaceSet&);
-        bool next(FontFace*& nextKey, FontFace*& nextValue);
+        bool next(JSC::ExecState&, RefPtr<FontFace>& nextKey, RefPtr<FontFace>& nextValue);
 
     private:
         Ref<FontFaceSet> m_target;
-        size_t m_index { 0 };
+        size_t m_index { 0 }; // FIXME: There needs to be a mechanism to handle when fonts are added or removed from the middle of the FontFaceSet.
     };
     Iterator createIterator() { return Iterator(*this); }
 
@@ -100,7 +102,8 @@
         Promise promise;
     };
 
-    FontFaceSet(JSC::ExecState&, Document&, const Vector<RefPtr<FontFace>>&);
+    FontFaceSet(Document&, const Vector<RefPtr<FontFace>>&);
+    FontFaceSet(Document&, CSSFontFaceSet&);
 
     void fulfillPromise();
 
@@ -119,8 +122,8 @@
     virtual void refEventTarget() override { ref(); }
     virtual void derefEventTarget() override { deref(); }
 
-    CSSFontFaceSet m_backing;
-    HashMap<RefPtr<FontFace>, Vector<Ref<PendingPromise>>> m_pendingPromises;
+    Ref<CSSFontFaceSet> m_backing;
+    HashMap<RefPtr<CSSFontFace>, Vector<Ref<PendingPromise>>> m_pendingPromises;
     Optional<Promise> m_promise;
 };
 

Modified: trunk/Source/WebCore/css/FontFaceSet.idl (196953 => 196954)


--- trunk/Source/WebCore/css/FontFaceSet.idl	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/css/FontFaceSet.idl	2016-02-22 21:40:02 UTC (rev 196954)
@@ -29,7 +29,7 @@
 };
 
 [
-    ConstructorCallWith=ScriptState&Document,
+    ConstructorCallWith=Document,
     Constructor(sequence<FontFace> initialFaces)
 ] interface FontFaceSet : EventTarget {
     boolean has(FontFace font);
@@ -48,7 +48,7 @@
     attribute EventHandler onloadingdone;
     attribute EventHandler onloadingerror;
 
-    [RaisesException] Promise load(DOMString font, optional DOMString text);
+    [RaisesException, CallWith=ScriptState] Promise load(DOMString font, optional DOMString text);
     [RaisesException] boolean check(DOMString font, optional DOMString text);
 
     [Custom] readonly attribute Promise ready;

Modified: trunk/Source/WebCore/dom/Document.cpp (196953 => 196954)


--- trunk/Source/WebCore/dom/Document.cpp	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/dom/Document.cpp	2016-02-22 21:40:02 UTC (rev 196954)
@@ -62,7 +62,7 @@
 #include "EventHandler.h"
 #include "ExtensionStyleSheets.h"
 #include "FocusController.h"
-#include "FontLoader.h"
+#include "FontFaceSet.h"
 #include "FormController.h"
 #include "FrameLoader.h"
 #include "FrameLoaderClient.h"
@@ -6684,14 +6684,10 @@
 }
 #endif
 
-#if ENABLE(FONT_LOAD_EVENTS)
-RefPtr<FontLoader> Document::fonts()
+Ref<FontFaceSet> Document::fonts()
 {
-    if (!m_fontloader)
-        m_fontloader = FontLoader::create(this);
-    return m_fontloader;
+    return fontSelector().fontFaceSet();
 }
-#endif
 
 float Document::deviceScaleFactor() const
 {

Modified: trunk/Source/WebCore/dom/Document.h (196953 => 196954)


--- trunk/Source/WebCore/dom/Document.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/dom/Document.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -201,9 +201,7 @@
 class DOMSecurityPolicy;
 #endif
 
-#if ENABLE(FONT_LOAD_EVENTS)
-class FontLoader;
-#endif
+class FontFaceSet;
 
 typedef int ExceptionCode;
 
@@ -1267,9 +1265,7 @@
 
     WEBCORE_EXPORT virtual SecurityOrigin* topOrigin() const override final;
 
-#if ENABLE(FONT_LOAD_EVENTS)
-    RefPtr<FontLoader> fonts();
-#endif
+    Ref<FontFaceSet> fonts();
 
     void ensurePlugInsInjectedScript(DOMWrapperWorld&);
 
@@ -1751,10 +1747,6 @@
 
     RefPtr<CSSFontSelector> m_fontSelector;
 
-#if ENABLE(FONT_LOAD_EVENTS)
-    RefPtr<FontLoader> m_fontloader;
-#endif
-
 #if ENABLE(WEB_REPLAY)
     RefPtr<JSC::InputCursor> m_inputCursor;
 #endif

Modified: trunk/Source/WebCore/dom/Document.idl (196953 => 196954)


--- trunk/Source/WebCore/dom/Document.idl	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/dom/Document.idl	2016-02-22 21:40:02 UTC (rev 196954)
@@ -265,7 +265,7 @@
     [Conditional=CSS_REGIONS] DOMNamedFlowCollection webkitGetNamedFlows();
 
 #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
-    [Conditional=FONT_LOAD_EVENTS] readonly attribute FontLoader fonts;
+    readonly attribute FontFaceSet fonts;
 #endif
 
 #if defined(ENABLE_IOS_TOUCH_EVENTS) && ENABLE_IOS_TOUCH_EVENTS

Modified: trunk/Source/WebCore/svg/SVGFontFaceElement.h (196953 => 196954)


--- trunk/Source/WebCore/svg/SVGFontFaceElement.h	2016-02-22 21:36:24 UTC (rev 196953)
+++ trunk/Source/WebCore/svg/SVGFontFaceElement.h	2016-02-22 21:40:02 UTC (rev 196954)
@@ -50,7 +50,7 @@
     SVGFontElement* associatedFontElement() const;
     void rebuildFontFace();
     
-    const StyleRuleFontFace& fontFaceRule() const { return m_fontFaceRule.get(); }
+    StyleRuleFontFace& fontFaceRule() { return m_fontFaceRule.get(); }
 
 private:
     SVGFontFaceElement(const QualifiedName&, Document&);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to