diff --git a/third_party/txt/src/minikin/FontCollection.cpp b/third_party/txt/src/minikin/FontCollection.cpp index 1e7744953ccfb..0018e8f1447b5 100644 --- a/third_party/txt/src/minikin/FontCollection.cpp +++ b/third_party/txt/src/minikin/FontCollection.cpp @@ -59,7 +59,7 @@ FontCollection::FontCollection( void FontCollection::init( const vector>& typefaces) { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); mId = sNextId++; vector lastChar; size_t nTypefaces = typefaces.size(); @@ -321,6 +321,15 @@ const std::shared_ptr& FontCollection::getFamilyForChar( } } if (bestFamilyIndex == -1) { + // libtxt: check if the fallback font provider can match this character + if (mFallbackFontProvider) { + const std::shared_ptr& fallback = + mFallbackFontProvider->matchFallbackFont(ch); + if (fallback) { + return fallback; + } + } + UErrorCode errorCode = U_ZERO_ERROR; const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode); if (U_SUCCESS(errorCode)) { @@ -380,7 +389,7 @@ bool FontCollection::hasVariationSelector(uint32_t baseCodepoint, return false; } - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); // Currently mRanges can not be used here since it isn't aware of the // variation sequence. diff --git a/third_party/txt/src/minikin/FontCollection.h b/third_party/txt/src/minikin/FontCollection.h index 0b292f918fdb0..1a6525cc3f7d9 100644 --- a/third_party/txt/src/minikin/FontCollection.h +++ b/third_party/txt/src/minikin/FontCollection.h @@ -32,6 +32,15 @@ class FontCollection { const std::vector>& typefaces); explicit FontCollection(std::shared_ptr&& typeface); + // libtxt extension: an interface for looking up fallback fonts for characters + // that do not match this collection's font families. + class FallbackFontProvider { + public: + virtual ~FallbackFontProvider() = default; + virtual const std::shared_ptr& matchFallbackFont( + uint32_t ch) = 0; + }; + struct Run { FakedFont fakedFont; int start; @@ -63,6 +72,10 @@ class FontCollection { uint32_t getId() const; + void set_fallback_font_provider(std::unique_ptr ffp) { + mFallbackFontProvider = std::move(ffp); + } + private: static const int kLogCharsPerPage = 8; static const int kPageMask = (1 << kLogCharsPerPage) - 1; @@ -131,6 +144,9 @@ class FontCollection { // Set of supported axes in this collection. std::unordered_set mSupportedAxes; + + // libtxt extension: Fallback font provider. + std::unique_ptr mFallbackFontProvider; }; } // namespace minikin diff --git a/third_party/txt/src/minikin/FontFamily.cpp b/third_party/txt/src/minikin/FontFamily.cpp index 39cbab3787421..b301d20c2f2c4 100644 --- a/third_party/txt/src/minikin/FontFamily.cpp +++ b/third_party/txt/src/minikin/FontFamily.cpp @@ -56,7 +56,7 @@ android::hash_t FontStyle::hash() const { // static uint32_t FontStyle::registerLanguageList(const std::string& languages) { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); return FontLanguageListCache::getId(languages); } @@ -115,7 +115,7 @@ FontFamily::FontFamily(uint32_t langId, int variant, std::vector&& fonts) bool FontFamily::analyzeStyle(const std::shared_ptr& typeface, int* weight, bool* italic) { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2'); HbBlob os2Table(getFontTable(typeface.get(), os2Tag)); if (os2Table.get() == nullptr) @@ -175,7 +175,7 @@ bool FontFamily::isColorEmojiFamily() const { } void FontFamily::computeCoverage() { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); const FontStyle defaultStyle; const MinikinFont* typeface = getClosestMatch(defaultStyle).font; const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p'); @@ -233,7 +233,7 @@ std::shared_ptr FontFamily::createFamilyWithVariation( std::vector fonts; for (const Font& font : mFonts) { bool supportedVariations = false; - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); std::unordered_set supportedAxes = font.getSupportedAxesLocked(); if (!supportedAxes.empty()) { for (const FontVariation& variation : variations) { diff --git a/third_party/txt/src/minikin/Layout.cpp b/third_party/txt/src/minikin/Layout.cpp index 3296171069223..17a80910f8c46 100644 --- a/third_party/txt/src/minikin/Layout.cpp +++ b/third_party/txt/src/minikin/Layout.cpp @@ -604,7 +604,7 @@ void Layout::doLayout(const uint16_t* buf, const FontStyle& style, const MinikinPaint& paint, const std::shared_ptr& collection) { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); LayoutContext ctx; ctx.style = style; @@ -628,7 +628,7 @@ float Layout::measureText(const uint16_t* buf, const MinikinPaint& paint, const std::shared_ptr& collection, float* advances) { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); LayoutContext ctx; ctx.style = style; @@ -1197,7 +1197,7 @@ void Layout::getBounds(MinikinRect* bounds) const { } void Layout::purgeCaches() { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache; layoutCache.clear(); purgeHbFontCacheLocked(); diff --git a/third_party/txt/src/minikin/MinikinFont.cpp b/third_party/txt/src/minikin/MinikinFont.cpp index a39699475daf9..5d3715bf08937 100644 --- a/third_party/txt/src/minikin/MinikinFont.cpp +++ b/third_party/txt/src/minikin/MinikinFont.cpp @@ -21,7 +21,7 @@ namespace minikin { MinikinFont::~MinikinFont() { - std::lock_guard _l(gMinikinLock); + std::lock_guard _l(gMinikinLock); purgeHbFontLocked(this); } diff --git a/third_party/txt/src/minikin/MinikinInternal.cpp b/third_party/txt/src/minikin/MinikinInternal.cpp index 69e87f0c26ba4..09a5e9c7452d6 100644 --- a/third_party/txt/src/minikin/MinikinInternal.cpp +++ b/third_party/txt/src/minikin/MinikinInternal.cpp @@ -24,7 +24,7 @@ namespace minikin { -std::mutex gMinikinLock; +std::recursive_mutex gMinikinLock; void assertMinikinLocked() { #ifdef ENABLE_RACE_DETECTION diff --git a/third_party/txt/src/minikin/MinikinInternal.h b/third_party/txt/src/minikin/MinikinInternal.h index fe887123e3f25..c07ad479a82f0 100644 --- a/third_party/txt/src/minikin/MinikinInternal.h +++ b/third_party/txt/src/minikin/MinikinInternal.h @@ -31,7 +31,7 @@ namespace minikin { // Presently, that's implemented by through a global lock, and having // all external interfaces take that lock. -extern std::mutex gMinikinLock; +extern std::recursive_mutex gMinikinLock; // Aborts if gMinikinLock is not acquired. Do nothing on the release build. void assertMinikinLocked(); diff --git a/third_party/txt/src/txt/font_collection.cc b/third_party/txt/src/txt/font_collection.cc index b8ba00baa49c6..1bca40a08e636 100644 --- a/third_party/txt/src/txt/font_collection.cc +++ b/third_party/txt/src/txt/font_collection.cc @@ -41,8 +41,29 @@ const std::vector fallback_characters{ 0x627, // Arabic }; +// Font families that will be used as a last resort if no font manager provides +// a font matching a particular character. +const std::vector last_resort_fonts{ + "Arial", +}; + } // anonymous namespace +class TxtFallbackFontProvider + : public minikin::FontCollection::FallbackFontProvider { + public: + TxtFallbackFontProvider(std::shared_ptr font_collection) + : font_collection_(font_collection) {} + + virtual const std::shared_ptr& matchFallbackFont( + uint32_t ch) { + return font_collection_->MatchFallbackFont(ch); + } + + private: + std::shared_ptr font_collection_; +}; + FontCollection::FontCollection() = default; FontCollection::~FontCollection() = default; @@ -117,6 +138,8 @@ FontCollection::GetMinikinFontCollectionForFamily(const std::string& family) { // Create the minikin font collection. auto font_collection = std::make_shared(std::move(minikin_families)); + font_collection->set_fallback_font_provider( + std::make_unique(shared_from_this())); // Cache the font collection for future queries. font_collections_cache_[family] = font_collection; @@ -133,29 +156,62 @@ FontCollection::GetMinikinFontCollectionForFamily(const std::string& family) { return nullptr; } -void FontCollection::UpdateFallbackFonts(sk_sp manager) { - char language_tag[ULOC_FULLNAME_CAPACITY]; - UErrorCode uerr; - uloc_toLanguageTag(icu::Locale::getDefault().getName(), language_tag, - ULOC_FULLNAME_CAPACITY, FALSE, &uerr); - if (U_FAILURE(uerr)) - return; - const char* bcp47[] = {language_tag}; - - for (SkUnichar fallback_char : fallback_characters) { - if (fallback_fonts_.count(fallback_char)) +const std::shared_ptr& FontCollection::MatchFallbackFont( + uint32_t ch) { + for (const auto& manager : skia_font_managers_) { + sk_sp typeface( + manager->matchFamilyStyleCharacter(0, SkFontStyle(), nullptr, 0, ch)); + if (!typeface) continue; - sk_sp skia_typeface(manager->matchFamilyStyleCharacter( - 0, SkFontStyle(), bcp47, 1, fallback_char)); - if (!skia_typeface) - continue; + return GetFontFamilyForTypeface(typeface); + } - std::vector minikin_fonts; - minikin_fonts.emplace_back(std::make_shared(skia_typeface), - minikin::FontStyle()); - fallback_fonts_[fallback_char] = - std::make_shared(std::move(minikin_fonts)); + return null_family_; +} + +const std::shared_ptr& +FontCollection::GetFontFamilyForTypeface(const sk_sp& typeface) { + SkFontID typeface_id = typeface->uniqueID(); + auto fallback_it = fallback_fonts_.find(typeface_id); + if (fallback_it != fallback_fonts_.end()) { + return fallback_it->second; + } + + std::vector minikin_fonts; + minikin_fonts.emplace_back(std::make_shared(typeface), + minikin::FontStyle()); + auto insert_it = fallback_fonts_.insert(std::make_pair( + typeface_id, + std::make_shared(std::move(minikin_fonts)))); + + // Clear the cache to force creation of new font collections that will include + // this fallback font. + font_collections_cache_.clear(); + + return insert_it.first->second; +} + +void FontCollection::UpdateFallbackFonts(sk_sp manager) { + // Prepopulate the fallback font cache with fonts matching some widely + // used character classes. + for (SkUnichar fallback_char : fallback_characters) { + sk_sp typeface(manager->matchFamilyStyleCharacter( + 0, SkFontStyle(), nullptr, 0, fallback_char)); + if (typeface) { + // Create a Minikin font family for this typeface if one does not already + // exist. + GetFontFamilyForTypeface(typeface); + } + } + + // Add additional font families to be used if nothing else matches. + for (const std::string& family : last_resort_fonts) { + sk_sp typeface( + manager->matchFamilyStyle(family.c_str(), SkFontStyle())); + if (typeface) { + GetFontFamilyForTypeface(typeface); + } } } diff --git a/third_party/txt/src/txt/font_collection.h b/third_party/txt/src/txt/font_collection.h index c6a838ec34668..ccb52f5ecbceb 100644 --- a/third_party/txt/src/txt/font_collection.h +++ b/third_party/txt/src/txt/font_collection.h @@ -31,7 +31,7 @@ namespace txt { -class FontCollection { +class FontCollection : public std::enable_shared_from_this { public: FontCollection(); @@ -46,12 +46,18 @@ class FontCollection { std::shared_ptr GetMinikinFontCollectionForFamily( const std::string& family); + const std::shared_ptr& MatchFallbackFont(uint32_t ch); + private: std::deque> skia_font_managers_; std::unordered_map> font_collections_cache_; - std::unordered_map> + std::unordered_map> fallback_fonts_; + std::shared_ptr null_family_; + + const std::shared_ptr& GetFontFamilyForTypeface( + const sk_sp& typeface); void UpdateFallbackFonts(sk_sp manager);