summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/CSSFontFace.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/CSSFontFace.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/css/CSSFontFace.cpp')
-rw-r--r--Source/WebCore/css/CSSFontFace.cpp634
1 files changed, 539 insertions, 95 deletions
diff --git a/Source/WebCore/css/CSSFontFace.cpp b/Source/WebCore/css/CSSFontFace.cpp
index f8eab28e0..9bae31cdd 100644
--- a/Source/WebCore/css/CSSFontFace.cpp
+++ b/Source/WebCore/css/CSSFontFace.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -27,155 +27,599 @@
#include "CSSFontFace.h"
#include "CSSFontFaceSource.h"
+#include "CSSFontFaceSrcValue.h"
+#include "CSSFontFamily.h"
+#include "CSSFontFeatureValue.h"
#include "CSSFontSelector.h"
+#include "CSSPrimitiveValueMappings.h"
#include "CSSSegmentedFontFace.h"
+#include "CSSUnicodeRangeValue.h"
+#include "CSSValue.h"
+#include "CSSValueList.h"
#include "Document.h"
+#include "Font.h"
#include "FontDescription.h"
-#include "FontLoader.h"
+#include "FontFace.h"
+#include "FontVariantBuilder.h"
#include "RuntimeEnabledFeatures.h"
-#include "SimpleFontData.h"
+#include "Settings.h"
+#include "StyleProperties.h"
+#include "StyleRule.h"
namespace WebCore {
-bool CSSFontFace::isLoaded() const
+template<typename T> void iterateClients(HashSet<CSSFontFace::Client*>& clients, T callback)
{
- size_t size = m_sources.size();
- for (size_t i = 0; i < size; i++) {
- if (!m_sources[i]->isLoaded())
- return false;
+ Vector<Ref<CSSFontFace::Client>> clientsCopy;
+ clientsCopy.reserveInitialCapacity(clients.size());
+ for (auto* client : clients)
+ clientsCopy.uncheckedAppend(*client);
+
+ for (auto* client : clients)
+ callback(*client);
+}
+
+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()) {
+ const 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_timeoutTimer(*this, &CSSFontFace::timeoutFired)
+ , m_fontSelector(fontSelector)
+ , m_cssConnection(cssConnection)
+ , m_wrapper(wrapper ? wrapper->createWeakPtr() : WeakPtr<FontFace>())
+ , m_isLocalFallback(isLocalFallback)
+ , m_mayBePurged(!wrapper)
+{
+}
+
+CSSFontFace::~CSSFontFace()
+{
+}
+
+bool CSSFontFace::setFamilies(CSSValue& family)
+{
+ if (!is<CSSValueList>(family))
+ return false;
+
+ CSSValueList& familyList = downcast<CSSValueList>(family);
+ if (!familyList.length())
+ return false;
+
+ 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());
+ });
+
return true;
}
-bool CSSFontFace::isValid() const
+std::optional<FontTraitsMask> CSSFontFace::calculateStyleMask(CSSValue& style)
{
- size_t size = m_sources.size();
- for (size_t i = 0; i < size; i++) {
- if (m_sources[i]->isValid())
- return true;
+ if (!is<CSSPrimitiveValue>(style))
+ return std::nullopt;
+
+ switch (downcast<CSSPrimitiveValue>(style).valueID()) {
+ case CSSValueNormal:
+ return FontStyleNormalMask;
+ case CSSValueItalic:
+ case CSSValueOblique:
+ return FontStyleItalicMask;
+ default:
+ return FontStyleNormalMask;
+ }
+
+ return FontStyleNormalMask;
+}
+
+bool CSSFontFace::setStyle(CSSValue& style)
+{
+ 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);
+ });
+
+ return true;
+ }
+ return false;
+}
+
+std::optional<FontTraitsMask> CSSFontFace::calculateWeightMask(CSSValue& weight)
+{
+ if (!is<CSSPrimitiveValue>(weight))
+ return std::nullopt;
+
+ switch (downcast<CSSPrimitiveValue>(weight).valueID()) {
+ case CSSValueBold:
+ case CSSValueBolder:
+ case CSSValue700:
+ return FontWeight700Mask;
+ case CSSValueNormal:
+ case CSSValue400:
+ return FontWeight400Mask;
+ case CSSValue900:
+ return FontWeight900Mask;
+ case CSSValue800:
+ return FontWeight800Mask;
+ case CSSValue600:
+ return FontWeight600Mask;
+ case CSSValue500:
+ return FontWeight500Mask;
+ case CSSValue300:
+ return FontWeight300Mask;
+ case CSSValueLighter:
+ case CSSValue200:
+ return FontWeight200Mask;
+ case CSSValue100:
+ return FontWeight100Mask;
+ default:
+ return FontWeight400Mask;
+ }
+
+ 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());
+
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight);
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
+
+ return true;
}
+
return false;
}
-void CSSFontFace::addedToSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
+bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
{
- m_segmentedFontFaces.add(segmentedFontFace);
+ if (!is<CSSValueList>(unicodeRange))
+ return false;
+
+ m_ranges.clear();
+ auto& list = downcast<CSSValueList>(unicodeRange);
+ for (auto& rangeValue : list) {
+ auto& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
+ m_ranges.append({ range.from(), range.to() });
+ }
+
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange);
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
+
+ return true;
}
-void CSSFontFace::removedFromSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
+bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures)
{
- m_segmentedFontFaces.remove(segmentedFontFace);
+ auto ligatures = extractFontVariantLigatures(variantLigatures);
+
+ m_variantSettings.commonLigatures = ligatures.commonLigatures;
+ m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
+ 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);
+ });
+
+ return true;
}
-void CSSFontFace::addSource(std::unique_ptr<CSSFontFaceSource> source)
+bool CSSFontFace::setVariantPosition(CSSValue& variantPosition)
{
- source->setFontFace(this);
- m_sources.append(std::move(source));
+ if (!is<CSSPrimitiveValue>(variantPosition))
+ return false;
+
+ m_variantSettings.position = downcast<CSSPrimitiveValue>(variantPosition);
+
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition);
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
+
+ return true;
}
-void CSSFontFace::fontLoaded(CSSFontFaceSource* source)
+bool CSSFontFace::setVariantCaps(CSSValue& variantCaps)
{
- if (source != m_activeSource)
- return;
+ if (!is<CSSPrimitiveValue>(variantCaps))
+ return false;
- // FIXME: Can we assert that m_segmentedFontFaces is not empty? That may
- // require stopping in-progress font loading when the last
- // CSSSegmentedFontFace is removed.
- if (m_segmentedFontFaces.isEmpty())
- return;
+ m_variantSettings.caps = downcast<CSSPrimitiveValue>(variantCaps);
- // Use one of the CSSSegmentedFontFaces' font selector. They all have
- // the same font selector, so it's wasteful to store it in the CSSFontFace.
- CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
- fontSelector->fontLoaded();
-
-#if ENABLE(FONT_LOAD_EVENTS)
- if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == Loading) {
- if (source->ensureFontData())
- notifyFontLoader(Loaded);
- else if (!isValid())
- notifyFontLoader(Error);
- }
-#endif
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps);
- HashSet<CSSSegmentedFontFace*>::iterator end = m_segmentedFontFaces.end();
- for (HashSet<CSSSegmentedFontFace*>::iterator it = m_segmentedFontFaces.begin(); it != end; ++it)
- (*it)->fontLoaded(this);
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
-#if ENABLE(FONT_LOAD_EVENTS)
- if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
- notifyLoadingDone();
-#endif
+ return true;
}
-PassRefPtr<SimpleFontData> CSSFontFace::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
+bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric)
{
- m_activeSource = 0;
- if (!isValid())
- return 0;
+ auto numeric = extractFontVariantNumeric(variantNumeric);
- ASSERT(!m_segmentedFontFaces.isEmpty());
- CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
+ m_variantSettings.numericFigure = numeric.figure;
+ m_variantSettings.numericSpacing = numeric.spacing;
+ m_variantSettings.numericFraction = numeric.fraction;
+ m_variantSettings.numericOrdinal = numeric.ordinal;
+ m_variantSettings.numericSlashedZero = numeric.slashedZero;
-#if ENABLE(FONT_LOAD_EVENTS)
- if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == NotLoaded)
- notifyFontLoader(Loading);
-#endif
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantNumeric, &variantNumeric);
- size_t size = m_sources.size();
- for (size_t i = 0; i < size; ++i) {
- if (RefPtr<SimpleFontData> result = m_sources[i]->getFontData(fontDescription, syntheticBold, syntheticItalic, fontSelector)) {
- m_activeSource = m_sources[i].get();
-#if ENABLE(FONT_LOAD_EVENTS)
- if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == Loading && m_sources[i]->isLoaded()) {
- notifyFontLoader(Loaded);
- notifyLoadingDone();
- }
-#endif
- return result.release();
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
+
+ return true;
+}
+
+bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates)
+{
+ if (!is<CSSPrimitiveValue>(variantAlternates))
+ return false;
+
+ m_variantSettings.alternates = downcast<CSSPrimitiveValue>(variantAlternates);
+
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates);
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
+
+ return true;
+}
+
+bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian)
+{
+ auto eastAsian = extractFontVariantEastAsian(variantEastAsian);
+
+ m_variantSettings.eastAsianVariant = eastAsian.variant;
+ 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);
+ });
+
+ return true;
+}
+
+void CSSFontFace::setFeatureSettings(CSSValue& featureSettings)
+{
+ // Can only call this with a primitive value of normal, or a value list containing font feature values.
+ ASSERT(is<CSSPrimitiveValue>(featureSettings) || is<CSSValueList>(featureSettings));
+
+ FontFeatureSettings settings;
+
+ if (is<CSSValueList>(featureSettings)) {
+ auto& list = downcast<CSSValueList>(featureSettings);
+ for (auto& rangeValue : list) {
+ auto& feature = downcast<CSSFontFeatureValue>(rangeValue.get());
+ settings.insert({ feature.tag(), feature.value() });
}
}
-#if ENABLE(FONT_LOAD_EVENTS)
- if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled() && m_loadState == Loading) {
- notifyFontLoader(Error);
- notifyLoadingDone();
+ if (m_featureSettings == settings)
+ return;
+
+ m_featureSettings = WTFMove(settings);
+
+ if (m_cssConnection)
+ m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFeatureSettings, &featureSettings);
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontPropertyChanged(*this);
+ });
+}
+
+bool CSSFontFace::rangesMatchCodePoint(UChar32 character) const
+{
+ if (m_ranges.isEmpty())
+ return true;
+
+ for (auto& range : m_ranges) {
+ if (range.from <= character && character <= range.to)
+ return true;
}
-#endif
- return 0;
+ return false;
}
-#if ENABLE(FONT_LOAD_EVENTS)
-void CSSFontFace::notifyFontLoader(LoadState newState)
+void CSSFontFace::fontLoadEventOccurred()
{
- m_loadState = newState;
+ Ref<CSSFontFace> protectedThis(*this);
- Document* document = (*m_segmentedFontFaces.begin())->fontSelector()->document();
- if (!document)
- return;
+ // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source.
+ // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly
+ // when a source is failed or succeeded before we have asked it to load.
+ if (m_sourcesPopulated)
+ pump();
+
+ ASSERT(m_fontSelector);
+ m_fontSelector->fontLoaded();
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontLoaded(*this);
+ });
+}
+
+void CSSFontFace::timeoutFired()
+{
+ setStatus(Status::TimedOut);
+
+ fontLoadEventOccurred();
+}
+
+bool CSSFontFace::allSourcesFailed() const
+{
+ for (auto& source : m_sources) {
+ if (source->status() != CSSFontFaceSource::Status::Failure)
+ return false;
+ }
+ return true;
+}
+
+void CSSFontFace::addClient(Client& client)
+{
+ m_clients.add(&client);
+}
- switch (newState) {
- case Loading:
- document->fontloader()->beginFontLoading(m_rule.get());
+void CSSFontFace::removeClient(Client& client)
+{
+ ASSERT(m_clients.contains(&client));
+ m_clients.remove(&client);
+}
+
+void CSSFontFace::initializeWrapper()
+{
+ switch (m_status) {
+ case Status::Pending:
break;
- case Loaded:
- document->fontloader()->fontLoaded(m_rule.get());
+ case Status::Loading:
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
break;
- case Error:
- document->fontloader()->loadError(m_rule.get(), m_activeSource);
+ case Status::TimedOut:
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
break;
- default:
+ case Status::Success:
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
+ break;
+ case Status::Failure:
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
+ m_wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
break;
}
+ m_mayBePurged = false;
}
-void CSSFontFace::notifyLoadingDone()
+Ref<FontFace> CSSFontFace::wrapper()
{
- Document* document = (*m_segmentedFontFaces.begin())->fontSelector()->document();
- if (document)
- document->fontloader()->loadingDone();
+ if (m_wrapper)
+ return *m_wrapper.get();
+
+ auto wrapper = FontFace::create(*this);
+ m_wrapper = wrapper->createWeakPtr();
+ initializeWrapper();
+ 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));
+
+ // We should never add sources in the middle of loading.
+ ASSERT(!m_sourcesPopulated);
+}
+
+void CSSFontFace::setStatus(Status newStatus)
+{
+ switch (newStatus) {
+ case Status::Pending:
+ ASSERT_NOT_REACHED();
+ break;
+ case Status::Loading:
+ ASSERT(m_status == Status::Pending);
+ break;
+ case Status::TimedOut:
+ ASSERT(m_status == Status::Loading);
+ break;
+ case Status::Success:
+ ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
+ break;
+ case Status::Failure:
+ ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
+ break;
+ }
+
+ if (newStatus == Status::Loading)
+ m_timeoutTimer.startOneShot(webFontsShouldAlwaysFallBack() ? 0 : 3);
+ else if (newStatus == Status::Success || newStatus == Status::Failure)
+ m_timeoutTimer.stop();
+
+ iterateClients(m_clients, [&](Client& client) {
+ client.fontStateChanged(*this, m_status, newStatus);
+ });
+
+ m_status = newStatus;
+}
+
+void CSSFontFace::fontLoaded(CSSFontFaceSource&)
+{
+ ASSERT(!webFontsShouldAlwaysFallBack());
+
+ fontLoadEventOccurred();
+}
+
+bool CSSFontFace::webFontsShouldAlwaysFallBack() const
+{
+ return m_fontSelector && m_fontSelector->document() && m_fontSelector->document()->settings().webFontsAlwaysFallBack();
+}
+
+size_t CSSFontFace::pump()
+{
+ size_t i;
+ for (i = 0; i < m_sources.size(); ++i) {
+ auto& source = m_sources[i];
+
+ 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);
+ }
+
+ switch (source->status()) {
+ case CSSFontFaceSource::Status::Pending:
+ ASSERT_NOT_REACHED();
+ break;
+ case CSSFontFaceSource::Status::Loading:
+ ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
+ if (m_status == Status::Pending)
+ setStatus(Status::Loading);
+ return i;
+ case CSSFontFaceSource::Status::Success:
+ ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Success);
+ if (m_status == Status::Pending)
+ setStatus(Status::Loading);
+ if (m_status == Status::Loading || m_status == Status::TimedOut)
+ setStatus(Status::Success);
+ return i;
+ case CSSFontFaceSource::Status::Failure:
+ if (m_status == Status::Pending)
+ setStatus(Status::Loading);
+ break;
+ }
+ }
+ if (m_sources.isEmpty() && m_status == Status::Pending)
+ setStatus(Status::Loading);
+ if (m_status == Status::Loading || m_status == Status::TimedOut)
+ setStatus(Status::Failure);
+ return m_sources.size();
+}
+
+void CSSFontFace::load()
+{
+ pump();
+}
+
+RefPtr<Font> CSSFontFace::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
+{
+ if (allSourcesFailed())
+ return nullptr;
+
+ // Our status is derived from the first non-failed source. However, this source may
+ // return null from font(), which means we need to continue looping through the remainder
+ // of the sources to try to find a font to use. These subsequent tries should not affect
+ // our own state, though.
+ size_t startIndex = pump();
+ bool fontIsLoading = false;
+ for (size_t i = startIndex; i < m_sources.size(); ++i) {
+ auto& source = m_sources[i];
+ if (source->status() == CSSFontFaceSource::Status::Pending) {
+ ASSERT(m_fontSelector);
+ if (fontIsLoading)
+ continue;
+ source->load(*m_fontSelector);
+ }
+
+ switch (source->status()) {
+ case CSSFontFaceSource::Status::Pending:
+ ASSERT_NOT_REACHED();
+ break;
+ case CSSFontFaceSource::Status::Loading:
+ ASSERT(!fontIsLoading);
+ fontIsLoading = true;
+ if (status() == Status::TimedOut)
+ continue;
+ return Font::create(FontCache::singleton().lastResortFallbackFontForEveryCharacter(fontDescription)->platformData(), true, true);
+ case CSSFontFaceSource::Status::Success:
+ if (RefPtr<Font> result = source->font(fontDescription, syntheticBold, syntheticItalic, m_featureSettings, m_variantSettings))
+ return result;
+ break;
+ case CSSFontFaceSource::Status::Failure:
+ break;
+ }
+ }
+
+ return nullptr;
+}
+
+bool CSSFontFace::purgeable() const
+{
+ return cssConnection() && m_mayBePurged;
+}
+
+void CSSFontFace::updateStyleIfNeeded()
+{
+ if (m_fontSelector && m_fontSelector->document())
+ m_fontSelector->document()->updateStyleIfNeeded();
}
-#endif
#if ENABLE(SVG_FONTS)
bool CSSFontFace::hasSVGFontFaceSource() const