Changeset 252044 in webkit


Ignore:
Timestamp:
Nov 5, 2019 12:17:58 AM (4 years ago)
Author:
Carlos Garcia Campos
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):

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r252036 r252044  
     12019-11-05  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [FreeType] Too slow running encoding/legacy-mb-korean/euc-kr WPT tests
     4        https://bugs.webkit.org/show_bug.cgi?id=203544
     5
     6        Reviewed by Carlos Alberto Lopez Perez.
     7
     8        Use a cache for system fallbacks to keep the fonts sorted by font description. When a system fallback is needed
     9        again for the same font description, but different characters, we just iterate the cached font set comparing the
     10        charsets to get the best one. This avoids using FcFontMatch and FcFontSort is only called once per font description.
     11
     12        * platform/graphics/FontCache.h:
     13        * platform/graphics/freetype/FontCacheFreeType.cpp:
     14        (WebCore::CachedFontSet::CachedFontSet):
     15        (WebCore::CachedFontSet::bestForCharacters):
     16        (WebCore::FallbackFontDescriptionKey::FallbackFontDescriptionKey):
     17        (WebCore::FallbackFontDescriptionKey::operator== const):
     18        (WebCore::FallbackFontDescriptionKey::operator!= const):
     19        (WebCore::FallbackFontDescriptionKey::isHashTableDeletedValue const):
     20        (WebCore::FallbackFontDescriptionKey::computeHash const):
     21        (WebCore::FallbackFontDescriptionKeyHash::hash):
     22        (WebCore::FallbackFontDescriptionKeyHash::equal):
     23        (WebCore::systemFallbackCache):
     24        (WebCore::FontCache::systemFallbackForCharacters):
     25        (WebCore::FontCache::platformPurgeInactiveFontData):
     26
    1272019-11-04  Chris Dumez  <cdumez@apple.com>
    228
  • trunk/Source/WebCore/platform/graphics/FontCache.h

    r251413 r252044  
    293293}
    294294
    295 #if !PLATFORM(COCOA)
     295#if !PLATFORM(COCOA) && !USE(FREETYPE)
    296296
    297297inline void FontCache::platformPurgeInactiveFontData()
  • trunk/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp

    r248846 r252044  
    2525#include "CairoUniquePtr.h"
    2626#include "CairoUtilities.h"
     27#include "CharacterProperties.h"
    2728#include "FcUniquePtr.h"
    2829#include "FloatConversion.h"
     
    3738#include <fontconfig/fcfreetype.h>
    3839#include <wtf/Assertions.h>
     40#include <wtf/HashFunctions.h>
     41#include <wtf/HashMap.h>
    3942#include <wtf/text/CString.h>
    4043
     
    119122}
    120123
     124struct CachedPattern {
     125    // The pattern is owned by the CachedFontSet.
     126    FcPattern* pattern { nullptr };
     127    FcCharSet* charSet { nullptr };
     128};
     129
     130class CachedFontSet {
     131    WTF_MAKE_NONCOPYABLE(CachedFontSet); WTF_MAKE_FAST_ALLOCATED;
     132public:
     133    explicit CachedFontSet(RefPtr<FcPattern>&& pattern)
     134        : m_pattern(WTFMove(pattern))
     135    {
     136        FcResult result;
     137        m_fontSet.reset(FcFontSort(nullptr, m_pattern.get(), FcTrue, nullptr, &result));
     138        for (int i = 0; i < m_fontSet->nfont; ++i) {
     139            FcPattern* pattern = m_fontSet->fonts[i];
     140            FcCharSet* charSet;
     141
     142            if (FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charSet) == FcResultMatch)
     143                m_patterns.append({ pattern, charSet });
     144        }
     145    }
     146
     147    RefPtr<FcPattern> bestForCharacters(const UChar* characters, unsigned length)
     148    {
     149        if (m_patterns.isEmpty()) {
     150            FcResult result;
     151            return adoptRef(FcFontMatch(nullptr, m_pattern.get(), &result));
     152        }
     153
     154        FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate());
     155        UTF16UChar32Iterator iterator(characters, length);
     156        UChar32 character = iterator.next();
     157        bool hasNonIgnorableCharacters = false;
     158        while (character != iterator.end()) {
     159            if (!isDefaultIgnorableCodePoint(character)) {
     160                FcCharSetAddChar(fontConfigCharSet.get(), character);
     161                hasNonIgnorableCharacters = true;
     162            }
     163            character = iterator.next();
     164        }
     165
     166        FcPattern* bestPattern = nullptr;
     167        int minScore = std::numeric_limits<int>::max();
     168        if (hasNonIgnorableCharacters) {
     169            for (const auto& cachedPattern : m_patterns) {
     170                if (!cachedPattern.charSet)
     171                    continue;
     172
     173                int score = FcCharSetSubtractCount(fontConfigCharSet.get(), cachedPattern.charSet);
     174                if (!score)
     175                    return adoptRef(FcFontRenderPrepare(nullptr, m_pattern.get(), cachedPattern.pattern));
     176
     177                if (score < minScore) {
     178                    bestPattern = cachedPattern.pattern;
     179                    minScore = score;
     180                }
     181            }
     182        }
     183
     184        if (bestPattern)
     185            return adoptRef(FcFontRenderPrepare(nullptr, m_pattern.get(), bestPattern));
     186
     187        // If there aren't fonts with the given characters or all characters are ignorable, the first one is the best match.
     188        return adoptRef(FcFontRenderPrepare(nullptr, m_pattern.get(), m_patterns[0].pattern));
     189    }
     190
     191private:
     192    RefPtr<FcPattern> m_pattern;
     193    FcUniquePtr<FcFontSet> m_fontSet;
     194    Vector<CachedPattern> m_patterns;
     195};
     196
     197struct FallbackFontDescriptionKey {
     198    FallbackFontDescriptionKey() = default;
     199
     200    FallbackFontDescriptionKey(const FontDescription& description, FontCache::PreferColoredFont preferColoredFont)
     201        : descriptionKey(description)
     202        , coloredFont(preferColoredFont == FontCache::PreferColoredFont::Yes)
     203    {
     204    }
     205
     206    explicit FallbackFontDescriptionKey(WTF::HashTableDeletedValueType deletedValue)
     207        : descriptionKey(deletedValue)
     208    {
     209    }
     210
     211    bool operator==(const FallbackFontDescriptionKey& other) const
     212    {
     213        return descriptionKey == other.descriptionKey && coloredFont == other.coloredFont;
     214    }
     215
     216    bool operator!=(const FallbackFontDescriptionKey& other) const
     217    {
     218        return !(*this == other);
     219    }
     220
     221    bool isHashTableDeletedValue() const { return descriptionKey.isHashTableDeletedValue(); }
     222
     223    unsigned computeHash() const
     224    {
     225        return WTF::pairIntHash(descriptionKey.computeHash(), WTF::DefaultHash<bool>::Hash::hash(coloredFont));
     226    }
     227
     228    FontDescriptionKey descriptionKey;
     229    bool coloredFont { false };
     230};
     231
     232struct FallbackFontDescriptionKeyHash {
     233    static unsigned hash(const FallbackFontDescriptionKey& key) { return key.computeHash(); }
     234    static bool equal(const FallbackFontDescriptionKey& a, const FallbackFontDescriptionKey& b) { return a == b; }
     235    static const bool safeToCompareToEmptyOrDeleted = true;
     236};
     237
     238using SystemFallbackCache = HashMap<FallbackFontDescriptionKey, std::unique_ptr<CachedFontSet>, FallbackFontDescriptionKeyHash, SimpleClassHashTraits<FallbackFontDescriptionKey>>;
     239static SystemFallbackCache& systemFallbackCache()
     240{
     241    static NeverDestroyed<SystemFallbackCache> cache;
     242    return cache.get();
     243}
     244
    121245RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font*, IsForPlatformFont, PreferColoredFont preferColoredFont, const UChar* characters, unsigned length)
    122246{
    123     FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate());
    124     UTF16UChar32Iterator iterator(characters, length);
    125     UChar32 character = iterator.next();
    126     while (character != iterator.end()) {
    127         FcCharSetAddChar(fontConfigCharSet.get(), character);
    128         character = iterator.next();
    129     }
    130 
    131     RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
    132     FcPatternAddCharSet(pattern.get(), FC_CHARSET, fontConfigCharSet.get());
    133 
    134     FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue);
     247    auto addResult = systemFallbackCache().ensure(FallbackFontDescriptionKey(description, preferColoredFont), [&description, preferColoredFont]() -> std::unique_ptr<CachedFontSet> {
     248        RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate());
     249        FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue);
    135250#ifdef FC_COLOR
    136     if (preferColoredFont == PreferColoredFont::Yes)
    137         FcPatternAddBool(pattern.get(), FC_COLOR, FcTrue);
     251        if (preferColoredFont == PreferColoredFont::Yes)
     252            FcPatternAddBool(pattern.get(), FC_COLOR, FcTrue);
    138253#endif
    139 
    140     if (!configurePatternForFontDescription(pattern.get(), description))
     254        if (!configurePatternForFontDescription(pattern.get(), description))
     255            return nullptr;
     256
     257        FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
     258        cairo_ft_font_options_substitute(getDefaultCairoFontOptions(), pattern.get());
     259        FcDefaultSubstitute(pattern.get());
     260
     261        return makeUnique<CachedFontSet>(WTFMove(pattern));
     262    });
     263
     264    if (!addResult.iterator->value)
    141265        return nullptr;
    142266
    143     FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern);
    144     cairo_ft_font_options_substitute(getDefaultCairoFontOptions(), pattern.get());
    145     FcDefaultSubstitute(pattern.get());
    146 
    147     FcResult fontConfigResult;
    148     RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(nullptr, pattern.get(), &fontConfigResult));
     267    RefPtr<FcPattern> resultPattern = addResult.iterator->value->bestForCharacters(characters, length);
    149268    if (!resultPattern)
    150269        return nullptr;
     
    156275    FontPlatformData alternateFontData(fontFace.get(), resultPattern.get(), description.computedPixelSize(), fixedWidth, syntheticBold, syntheticOblique, description.orientation());
    157276    return fontForPlatformData(alternateFontData);
     277}
     278
     279void FontCache::platformPurgeInactiveFontData()
     280{
     281    systemFallbackCache().clear();
    158282}
    159283
Note: See TracChangeset for help on using the changeset viewer.