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..53dd7e4f664386cc254cc7061001071bdccc2ab7 100644 |
| --- a/ui/gfx/font_fallback_android.cc |
| +++ b/ui/gfx/font_fallback_android.cc |
| @@ -2,15 +2,159 @@ |
| // 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 <array> |
| +#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 { |
| + |
| +constexpr int kMaxLocales = 1; |
| + |
| +enum KnownGlyph { |
| + UNDEFINED, |
| + UNKNOWN, |
| + KNOWN, |
| +}; |
| + |
| +using ScriptCharMap = std::array<UChar32, UScriptCode::USCRIPT_CODE_LIMIT>; |
| +base::LazyInstance<ScriptCharMap>::Leaky g_script_char_map = |
|
mthiesse
2017/05/08 14:46:35
Doesn't look like you need this map.
Just change
acondor_
2017/05/08 16:55:29
Good catch. Done.
|
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +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, look for a character of the same |
| + // script that was requested before. If this is the first one, store |
| + // it for future lookups. |
| + UErrorCode err; |
| + UScriptCode script = uscript_getScript(character, &err); |
| + UChar32 c; |
| + if (U_SUCCESS(err)) { |
| + UChar32& representative = g_script_char_map.Get()[script]; |
| + if (!representative) |
| + representative = character; |
| + c = representative; |
| + } else { |
| + c = character; |
| + } |
| + auto& supported = supported_characters_[c]; |
| + if (supported != UNDEFINED) |
| + return supported == KNOWN; |
| + uint16_t glyph_id; |
| + paint_.textToGlyphs(&c, 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<UChar32, KnownGlyph> supported_characters_; |
| + 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[kMaxLocales]; |
|
mthiesse
2017/05/08 14:46:35
I think this code would be more readable if you go
acondor_
2017/05/08 16:55:29
The array is needed, but I got rid of the rest.
|
| + int locale_count = 0; |
| + if (!locale_.empty()) |
| + bcp47_locales[locale_count++] = locale_.c_str(); |
| + sk_sp<SkTypeface> tf(font_mgr->matchFamilyStyleCharacter( |
| + nullptr, SkFontStyle(), bcp47_locales, locale_count, 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& font, |
| + UChar32 c, |
| + const std::string& locale) { |
| + if (FontSupportsChar(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 |