summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/CSSFontSelector.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/CSSFontSelector.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/css/CSSFontSelector.cpp')
-rw-r--r--Source/WebCore/css/CSSFontSelector.cpp678
1 files changed, 204 insertions, 474 deletions
diff --git a/Source/WebCore/css/CSSFontSelector.cpp b/Source/WebCore/css/CSSFontSelector.cpp
index e88567deb..44d84b04d 100644
--- a/Source/WebCore/css/CSSFontSelector.cpp
+++ b/Source/WebCore/css/CSSFontSelector.cpp
@@ -11,10 +11,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
@@ -31,20 +31,27 @@
#include "CSSFontFace.h"
#include "CSSFontFaceRule.h"
#include "CSSFontFaceSource.h"
-#include "CSSFontFaceSrcValue.h"
+#include "CSSFontFamily.h"
+#include "CSSFontFeatureValue.h"
#include "CSSPrimitiveValue.h"
+#include "CSSPrimitiveValueMappings.h"
#include "CSSPropertyNames.h"
#include "CSSSegmentedFontFace.h"
#include "CSSUnicodeRangeValue.h"
#include "CSSValueKeywords.h"
#include "CSSValueList.h"
+#include "CSSValuePool.h"
#include "CachedResourceLoader.h"
#include "Document.h"
+#include "Font.h"
#include "FontCache.h"
+#include "FontFace.h"
+#include "FontFaceSet.h"
+#include "FontSelectorClient.h"
+#include "FontVariantBuilder.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "Settings.h"
-#include "SimpleFontData.h"
#include "StyleProperties.h"
#include "StyleResolver.h"
#include "StyleRule.h"
@@ -52,286 +59,179 @@
#include <wtf/Ref.h>
#include <wtf/text/AtomicString.h>
-#if ENABLE(SVG)
-#include "SVGFontFaceElement.h"
-#include "SVGNames.h"
-#endif
-
namespace WebCore {
static unsigned fontSelectorId;
-CSSFontSelector::CSSFontSelector(Document* document)
- : m_document(document)
- , m_beginLoadingTimer(this, &CSSFontSelector::beginLoadTimerFired)
+CSSFontSelector::CSSFontSelector(Document& document)
+ : m_document(&document)
+ , m_cssFontFaceSet(CSSFontFaceSet::create())
+ , m_beginLoadingTimer(*this, &CSSFontSelector::beginLoadTimerFired)
, m_uniqueId(++fontSelectorId)
, m_version(0)
-
{
- // FIXME: An old comment used to say there was no need to hold a reference to m_document
- // because "we are guaranteed to be destroyed before the document". But there does not
- // seem to be any such guarantee.
-
ASSERT(m_document);
- fontCache()->addClient(this);
+ FontCache::singleton().addClient(*this);
+ m_cssFontFaceSet->addClient(*this);
}
CSSFontSelector::~CSSFontSelector()
{
clearDocument();
- fontCache()->removeClient(this);
+ m_cssFontFaceSet->removeClient(*this);
+ FontCache::singleton().removeClient(*this);
+}
+
+FontFaceSet& CSSFontSelector::fontFaceSet()
+{
+ if (!m_fontFaceSet) {
+ ASSERT(m_document);
+ m_fontFaceSet = FontFaceSet::create(*m_document, m_cssFontFaceSet.get());
+ }
+
+ return *m_fontFaceSet;
}
bool CSSFontSelector::isEmpty() const
{
- return m_fonts.isEmpty();
+ return !m_cssFontFaceSet->faceCount();
+}
+
+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()
+{
+ if (!m_buildIsUnderway)
+ return;
+
+ m_buildIsUnderway = false;
+
+ // 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);
+ m_stagingArea.clear();
}
-void CSSFontSelector::addFontFaceRule(const StyleRuleFontFace* fontFaceRule)
+void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isInitiatingElementInUserAgentShadowTree)
{
- // Obtain the font-family property and the src property. Both must be defined.
- const StyleProperties& style = fontFaceRule->properties();
+ if (m_buildIsUnderway) {
+ m_cssConnectionsEncounteredDuringBuild.add(&fontFaceRule);
+ m_stagingArea.append({fontFaceRule, isInitiatingElementInUserAgentShadowTree});
+ return;
+ }
+
+ const StyleProperties& style = fontFaceRule.properties();
RefPtr<CSSValue> fontFamily = style.getPropertyCSSValue(CSSPropertyFontFamily);
+ RefPtr<CSSValue> fontStyle = style.getPropertyCSSValue(CSSPropertyFontStyle);
+ RefPtr<CSSValue> fontWeight = style.getPropertyCSSValue(CSSPropertyFontWeight);
RefPtr<CSSValue> src = style.getPropertyCSSValue(CSSPropertySrc);
RefPtr<CSSValue> unicodeRange = style.getPropertyCSSValue(CSSPropertyUnicodeRange);
- if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList()))
+ RefPtr<CSSValue> featureSettings = style.getPropertyCSSValue(CSSPropertyFontFeatureSettings);
+ RefPtr<CSSValue> variantLigatures = style.getPropertyCSSValue(CSSPropertyFontVariantLigatures);
+ RefPtr<CSSValue> variantPosition = style.getPropertyCSSValue(CSSPropertyFontVariantPosition);
+ RefPtr<CSSValue> variantCaps = style.getPropertyCSSValue(CSSPropertyFontVariantCaps);
+ RefPtr<CSSValue> variantNumeric = style.getPropertyCSSValue(CSSPropertyFontVariantNumeric);
+ RefPtr<CSSValue> variantAlternates = style.getPropertyCSSValue(CSSPropertyFontVariantAlternates);
+ RefPtr<CSSValue> variantEastAsian = style.getPropertyCSSValue(CSSPropertyFontVariantEastAsian);
+ if (!is<CSSValueList>(fontFamily.get()) || !is<CSSValueList>(src.get()) || (unicodeRange && !is<CSSValueList>(*unicodeRange)))
return;
- CSSValueList* familyList = toCSSValueList(fontFamily.get());
- if (!familyList->length())
+ CSSValueList& familyList = downcast<CSSValueList>(*fontFamily);
+ if (!familyList.length())
return;
- CSSValueList* srcList = toCSSValueList(src.get());
- if (!srcList->length())
+ if (!fontStyle)
+ fontStyle = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr();
+
+ if (!fontWeight)
+ fontWeight = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
+
+ CSSValueList* rangeList = downcast<CSSValueList>(unicodeRange.get());
+
+ CSSValueList& srcList = downcast<CSSValueList>(*src);
+ if (!srcList.length())
return;
- CSSValueList* rangeList = toCSSValueList(unicodeRange.get());
-
- unsigned traitsMask = 0;
-
- if (RefPtr<CSSValue> fontStyle = style.getPropertyCSSValue(CSSPropertyFontStyle)) {
- if (!fontStyle->isPrimitiveValue())
- return;
-
- switch (toCSSPrimitiveValue(fontStyle.get())->getValueID()) {
- case CSSValueNormal:
- traitsMask |= FontStyleNormalMask;
- break;
- case CSSValueItalic:
- case CSSValueOblique:
- traitsMask |= FontStyleItalicMask;
- break;
- default:
- break;
- }
- } else
- traitsMask |= FontStyleNormalMask;
-
- if (RefPtr<CSSValue> fontWeight = style.getPropertyCSSValue(CSSPropertyFontWeight)) {
- if (!fontWeight->isPrimitiveValue())
- return;
-
- switch (toCSSPrimitiveValue(fontWeight.get())->getValueID()) {
- case CSSValueBold:
- case CSSValue700:
- traitsMask |= FontWeight700Mask;
- break;
- case CSSValueNormal:
- case CSSValue400:
- traitsMask |= FontWeight400Mask;
- break;
- case CSSValue900:
- traitsMask |= FontWeight900Mask;
- break;
- case CSSValue800:
- traitsMask |= FontWeight800Mask;
- break;
- case CSSValue600:
- traitsMask |= FontWeight600Mask;
- break;
- case CSSValue500:
- traitsMask |= FontWeight500Mask;
- break;
- case CSSValue300:
- traitsMask |= FontWeight300Mask;
- break;
- case CSSValue200:
- traitsMask |= FontWeight200Mask;
- break;
- case CSSValue100:
- traitsMask |= FontWeight100Mask;
- break;
- default:
- break;
- }
- } else
- traitsMask |= FontWeight400Mask;
-
- if (RefPtr<CSSValue> fontVariant = style.getPropertyCSSValue(CSSPropertyFontVariant)) {
- // font-variant descriptor can be a value list.
- if (fontVariant->isPrimitiveValue()) {
- RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
- list->append(fontVariant);
- fontVariant = list;
- } else if (!fontVariant->isValueList())
- return;
-
- CSSValueList* variantList = toCSSValueList(fontVariant.get());
- unsigned numVariants = variantList->length();
- if (!numVariants)
- return;
-
- for (unsigned i = 0; i < numVariants; ++i) {
- switch (toCSSPrimitiveValue(variantList->itemWithoutBoundsCheck(i))->getValueID()) {
- case CSSValueNormal:
- traitsMask |= FontVariantNormalMask;
- break;
- case CSSValueSmallCaps:
- traitsMask |= FontVariantSmallCapsMask;
- break;
- default:
- break;
- }
- }
- } else
- traitsMask |= FontVariantMask;
-
- // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
- RefPtr<CSSFontFace> fontFace;
-
- int srcLength = srcList->length();
-
- bool foundSVGFont = false;
-
- for (int i = 0; i < srcLength; i++) {
- // An item in the list either specifies a string (local font name) or a URL (remote font to download).
- CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->itemWithoutBoundsCheck(i));
- std::unique_ptr<CSSFontFaceSource> source;
-
-#if ENABLE(SVG_FONTS)
- foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
-#endif
- if (!item->isLocal()) {
- Settings* settings = m_document ? m_document->frame() ? &m_document->frame()->settings() : 0 : 0;
- bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
- if (allowDownloading && item->isSupportedFormat() && m_document) {
- CachedFont* cachedFont = item->cachedFont(m_document);
- if (cachedFont) {
- source = std::make_unique<CSSFontFaceSource>(item->resource(), cachedFont);
-#if ENABLE(SVG_FONTS)
- if (foundSVGFont)
- source->setHasExternalSVGFont(true);
-#endif
- }
- }
- } else {
- source = std::make_unique<CSSFontFaceSource>(item->resource());
- }
-
- if (!fontFace) {
- RefPtr<CSSFontFaceRule> rule;
-#if ENABLE(FONT_LOAD_EVENTS)
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=112116 - This CSSFontFaceRule has no parent.
- if (RuntimeEnabledFeatures::sharedFeatures().fontLoadEventsEnabled())
- rule = static_pointer_cast<CSSFontFaceRule>(fontFaceRule->createCSSOMWrapper());
-#endif
- fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask), rule);
- }
-
- if (source) {
-#if ENABLE(SVG_FONTS)
- source->setSVGFontFaceElement(item->svgFontFaceElement());
-#endif
- fontFace->addSource(std::move(source));
- }
- }
+ m_creatingFont = true;
+ Ref<CSSFontFace> fontFace = CSSFontFace::create(this, &fontFaceRule);
- ASSERT(fontFace);
+ if (!fontFace->setFamilies(*fontFamily))
+ return;
+ if (!fontFace->setStyle(*fontStyle))
+ return;
+ if (!fontFace->setWeight(*fontWeight))
+ return;
+ if (rangeList && !fontFace->setUnicodeRange(*rangeList))
+ return;
+ if (variantLigatures && !fontFace->setVariantLigatures(*variantLigatures))
+ return;
+ if (variantPosition && !fontFace->setVariantPosition(*variantPosition))
+ return;
+ if (variantCaps && !fontFace->setVariantCaps(*variantCaps))
+ return;
+ if (variantNumeric && !fontFace->setVariantNumeric(*variantNumeric))
+ return;
+ if (variantAlternates && !fontFace->setVariantAlternates(*variantAlternates))
+ return;
+ if (variantEastAsian && !fontFace->setVariantEastAsian(*variantEastAsian))
+ return;
+ if (featureSettings)
+ fontFace->setFeatureSettings(*featureSettings);
- if (fontFace && !fontFace->isValid())
+ CSSFontFace::appendSources(fontFace, srcList, m_document, isInitiatingElementInUserAgentShadowTree);
+ if (fontFace->allSourcesFailed())
return;
- if (rangeList) {
- unsigned numRanges = rangeList->length();
- for (unsigned i = 0; i < numRanges; i++) {
- CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i));
- fontFace->addRange(range->from(), range->to());
- }
+ if (RefPtr<CSSFontFace> existingFace = m_cssFontFaceSet->lookUpByCSSConnection(fontFaceRule)) {
+ // This adoption is fairly subtle. Script can trigger a purge of m_cssFontFaceSet at any time,
+ // which will cause us to just rely on the memory cache to retain the bytes of the file the next
+ // time we build up the CSSFontFaceSet. However, when the CSS Font Loading API is involved,
+ // the FontFace and FontFaceSet objects need to retain state. We create the new CSSFontFace object
+ // while the old one is still in scope so that the memory cache will be forced to retain the bytes
+ // of the resource. This means that the CachedFont will temporarily have two clients (until the
+ // old CSSFontFace goes out of scope, which should happen at the end of this "if" block). Because
+ // the CSSFontFaceSource objects will inspect their CachedFonts, the new CSSFontFace is smart enough
+ // to enter the correct state() during the next pump(). This approach of making a new CSSFontFace is
+ // simpler than computing and applying a diff of the StyleProperties.
+ m_cssFontFaceSet->remove(*existingFace);
+ if (auto* existingWrapper = existingFace->existingWrapper())
+ existingWrapper->adopt(fontFace.get());
}
- // Hash under every single family name.
- int familyLength = familyList->length();
- for (int i = 0; i < familyLength; i++) {
- CSSPrimitiveValue* item = toCSSPrimitiveValue(familyList->itemWithoutBoundsCheck(i));
- String familyName;
- if (item->isString()) {
- familyName = item->getStringValue();
- } else if (item->isValueID()) {
- // 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 (item->getValueID()) {
- case CSSValueSerif:
- familyName = serifFamily;
- break;
- case CSSValueSansSerif:
- familyName = sansSerifFamily;
- break;
- case CSSValueCursive:
- familyName = cursiveFamily;
- break;
- case CSSValueFantasy:
- familyName = fantasyFamily;
- break;
- case CSSValueMonospace:
- familyName = monospaceFamily;
- break;
- case CSSValueWebkitPictograph:
- familyName = pictographFamily;
- break;
- default:
- break;
- }
- }
-
- if (familyName.isEmpty())
- continue;
-
- std::unique_ptr<Vector<RefPtr<CSSFontFace>>>& familyFontFaces = m_fontFaces.add(familyName, nullptr).iterator->value;
- if (!familyFontFaces) {
- familyFontFaces = std::make_unique<Vector<RefPtr<CSSFontFace>>>();
-
- ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
-
- Vector<unsigned> locallyInstalledFontsTraitsMasks;
- fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
- if (unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size()) {
- auto familyLocallyInstalledFaces = std::make_unique<Vector<RefPtr<CSSFontFace>>>();
-
- for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
- RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), 0, true);
- locallyInstalledFontFace->addSource(std::make_unique<CSSFontFaceSource>(familyName));
- ASSERT(locallyInstalledFontFace->isValid());
- familyLocallyInstalledFaces->append(locallyInstalledFontFace);
- }
-
- m_locallyInstalledFontFaces.set(familyName, std::move(familyLocallyInstalledFaces));
- }
- }
-
- familyFontFaces->append(fontFace);
-
- ++m_version;
- }
+ m_cssFontFaceSet->add(fontFace.get());
+ m_creatingFont = false;
+ ++m_version;
}
-void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
+void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient& client)
{
- m_clients.add(client);
+ m_clients.add(&client);
}
-void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
+void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient& client)
{
- m_clients.remove(client);
+ m_clients.remove(&client);
}
void CSSFontSelector::dispatchInvalidationCallbacks()
@@ -341,16 +241,7 @@ void CSSFontSelector::dispatchInvalidationCallbacks()
Vector<FontSelectorClient*> clients;
copyToVector(m_clients, clients);
for (size_t i = 0; i < clients.size(); ++i)
- clients[i]->fontsNeedUpdate(this);
-
- // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks.
- if (!m_document)
- return;
- if (StyleResolver* styleResolver = m_document->styleResolverIfExists())
- styleResolver->invalidateMatchedPropertiesCache();
- if (m_document->inPageCache() || !m_document->renderView())
- return;
- m_document->scheduleForcedStyleRecalc();
+ clients[i]->fontsNeedUpdate(*this);
}
void CSSFontSelector::fontLoaded()
@@ -358,202 +249,60 @@ void CSSFontSelector::fontLoaded()
dispatchInvalidationCallbacks();
}
+void CSSFontSelector::fontModified()
+{
+ if (!m_creatingFont)
+ dispatchInvalidationCallbacks();
+}
+
void CSSFontSelector::fontCacheInvalidated()
{
dispatchInvalidationCallbacks();
}
-static PassRefPtr<SimpleFontData> fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
+static const AtomicString& resolveGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
{
- if (!document || !document->frame())
- return 0;
+ if (!document)
+ return familyName;
- const Settings& settings = document->frame()->settings();
+ const Settings& settings = document->settings();
- AtomicString genericFamily;
UScriptCode script = fontDescription.script();
-
if (familyName == serifFamily)
- genericFamily = settings.serifFontFamily(script);
- else if (familyName == sansSerifFamily)
- genericFamily = settings.sansSerifFontFamily(script);
- else if (familyName == cursiveFamily)
- genericFamily = settings.cursiveFontFamily(script);
- else if (familyName == fantasyFamily)
- genericFamily = settings.fantasyFontFamily(script);
- else if (familyName == monospaceFamily)
- genericFamily = settings.fixedFontFamily(script);
- else if (familyName == pictographFamily)
- genericFamily = settings.pictographFontFamily(script);
- else if (familyName == standardFamily)
- genericFamily = settings.standardFontFamily(script);
-
- if (!genericFamily.isEmpty())
- return fontCache()->getCachedFontData(fontDescription, genericFamily);
-
- return nullptr;
+ return settings.serifFontFamily(script);
+ if (familyName == sansSerifFamily)
+ return settings.sansSerifFontFamily(script);
+ if (familyName == cursiveFamily)
+ return settings.cursiveFontFamily(script);
+ if (familyName == fantasyFamily)
+ return settings.fantasyFontFamily(script);
+ if (familyName == monospaceFamily)
+ return settings.fixedFontFamily(script);
+ if (familyName == pictographFamily)
+ return settings.pictographFontFamily(script);
+ if (familyName == standardFamily)
+ return settings.standardFontFamily(script);
+
+ return familyName;
}
-static FontTraitsMask desiredTraitsMaskForComparison;
-
-static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second)
+FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescription, const AtomicString& familyName)
{
- FontTraitsMask firstTraitsMask = first->traitsMask();
- FontTraitsMask secondTraitsMask = second->traitsMask();
-
- bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
- bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
-
- if (firstHasDesiredVariant != secondHasDesiredVariant)
- return firstHasDesiredVariant;
-
- // We need to check font-variant css property for CSS2.1 compatibility.
- if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
- // Prefer a font that has indicated that it can only support small-caps to a font that claims to support
- // all variants. The specialized font is more likely to be true small-caps and not require synthesis.
- bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask);
- bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask);
- if (firstRequiresSmallCaps != secondRequiresSmallCaps)
- return firstRequiresSmallCaps;
- }
-
- 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;
- unsigned w = FontWeight100Bit;
- while (!(desiredTraitsMaskForComparison & (1 << w))) {
- w++;
- ruleSetIndex++;
- }
-
- ASSERT_WITH_SECURITY_IMPLICATION(ruleSetIndex < fallbackRuleSets);
- 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;
-}
+ // If this ASSERT() fires, it usually means you forgot a document.updateStyleIfNeeded() somewhere.
+ ASSERT(!m_buildIsUnderway || m_isComputingRootStyleFont);
-PassRefPtr<FontData> CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
-{
- if (m_fontFaces.isEmpty()) {
- if (familyName.startsWith("-webkit-"))
- return fontDataForGenericFamily(m_document, fontDescription, familyName);
- if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont())
- return fontDataForGenericFamily(m_document, fontDescription, standardFamily);
- return 0;
- }
+ // 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;
- CSSSegmentedFontFace* face = getFontFace(fontDescription, familyName);
- // If no face was found, then return 0 and let the OS come up with its best match for the name.
+ AtomicString familyForLookup = resolveGenericFamilyFirst ? resolveGenericFamily(m_document, fontDescription, familyName) : familyName;
+ auto* face = m_cssFontFaceSet->fontFace(fontDescription.traitsMask(), familyForLookup);
if (!face) {
- // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
- // settings.
- if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont())
- return fontDataForGenericFamily(m_document, fontDescription, standardFamily);
- return fontDataForGenericFamily(m_document, fontDescription, familyName);
+ if (!resolveGenericFamilyFirst)
+ familyForLookup = resolveGenericFamily(m_document, fontDescription, familyName);
+ return FontRanges(FontCache::singleton().fontForFamily(fontDescription, familyForLookup));
}
- // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over.
- return face->getFontData(fontDescription);
-}
-
-CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& family)
-{
- Vector<RefPtr<CSSFontFace>>* familyFontFaces = m_fontFaces.get(family);
- if (!familyFontFaces || familyFontFaces->isEmpty())
- return 0;
-
- std::unique_ptr<HashMap<unsigned, RefPtr<CSSSegmentedFontFace>>>& segmentedFontFaceCache = m_fonts.add(family, nullptr).iterator->value;
- if (!segmentedFontFaceCache)
- segmentedFontFaceCache = std::make_unique<HashMap<unsigned, RefPtr<CSSSegmentedFontFace>>>();
-
- FontTraitsMask traitsMask = fontDescription.traitsMask();
-
- RefPtr<CSSSegmentedFontFace>& face = segmentedFontFaceCache->add(traitsMask, nullptr).iterator->value;
- if (!face) {
- face = CSSSegmentedFontFace::create(this);
-
- // Collect all matching faces and sort them in order of preference.
- Vector<CSSFontFace*, 32> candidateFontFaces;
- for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
- CSSFontFace* candidate = familyFontFaces->at(i).get();
- unsigned candidateTraitsMask = candidate->traitsMask();
- if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
- continue;
- if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
- continue;
-#if ENABLE(SVG_FONTS)
- // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
- // of small-caps synthesis and just ignore the font face as a candidate.
- if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask))
- continue;
-#endif
- candidateFontFaces.append(candidate);
- }
-
- if (Vector<RefPtr<CSSFontFace>>* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
- unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
- for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
- CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
- unsigned candidateTraitsMask = candidate->traitsMask();
- if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
- continue;
- if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
- continue;
- candidateFontFaces.append(candidate);
- }
- }
-
- desiredTraitsMaskForComparison = traitsMask;
- std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
- unsigned numCandidates = candidateFontFaces.size();
- for (unsigned i = 0; i < numCandidates; ++i)
- face->appendFontFace(candidateFontFaces[i]);
- }
- return face.get();
+ return face->fontRanges(fontDescription);
}
void CSSFontSelector::clearDocument()
@@ -566,93 +315,74 @@ void CSSFontSelector::clearDocument()
m_beginLoadingTimer.stop();
- CachedResourceLoader* cachedResourceLoader = m_document->cachedResourceLoader();
- for (size_t i = 0; i < m_fontsToBeginLoading.size(); ++i) {
+ CachedResourceLoader& cachedResourceLoader = m_document->cachedResourceLoader();
+ for (auto& fontHandle : m_fontsToBeginLoading) {
// Balances incrementRequestCount() in beginLoadingFontSoon().
- cachedResourceLoader->decrementRequestCount(m_fontsToBeginLoading[i].get());
+ cachedResourceLoader.decrementRequestCount(*fontHandle);
}
-
m_fontsToBeginLoading.clear();
- m_document = 0;
+ m_document = nullptr;
+
+ m_cssFontFaceSet->clear();
+ m_clients.clear();
}
-void CSSFontSelector::beginLoadingFontSoon(CachedFont* font)
+void CSSFontSelector::beginLoadingFontSoon(CachedFont& font)
{
if (!m_document)
return;
- m_fontsToBeginLoading.append(font);
+ m_fontsToBeginLoading.append(&font);
// Increment the request count now, in order to prevent didFinishLoad from being dispatched
// after this font has been requested but before it began loading. Balanced by
// decrementRequestCount() in beginLoadTimerFired() and in clearDocument().
- m_document->cachedResourceLoader()->incrementRequestCount(font);
+ m_document->cachedResourceLoader().incrementRequestCount(font);
m_beginLoadingTimer.startOneShot(0);
}
-void CSSFontSelector::beginLoadTimerFired(Timer<WebCore::CSSFontSelector>&)
+void CSSFontSelector::beginLoadTimerFired()
{
Vector<CachedResourceHandle<CachedFont>> fontsToBeginLoading;
fontsToBeginLoading.swap(m_fontsToBeginLoading);
// CSSFontSelector could get deleted via beginLoadIfNeeded() or loadDone() unless protected.
- Ref<CSSFontSelector> protect(*this);
+ Ref<CSSFontSelector> protectedThis(*this);
- CachedResourceLoader* cachedResourceLoader = m_document->cachedResourceLoader();
- for (size_t i = 0; i < fontsToBeginLoading.size(); ++i) {
- fontsToBeginLoading[i]->beginLoadIfNeeded(cachedResourceLoader);
+ CachedResourceLoader& cachedResourceLoader = m_document->cachedResourceLoader();
+ for (auto& fontHandle : fontsToBeginLoading) {
+ fontHandle->beginLoadIfNeeded(cachedResourceLoader);
// Balances incrementRequestCount() in beginLoadingFontSoon().
- cachedResourceLoader->decrementRequestCount(fontsToBeginLoading[i].get());
+ cachedResourceLoader.decrementRequestCount(*fontHandle);
}
// Ensure that if the request count reaches zero, the frame loader will know about it.
- cachedResourceLoader->loadDone(0);
+ cachedResourceLoader.loadDone();
// New font loads may be triggered by layout after the document load is complete but before we have dispatched
// didFinishLoading for the frame. Make sure the delegate is always dispatched by checking explicitly.
if (m_document && m_document->frame())
m_document->frame()->loader().checkLoadComplete();
}
-bool CSSFontSelector::resolvesFamilyFor(const FontDescription& description) const
-{
- for (unsigned i = 0; i < description.familyCount(); ++i) {
- const AtomicString& familyName = description.familyAt(i);
- if (description.genericFamily() == FontDescription::StandardFamily && !description.isSpecifiedFont())
- return true;
- if (familyName.isEmpty())
- continue;
- if (m_fontFaces.contains(familyName))
- return true;
- DEFINE_STATIC_LOCAL(String, webkitPrefix, ("-webkit-"));
- if (familyName.startsWith(webkitPrefix))
- return true;
-
- }
- return false;
-}
-size_t CSSFontSelector::fallbackFontDataCount()
+size_t CSSFontSelector::fallbackFontCount()
{
if (!m_document)
return 0;
- if (Settings* settings = m_document->settings())
- return settings->fontFallbackPrefersPictographs() ? 1 : 0;
-
- return 0;
+ return m_document->settings().fontFallbackPrefersPictographs() ? 1 : 0;
}
-PassRefPtr<FontData> CSSFontSelector::getFallbackFontData(const FontDescription& fontDescription, size_t index)
+RefPtr<Font> CSSFontSelector::fallbackFontAt(const FontDescription& fontDescription, size_t index)
{
ASSERT_UNUSED(index, !index);
if (!m_document)
- return 0;
+ return nullptr;
- Settings* settings = m_document->settings();
- if (!settings || !settings->fontFallbackPrefersPictographs())
- return 0;
+ if (!m_document->settings().fontFallbackPrefersPictographs())
+ return nullptr;
- return fontCache()->getCachedFontData(fontDescription, settings->pictographFontFamily());
+ return FontCache::singleton().fontForFamily(fontDescription, m_document->settings().pictographFontFamily());
}
}