diff --git a/third_party/txt/src/minikin/FontCollection.cpp b/third_party/txt/src/minikin/FontCollection.cpp index ebbb104dd146d0c66fa6f7825ab1fa15ca1ea4f5..a9dcc66b522e36a65dc4ffaadfe0ac67367b67ef 100644 --- a/third_party/txt/src/minikin/FontCollection.cpp +++ b/third_party/txt/src/minikin/FontCollection.cpp @@ -44,6 +44,12 @@ const uint32_t TEXT_STYLE_VS = 0xFE0E; uint32_t FontCollection::sNextId = 0; +// libtxt: return a locale string for a language list ID +std::string GetFontLocale(uint32_t langListId) { + const FontLanguages& langs = FontLanguageListCache::getById(langListId); + return langs.size() ? langs[0].getString() : ""; +} + FontCollection::FontCollection(std::shared_ptr&& typeface) : mMaxChar(0) { std::vector> typefaces; @@ -295,7 +301,8 @@ const std::shared_ptr& FontCollection::getFamilyForChar( // libtxt: check if the fallback font provider can match this character if (mFallbackFontProvider) { const std::shared_ptr& fallback = - mFallbackFontProvider->matchFallbackFont(ch); + mFallbackFontProvider->matchFallbackFont(ch, + GetFontLocale(langListId)); if (fallback) { return fallback; } @@ -332,7 +339,8 @@ const std::shared_ptr& FontCollection::getFamilyForChar( // libtxt: check if the fallback font provider can match this character if (mFallbackFontProvider) { const std::shared_ptr& fallback = - mFallbackFontProvider->matchFallbackFont(ch); + mFallbackFontProvider->matchFallbackFont(ch, + GetFontLocale(langListId)); if (fallback) { return fallback; } diff --git a/third_party/txt/src/minikin/FontCollection.h b/third_party/txt/src/minikin/FontCollection.h index 1a6525cc3f7d9cd03b63a88d06386f5c37417b35..48365a64ac8414ea925024d6775aba399581ae23 100644 --- a/third_party/txt/src/minikin/FontCollection.h +++ b/third_party/txt/src/minikin/FontCollection.h @@ -38,7 +38,8 @@ class FontCollection { public: virtual ~FallbackFontProvider() = default; virtual const std::shared_ptr& matchFallbackFont( - uint32_t ch) = 0; + uint32_t ch, + std::string locale) = 0; }; struct Run { diff --git a/third_party/txt/src/txt/font_collection.cc b/third_party/txt/src/txt/font_collection.cc index 05eebb4bf7ab307c407b05fe9987159a7942735d..982524d4fe8ca5961464a479a37b5e99b28796c8 100644 --- a/third_party/txt/src/txt/font_collection.cc +++ b/third_party/txt/src/txt/font_collection.cc @@ -30,15 +30,16 @@ namespace txt { -namespace { - -// 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", -}; +bool FontCollection::FamilyKey::operator==( + const FontCollection::FamilyKey& other) const { + return font_family == other.font_family && locale == other.locale; +} -} // anonymous namespace +size_t FontCollection::FamilyKey::Hasher::operator()( + const FontCollection::FamilyKey& key) const { + return std::hash()(key.font_family) ^ + std::hash()(key.locale); +} class TxtFallbackFontProvider : public minikin::FontCollection::FallbackFontProvider { @@ -47,8 +48,9 @@ class TxtFallbackFontProvider : font_collection_(font_collection) {} virtual const std::shared_ptr& matchFallbackFont( - uint32_t ch) { - return font_collection_->MatchFallbackFont(ch); + uint32_t ch, + std::string locale) { + return font_collection_->MatchFallbackFont(ch, locale); } private: @@ -92,15 +94,19 @@ void FontCollection::DisableFontFallback() { } std::shared_ptr -FontCollection::GetMinikinFontCollectionForFamily(const std::string& family) { +FontCollection::GetMinikinFontCollectionForFamily( + const std::string& font_family, + const std::string& locale) { // Look inside the font collections cache first. - auto cached = font_collections_cache_.find(family); + FamilyKey family_key(font_family, locale); + auto cached = font_collections_cache_.find(family_key); if (cached != font_collections_cache_.end()) { return cached->second; } for (sk_sp& manager : GetFontManagerOrder()) { - sk_sp font_style_set(manager->matchFamily(family.c_str())); + sk_sp font_style_set( + manager->matchFamily(font_family.c_str())); if (font_style_set == nullptr || font_style_set->count() == 0) { continue; } @@ -136,8 +142,8 @@ FontCollection::GetMinikinFontCollectionForFamily(const std::string& family) { minikin_family, }; if (enable_font_fallback_) { - for (const auto& fallback : fallback_fonts_) - minikin_families.push_back(fallback.second); + for (SkFontID font_id : fallback_fonts_for_locale_[locale]) + minikin_families.push_back(fallback_fonts_[font_id]); } // Create the minikin font collection. @@ -149,16 +155,16 @@ FontCollection::GetMinikinFontCollectionForFamily(const std::string& family) { } // Cache the font collection for future queries. - font_collections_cache_[family] = font_collection; + font_collections_cache_[family_key] = font_collection; return font_collection; } const auto default_font_family = GetDefaultFontFamily(); - if (family != default_font_family) { + if (font_family != default_font_family) { std::shared_ptr default_collection = - GetMinikinFontCollectionForFamily(default_font_family); - font_collections_cache_[family] = default_collection; + GetMinikinFontCollectionForFamily(default_font_family, ""); + font_collections_cache_[family_key] = default_collection; return default_collection; } @@ -167,21 +173,27 @@ FontCollection::GetMinikinFontCollectionForFamily(const std::string& family) { } const std::shared_ptr& FontCollection::MatchFallbackFont( - uint32_t ch) { + uint32_t ch, + std::string locale) { for (const sk_sp& manager : GetFontManagerOrder()) { - sk_sp typeface( - manager->matchFamilyStyleCharacter(0, SkFontStyle(), nullptr, 0, ch)); + std::vector bcp47; + if (!locale.empty()) + bcp47.push_back(locale.c_str()); + sk_sp typeface(manager->matchFamilyStyleCharacter( + 0, SkFontStyle(), bcp47.data(), bcp47.size(), ch)); if (!typeface) continue; - return GetFontFamilyForTypeface(typeface); + fallback_fonts_for_locale_[locale].insert(typeface->uniqueID()); + + return GetFallbackFont(typeface); } return null_family_; } const std::shared_ptr& -FontCollection::GetFontFamilyForTypeface(const sk_sp& typeface) { +FontCollection::GetFallbackFont(const sk_sp& typeface) { SkFontID typeface_id = typeface->uniqueID(); auto fallback_it = fallback_fonts_.find(typeface_id); if (fallback_it != fallback_fonts_.end()) { @@ -202,14 +214,4 @@ FontCollection::GetFontFamilyForTypeface(const sk_sp& typeface) { return insert_it.first->second; } -void FontCollection::UpdateFallbackFonts(sk_sp manager) { - for (const std::string& family : last_resort_fonts) { - sk_sp typeface( - manager->matchFamilyStyle(family.c_str(), SkFontStyle())); - if (typeface) { - GetFontFamilyForTypeface(typeface); - } - } -} - } // namespace txt diff --git a/third_party/txt/src/txt/font_collection.h b/third_party/txt/src/txt/font_collection.h index 4da4e3d02552cbcf8529f0c2f704828c4e93ed4d..0640a0974a2ea1a233bd167da9339be638071da2 100644 --- a/third_party/txt/src/txt/font_collection.h +++ b/third_party/txt/src/txt/font_collection.h @@ -17,8 +17,8 @@ #ifndef LIB_TXT_SRC_FONT_COLLECTION_H_ #define LIB_TXT_SRC_FONT_COLLECTION_H_ -#include #include +#include #include #include #include "lib/fxl/macros.h" @@ -28,6 +28,7 @@ #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/ports/SkFontMgr.h" #include "txt/asset_font_manager.h" +#include "txt/text_style.h" namespace txt { @@ -44,32 +45,51 @@ class FontCollection : public std::enable_shared_from_this { void SetTestFontManager(sk_sp font_manager); std::shared_ptr GetMinikinFontCollectionForFamily( - const std::string& family); + const std::string& family, + const std::string& locale); - const std::shared_ptr& MatchFallbackFont(uint32_t ch); + const std::shared_ptr& MatchFallbackFont( + uint32_t ch, + std::string locale); // Do not provide alternative fonts that can match characters which are // missing from the requested font family. void DisableFontFallback(); private: + struct FamilyKey { + FamilyKey(const std::string& family, const std::string& loc) + : font_family(family), locale(loc) {} + + std::string font_family; + std::string locale; + + bool operator==(const FamilyKey& other) const; + + struct Hasher { + size_t operator()(const FamilyKey& key) const; + }; + }; + sk_sp default_font_manager_; sk_sp asset_font_manager_; sk_sp test_font_manager_; - std::unordered_map> + std::unordered_map, + FamilyKey::Hasher> font_collections_cache_; std::unordered_map> fallback_fonts_; + std::unordered_map> + fallback_fonts_for_locale_; std::shared_ptr null_family_; bool enable_font_fallback_; std::vector> GetFontManagerOrder() const; - const std::shared_ptr& GetFontFamilyForTypeface( + const std::shared_ptr& GetFallbackFont( const sk_sp& typeface); - void UpdateFallbackFonts(sk_sp manager); - FXL_DISALLOW_COPY_AND_ASSIGN(FontCollection); }; diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index bcebc596684aff979053404d8000ae3029502819..a2fd816a84dd5a28dda4707d23b13cbd3726a51e 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -160,16 +160,6 @@ void GetFontAndMinikinPaint(const TextStyle& style, paint->paintFlags |= minikin::LinearTextFlag; } -sk_sp GetDefaultSkiaTypeface( - const std::shared_ptr& font_collection, - const TextStyle& style) { - std::shared_ptr collection = - font_collection->GetMinikinFontCollectionForFamily(style.font_family); - minikin::FakedFont faked_font = - collection->baseFontFaked(GetMinikinFontStyle(style)); - return static_cast(faked_font.font)->GetSkTypeface(); -} - void FindWords(const std::vector& text, size_t start, size_t end, @@ -286,8 +276,7 @@ bool Paragraph::ComputeLineBreaks() { minikin::MinikinPaint paint; GetFontAndMinikinPaint(run.style, &font, &paint); std::shared_ptr collection = - font_collection_->GetMinikinFontCollectionForFamily( - run.style.font_family); + GetMinikinFontCollectionForStyle(run.style); if (collection == nullptr) { FXL_LOG(INFO) << "Could not find font collection for family \"" << run.style.font_family << "\"."; @@ -502,8 +491,7 @@ void Paragraph::Layout(double width, bool force) { paint.setTextSize(run.style().font_size); std::shared_ptr minikin_font_collection = - font_collection_->GetMinikinFontCollectionForFamily( - run.style().font_family); + GetMinikinFontCollectionForStyle(run.style()); // Lay out this run. uint16_t* text_ptr = text_.data(); @@ -753,7 +741,7 @@ void Paragraph::Layout(double width, bool force) { if (paint_records.empty()) { SkPaint::FontMetrics metrics; TextStyle style(paragraph_style_.GetTextStyle()); - paint.setTypeface(GetDefaultSkiaTypeface(font_collection_, style)); + paint.setTypeface(GetDefaultSkiaTypeface(style)); paint.setTextSize(style.font_size); paint.getFontMetrics(&metrics); update_line_metrics(metrics, style); @@ -855,6 +843,31 @@ void Paragraph::SetFontCollection( font_collection_ = std::move(font_collection); } +std::shared_ptr +Paragraph::GetMinikinFontCollectionForStyle(const TextStyle& style) { + std::string locale; + if (!style.locale.empty()) { + uint32_t language_list_id = + minikin::FontStyle::registerLanguageList(style.locale); + const minikin::FontLanguages& langs = + minikin::FontLanguageListCache::getById(language_list_id); + if (langs.size()) { + locale = langs[0].getString(); + } + } + + return font_collection_->GetMinikinFontCollectionForFamily(style.font_family, + locale); +} + +sk_sp Paragraph::GetDefaultSkiaTypeface(const TextStyle& style) { + std::shared_ptr collection = + GetMinikinFontCollectionForStyle(style); + minikin::FakedFont faked_font = + collection->baseFontFaked(GetMinikinFontStyle(style)); + return static_cast(faked_font.font)->GetSkTypeface(); +} + // The x,y coordinates will be the very top left corner of the rendered // paragraph. void Paragraph::Paint(SkCanvas* canvas, double x, double y) { diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 894439abc5965dad5a047a064d62d9e2deca48c3..edbff5e56a80fc50bf419563cfc4468462750146 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -313,6 +313,13 @@ class Paragraph { // Draws the background onto the canvas. void PaintBackground(SkCanvas* canvas, const PaintRecord& record); + // Obtain a Minikin font collection matching this text style. + std::shared_ptr GetMinikinFontCollectionForStyle( + const TextStyle& style); + + // Get a default SkTypeface for a text style. + sk_sp GetDefaultSkiaTypeface(const TextStyle& style); + FXL_DISALLOW_COPY_AND_ASSIGN(Paragraph); };