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 |