Skip to content

Commit

Permalink
Allow creation of a CSSFontSelector with a non-Document ScriptExecuti…
Browse files Browse the repository at this point in the history
…onContext

https://bugs.webkit.org/show_bug.cgi?id=222735

Reviewed by Darin Adler.

Replace Document member of CSSFontSelector with a ScriptExecutionContext.
This also changes make_names.pl string header generation to allow for easier enumeration of font family strings.

No new tests as new behaviour is currently unused. Existing behaviour covered by existing tests.

* bindings/scripts/StaticString.pm:
(GenerateStrings): Revert change from bug 222552
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::CSSFontSelector):
(WebCore::m_version):
(WebCore::CSSFontSelector::fontFaceSet):
(WebCore::CSSFontSelector::addFontFaceRule):
(WebCore::CSSFontSelector::fontStyleUpdateNeeded):
(WebCore::CSSFontSelector::resolveGenericFamily):
(WebCore::CSSFontSelector::fontRangesForFamily):
(WebCore::CSSFontSelector::stopLoadingAndClearFonts):
(WebCore::CSSFontSelector::beginLoadingFontSoon):
(WebCore::CSSFontSelector::loadPendingFonts):
(WebCore::CSSFontSelector::fontLoadingTimerFired):
(WebCore::CSSFontSelector::fallbackFontCount):
(WebCore::CSSFontSelector::fallbackFontAt):
* css/CSSFontSelector.h:
* css/FontFaceSet.cpp:
(WebCore::FontFaceSet::create):
(WebCore::FontFaceSet::FontFaceSet):
* css/FontFaceSet.h:
* css/FontFaceSet.idl:
* dom/Document.h:
* dom/ScriptExecutionContext.h:
* dom/make_names.pl:
(printNamesHeaderFile): Make global string data and names accessible via a Vector and add an enum of name indices.
* platform/graphics/FontGenericFamilies.cpp:
(WebCore:: const):
* platform/graphics/FontGenericFamilies.h:


Canonical link: https://commits.webkit.org/235005@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@274069 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Chris Lord committed Mar 8, 2021
1 parent e730ca1 commit d56fc20
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 95 deletions.
42 changes: 42 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,45 @@
2021-03-08 Chris Lord <clord@igalia.com>

Allow creation of a CSSFontSelector with a non-Document ScriptExecutionContext
https://bugs.webkit.org/show_bug.cgi?id=222735

Reviewed by Darin Adler.

Replace Document member of CSSFontSelector with a ScriptExecutionContext.
This also changes make_names.pl string header generation to allow for easier enumeration of font family strings.

No new tests as new behaviour is currently unused. Existing behaviour covered by existing tests.

* bindings/scripts/StaticString.pm:
(GenerateStrings): Revert change from bug 222552
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::CSSFontSelector):
(WebCore::m_version):
(WebCore::CSSFontSelector::fontFaceSet):
(WebCore::CSSFontSelector::addFontFaceRule):
(WebCore::CSSFontSelector::fontStyleUpdateNeeded):
(WebCore::CSSFontSelector::resolveGenericFamily):
(WebCore::CSSFontSelector::fontRangesForFamily):
(WebCore::CSSFontSelector::stopLoadingAndClearFonts):
(WebCore::CSSFontSelector::beginLoadingFontSoon):
(WebCore::CSSFontSelector::loadPendingFonts):
(WebCore::CSSFontSelector::fontLoadingTimerFired):
(WebCore::CSSFontSelector::fallbackFontCount):
(WebCore::CSSFontSelector::fallbackFontAt):
* css/CSSFontSelector.h:
* css/FontFaceSet.cpp:
(WebCore::FontFaceSet::create):
(WebCore::FontFaceSet::FontFaceSet):
* css/FontFaceSet.h:
* css/FontFaceSet.idl:
* dom/Document.h:
* dom/ScriptExecutionContext.h:
* dom/make_names.pl:
(printNamesHeaderFile): Make global string data and names accessible via a Vector and add an enum of name indices.
* platform/graphics/FontGenericFamilies.cpp:
(WebCore:: const):
* platform/graphics/FontGenericFamilies.h:

2021-03-08 Rob Buis <rbuis@igalia.com>

Support aspect-ratio in intrinsic sizing
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/bindings/scripts/StaticString.pm
Expand Up @@ -43,7 +43,7 @@ END

for my $name (sort keys %strings) {
my $value = $strings{$name};
push(@result, "const StringImpl::StaticStringImpl ${name}Data(\"${value}\");\n");
push(@result, "static constexpr StringImpl::StaticStringImpl ${name}Data(\"${value}\");\n");
}

push(@result, <<END);
Expand Down
130 changes: 66 additions & 64 deletions Source/WebCore/css/CSSFontSelector.cpp
Expand Up @@ -59,18 +59,29 @@

namespace WebCore {

using namespace WebKitFontFamilyNames;

static unsigned fontSelectorId;

CSSFontSelector::CSSFontSelector(Document& document)
: ActiveDOMObject(document)
, m_document(makeWeakPtr(document))
CSSFontSelector::CSSFontSelector(ScriptExecutionContext& context)
: ActiveDOMObject(&context)
, m_context(makeWeakPtr(context))
, m_cssFontFaceSet(CSSFontFaceSet::create(this))
, m_fontModifiedObserver([this] { fontModified(); })
, m_fontLoadingTimer(*this, &CSSFontSelector::fontLoadingTimerFired)
, m_uniqueId(++fontSelectorId)
, m_version(0)
{
ASSERT(m_document);
if (is<Document>(context)) {
m_fontFamilyNames.reserveInitialCapacity(familyNames->size());
for (auto& familyName : familyNames.get())
m_fontFamilyNames.uncheckedConstructAndAppend(familyName);
} else {
m_fontFamilyNames.reserveInitialCapacity(familyNamesData->size());
for (auto& familyName : familyNamesData.get())
m_fontFamilyNames.uncheckedAppend(familyName);
}

FontCache::singleton().addClient(*this);
m_cssFontFaceSet->addFontModifiedObserver(m_fontModifiedObserver);
LOG(Fonts, "CSSFontSelector %p ctor", this);
Expand All @@ -94,8 +105,8 @@ FontFaceSet* CSSFontSelector::fontFaceSetIfExists()
FontFaceSet& CSSFontSelector::fontFaceSet()
{
if (!m_fontFaceSet) {
ASSERT(m_document);
m_fontFaceSet = FontFaceSet::create(*m_document, m_cssFontFaceSet.get());
ASSERT(m_context);
m_fontFaceSet = FontFaceSet::create(*m_context, m_cssFontFaceSet.get());
}

return *m_fontFaceSet;
Expand Down Expand Up @@ -197,7 +208,7 @@ void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isIn
if (loadingBehavior)
fontFace->setLoadingBehavior(*loadingBehavior);

CSSFontFace::appendSources(fontFace, srcList, m_document.get(), isInitiatingElementInUserAgentShadowTree);
CSSFontFace::appendSources(fontFace, srcList, m_context.get(), isInitiatingElementInUserAgentShadowTree);
if (fontFace->computeFailureState())
return;

Expand Down Expand Up @@ -231,14 +242,6 @@ void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient& cli
m_clients.remove(&client);
}

ScriptExecutionContext* CSSFontSelector::scriptExecutionContext() const
{
// This class returns a ScriptExecutionContext despite holding a Document as preparation for a future
// where it will actually hold a ScriptExecutionContext (which would be either a Document or a
// WorkerGlobalScope, in the case of using fonts in OffscreenCanvas).
return m_document.get();
}

void CSSFontSelector::dispatchInvalidationCallbacks()
{
++m_version;
Expand Down Expand Up @@ -269,41 +272,32 @@ void CSSFontSelector::fontModified()

void CSSFontSelector::fontStyleUpdateNeeded(CSSFontFace&)
{
if (m_document)
m_document->updateStyleIfNeeded();
if (is<Document>(m_context.get()))
downcast<Document>(*m_context).updateStyleIfNeeded();
}

void CSSFontSelector::fontCacheInvalidated()
{
dispatchInvalidationCallbacks();
}

static Optional<AtomString> resolveGenericFamily(Document* document, const FontDescription& fontDescription, const AtomString& familyName)
Optional<AtomString> CSSFontSelector::resolveGenericFamily(const FontDescription& fontDescription, const AtomString& familyName)
{
auto platformResult = FontDescription::platformResolveGenericFamily(fontDescription.script(), fontDescription.computedLocale(), familyName);
if (!platformResult.isNull())
return platformResult;

if (!document)
if (!m_context)
return WTF::nullopt;

const Settings& settings = document->settings();
const auto& settings = m_context->settingsValues();

UScriptCode script = fontDescription.script();
if (familyName == serifFamily)
return AtomString(settings.serifFontFamily(script));
if (familyName == sansSerifFamily)
return AtomString(settings.sansSerifFontFamily(script));
if (familyName == cursiveFamily)
return AtomString(settings.cursiveFontFamily(script));
if (familyName == fantasyFamily)
return AtomString(settings.fantasyFontFamily(script));
if (familyName == monospaceFamily)
return AtomString(settings.fixedFontFamily(script));
if (familyName == pictographFamily)
return AtomString(settings.pictographFontFamily(script));
if (familyName == standardFamily)
return AtomString(settings.standardFontFamily(script));
auto familyNameIndex = m_fontFamilyNames.find(familyName);
if (familyNameIndex != notFound) {
if (auto familyString = settings.fontGenericFamilies.fontFamily(static_cast<FamilyNamesIndex>(familyNameIndex), script))
return AtomString(*familyString);
}

return WTF::nullopt;
}
Expand All @@ -314,34 +308,31 @@ FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescr
ASSERT(!m_buildIsUnderway || m_computingRootStyleFontCount);

// 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;
bool resolveGenericFamilyFirst = familyName == m_fontFamilyNames[static_cast<int>(FamilyNamesIndex::StandardFamily)];

AtomString familyForLookup = familyName;
Optional<FontDescription> overrideFontDescription;
const FontDescription* fontDescriptionForLookup = &fontDescription;
auto resolveGenericFamily = [&]() {
if (auto genericFamilyOptional = WebCore::resolveGenericFamily(m_document.get(), fontDescription, familyName))
auto resolveAndAssignGenericFamily = [&]() {
if (auto genericFamilyOptional = resolveGenericFamily(fontDescription, familyName))
familyForLookup = *genericFamilyOptional;
};

if (resolveGenericFamilyFirst)
resolveGenericFamily();
resolveAndAssignGenericFamily();
Document* document = is<Document>(m_context.get()) ? &downcast<Document>(*m_context) : nullptr;
auto* face = m_cssFontFaceSet->fontFace(fontDescriptionForLookup->fontSelectionRequest(), familyForLookup);
if (face) {
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
if (m_document)
ResourceLoadObserver::shared().logFontLoad(*m_document, familyForLookup.string(), true);
}
if (document && RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logFontLoad(*document, familyForLookup.string(), true);
return face->fontRanges(*fontDescriptionForLookup);
}

if (!resolveGenericFamilyFirst)
resolveGenericFamily();
resolveAndAssignGenericFamily();
auto font = FontCache::singleton().fontForFamily(*fontDescriptionForLookup, familyForLookup);
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) {
if (m_document)
ResourceLoadObserver::shared().logFontLoad(*m_document, familyForLookup.string(), !!font);
}
if (document && RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logFontLoad(*document, familyForLookup.string(), !!font);
return FontRanges { WTFMove(font) };
}

Expand All @@ -356,27 +347,32 @@ void CSSFontSelector::stopLoadingAndClearFonts()
m_isStopped = true;
m_fontLoadingTimer.stop();

CachedResourceLoader& cachedResourceLoader = m_document->cachedResourceLoader();
for (auto& fontHandle : m_fontsToBeginLoading) {
// Balances incrementRequestCount() in beginLoadingFontSoon().
cachedResourceLoader.decrementRequestCount(*fontHandle);
if (is<Document>(m_context.get())) {
auto& document = downcast<Document>(*m_context);
CachedResourceLoader& cachedResourceLoader = document.cachedResourceLoader();
for (auto& fontHandle : m_fontsToBeginLoading) {
// Balances incrementRequestCount() in beginLoadingFontSoon().
cachedResourceLoader.decrementRequestCount(*fontHandle);
}
m_fontsToBeginLoading.clear();
}
m_fontsToBeginLoading.clear();

m_cssFontFaceSet->clear();
m_clients.clear();
}

void CSSFontSelector::beginLoadingFontSoon(CachedFont& font)
{
if (m_isStopped)
if (m_isStopped || !is<Document>(m_context.get()))
return;

auto& document = downcast<Document>(*m_context);

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 fontLoadingTimerFired() and in stopLoadingAndClearFonts().
m_document->cachedResourceLoader().incrementRequestCount(font);
document.cachedResourceLoader().incrementRequestCount(font);

if (!m_isFontLoadingSuspended && !m_fontLoadingTimer.isActive())
m_fontLoadingTimer.startOneShot(0_s);
Expand All @@ -389,16 +385,18 @@ void CSSFontSelector::suspendFontLoadingTimer()

void CSSFontSelector::loadPendingFonts()
{
if (m_isFontLoadingSuspended)
if (m_isFontLoadingSuspended || !is<Document>(m_context.get()))
return;

auto& document = downcast<Document>(*m_context);

Vector<CachedResourceHandle<CachedFont>> fontsToBeginLoading;
fontsToBeginLoading.swap(m_fontsToBeginLoading);

// CSSFontSelector could get deleted via beginLoadIfNeeded() or loadDone() unless protected.
Ref<CSSFontSelector> protectedThis(*this);

CachedResourceLoader& cachedResourceLoader = m_document->cachedResourceLoader();
CachedResourceLoader& cachedResourceLoader = document.cachedResourceLoader();
for (auto& fontHandle : fontsToBeginLoading) {
fontHandle->beginLoadIfNeeded(cachedResourceLoader);
// Balances incrementRequestCount() in beginLoadingFontSoon().
Expand All @@ -408,26 +406,30 @@ void CSSFontSelector::loadPendingFonts()

void CSSFontSelector::fontLoadingTimerFired()
{
if (!is<Document>(m_context.get()))
return;

auto& document = downcast<Document>(*m_context);
Ref<CSSFontSelector> protectedThis(*this);

loadPendingFonts();

// FIXME: Use SubresourceLoader instead.
// Call FrameLoader::loadDone before FrameLoader::subresourceLoadDone to match the order in SubresourceLoader::notifyDone.
m_document->cachedResourceLoader().loadDone(LoadCompletionType::Finish);
document.cachedResourceLoader().loadDone(LoadCompletionType::Finish);
// Ensure that if the request count reaches zero, the frame loader will know about it.
// 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();
if (document.frame())
document.frame()->loader().checkLoadComplete();
}

size_t CSSFontSelector::fallbackFontCount()
{
if (m_isStopped)
return 0;

return m_document->settings().fontFallbackPrefersPictographs() ? 1 : 0;
return m_context->settingsValues().fontFallbackPrefersPictographs ? 1 : 0;
}

RefPtr<Font> CSSFontSelector::fallbackFontAt(const FontDescription& fontDescription, size_t index)
Expand All @@ -437,12 +439,12 @@ RefPtr<Font> CSSFontSelector::fallbackFontAt(const FontDescription& fontDescript
if (m_isStopped)
return nullptr;

if (!m_document->settings().fontFallbackPrefersPictographs())
if (!m_context->settingsValues().fontFallbackPrefersPictographs)
return nullptr;
auto& pictographFontFamily = m_document->settings().pictographFontFamily();
auto& pictographFontFamily = m_context->settingsValues().fontGenericFamilies.pictographFontFamily();
auto font = FontCache::singleton().fontForFamily(fontDescription, pictographFontFamily);
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
ResourceLoadObserver::shared().logFontLoad(*m_document, pictographFontFamily, !!font);
if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled() && is<Document>(m_context.get()))
ResourceLoadObserver::shared().logFontLoad(downcast<Document>(*m_context), pictographFontFamily, !!font);

return font;
}
Expand Down
16 changes: 10 additions & 6 deletions Source/WebCore/css/CSSFontSelector.h
Expand Up @@ -45,14 +45,14 @@ class CSSPrimitiveValue;
class CSSSegmentedFontFace;
class CSSValueList;
class CachedFont;
class Document;
class ScriptExecutionContext;
class StyleRuleFontFace;

class CSSFontSelector final : public FontSelector, public CSSFontFace::Client, public CanMakeWeakPtr<CSSFontSelector>, public ActiveDOMObject {
public:
static Ref<CSSFontSelector> create(Document& document)
static Ref<CSSFontSelector> create(ScriptExecutionContext& context)
{
return adoptRef(*new CSSFontSelector(document));
return adoptRef(*new CSSFontSelector(context));
}
virtual ~CSSFontSelector();

Expand All @@ -77,7 +77,7 @@ class CSSFontSelector final : public FontSelector, public CSSFontFace::Client, p
void registerForInvalidationCallbacks(FontSelectorClient&) final;
void unregisterForInvalidationCallbacks(FontSelectorClient&) final;

ScriptExecutionContext* scriptExecutionContext() const;
ScriptExecutionContext* scriptExecutionContext() const { return m_context.get(); }

void beginLoadingFontSoon(CachedFont&);
void suspendFontLoadingTimer();
Expand All @@ -95,12 +95,14 @@ class CSSFontSelector final : public FontSelector, public CSSFontFace::Client, p
void deref() final { FontSelector::deref(); }

private:
explicit CSSFontSelector(Document&);
explicit CSSFontSelector(ScriptExecutionContext&);

void dispatchInvalidationCallbacks();

void opportunisticallyStartFontDataURLLoading(const FontCascadeDescription&, const AtomString& family) final;

Optional<AtomString> resolveGenericFamily(const FontDescription&, const AtomString& family);

// CSSFontFace::Client
void fontLoaded(CSSFontFace&) final;
void fontStyleUpdateNeeded(CSSFontFace&) final;
Expand All @@ -120,7 +122,7 @@ class CSSFontSelector final : public FontSelector, public CSSFontFace::Client, p
};
Vector<PendingFontFaceRule> m_stagingArea;

WeakPtr<Document> m_document;
WeakPtr<ScriptExecutionContext> m_context;
RefPtr<FontFaceSet> m_fontFaceSet;
Ref<CSSFontFaceSet> m_cssFontFaceSet;
HashSet<FontSelectorClient*> m_clients;
Expand All @@ -140,6 +142,8 @@ class CSSFontSelector final : public FontSelector, public CSSFontFace::Client, p
bool m_creatingFont { false };
bool m_buildIsUnderway { false };
bool m_isStopped { false };

WTF::Vector<AtomString> m_fontFamilyNames;
};

} // namespace WebCore

0 comments on commit d56fc20

Please sign in to comment.