Title: [201551] trunk/Source/WebCore
Revision
201551
Author
[email protected]
Date
2016-06-01 07:29:30 -0700 (Wed, 01 Jun 2016)

Log Message

Precache primary font in a secondary thread
https://bugs.webkit.org/show_bug.cgi?id=158243

Reviewed by Andreas Kling.

We know the font families and descriptions to use on style resolution. The actual fonts are only needed for
layout. There is often time to load and cache fonts asynchronously before they are accessed. This can substantially
reduce font related workload in the main thread.

* css/CSSFontFace.cpp:
(WebCore::CSSFontFace::font):
(WebCore::CSSFontFace::resolveFamilies):
(WebCore::CSSFontFace::hasSVGFontFaceSource):
* css/CSSFontFace.h:
* css/CSSFontFaceSource.cpp:
(WebCore::CSSFontFaceSource::font):
(WebCore::CSSFontFaceSource::url):
(WebCore::CSSFontFaceSource::isSVGFontFaceSource):
* css/CSSFontFaceSource.h:
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::fallbackFontAt):
(WebCore::CSSFontSelector::resolveFamilies):

    Add a function for resolving font families of a cascade to their final values.

* css/CSSFontSelector.h:
* css/CSSSegmentedFontFace.cpp:
(WebCore::CSSSegmentedFontFace::fontRanges):
(WebCore::CSSSegmentedFontFace::resolveFamilies):
* css/CSSSegmentedFontFace.h:
* platform/graphics/FontCache.cpp:
(WebCore::fontPlatformDataCache):
(WebCore::precacheTasksInProgress):
(WebCore::alternateFamilyName):
(WebCore::FontCache::getCachedFontPlatformData):
(WebCore::FontCache::invalidate):
(WebCore::FontCache::precache):

    Precache fonts by trying to load them asyncronously one by one. On success the font is cached into font platform data cache.

(WebCore::FontCache::similarFont):
* platform/graphics/FontCache.h:
* platform/graphics/FontCascade.cpp:
(WebCore::pruneSystemFallbackFonts):
(WebCore::precachePrimaryFamily):

    When initializing a new font cascade resolve any platform fonts to their actual names using FontSelector,
    then precache the primary font for the cascade.

    Web fonts are ignored for now.

(WebCore::retrieveOrAddCachedFonts):
* platform/graphics/FontSelector.h:
(WebCore::FontSelector::~FontSelector):
* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::FontCache::setFontWhitelist):
(WebCore::fontWithFamily):
(WebCore::autoActivateFont):
(WebCore::createFontPlatformDataThreadSafe):

    Factor thread safe part of createFontPlatformData to a function.

(WebCore::FontCache::createFontPlatformData):

    Do the main thread only hash lookups here then call to createFontPlatformDataThreadSafe.

(WebCore::fallbackDedupSet):
(WebCore::FontCache::systemFallbackForCharacters):
(WebCore::FontCache::platformPrecache):

    Try to initialize font asynchronously in a dispatch queue, call completion handler on success or failure.

(WebCore::FontCache::platformCancelPrecache):

    Cancel ongoing precache operation.

(WebCore::platformFontLookupWithFamily): Deleted.

    This was inlined to the only client, fontWithFamily.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (201550 => 201551)


--- trunk/Source/WebCore/ChangeLog	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/ChangeLog	2016-06-01 14:29:30 UTC (rev 201551)
@@ -1,3 +1,85 @@
+2016-05-31  Antti Koivisto  <[email protected]>
+
+        Precache primary font in a secondary thread
+        https://bugs.webkit.org/show_bug.cgi?id=158243
+
+        Reviewed by Andreas Kling.
+
+        We know the font families and descriptions to use on style resolution. The actual fonts are only needed for
+        layout. There is often time to load and cache fonts asynchronously before they are accessed. This can substantially
+        reduce font related workload in the main thread.
+
+        * css/CSSFontFace.cpp:
+        (WebCore::CSSFontFace::font):
+        (WebCore::CSSFontFace::resolveFamilies):
+        (WebCore::CSSFontFace::hasSVGFontFaceSource):
+        * css/CSSFontFace.h:
+        * css/CSSFontFaceSource.cpp:
+        (WebCore::CSSFontFaceSource::font):
+        (WebCore::CSSFontFaceSource::url):
+        (WebCore::CSSFontFaceSource::isSVGFontFaceSource):
+        * css/CSSFontFaceSource.h:
+        * css/CSSFontSelector.cpp:
+        (WebCore::CSSFontSelector::fallbackFontAt):
+        (WebCore::CSSFontSelector::resolveFamilies):
+
+            Add a function for resolving font families of a cascade to their final values.
+
+        * css/CSSFontSelector.h:
+        * css/CSSSegmentedFontFace.cpp:
+        (WebCore::CSSSegmentedFontFace::fontRanges):
+        (WebCore::CSSSegmentedFontFace::resolveFamilies):
+        * css/CSSSegmentedFontFace.h:
+        * platform/graphics/FontCache.cpp:
+        (WebCore::fontPlatformDataCache):
+        (WebCore::precacheTasksInProgress):
+        (WebCore::alternateFamilyName):
+        (WebCore::FontCache::getCachedFontPlatformData):
+        (WebCore::FontCache::invalidate):
+        (WebCore::FontCache::precache):
+
+            Precache fonts by trying to load them asyncronously one by one. On success the font is cached into font platform data cache.
+
+        (WebCore::FontCache::similarFont):
+        * platform/graphics/FontCache.h:
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::pruneSystemFallbackFonts):
+        (WebCore::precachePrimaryFamily):
+
+            When initializing a new font cascade resolve any platform fonts to their actual names using FontSelector,
+            then precache the primary font for the cascade.
+
+            Web fonts are ignored for now.
+
+        (WebCore::retrieveOrAddCachedFonts):
+        * platform/graphics/FontSelector.h:
+        (WebCore::FontSelector::~FontSelector):
+        * platform/graphics/cocoa/FontCacheCoreText.cpp:
+        (WebCore::FontCache::setFontWhitelist):
+        (WebCore::fontWithFamily):
+        (WebCore::autoActivateFont):
+        (WebCore::createFontPlatformDataThreadSafe):
+
+            Factor thread safe part of createFontPlatformData to a function.
+
+        (WebCore::FontCache::createFontPlatformData):
+
+            Do the main thread only hash lookups here then call to createFontPlatformDataThreadSafe.
+
+        (WebCore::fallbackDedupSet):
+        (WebCore::FontCache::systemFallbackForCharacters):
+        (WebCore::FontCache::platformPrecache):
+
+            Try to initialize font asynchronously in a dispatch queue, call completion handler on success or failure.
+
+        (WebCore::FontCache::platformCancelPrecache):
+
+            Cancel ongoing precache operation.
+
+        (WebCore::platformFontLookupWithFamily): Deleted.
+
+            This was inlined to the only client, fontWithFamily.
+
 2016-06-01  Adam Bergkvist  <[email protected]>
 
         WebRTC: Add RTCRtpTransceiver interface and RTCPeerConnection.addTransceiver()

Modified: trunk/Source/WebCore/css/CSSFontFace.cpp (201550 => 201551)


--- trunk/Source/WebCore/css/CSSFontFace.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSFontFace.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -520,6 +520,19 @@
     return nullptr;
 }
 
+Vector<ResolvedFontFamily> CSSFontFace::resolveFamilies() const
+{
+    Vector<ResolvedFontFamily> result;
+    for (auto& source : m_sources) {
+        if (source->familyNameOrURI().isEmpty())
+            continue;
+        if (source->status() == CSSFontFaceSource::Status::Failure)
+            continue;
+        result.append({ source->familyNameOrURI(), source->url() });
+    }
+    return result;
+}
+
 #if ENABLE(SVG_FONTS)
 bool CSSFontFace::hasSVGFontFaceSource() const
 {

Modified: trunk/Source/WebCore/css/CSSFontFace.h (201550 => 201551)


--- trunk/Source/WebCore/css/CSSFontFace.h	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSFontFace.h	2016-06-01 14:29:30 UTC (rev 201551)
@@ -27,6 +27,7 @@
 
 #include "CSSFontFaceRule.h"
 #include "FontFeatureSettings.h"
+#include "FontSelector.h"
 #include "TextFlags.h"
 #include <memory>
 #include <wtf/Forward.h>
@@ -135,6 +136,8 @@
     // We don't guarantee that the FontFace wrapper will be the same every time you ask for it.
     Ref<FontFace> wrapper();
 
+    Vector<ResolvedFontFamily> resolveFamilies() const;
+
 #if ENABLE(SVG_FONTS)
     bool hasSVGFontFaceSource() const;
 #endif

Modified: trunk/Source/WebCore/css/CSSFontFaceSource.cpp (201550 => 201551)


--- trunk/Source/WebCore/css/CSSFontFaceSource.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSFontFaceSource.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -188,6 +188,13 @@
     return nullptr;
 }
 
+Optional<URL> CSSFontFaceSource::url() const
+{
+    if (!m_font)
+        return Nullopt;
+    return m_font->url();
+}
+
 #if ENABLE(SVG_FONTS)
 bool CSSFontFaceSource::isSVGFontFaceSource() const
 {

Modified: trunk/Source/WebCore/css/CSSFontFaceSource.h (201550 => 201551)


--- trunk/Source/WebCore/css/CSSFontFaceSource.h	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSFontFaceSource.h	2016-06-01 14:29:30 UTC (rev 201551)
@@ -28,6 +28,7 @@
 
 #include "CachedFontClient.h"
 #include "CachedResourceHandle.h"
+#include "URL.h"
 #include <runtime/ArrayBufferView.h>
 #include <wtf/text/AtomicString.h>
 
@@ -71,6 +72,8 @@
     bool isSVGFontFaceSource() const;
 #endif
 
+    Optional<URL> url() const;
+
 private:
     void fontLoaded(CachedFont&) override;
 

Modified: trunk/Source/WebCore/css/CSSFontSelector.cpp (201550 => 201551)


--- trunk/Source/WebCore/css/CSSFontSelector.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSFontSelector.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -334,4 +334,22 @@
     return FontCache::singleton().fontForFamily(fontDescription, settings->pictographFontFamily());
 }
 
+Vector<ResolvedFontFamily> CSSFontSelector::resolveFamilies(const Vector<AtomicString>& families, const FontDescription& fontDescription, UChar32 character)
+{
+    Vector<ResolvedFontFamily> result;
+
+    for (auto& family : families) {
+        if (family.isEmpty())
+            continue;
+        auto* segmentedFace = m_cssFontFaceSet->getFontFace(fontDescription.traitsMask(), family);
+        if (!segmentedFace) {
+            result.append({ resolveGenericFamily(m_document, fontDescription, family), { } });
+            continue;
+        }
+        result.appendVector(segmentedFace->resolveFamilies(character));
+    }
+
+    return result;
 }
+
+}

Modified: trunk/Source/WebCore/css/CSSFontSelector.h (201550 => 201551)


--- trunk/Source/WebCore/css/CSSFontSelector.h	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSFontSelector.h	2016-06-01 14:29:30 UTC (rev 201551)
@@ -64,6 +64,8 @@
     size_t fallbackFontCount() override;
     RefPtr<Font> fallbackFontAt(const FontDescription&, size_t) override;
 
+    Vector<ResolvedFontFamily> resolveFamilies(const Vector<AtomicString>&, const FontDescription&, UChar32) override;
+
     void clearDocument();
 
     void addFontFaceRule(StyleRuleFontFace&, bool isInitiatingElementInUserAgentShadowTree);

Modified: trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp (201550 => 201551)


--- trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSSegmentedFontFace.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -138,4 +138,20 @@
     return result;
 }
 
+Vector<ResolvedFontFamily> CSSSegmentedFontFace::resolveFamilies(UChar32 character) const
+{
+    for (auto& face : m_fontFaces) {
+        bool inRange = face->ranges().isEmpty();
+        for (auto& range : face->ranges()) {
+            if (character >= range.from && character <= range.to) {
+                inRange = true;
+                break;
+            }
+        }
+        if (inRange)
+            return face->resolveFamilies();
+    }
+    return { };
 }
+
+}

Modified: trunk/Source/WebCore/css/CSSSegmentedFontFace.h (201550 => 201551)


--- trunk/Source/WebCore/css/CSSSegmentedFontFace.h	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/css/CSSSegmentedFontFace.h	2016-06-01 14:29:30 UTC (rev 201551)
@@ -28,6 +28,7 @@
 
 #include "CSSFontFace.h"
 #include "FontCache.h"
+#include "FontSelector.h"
 #include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
@@ -57,6 +58,8 @@
     void ref() override { RefCounted<CSSSegmentedFontFace>::ref(); }
     void deref() override { RefCounted<CSSSegmentedFontFace>::deref(); }
 
+    Vector<ResolvedFontFamily> resolveFamilies(UChar32 character) const;
+
 private:
     CSSSegmentedFontFace();
     void fontLoaded(CSSFontFace&) override;

Modified: trunk/Source/WebCore/platform/graphics/FontCache.cpp (201550 => 201551)


--- trunk/Source/WebCore/platform/graphics/FontCache.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/platform/graphics/FontCache.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -106,6 +106,7 @@
         , m_fontFaceFeatures(fontFaceFeatures ? *fontFaceFeatures : FontFeatureSettings())
         , m_fontFaceVariantSettings(fontFaceVariantSettings ? *fontFaceVariantSettings : FontVariantSettings())
     { }
+    FontPlatformDataCacheKey(const FontPlatformDataCacheKey&) = default;
 
     explicit FontPlatformDataCacheKey(HashTableDeletedValueType t)
         : m_fontDescriptionKey(t)
@@ -159,6 +160,16 @@
     return cache;
 }
 
+#if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP)
+using PrecacheMap = HashMap<FontPlatformDataCacheKey, FontCache::PrecacheTask*, FontPlatformDataCacheKeyHash, WTF::SimpleClassHashTraits<FontPlatformDataCacheKey>>;
+
+static PrecacheMap& precacheTasksInProgress()
+{
+    static NeverDestroyed<PrecacheMap> map;
+    return map;
+}
+#endif
+
 static AtomicString alternateFamilyName(const AtomicString& familyName)
 {
     switch (familyName.length()) {
@@ -243,6 +254,12 @@
 
     FontPlatformDataCacheKey key(familyName, fontDescription, fontFaceFeatures, fontFaceVariantSettings);
 
+#if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP)
+    auto* precacheTask = precacheTasksInProgress().get(key);
+    if (precacheTask)
+        platformCancelPrecache(*precacheTask);
+#endif
+
     auto addResult = fontPlatformDataCache().add(key, nullptr);
     FontPlatformDataCache::iterator it = addResult.iterator;
     if (addResult.isNewEntry) {
@@ -489,6 +506,67 @@
     purgeInactiveFontData();
 }
 
+#if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP)
+void FontCache::precache(const Vector<AtomicString>& resolvedFamilies, const FontDescription& fontDescription)
+{
+    if (resolvedFamilies.isEmpty())
+        return;
+    auto& family = resolvedFamilies.first();
+
+    FontPlatformDataCacheKey key(family, fontDescription, nullptr, nullptr);
+
+    // Maybe we have it already?
+    auto it = fontPlatformDataCache().find(key);
+    if (it != fontPlatformDataCache().end()) {
+        if (it->value)
+            return;
+
+        // We already know this font isn't available. Try the next.
+        Vector<AtomicString> remainingFamilies;
+        remainingFamilies.appendRange(resolvedFamilies.begin() + 1, resolvedFamilies.end());
+        precache(remainingFamilies, fontDescription);
+        return;
+    }
+
+    auto taskAdd = precacheTasksInProgress().add(key, nullptr);
+    if (!taskAdd.isNewEntry)
+        return;
+
+    auto& task = platformPrecache(family, fontDescription, [key, resolvedFamilies, fontDescription] (auto platformData, bool wasCanceled) {
+        precacheTasksInProgress().remove(key);
+
+        if (wasCanceled)
+            return;
+
+        if (platformData) {
+            auto r = fontPlatformDataCache().add(key, WTFMove(platformData));
+            fprintf(stderr, "success %d\n", r.isNewEntry);
+            return;
+        }
+
+        // Didn't find the font. Try the next one.
+        Vector<AtomicString> remainingFamilies;
+
+        auto alternateName = alternateFamilyName(resolvedFamilies.first());
+        if (!alternateName.isNull()) {
+            remainingFamilies = resolvedFamilies;
+            remainingFamilies.first() = alternateName;
+        } else {
+            fontPlatformDataCache().add(key, nullptr);
+            remainingFamilies.appendRange(resolvedFamilies.begin() + 1, resolvedFamilies.end());
+        }
+
+        singleton().precache(remainingFamilies, fontDescription);
+    });
+
+    taskAdd.iterator->value = &task;
+}
+#else
+void FontCache::precache(const Vector<AtomicString>&, const FontDescription&)
+{
+}
+#endif
+
 #if !PLATFORM(COCOA)
 RefPtr<Font> FontCache::similarFont(const FontDescription&, const AtomicString&)
 {

Modified: trunk/Source/WebCore/platform/graphics/FontCache.h (201550 => 201551)


--- trunk/Source/WebCore/platform/graphics/FontCache.h	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/platform/graphics/FontCache.h	2016-06-01 14:29:30 UTC (rev 201551)
@@ -193,6 +193,8 @@
     WEBCORE_EXPORT Ref<Font> fontForPlatformData(const FontPlatformData&);
     RefPtr<Font> similarFont(const FontDescription&, const AtomicString& family);
 
+    void precache(const Vector<AtomicString>& resolvedFamilies, const FontDescription&);
+
     void addClient(FontSelector&);
     void removeClient(FontSelector&);
 
@@ -212,6 +214,8 @@
     RefPtr<OpenTypeVerticalData> verticalData(const FontPlatformData&);
 #endif
 
+    struct PrecacheTask;
+
 private:
     FontCache();
     ~FontCache() = delete;
@@ -227,6 +231,12 @@
 #endif
     std::unique_ptr<FontPlatformData> createFontPlatformData(const FontDescription&, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings);
 
+#if PLATFORM(COCOA) && ENABLE(PLATFORM_FONT_LOOKUP)
+    using PrecacheCompletionHandler = std::function<void (std::unique_ptr<FontPlatformData>, bool wasCanceled)>;
+    PrecacheTask& platformPrecache(const AtomicString& family, const FontDescription&, PrecacheCompletionHandler&&);
+    void platformCancelPrecache(PrecacheTask&);
+#endif
+
     Timer m_purgeTimer;
 
 #if PLATFORM(COCOA)

Modified: trunk/Source/WebCore/platform/graphics/FontCascade.cpp (201550 => 201551)


--- trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -261,6 +261,29 @@
         entry->fonts->pruneSystemFallbacks();
 }
 
+static void precachePrimaryFamily(const FontCascadeDescription& fontDescription, FontSelector& fontSelector)
+{
+    Vector<AtomicString> families;
+    for (unsigned i = 0; i < fontDescription.familyCount(); ++i)
+        families.append(fontDescription.familyAt(i));
+
+    // Primary family lookup falls back to the standard family.
+    families.append(standardFamily);
+
+    auto resolvedPrimaryFamilies = fontSelector.resolveFamilies(families, fontDescription, ' ');
+
+    Vector<AtomicString> resolvedPrimaryFamilyNames;
+    for (auto& family : resolvedPrimaryFamilies) {
+        // This doesn't handle web fonts for now.
+        if (family.url)
+            break;
+        resolvedPrimaryFamilyNames.append(family.name);
+    }
+
+    // Asynchronously find first available font and precache it so it is likely to be available when needed.
+    FontCache::singleton().precache(resolvedPrimaryFamilyNames, fontDescription);
+}
+
 static Ref<FontCascadeFonts> retrieveOrAddCachedFonts(const FontCascadeDescription& fontDescription, RefPtr<FontSelector>&& fontSelector)
 {
     auto key = makeFontCascadeCacheKey(fontDescription, fontSelector.get());
@@ -270,6 +293,9 @@
     if (!addResult.isNewEntry && keysMatch(addResult.iterator->value->key, key))
         return addResult.iterator->value->fonts.get();
 
+    if (fontSelector)
+        precachePrimaryFamily(fontDescription, *fontSelector);
+
     auto& newEntry = addResult.iterator->value;
     newEntry = std::make_unique<FontCascadeCacheEntry>(WTFMove(key), FontCascadeFonts::create(WTFMove(fontSelector)));
     Ref<FontCascadeFonts> glyphs = newEntry->fonts.get();

Modified: trunk/Source/WebCore/platform/graphics/FontSelector.h (201550 => 201551)


--- trunk/Source/WebCore/platform/graphics/FontSelector.h	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/platform/graphics/FontSelector.h	2016-06-01 14:29:30 UTC (rev 201551)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "FontRanges.h"
+#include "URL.h"
 #include <wtf/Forward.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
@@ -44,6 +45,11 @@
     virtual bool isLoading() const = 0;
 };
 
+struct ResolvedFontFamily {
+    AtomicString name;
+    Optional<URL> url;
+};
+
 class FontSelector : public RefCounted<FontSelector> {
 public:
     virtual ~FontSelector() { }
@@ -58,6 +64,8 @@
     virtual void registerForInvalidationCallbacks(FontSelectorClient&) = 0;
     virtual void unregisterForInvalidationCallbacks(FontSelectorClient&) = 0;
 
+    virtual Vector<ResolvedFontFamily> resolveFamilies(const Vector<AtomicString>& families, const FontDescription&, UChar32 character) = 0;
+
     virtual unsigned uniqueId() const = 0;
     virtual unsigned version() const = 0;
 };

Modified: trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp (201550 => 201551)


--- trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp	2016-06-01 11:57:55 UTC (rev 201550)
+++ trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp	2016-06-01 14:29:30 UTC (rev 201551)
@@ -34,6 +34,8 @@
 #include <wtf/HashSet.h>
 #include <wtf/MainThread.h>
 #include <wtf/NeverDestroyed.h>
+#include <wtf/RunLoop.h>
+#include <wtf/WorkQueue.h>
 
 namespace WebCore {
 
@@ -660,27 +662,19 @@
         whitelist.add(item);
 }
 
-#if ENABLE(PLATFORM_FONT_LOOKUP)
-static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, float size)
+static RetainPtr<CTFontRef> fontWithFamily(const String& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size, bool isWhitelisted)
 {
-    const auto& whitelist = fontWhitelist();
-    if (whitelist.size() && !whitelist.contains(family))
-        return nullptr;
-
-    return adoptCF(CTFontCreateForCSS(family.string().createCFString().get(), toCoreTextFontWeight(weight), requestedTraits, size));
-}
-#endif
-
-static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size)
-{
     if (family.isEmpty())
         return nullptr;
 
     RetainPtr<CTFontRef> foundFont = platformFontWithFamilySpecialCase(family, weight, desiredTraits, size);
     if (!foundFont) {
 #if ENABLE(PLATFORM_FONT_LOOKUP)
-        foundFont = platformFontLookupWithFamily(family, desiredTraits, weight, size);
+        if (!isWhitelisted)
+            return nullptr;
+        foundFont = adoptCF(CTFontCreateForCSS(family.createCFString().get(), toCoreTextFontWeight(weight), desiredTraits, size));
 #else
+        UNUSED_PARAM(isWhitelisted);
         foundFont = platformFontWithFamily(family, desiredTraits, weight, textRenderingMode, size);
 #endif
     }
@@ -719,24 +713,24 @@
 }
 #endif
 
-std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings)
+// This is only thread safe with ENABLE(PLATFORM_FONT_LOOKUP) due to fontWithFamily() implementation
+static std::unique_ptr<FontPlatformData> createFontPlatformDataThreadSafe(const FontDescription& fontDescription, const String& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, bool isWhitelisted, bool shouldAutoActivateIfNeeded)
 {
     CTFontSymbolicTraits traits = computeTraits(fontDescription);
     float size = fontDescription.computedPixelSize();
 
-    RetainPtr<CTFontRef> font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size);
+    RetainPtr<CTFontRef> font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size, isWhitelisted);
 
 #if PLATFORM(MAC)
-    if (!font) {
-        if (!shouldAutoActivateFontIfNeeded(family))
-            return nullptr;
-
+    if (!font && shouldAutoActivateIfNeeded) {
         // Auto activate the font before looking for it a second time.
         // Ignore the result because we want to use our own algorithm to actually find the font.
-        autoActivateFont(family.string(), size);
+        autoActivateFont(family, size);
 
-        font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size);
+        font = fontWithFamily(family, traits, fontDescription.weight(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontFaceFeatures, fontFaceVariantSettings, fontDescription.textRenderingMode(), size, isWhitelisted);
     }
+#else
+    UNUSED_PARAM(shouldAutoActivateIfNeeded);
 #endif
 
     if (!font)
@@ -748,6 +742,19 @@
     return std::make_unique<FontPlatformData>(font.get(), size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant(), fontDescription.textRenderingMode());
 }
 
+std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings)
+{
+    const auto& whitelist = fontWhitelist();
+    bool isWhitelisted = whitelist.isEmpty() || whitelist.contains(family);
+
+    bool shouldAutoActivateIfNeeded = false;
+#if PLATFORM(MAC)
+    shouldAutoActivateIfNeeded = shouldAutoActivateFontIfNeeded(family);
+#endif
+
+    return createFontPlatformDataThreadSafe(fontDescription, family, fontFaceFeatures, fontFaceVariantSettings, isWhitelisted, shouldAutoActivateIfNeeded);
+}
+
 typedef HashSet<RetainPtr<CTFontRef>, WTF::RetainPtrObjectHash<CTFontRef>, WTF::RetainPtrObjectHashTraits<CTFontRef>> FallbackDedupSet;
 static FallbackDedupSet& fallbackDedupSet()
 {
@@ -796,4 +803,53 @@
     return fontForPlatformData(alternateFont);
 }
 
+#if ENABLE(PLATFORM_FONT_LOOKUP)
+struct FontCache::PrecacheTask {
+    String family;
+    FontDescription fontDescription;
+    bool shouldAutoActivateIfNeeded { false };
+    bool isWhitelisted { true };
+    PrecacheCompletionHandler completionHandler;
+
+    std::unique_ptr<FontPlatformData> result;
+    std::atomic_bool isCanceled { false };
+};
+
+FontCache::PrecacheTask& FontCache::platformPrecache(const AtomicString& family, const FontDescription& fontDescription, PrecacheCompletionHandler&& completionHandler)
+{
+    static WorkQueue& queue = WorkQueue::create("org.webkit.font-precache", WorkQueue::Type::Serial, WorkQueue::QOS::UserInitiated).leakRef();
+
+    auto task = std::make_unique<PrecacheTask>();
+    task->family = family;
+    task->fontDescription = fontDescription;
+    const auto& whitelist = fontWhitelist();
+    task->isWhitelisted = whitelist.isEmpty() || whitelist.contains(family);
+#if PLATFORM(MAC)
+    task->shouldAutoActivateIfNeeded = shouldAutoActivateFontIfNeeded(family);
+#endif
+    task->completionHandler = WTFMove(completionHandler);
+
+    auto& resultTask = *task;
+
+    queue.dispatch([task = task.release()] {
+        if (!task->isCanceled) {
+            auto family = task->family.isolatedCopy();
+            task->result = createFontPlatformDataThreadSafe(task->fontDescription, family, nullptr, nullptr, task->isWhitelisted, task->shouldAutoActivateIfNeeded);
+        }
+
+        RunLoop::main().dispatch([task] {
+            std::unique_ptr<PrecacheTask> deleter(task);
+            task->completionHandler(WTFMove(task->result), task->isCanceled);
+        });
+    });
+
+    return resultTask;
 }
+
+void FontCache::platformCancelPrecache(FontCache::PrecacheTask& task)
+{
+    task.isCanceled = true;
+}
+#endif
+
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to