Chromium Code Reviews| Index: ui/gfx/font_fallback_android.cc |
| diff --git a/ui/gfx/font_fallback_android.cc b/ui/gfx/font_fallback_android.cc |
| index e41fa9d28a2eba75f2808088028f394849decc63..659c8112a529bafa30ea396e39a20a2b67c0120b 100644 |
| --- a/ui/gfx/font_fallback_android.cc |
| +++ b/ui/gfx/font_fallback_android.cc |
| @@ -2,15 +2,143 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "ui/gfx/font_fallback.h" |
| +#include "ui/gfx/font_fallback_android.h" |
| +#include <map> |
| +#include <set> |
| #include <string> |
| #include <vector> |
| +#include "base/lazy_instance.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "third_party/icu/source/common/unicode/uscript.h" |
| +#include "third_party/skia/include/core/SkPaint.h" |
| +#include "third_party/skia/include/core/SkTypeface.h" |
| +#include "third_party/skia/include/ports/SkFontMgr.h" |
| +#include "ui/gfx/platform_font_linux.h" |
| + |
| namespace gfx { |
| +namespace { |
| + |
| +enum KnownGlyph { |
| + UNDEFINED, |
| + UNKNOWN, |
| + KNOWN, |
| +}; |
| + |
| +class CachedFont { |
| + public: |
| + static std::unique_ptr<CachedFont> CreateForTypeface( |
| + sk_sp<SkTypeface> typeface) { |
| + return base::WrapUnique<CachedFont>(new CachedFont(typeface)); |
| + } |
| + bool HasGlyphForCharacter(UChar32 character) { |
| + // In order to increase cache hits, the cache is script based rather than |
| + // character based. This also limits the cache size to the number of Unicode |
| + // scripts (174). |
|
mthiesse
2017/05/08 17:09:18
nit: The 174 number will get stale, "174 at time o
|
| + UErrorCode err; |
| + UScriptCode script = uscript_getScript(character, &err); |
| + if (!U_SUCCESS(err) || script == UScriptCode::USCRIPT_COMMON) |
| + return false; |
| + auto& supported = supported_scripts_[script]; |
| + if (supported != UNDEFINED) |
| + return supported == KNOWN; |
| + uint16_t glyph_id; |
| + paint_.textToGlyphs(&character, sizeof(UChar32), &glyph_id); |
| + supported = glyph_id ? KNOWN : UNKNOWN; |
| + return glyph_id; |
| + } |
| + std::string GetFontName() { return name_; } |
| + |
| + private: |
| + CachedFont(sk_sp<SkTypeface> skia_face) { |
| + SkString sk_name; |
| + skia_face->getFamilyName(&sk_name); |
| + name_ = sk_name.c_str(); |
| + paint_.setTypeface(std::move(skia_face)); |
| + paint_.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
| + } |
| + |
| + SkPaint paint_; |
| + std::map<UScriptCode, KnownGlyph> supported_scripts_; |
| + std::string name_; |
| +}; |
| + |
| +using FontCache = std::map<SkFontID, std::unique_ptr<CachedFont>>; |
| +base::LazyInstance<FontCache>::Leaky g_fonts = LAZY_INSTANCE_INITIALIZER; |
| + |
| +class CachedFontSet { |
| + public: |
| + CachedFontSet() : locale_() {} |
| + ~CachedFontSet() = default; |
| + void SetLocale(const std::string& locale) { |
| + // Store font list for one locale at a time. |
| + if (locale != locale_) { |
| + font_ids_.clear(); |
| + unknown_chars_.clear(); |
| + locale_ = locale; |
| + } |
| + } |
| + |
| + std::string GetFallbackFontNameForChar(UChar32 c) { |
| + if (unknown_chars_.find(c) != unknown_chars_.end()) |
| + return ""; |
| + for (SkFontID font_id : font_ids_) { |
| + std::unique_ptr<CachedFont>& font = g_fonts.Get()[font_id]; |
| + if (font->HasGlyphForCharacter(c)) |
| + return font->GetFontName(); |
| + } |
| + sk_sp<SkFontMgr> font_mgr(SkFontMgr::RefDefault()); |
| + const char* bcp47_locales[] = {locale_.c_str()}; |
| + sk_sp<SkTypeface> tf(font_mgr->matchFamilyStyleCharacter( |
| + nullptr, SkFontStyle(), locale_.empty() ? nullptr : bcp47_locales, |
| + locale_.empty() ? 0 : 1, c)); |
| + if (tf) { |
| + SkFontID font_id = tf->uniqueID(); |
| + font_ids_.push_back(font_id); |
| + std::unique_ptr<CachedFont>& cached_font = g_fonts.Get()[font_id]; |
| + if (!cached_font) |
| + cached_font = CachedFont::CreateForTypeface(tf); |
| + return cached_font->GetFontName(); |
| + } |
| + unknown_chars_.insert(c); |
| + return std::string(); |
| + } |
| + |
| + private: |
| + std::string locale_; |
| + std::vector<SkFontID> font_ids_; |
| + std::set<UChar32> unknown_chars_; |
| +}; |
| + |
| +base::LazyInstance<CachedFontSet>::Leaky g_cached_font_set = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +bool FontSupportsChar(const gfx::Font& font, UChar32 c) { |
| + sk_sp<SkTypeface> typeface = |
| + static_cast<PlatformFontLinux*>(font.platform_font())->typeface(); |
| + std::unique_ptr<CachedFont>& cached_font = |
| + g_fonts.Get()[typeface->uniqueID()]; |
| + if (!cached_font) |
| + cached_font = CachedFont::CreateForTypeface(typeface); |
| + return cached_font->HasGlyphForCharacter(c); |
| +} |
| + |
| +} // namespace |
| + |
| std::vector<Font> GetFallbackFonts(const Font& font) { |
| return std::vector<Font>(); |
| } |
| +std::string GetFallbackFontNameForChar(const Font& default_font, |
| + UChar32 c, |
| + const std::string& locale) { |
| + if (FontSupportsChar(default_font, c)) |
| + return std::string(); |
| + CachedFontSet& cached_font_set = g_cached_font_set.Get(); |
| + cached_font_set.SetLocale(locale); |
| + return cached_font_set.GetFallbackFontNameForChar(c); |
| +} |
| + |
| } // namespace gfx |