Diff
Modified: trunk/LayoutTests/ChangeLog (201886 => 201887)
--- trunk/LayoutTests/ChangeLog 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/LayoutTests/ChangeLog 2016-06-09 22:03:53 UTC (rev 201887)
@@ -1,3 +1,13 @@
+2016-06-09 Myles C. Maxfield <mmaxfi...@apple.com>
+
+ Deleting a CSSOM style rule invalidates any previously-added FontFaces
+ https://bugs.webkit.org/show_bug.cgi?id=158450
+
+ Reviewed by Darin Adler.
+
+ * fast/text/font-face-set-cssom-expected.txt: Added.
+ * fast/text/font-face-set-cssom.html: Added.
+
2016-06-09 Ryan Haddad <ryanhad...@apple.com>
Marking webgl/webgl-backing-store-size-update.html as a flaky timeout on mac-wk1
Added: trunk/LayoutTests/fast/text/font-face-set-cssom-expected.txt (0 => 201887)
--- trunk/LayoutTests/fast/text/font-face-set-cssom-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-set-cssom-expected.txt 2016-06-09 22:03:53 UTC (rev 201887)
@@ -0,0 +1,48 @@
+This test makes sure that the CSS Font Loading API plays nicely with modifying @font-face rules with the CSSOM.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS item1.getBoundingClientRect().width is 48
+PASS item2.getBoundingClientRect().width is not 48
+PASS item3.getBoundingClientRect().width is not 48
+PASS item4.getBoundingClientRect().width is not 48
+PASS item5.getBoundingClientRect().width is not 48
+PASS item6.getBoundingClientRect().width is not 48
+PASS item1.getBoundingClientRect().width is 48
+PASS item2.getBoundingClientRect().width is 48
+PASS item3.getBoundingClientRect().width is not 48
+PASS item4.getBoundingClientRect().width is not 48
+PASS item5.getBoundingClientRect().width is not 48
+PASS item6.getBoundingClientRect().width is not 48
+PASS item1.getBoundingClientRect().width is 48
+PASS item2.getBoundingClientRect().width is 48
+PASS item3.getBoundingClientRect().width is 48
+PASS item4.getBoundingClientRect().width is not 48
+PASS item5.getBoundingClientRect().width is not 48
+PASS item6.getBoundingClientRect().width is not 48
+PASS item1.getBoundingClientRect().width is 48
+PASS item2.getBoundingClientRect().width is 48
+PASS item3.getBoundingClientRect().width is not 48
+PASS item4.getBoundingClientRect().width is not 48
+PASS item5.getBoundingClientRect().width is not 48
+PASS item6.getBoundingClientRect().width is not 48
+PASS connectedFontFace.family is "WebFont2"
+PASS connectedFontFace.family is "WebFont5"
+PASS item1.getBoundingClientRect().width is 48
+PASS item2.getBoundingClientRect().width is not 48
+PASS item3.getBoundingClientRect().width is not 48
+PASS item4.getBoundingClientRect().width is not 48
+PASS item5.getBoundingClientRect().width is 48
+PASS item6.getBoundingClientRect().width is not 48
+PASS styleSheet.cssRules[0].style.fontFamily is "WebFont6"
+PASS item1.getBoundingClientRect().width is 48
+PASS item2.getBoundingClientRect().width is not 48
+PASS item3.getBoundingClientRect().width is not 48
+PASS item4.getBoundingClientRect().width is not 48
+PASS item5.getBoundingClientRect().width is not 48
+PASS item6.getBoundingClientRect().width is 48
+PASS successfullyParsed is true
+
+TEST COMPLETE
+l l l l l l
Added: trunk/LayoutTests/fast/text/font-face-set-cssom.html (0 => 201887)
--- trunk/LayoutTests/fast/text/font-face-set-cssom.html (rev 0)
+++ trunk/LayoutTests/fast/text/font-face-set-cssom.html 2016-06-09 22:03:53 UTC (rev 201887)
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style id="styleElement">
+</style>
+</head>
+<body>
+<span id="item1" style="font: 48px WebFont;">l</span>
+<span id="item2" style="font: 48px WebFont2;">l</span>
+<span id="item3" style="font: 48px WebFont3;">l</span>
+<span id="item4" style="font: 48px WebFont4;">l</span>
+<span id="item5" style="font: 48px WebFont5;">l</span>
+<span id="item6" style="font: 48px WebFont6;">l</span>
+<script>
+description("This test makes sure that the CSS Font Loading API plays nicely with modifying @font-face rules with the CSSOM.");
+
+var item1 = document.getElementById("item1");
+var item2 = document.getElementById("item2");
+var item3 = document.getElementById("item3");
+var item4 = document.getElementById("item4");
+var item5 = document.getElementById("item5");
+var item6 = document.getElementById("item6");
+
+var fontFace = new FontFace("WebFont", "local('Ahem')", {});
+document.fonts.add(fontFace);
+fontFace.load();
+
+shouldBe("item1.getBoundingClientRect().width", "48");
+shouldNotBe("item2.getBoundingClientRect().width", "48");
+shouldNotBe("item3.getBoundingClientRect().width", "48");
+shouldNotBe("item4.getBoundingClientRect().width", "48");
+shouldNotBe("item5.getBoundingClientRect().width", "48");
+shouldNotBe("item6.getBoundingClientRect().width", "48");
+
+var styleSheet = document.getElementById("styleElement").sheet;
+styleSheet.insertRule("@font-face { font-family: 'WebFont2'; src: local('Ahem'); }", 0);
+
+shouldBe("item1.getBoundingClientRect().width", "48");
+shouldBe("item2.getBoundingClientRect().width", "48");
+shouldNotBe("item3.getBoundingClientRect().width", "48");
+shouldNotBe("item4.getBoundingClientRect().width", "48");
+shouldNotBe("item5.getBoundingClientRect().width", "48");
+shouldNotBe("item6.getBoundingClientRect().width", "48");
+
+styleSheet.insertRule("@font-face { font-family: 'WebFont3'; src: local('Ahem'); }", 0);
+
+shouldBe("item1.getBoundingClientRect().width", "48");
+shouldBe("item2.getBoundingClientRect().width", "48");
+shouldBe("item3.getBoundingClientRect().width", "48");
+shouldNotBe("item4.getBoundingClientRect().width", "48");
+shouldNotBe("item5.getBoundingClientRect().width", "48");
+shouldNotBe("item6.getBoundingClientRect().width", "48");
+
+styleSheet.deleteRule(0);
+
+shouldBe("item1.getBoundingClientRect().width", "48");
+shouldBe("item2.getBoundingClientRect().width", "48");
+shouldNotBe("item3.getBoundingClientRect().width", "48");
+shouldNotBe("item4.getBoundingClientRect().width", "48");
+shouldNotBe("item5.getBoundingClientRect().width", "48");
+shouldNotBe("item6.getBoundingClientRect().width", "48");
+
+var connectedFontFace = document.fonts.keys().next().value;
+shouldBeEqualToString("connectedFontFace.family", "WebFont2");
+
+styleSheet.cssRules[0].style.fontFamily = "WebFont5";
+
+shouldBeEqualToString("connectedFontFace.family", "WebFont5");
+
+shouldBe("item1.getBoundingClientRect().width", "48");
+shouldNotBe("item2.getBoundingClientRect().width", "48");
+shouldNotBe("item3.getBoundingClientRect().width", "48");
+shouldNotBe("item4.getBoundingClientRect().width", "48");
+shouldBe("item5.getBoundingClientRect().width", "48");
+shouldNotBe("item6.getBoundingClientRect().width", "48");
+
+connectedFontFace.family = "WebFont6";
+
+shouldBeEqualToString("styleSheet.cssRules[0].style.fontFamily", "WebFont6");
+
+shouldBe("item1.getBoundingClientRect().width", "48");
+shouldNotBe("item2.getBoundingClientRect().width", "48");
+shouldNotBe("item3.getBoundingClientRect().width", "48");
+shouldNotBe("item4.getBoundingClientRect().width", "48");
+shouldNotBe("item5.getBoundingClientRect().width", "48");
+shouldBe("item6.getBoundingClientRect().width", "48");
+
+</script>
+<script src=""
+</body>
+<html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (201886 => 201887)
--- trunk/Source/WebCore/ChangeLog 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/ChangeLog 2016-06-09 22:03:53 UTC (rev 201887)
@@ -1,3 +1,93 @@
+2016-06-09 Myles C. Maxfield <mmaxfi...@apple.com>
+
+ Deleting a CSSOM style rule invalidates any previously-added FontFaces
+ https://bugs.webkit.org/show_bug.cgi?id=158450
+
+ Reviewed by Darin Adler.
+
+ This patch has two pieces: updating the CSSOM when the FontFace changes, and
+ updating the FontFace when the CSSOM changes.
+
+ 1: Updating the CSSOM when the FontFace changes: CSSFontFaces already have a RefPtr
+ to their StyleRuleFontFace which represents their CSS-connection. When changing a
+ property of the CSSFontFace, we simply reach into the StyleRule and update it to
+ match. Our existing infrastructure of invalidation due to the attribute changes
+ makes sure that all the necessary updates occur.
+
+ 2. Updating the FontFace when the CSSOM changes: If the CSSOM changes in a trivial
+ way (for example, a new @font-face is appended to the end of the last <style>
+ element), we can handle it directly. However, when something more invasive occurs,
+ we end up clearing the entire CSSFontSelector, and then adding all the style rules
+ from scratch. This involves three steps:
+ a) CSSFontSelector::buildStarted() is run, which means "we're about to start
+ building up all the @font-face rules from scratch." We take this opportunity
+ to purge as many fonts as possible. This is valuable because, for example,
+ this function gets run when the page gets put into the page cache, so we
+ want to destroy as much as possible. Not everything can be purged, however -
+ only CSS-connected fonts which have never been inspected by script are
+ purgeable. We don't allow fonts inspected by script to be purged because
+ purging might result in a font appearing from _javascript_ to transition from
+ a success -> failure state, which we don't allow.
+ b) Upon style recalc (possibly asynchronously) CSSFontSelector::addFontFaceRule()
+ is called for each @font-face rule. We actually detect that we're in the
+ middle of a style rebuild, and defer this step.
+ c) When we're done adding all the font face rules, we call
+ CSSFontSelector::buildCompleted(). This is where we compare the newly built-
+ up list of font faces with what existed previously (as remembered in
+ CSSFontSelector::buildStarted()) in order to detect font faces which were
+ deleted from the document. Fonts which were newly added to the document
+ are handled naturally.
+ Fonts which have a property modified on them are created as if they were new.
+ However, instead of simply adding the CSSFontFace, we search for the existing
+ CSSFontFace (by CSS connection pointer) and tell the existing FontFace to
+ adopt this new CSSFontFace. This means that the _javascript_ object will just
+ pick up any newly-written values in the CSSOM. It also means that the
+ "status" attribute of the _javascript_ object is reset, but this is expected
+ and allowed by the spec. (For example, if you change the "src" attribute of
+ an @font-face block via the CSSOM, all bets are off when you inspect the
+ FontFace JS object representing that block.)
+
+ Test: fast/text/font-face-set-cssom.html
+
+ * css/CSSFontFace.cpp:
+ (WebCore::CSSFontFace::CSSFontFace):
+ (WebCore::CSSFontFace::setFamilies):
+ (WebCore::CSSFontFace::setStyle):
+ (WebCore::CSSFontFace::setWeight):
+ (WebCore::CSSFontFace::setUnicodeRange):
+ (WebCore::CSSFontFace::setVariantLigatures):
+ (WebCore::CSSFontFace::setVariantPosition):
+ (WebCore::CSSFontFace::setVariantCaps):
+ (WebCore::CSSFontFace::setVariantNumeric):
+ (WebCore::CSSFontFace::setVariantAlternates):
+ (WebCore::CSSFontFace::setVariantEastAsian):
+ (WebCore::CSSFontFace::setFeatureSettings):
+ (WebCore::CSSFontFace::initializeWrapper):
+ (WebCore::CSSFontFace::wrapper):
+ (WebCore::CSSFontFace::setWrapper):
+ (WebCore::CSSFontFace::purgeable):
+ (WebCore::CSSFontFace::updateStyleIfNeeded):
+ * css/CSSFontFace.h:
+ * css/CSSFontFaceSet.cpp:
+ (WebCore::CSSFontFaceSet::remove):
+ (WebCore::CSSFontFaceSet::containsCSSConnection):
+ (WebCore::CSSFontFaceSet::purge):
+ * css/CSSFontFaceSet.h:
+ * css/CSSFontSelector.cpp:
+ (WebCore::CSSFontSelector::buildStarted):
+ (WebCore::CSSFontSelector::buildCompleted):
+ (WebCore::CSSFontSelector::addFontFaceRule):
+ * css/CSSFontSelector.h:
+ * css/FontFace.cpp:
+ (WebCore::FontFace::family):
+ (WebCore::FontFace::style):
+ (WebCore::FontFace::weight):
+ (WebCore::FontFace::unicodeRange):
+ (WebCore::FontFace::variant):
+ (WebCore::FontFace::featureSettings):
+ (WebCore::FontFace::adopt):
+ * css/FontFace.h:
+
2016-06-09 Andy Estes <aes...@apple.com>
Define printing{Minimum,Maximum}ShrinkFactor in only one place
Modified: trunk/Source/WebCore/css/CSSFontFace.cpp (201886 => 201887)
--- trunk/Source/WebCore/css/CSSFontFace.cpp 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/CSSFontFace.cpp 2016-06-09 22:03:53 UTC (rev 201887)
@@ -94,6 +94,7 @@
, m_cssConnection(cssConnection)
, m_wrapper(wrapper ? wrapper->createWeakPtr() : WeakPtr<FontFace>())
, m_isLocalFallback(isLocalFallback)
+ , m_mayBePurged(!wrapper)
{
}
@@ -113,6 +114,9 @@
RefPtr<CSSValueList> oldFamilies = m_families;
m_families = &familyList;
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFamily, &family);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this, oldFamilies.get());
});
@@ -143,6 +147,9 @@
if (auto mask = calculateStyleMask(style)) {
m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontStyleMask)) | mask.value());
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStyle, &style);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -192,6 +199,9 @@
if (auto mask = calculateWeightMask(weight)) {
m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontWeightMask)) | mask.value());
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -214,6 +224,9 @@
m_ranges.append({ range.from(), range.to() });
}
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -230,6 +243,9 @@
m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
m_variantSettings.contextualAlternates = ligatures.contextualAlternates;
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantLigatures, &variantLigatures);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -244,6 +260,9 @@
m_variantSettings.position = downcast<CSSPrimitiveValue>(variantPosition);
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -258,6 +277,9 @@
m_variantSettings.caps = downcast<CSSPrimitiveValue>(variantCaps);
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -275,6 +297,9 @@
m_variantSettings.numericOrdinal = numeric.ordinal;
m_variantSettings.numericSlashedZero = numeric.slashedZero;
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantNumeric, &variantNumeric);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -289,6 +314,9 @@
m_variantSettings.alternates = downcast<CSSPrimitiveValue>(variantAlternates);
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -304,6 +332,9 @@
m_variantSettings.eastAsianWidth = eastAsian.width;
m_variantSettings.eastAsianRuby = eastAsian.ruby;
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantEastAsian, &variantEastAsian);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -331,6 +362,9 @@
m_featureSettings = WTFMove(settings);
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFeatureSettings, &featureSettings);
+
iterateClients(m_clients, [&](Client& client) {
client.fontPropertyChanged(*this);
});
@@ -381,35 +415,47 @@
m_clients.remove(&client);
}
-Ref<FontFace> CSSFontFace::wrapper()
+void CSSFontFace::initializeWrapper()
{
- if (m_wrapper)
- return Ref<FontFace>(*m_wrapper.get());
-
- Ref<FontFace> wrapper = FontFace::create(*this);
switch (m_status) {
case Status::Pending:
break;
case Status::Loading:
- wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_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);
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_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);
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_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);
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
break;
}
+}
+
+Ref<FontFace> CSSFontFace::wrapper()
+{
+ if (m_wrapper)
+ return *m_wrapper.get();
+
+ auto wrapper = FontFace::create(*this);
m_wrapper = wrapper->createWeakPtr();
+ initializeWrapper();
+ m_mayBePurged = false;
return wrapper;
}
+void CSSFontFace::setWrapper(FontFace& newWrapper)
+{
+ m_wrapper = newWrapper.createWeakPtr();
+ initializeWrapper();
+}
+
void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
{
m_sources.append(WTFMove(source));
@@ -552,6 +598,17 @@
return nullptr;
}
+bool CSSFontFace::purgeable() const
+{
+ return cssConnection() && m_mayBePurged;
+}
+
+void CSSFontFace::updateStyleIfNeeded()
+{
+ if (m_fontSelector && m_fontSelector->document())
+ m_fontSelector->document()->updateStyleIfNeeded();
+}
+
#if ENABLE(SVG_FONTS)
bool CSSFontFace::hasSVGFontFaceSource() const
{
Modified: trunk/Source/WebCore/css/CSSFontFace.h (201886 => 201887)
--- trunk/Source/WebCore/css/CSSFontFace.h 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/CSSFontFace.h 2016-06-09 22:03:53 UTC (rev 201887)
@@ -135,9 +135,15 @@
// We don't guarantee that the FontFace wrapper will be the same every time you ask for it.
Ref<FontFace> wrapper();
+ void setWrapper(FontFace&);
+ FontFace* existingWrapper() { return m_wrapper.get(); }
bool webFontsShouldAlwaysFallBack() const;
+ bool purgeable() const;
+
+ void updateStyleIfNeeded();
+
#if ENABLE(SVG_FONTS)
bool hasSVGFontFaceSource() const;
#endif
@@ -149,6 +155,8 @@
void setStatus(Status);
void notifyClientsOfFontPropertyChange();
+ void initializeWrapper();
+
void fontLoadEventOccurred();
void timeoutFired();
@@ -166,6 +174,7 @@
Status m_status { Status::Pending };
bool m_isLocalFallback { false };
bool m_sourcesPopulated { false };
+ bool m_mayBePurged { true };
};
}
Modified: trunk/Source/WebCore/css/CSSFontFaceSet.cpp (201886 => 201887)
--- trunk/Source/WebCore/css/CSSFontFaceSet.cpp 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/CSSFontFaceSet.cpp 2016-06-09 22:03:53 UTC (rev 201887)
@@ -95,9 +95,10 @@
return false;
}
-void CSSFontFaceSet::registerLocalFontFacesForFamily(const String& familyName)
+void CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered(const String& familyName)
{
- ASSERT(!m_locallyInstalledFacesLookupTable.contains(familyName));
+ if (m_locallyInstalledFacesLookupTable.contains(familyName))
+ return;
Vector<FontTraitsMask> traitsMasks = FontCache::singleton().getTraitsInFamily(familyName);
if (traitsMasks.isEmpty())
@@ -160,7 +161,7 @@
if (addResult.isNewEntry) {
// m_locallyInstalledFontFaces grows without bound, eventually encorporating every font installed on the system.
// This is by design.
- registerLocalFontFacesForFamily(familyName);
+ ensureLocalFontFacesForFamilyRegistered(familyName);
familyFontFaces = { };
}
@@ -187,6 +188,11 @@
if (face.status() == CSSFontFace::Status::Loading || face.status() == CSSFontFace::Status::TimedOut)
incrementActiveCount();
+
+ if (face.cssConnection()) {
+ auto addResult = m_constituentCSSConnections.add(face.cssConnection(), &face);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+ }
}
void CSSFontFaceSet::removeFromFacesLookupTable(const CSSFontFace& face, const CSSValueList& familiesToSearchFor)
@@ -222,6 +228,11 @@
if (face.families())
removeFromFacesLookupTable(face, *face.families());
+ if (face.cssConnection()) {
+ bool removed = m_constituentCSSConnections.remove(face.cssConnection());
+ ASSERT_UNUSED(removed, removed);
+ }
+
for (size_t i = 0; i < m_faces.size(); ++i) {
if (m_faces[i].ptr() == &face) {
if (i < m_facesPartitionIndex)
@@ -236,6 +247,23 @@
ASSERT_NOT_REACHED();
}
+CSSFontFace* CSSFontFaceSet::lookupByCSSConnection(StyleRuleFontFace& target)
+{
+ return m_constituentCSSConnections.get(&target);
+}
+
+void CSSFontFaceSet::purge()
+{
+ Vector<std::reference_wrapper<CSSFontFace>> toRemove;
+ for (auto& face : m_faces) {
+ if (face->purgeable())
+ toRemove.append(face.get());
+ }
+
+ for (auto& item : toRemove)
+ remove(item.get());
+}
+
void CSSFontFaceSet::clear()
{
for (auto& face : m_faces)
@@ -244,6 +272,7 @@
m_facesLookupTable.clear();
m_locallyInstalledFacesLookupTable.clear();
m_cache.clear();
+ m_constituentCSSConnections.clear();
m_facesPartitionIndex = 0;
m_status = Status::Loaded;
}
Modified: trunk/Source/WebCore/css/CSSFontFaceSet.h (201886 => 201887)
--- trunk/Source/WebCore/css/CSSFontFaceSet.h 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/CSSFontFaceSet.h 2016-06-09 22:03:53 UTC (rev 201887)
@@ -60,9 +60,12 @@
size_t faceCount() const { return m_faces.size(); }
void add(CSSFontFace&);
void remove(const CSSFontFace&);
+ void purge();
void clear();
CSSFontFace& operator[](size_t i);
+ CSSFontFace* lookupByCSSConnection(StyleRuleFontFace&);
+
bool check(const String& font, const String& text, ExceptionCode&);
CSSSegmentedFontFace* getFontFace(FontTraitsMask, const AtomicString& family);
@@ -91,7 +94,7 @@
void fontStateChanged(CSSFontFace&, CSSFontFace::Status oldState, CSSFontFace::Status newState) override;
void fontPropertyChanged(CSSFontFace&, CSSValueList* oldFamilies = nullptr) override;
- void registerLocalFontFacesForFamily(const String&);
+ void ensureLocalFontFacesForFamilyRegistered(const String&);
static String familyNameFromPrimitive(const CSSPrimitiveValue&);
@@ -100,6 +103,7 @@
HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_facesLookupTable;
HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_locallyInstalledFacesLookupTable;
HashMap<String, HashMap<unsigned, RefPtr<CSSSegmentedFontFace>>, ASCIICaseInsensitiveHash> m_cache;
+ HashMap<StyleRuleFontFace*, CSSFontFace*> m_constituentCSSConnections;
size_t m_facesPartitionIndex { 0 }; // All entries in m_faces before this index are CSS-connected.
Status m_status { Status::Loaded };
HashSet<CSSFontFaceSetClient*> m_clients;
Modified: trunk/Source/WebCore/css/CSSFontSelector.cpp (201886 => 201887)
--- trunk/Source/WebCore/css/CSSFontSelector.cpp 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/CSSFontSelector.cpp 2016-06-09 22:03:53 UTC (rev 201887)
@@ -45,6 +45,7 @@
#include "Document.h"
#include "Font.h"
#include "FontCache.h"
+#include "FontFace.h"
#include "FontFaceSet.h"
#include "FontSelectorClient.h"
#include "FontVariantBuilder.h"
@@ -101,7 +102,17 @@
void CSSFontSelector::buildStarted()
{
m_buildIsUnderway = true;
+ m_stagingArea.clear();
+ m_cssFontFaceSet->purge();
++m_version;
+
+ m_cssConnectionsPossiblyToRemove.clear();
+ m_cssConnectionsEncounteredDuringBuild.clear();
+ for (size_t i = 0; i < m_cssFontFaceSet->faceCount(); ++i) {
+ CSSFontFace& face = m_cssFontFaceSet.get()[i];
+ if (face.cssConnection())
+ m_cssConnectionsPossiblyToRemove.add(&face);
+ }
}
void CSSFontSelector::buildCompleted()
@@ -111,7 +122,13 @@
m_buildIsUnderway = false;
- m_cssFontFaceSet->clear();
+ // Some font faces weren't re-added during the build process.
+ for (auto& face : m_cssConnectionsPossiblyToRemove) {
+ auto* connection = face->cssConnection();
+ ASSERT(connection);
+ if (!m_cssConnectionsEncounteredDuringBuild.contains(connection))
+ m_cssFontFaceSet->remove(*face);
+ }
for (auto& item : m_stagingArea)
addFontFaceRule(item.styleRuleFontFace, item.isInitiatingElementInUserAgentShadowTree);
@@ -121,6 +138,7 @@
void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isInitiatingElementInUserAgentShadowTree)
{
if (m_buildIsUnderway) {
+ m_cssConnectionsEncounteredDuringBuild.add(&fontFaceRule);
m_stagingArea.append({fontFaceRule, isInitiatingElementInUserAgentShadowTree});
return;
}
@@ -187,6 +205,12 @@
if (fontFace->allSourcesFailed())
return;
+ if (RefPtr<CSSFontFace> existingFace = m_cssFontFaceSet->lookupByCSSConnection(fontFaceRule)) {
+ m_cssFontFaceSet->remove(*existingFace);
+ if (auto* existingWrapper = existingFace->existingWrapper())
+ existingWrapper->adopt(fontFace.get());
+ }
+
m_cssFontFaceSet->add(fontFace.get());
m_creatingFont = false;
++m_version;
Modified: trunk/Source/WebCore/css/CSSFontSelector.h (201886 => 201887)
--- trunk/Source/WebCore/css/CSSFontSelector.h 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/CSSFontSelector.h 2016-06-09 22:03:53 UTC (rev 201887)
@@ -105,6 +105,8 @@
HashSet<FontSelectorClient*> m_clients;
Vector<CachedResourceHandle<CachedFont>> m_fontsToBeginLoading;
+ HashSet<RefPtr<CSSFontFace>> m_cssConnectionsPossiblyToRemove;
+ HashSet<RefPtr<StyleRuleFontFace>> m_cssConnectionsEncounteredDuringBuild;
Timer m_beginLoadingTimer;
unsigned m_uniqueId;
Modified: trunk/Source/WebCore/css/FontFace.cpp (201886 => 201887)
--- trunk/Source/WebCore/css/FontFace.cpp 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/FontFace.cpp 2016-06-09 22:03:53 UTC (rev 201887)
@@ -270,11 +270,13 @@
String FontFace::family() const
{
+ const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
return m_backing->families()->cssText();
}
String FontFace::style() const
{
+ const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
switch (m_backing->traitsMask() & FontStyleMask) {
case FontStyleNormalMask:
return String("normal", String::ConstructFromLiteral);
@@ -287,6 +289,7 @@
String FontFace::weight() const
{
+ const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
switch (m_backing->traitsMask() & FontWeightMask) {
case FontWeight100Mask:
return String("100", String::ConstructFromLiteral);
@@ -318,6 +321,7 @@
String FontFace::unicodeRange() const
{
+ const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
if (!m_backing->ranges().size())
return "U+0-10FFFF";
RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
@@ -328,11 +332,13 @@
String FontFace::variant() const
{
+ const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
return computeFontVariant(m_backing->variantSettings())->cssText();
}
String FontFace::featureSettings() const
{
+ const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
if (!m_backing->featureSettings().size())
return "normal";
RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
@@ -359,6 +365,15 @@
return LoadStatus::Error;
}
+void FontFace::adopt(CSSFontFace& newFace)
+{
+ m_promise = Nullopt;
+ m_backing->removeClient(*this);
+ m_backing = newFace;
+ m_backing->addClient(*this);
+ newFace.setWrapper(*this);
+}
+
void FontFace::fontStateChanged(CSSFontFace& face, CSSFontFace::Status, CSSFontFace::Status newState)
{
ASSERT_UNUSED(face, &face == m_backing.ptr());
Modified: trunk/Source/WebCore/css/FontFace.h (201886 => 201887)
--- trunk/Source/WebCore/css/FontFace.h 2016-06-09 21:41:39 UTC (rev 201886)
+++ trunk/Source/WebCore/css/FontFace.h 2016-06-09 22:03:53 UTC (rev 201887)
@@ -69,6 +69,8 @@
Optional<Promise>& promise() { return m_promise; }
void registerLoaded(Promise&&);
+ void adopt(CSSFontFace&);
+
void load();
CSSFontFace& backing() { return m_backing; }