Title: [252044] trunk/Source/WebCore
Revision
252044
Author
carlo...@webkit.org
Date
2019-11-05 00:17:58 -0800 (Tue, 05 Nov 2019)

Log Message

[FreeType] Too slow running encoding/legacy-mb-korean/euc-kr WPT tests
https://bugs.webkit.org/show_bug.cgi?id=203544

Reviewed by Carlos Alberto Lopez Perez.

Use a cache for system fallbacks to keep the fonts sorted by font description. When a system fallback is needed
again for the same font description, but different characters, we just iterate the cached font set comparing the
charsets to get the best one. This avoids using FcFontMatch and FcFontSort is only called once per font description.

* platform/graphics/FontCache.h:
* platform/graphics/freetype/FontCacheFreeType.cpp:
(WebCore::CachedFontSet::CachedFontSet):
(WebCore::CachedFontSet::bestForCharacters):
(WebCore::FallbackFontDescriptionKey::FallbackFontDescriptionKey):
(WebCore::FallbackFontDescriptionKey::operator== const):
(WebCore::FallbackFontDescriptionKey::operator!= const):
(WebCore::FallbackFontDescriptionKey::isHashTableDeletedValue const):
(WebCore::FallbackFontDescriptionKey::computeHash const):
(WebCore::FallbackFontDescriptionKeyHash::hash):
(WebCore::FallbackFontDescriptionKeyHash::equal):
(WebCore::systemFallbackCache):
(WebCore::FontCache::systemFallbackForCharacters):
(WebCore::FontCache::platformPurgeInactiveFontData):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (252043 => 252044)


--- trunk/Source/WebCore/ChangeLog	2019-11-05 07:48:33 UTC (rev 252043)
+++ trunk/Source/WebCore/ChangeLog	2019-11-05 08:17:58 UTC (rev 252044)
@@ -1,3 +1,29 @@
+2019-11-05  Carlos Garcia Campos  <cgar...@igalia.com>
+
+        [FreeType] Too slow running encoding/legacy-mb-korean/euc-kr WPT tests
+        https://bugs.webkit.org/show_bug.cgi?id=203544
+
+        Reviewed by Carlos Alberto Lopez Perez.
+
+        Use a cache for system fallbacks to keep the fonts sorted by font description. When a system fallback is needed
+        again for the same font description, but different characters, we just iterate the cached font set comparing the
+        charsets to get the best one. This avoids using FcFontMatch and FcFontSort is only called once per font description.
+
+        * platform/graphics/FontCache.h:
+        * platform/graphics/freetype/FontCacheFreeType.cpp:
+        (WebCore::CachedFontSet::CachedFontSet):
+        (WebCore::CachedFontSet::bestForCharacters):
+        (WebCore::FallbackFontDescriptionKey::FallbackFontDescriptionKey):
+        (WebCore::FallbackFontDescriptionKey::operator== const):
+        (WebCore::FallbackFontDescriptionKey::operator!= const):
+        (WebCore::FallbackFontDescriptionKey::isHashTableDeletedValue const):
+        (WebCore::FallbackFontDescriptionKey::computeHash const):
+        (WebCore::FallbackFontDescriptionKeyHash::hash):
+        (WebCore::FallbackFontDescriptionKeyHash::equal):
+        (WebCore::systemFallbackCache):
+        (WebCore::FontCache::systemFallbackForCharacters):
+        (WebCore::FontCache::platformPurgeInactiveFontData):
+
 2019-11-04  Chris Dumez  <cdu...@apple.com>
 
         Drop SuspendableTaskQueue now that it is unused

Modified: trunk/Source/WebCore/platform/graphics/FontCache.h (252043 => 252044)


--- trunk/Source/WebCore/platform/graphics/FontCache.h	2019-11-05 07:48:33 UTC (rev 252043)
+++ trunk/Source/WebCore/platform/graphics/FontCache.h	2019-11-05 08:17:58 UTC (rev 252044)
@@ -292,7 +292,7 @@
     return createFontPlatformData(fontDescription, family, nullptr, nullptr, { });
 }
 
-#if !PLATFORM(COCOA)
+#if !PLATFORM(COCOA) && !USE(FREETYPE)
 
 inline void FontCache::platformPurgeInactiveFontData()
 {

Modified: trunk/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp (252043 => 252044)


--- trunk/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp	2019-11-05 07:48:33 UTC (rev 252043)
+++ trunk/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp	2019-11-05 08:17:58 UTC (rev 252044)
@@ -24,6 +24,7 @@
 
 #include "CairoUniquePtr.h"
 #include "CairoUtilities.h"
+#include "CharacterProperties.h"
 #include "FcUniquePtr.h"
 #include "FloatConversion.h"
 #include "Font.h"
@@ -36,6 +37,8 @@
 #include <cairo.h>
 #include <fontconfig/fcfreetype.h>
 #include <wtf/Assertions.h>
+#include <wtf/HashFunctions.h>
+#include <wtf/HashMap.h>
 #include <wtf/text/CString.h>
 
 #if PLATFORM(GTK)
@@ -118,34 +121,150 @@
     }
 }
 
-RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font*, IsForPlatformFont, PreferColoredFont preferColoredFont, const UChar* characters, unsigned length)
-{
-    FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate());
-    UTF16UChar32Iterator iterator(characters, length);
-    UChar32 character = iterator.next();
-    while (character != iterator.end()) {
-        FcCharSetAddChar(fontConfigCharSet.get(), character);
-        character = iterator.next();
+struct CachedPattern {
+    // The pattern is owned by the CachedFontSet.
+    FcPattern* pattern { nullptr };
+    FcCharSet* charSet { nullptr };
+};
+
+class CachedFontSet {
+    WTF_MAKE_NONCOPYABLE(CachedFontSet); WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit CachedFontSet(RefPtr<FcPattern>&& pattern)
+        : m_pattern(WTFMove(pattern))
+    {
+        FcResult result;
+        m_fontSet.reset(FcFontSort(nullptr, m_pattern.get(), FcTrue, nullptr, &result));
+        for (int i = 0; i < m_fontSet->nfont; ++i) {
+            FcPattern* pattern = m_fontSet->fonts[i];
+            FcCharSet* charSet;
+
+            if (FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charSet) == FcResultMatch)
+                m_patterns.append({ pattern, charSet });
+        }
     }
 
-    RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
-    FcPatternAddCharSet(pattern.get(), FC_CHARSET, fontConfigCharSet.get());
+    RefPtr<FcPattern> bestForCharacters(const UChar* characters, unsigned length)
+    {
+        if (m_patterns.isEmpty()) {
+            FcResult result;
+            return adoptRef(FcFontMatch(nullptr, m_pattern.get(), &result));
+        }
 
-    FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue);
+        FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate());
+        UTF16UChar32Iterator iterator(characters, length);
+        UChar32 character = iterator.next();
+        bool hasNonIgnorableCharacters = false;
+        while (character != iterator.end()) {
+            if (!isDefaultIgnorableCodePoint(character)) {
+                FcCharSetAddChar(fontConfigCharSet.get(), character);
+                hasNonIgnorableCharacters = true;
+            }
+            character = iterator.next();
+        }
+
+        FcPattern* bestPattern = nullptr;
+        int minScore = std::numeric_limits<int>::max();
+        if (hasNonIgnorableCharacters) {
+            for (const auto& cachedPattern : m_patterns) {
+                if (!cachedPattern.charSet)
+                    continue;
+
+                int score = FcCharSetSubtractCount(fontConfigCharSet.get(), cachedPattern.charSet);
+                if (!score)
+                    return adoptRef(FcFontRenderPrepare(nullptr, m_pattern.get(), cachedPattern.pattern));
+
+                if (score < minScore) {
+                    bestPattern = cachedPattern.pattern;
+                    minScore = score;
+                }
+            }
+        }
+
+        if (bestPattern)
+            return adoptRef(FcFontRenderPrepare(nullptr, m_pattern.get(), bestPattern));
+
+        // If there aren't fonts with the given characters or all characters are ignorable, the first one is the best match.
+        return adoptRef(FcFontRenderPrepare(nullptr, m_pattern.get(), m_patterns[0].pattern));
+    }
+
+private:
+    RefPtr<FcPattern> m_pattern;
+    FcUniquePtr<FcFontSet> m_fontSet;
+    Vector<CachedPattern> m_patterns;
+};
+
+struct FallbackFontDescriptionKey {
+    FallbackFontDescriptionKey() = default;
+
+    FallbackFontDescriptionKey(const FontDescription& description, FontCache::PreferColoredFont preferColoredFont)
+        : descriptionKey(description)
+        , coloredFont(preferColoredFont == FontCache::PreferColoredFont::Yes)
+    {
+    }
+
+    explicit FallbackFontDescriptionKey(WTF::HashTableDeletedValueType deletedValue)
+        : descriptionKey(deletedValue)
+    {
+    }
+
+    bool operator==(const FallbackFontDescriptionKey& other) const
+    {
+        return descriptionKey == other.descriptionKey && coloredFont == other.coloredFont;
+    }
+
+    bool operator!=(const FallbackFontDescriptionKey& other) const
+    {
+        return !(*this == other);
+    }
+
+    bool isHashTableDeletedValue() const { return descriptionKey.isHashTableDeletedValue(); }
+
+    unsigned computeHash() const
+    {
+        return WTF::pairIntHash(descriptionKey.computeHash(), WTF::DefaultHash<bool>::Hash::hash(coloredFont));
+    }
+
+    FontDescriptionKey descriptionKey;
+    bool coloredFont { false };
+};
+
+struct FallbackFontDescriptionKeyHash {
+    static unsigned hash(const FallbackFontDescriptionKey& key) { return key.computeHash(); }
+    static bool equal(const FallbackFontDescriptionKey& a, const FallbackFontDescriptionKey& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+using SystemFallbackCache = HashMap<FallbackFontDescriptionKey, std::unique_ptr<CachedFontSet>, FallbackFontDescriptionKeyHash, SimpleClassHashTraits<FallbackFontDescriptionKey>>;
+static SystemFallbackCache& systemFallbackCache()
+{
+    static NeverDestroyed<SystemFallbackCache> cache;
+    return cache.get();
+}
+
+RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font*, IsForPlatformFont, PreferColoredFont preferColoredFont, const UChar* characters, unsigned length)
+{
+    auto addResult = systemFallbackCache().ensure(FallbackFontDescriptionKey(description, preferColoredFont), [&description, preferColoredFont]() -> std::unique_ptr<CachedFontSet> {
+        RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
+        FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue);
 #ifdef FC_COLOR
-    if (preferColoredFont == PreferColoredFont::Yes)
-        FcPatternAddBool(pattern.get(), FC_COLOR, FcTrue);
+        if (preferColoredFont == PreferColoredFont::Yes)
+            FcPatternAddBool(pattern.get(), FC_COLOR, FcTrue);
 #endif
+        if (!configurePatternForFontDescription(pattern.get(), description))
+            return nullptr;
 
-    if (!configurePatternForFontDescription(pattern.get(), description))
+        FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
+        cairo_ft_font_options_substitute(getDefaultCairoFontOptions(), pattern.get());
+        FcDefaultSubstitute(pattern.get());
+
+        return makeUnique<CachedFontSet>(WTFMove(pattern));
+    });
+
+    if (!addResult.iterator->value)
         return nullptr;
 
-    FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
-    cairo_ft_font_options_substitute(getDefaultCairoFontOptions(), pattern.get());
-    FcDefaultSubstitute(pattern.get());
-
-    FcResult fontConfigResult;
-    RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(nullptr, pattern.get(), &fontConfigResult));
+    RefPtr<FcPattern> resultPattern = addResult.iterator->value->bestForCharacters(characters, length);
     if (!resultPattern)
         return nullptr;
 
@@ -157,6 +276,11 @@
     return fontForPlatformData(alternateFontData);
 }
 
+void FontCache::platformPurgeInactiveFontData()
+{
+    systemFallbackCache().clear();
+}
+
 static Vector<String> patternToFamilies(FcPattern& pattern)
 {
     char* patternChars = reinterpret_cast<char*>(FcPatternFormat(&pattern, reinterpret_cast<const FcChar8*>("%{family}")));
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to