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}")));