diff --git a/third_party/txt/src/minikin/FontCollection.cpp b/third_party/txt/src/minikin/FontCollection.cpp index 91d1ac295cdc1..c823caf0a5da9 100644 --- a/third_party/txt/src/minikin/FontCollection.cpp +++ b/third_party/txt/src/minikin/FontCollection.cpp @@ -528,8 +528,27 @@ void FontCollection::itemize(const uint16_t* string, } start -= prevChLength; } - result->push_back( - {family->getClosestMatch(style), static_cast(start), 0}); + result->push_back({family->getClosestMatch(style, ch, variant), + static_cast(start), 0}); + run = &result->back(); + lastFamily = family.get(); + } else if (family.get() == lastFamily && + // We need to change this condition to more general logic. And + // when changing the font, it is necessary to check whether the + // existing characters also have glyphs. + !(U_GET_GC_MASK(prevCh) & U_GC_L_MASK) && + (U_GET_GC_MASK(ch) & U_GC_L_MASK)) { + size_t start = utf16Pos; + auto current_font = family->getClosestMatch(style, ch, variant); + if (result->back().fakedFont.font != current_font.font) { + const size_t prevChLength = U16_LENGTH(prevCh); + run->end -= prevChLength; + if (run->start == run->end) { + result->pop_back(); + } + start -= prevChLength; + } + result->push_back({current_font, static_cast(start), 0}); run = &result->back(); lastFamily = family.get(); } diff --git a/third_party/txt/src/minikin/FontFamily.cpp b/third_party/txt/src/minikin/FontFamily.cpp index 9f66e72f2f520..3f0ae176e3afb 100644 --- a/third_party/txt/src/minikin/FontFamily.cpp +++ b/third_party/txt/src/minikin/FontFamily.cpp @@ -146,15 +146,28 @@ static FontFakery computeFakery(FontStyle wanted, FontStyle actual) { return FontFakery(isFakeBold, isFakeItalic); } -FakedFont FontFamily::getClosestMatch(FontStyle style) const { +FakedFont FontFamily::getClosestMatch( + FontStyle style, + uint32_t codepoint /* = 0 */, + uint32_t variationSelector /* = 0 */) const { + int bestMatch = INT_MAX; const Font* bestFont = nullptr; - int bestMatch = 0; for (size_t i = 0; i < mFonts.size(); i++) { const Font& font = mFonts[i]; int match = computeMatch(font.style, style); - if (i == 0 || match < bestMatch) { - bestFont = &font; - bestMatch = match; + bool result = false; + if (codepoint != 0) { + hb_font_t* hb_font = getHbFontLocked(font.typeface.get()); + uint32_t unusedGlyph = 0; + result = hb_font_get_glyph(hb_font, codepoint, variationSelector, + &unusedGlyph); + hb_font_destroy(hb_font); + } + if (!codepoint || (codepoint && result)) { + if (match < bestMatch) { + bestFont = &font; + bestMatch = match; + } } } if (bestFont != nullptr) { diff --git a/third_party/txt/src/minikin/FontFamily.h b/third_party/txt/src/minikin/FontFamily.h index aac7a0d62bd12..1d9e6eefaa08c 100644 --- a/third_party/txt/src/minikin/FontFamily.h +++ b/third_party/txt/src/minikin/FontFamily.h @@ -140,7 +140,9 @@ class FontFamily { static bool analyzeStyle(const std::shared_ptr& typeface, int* weight, bool* italic); - FakedFont getClosestMatch(FontStyle style) const; + FakedFont getClosestMatch(FontStyle style, + uint32_t codepoint = 0, + uint32_t variationSelector = 0) const; uint32_t langId() const { return mLangId; } int variant() const { return mVariant; } diff --git a/third_party/txt/src/txt/font_collection.cc b/third_party/txt/src/txt/font_collection.cc index d3cb84e9aa666..3460f50d4b0c5 100644 --- a/third_party/txt/src/txt/font_collection.cc +++ b/third_party/txt/src/txt/font_collection.cc @@ -250,6 +250,28 @@ void FontCollection::SortSkTypefaces( int a_delta = std::abs(a_style.width() - SkFontStyle::kNormal_Width); int b_delta = std::abs(b_style.width() - SkFontStyle::kNormal_Width); + { + // A workaround to prevent emoji fonts being selected for normal text + // when normal and emojis are mixed at same font family. + + bool a_isContainEmoji = false; + bool b_isContainEmoji = false; + SkString postScriptName; + a->getPostScriptName(&postScriptName); + if (postScriptName.contains("Emoji")) { + a_isContainEmoji = true; + } + b->getPostScriptName(&postScriptName); + if (postScriptName.contains("Emoji")) { + b_isContainEmoji = true; + } + if (a_isContainEmoji && !b_isContainEmoji) { + return false; + } else if (!a_isContainEmoji && b_isContainEmoji) { + return true; + } + } + if (a_delta != b_delta) { // If a family name query is so generic it ends up bringing in fonts // of multiple widths (e.g. condensed, expanded), opt to be diff --git a/third_party/txt/src/txt/platform_linux.cc b/third_party/txt/src/txt/platform_linux.cc index b2e83a67d7967..98210dcabe26e 100644 --- a/third_party/txt/src/txt/platform_linux.cc +++ b/third_party/txt/src/txt/platform_linux.cc @@ -13,6 +13,9 @@ namespace txt { std::vector GetDefaultFontFamilies() { +#ifdef FLUTTER_USE_FONTCONFIG + return {"TizenDefaultFont"}; +#else return { "SamsungOneUI", "SamsungOneUIArabic", @@ -72,11 +75,12 @@ std::vector GetDefaultFontFamilies() { "BreezeSansFallback", "BreezeColorEmoji", }; +#endif } sk_sp GetDefaultFontManager() { #ifdef FLUTTER_USE_FONTCONFIG - return SkFontMgr_New_FontConfig(nullptr); + return SkFontMgr::RefDefault(); #else return SkFontMgr_New_Custom_Directory("/usr/share/fonts"); #endif