Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/font_fallback.h" | 5 #include "ui/gfx/font_fallback_android.h" |
| 6 | 6 |
| 7 #include <map> | |
| 8 #include <set> | |
| 7 #include <string> | 9 #include <string> |
| 8 #include <vector> | 10 #include <vector> |
| 9 | 11 |
| 12 #include "base/lazy_instance.h" | |
| 13 #include "base/memory/ptr_util.h" | |
| 14 #include "third_party/icu/source/common/unicode/uscript.h" | |
| 15 #include "third_party/skia/include/core/SkPaint.h" | |
| 16 #include "third_party/skia/include/core/SkTypeface.h" | |
| 17 #include "third_party/skia/include/ports/SkFontMgr.h" | |
| 18 #include "ui/gfx/platform_font_linux.h" | |
| 19 | |
| 10 namespace gfx { | 20 namespace gfx { |
| 11 | 21 |
| 22 namespace { | |
| 23 | |
| 24 enum KnownGlyph { | |
| 25 UNDEFINED, | |
| 26 UNKNOWN, | |
| 27 KNOWN, | |
| 28 }; | |
| 29 | |
| 30 class CachedFont { | |
| 31 public: | |
| 32 static std::unique_ptr<CachedFont> CreateForTypeface( | |
| 33 sk_sp<SkTypeface> typeface) { | |
| 34 return base::WrapUnique<CachedFont>(new CachedFont(typeface)); | |
| 35 } | |
| 36 bool HasGlyphForCharacter(UChar32 character) { | |
| 37 // In order to increase cache hits, the cache is script based rather than | |
| 38 // character based. This also limits the cache size to the number of Unicode | |
| 39 // scripts (174). | |
|
mthiesse
2017/05/08 17:09:18
nit: The 174 number will get stale, "174 at time o
| |
| 40 UErrorCode err; | |
| 41 UScriptCode script = uscript_getScript(character, &err); | |
| 42 if (!U_SUCCESS(err) || script == UScriptCode::USCRIPT_COMMON) | |
| 43 return false; | |
| 44 auto& supported = supported_scripts_[script]; | |
| 45 if (supported != UNDEFINED) | |
| 46 return supported == KNOWN; | |
| 47 uint16_t glyph_id; | |
| 48 paint_.textToGlyphs(&character, sizeof(UChar32), &glyph_id); | |
| 49 supported = glyph_id ? KNOWN : UNKNOWN; | |
| 50 return glyph_id; | |
| 51 } | |
| 52 std::string GetFontName() { return name_; } | |
| 53 | |
| 54 private: | |
| 55 CachedFont(sk_sp<SkTypeface> skia_face) { | |
| 56 SkString sk_name; | |
| 57 skia_face->getFamilyName(&sk_name); | |
| 58 name_ = sk_name.c_str(); | |
| 59 paint_.setTypeface(std::move(skia_face)); | |
| 60 paint_.setTextEncoding(SkPaint::kUTF32_TextEncoding); | |
| 61 } | |
| 62 | |
| 63 SkPaint paint_; | |
| 64 std::map<UScriptCode, KnownGlyph> supported_scripts_; | |
| 65 std::string name_; | |
| 66 }; | |
| 67 | |
| 68 using FontCache = std::map<SkFontID, std::unique_ptr<CachedFont>>; | |
| 69 base::LazyInstance<FontCache>::Leaky g_fonts = LAZY_INSTANCE_INITIALIZER; | |
| 70 | |
| 71 class CachedFontSet { | |
| 72 public: | |
| 73 CachedFontSet() : locale_() {} | |
| 74 ~CachedFontSet() = default; | |
| 75 void SetLocale(const std::string& locale) { | |
| 76 // Store font list for one locale at a time. | |
| 77 if (locale != locale_) { | |
| 78 font_ids_.clear(); | |
| 79 unknown_chars_.clear(); | |
| 80 locale_ = locale; | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 std::string GetFallbackFontNameForChar(UChar32 c) { | |
| 85 if (unknown_chars_.find(c) != unknown_chars_.end()) | |
| 86 return ""; | |
| 87 for (SkFontID font_id : font_ids_) { | |
| 88 std::unique_ptr<CachedFont>& font = g_fonts.Get()[font_id]; | |
| 89 if (font->HasGlyphForCharacter(c)) | |
| 90 return font->GetFontName(); | |
| 91 } | |
| 92 sk_sp<SkFontMgr> font_mgr(SkFontMgr::RefDefault()); | |
| 93 const char* bcp47_locales[] = {locale_.c_str()}; | |
| 94 sk_sp<SkTypeface> tf(font_mgr->matchFamilyStyleCharacter( | |
| 95 nullptr, SkFontStyle(), locale_.empty() ? nullptr : bcp47_locales, | |
| 96 locale_.empty() ? 0 : 1, c)); | |
| 97 if (tf) { | |
| 98 SkFontID font_id = tf->uniqueID(); | |
| 99 font_ids_.push_back(font_id); | |
| 100 std::unique_ptr<CachedFont>& cached_font = g_fonts.Get()[font_id]; | |
| 101 if (!cached_font) | |
| 102 cached_font = CachedFont::CreateForTypeface(tf); | |
| 103 return cached_font->GetFontName(); | |
| 104 } | |
| 105 unknown_chars_.insert(c); | |
| 106 return std::string(); | |
| 107 } | |
| 108 | |
| 109 private: | |
| 110 std::string locale_; | |
| 111 std::vector<SkFontID> font_ids_; | |
| 112 std::set<UChar32> unknown_chars_; | |
| 113 }; | |
| 114 | |
| 115 base::LazyInstance<CachedFontSet>::Leaky g_cached_font_set = | |
| 116 LAZY_INSTANCE_INITIALIZER; | |
| 117 | |
| 118 bool FontSupportsChar(const gfx::Font& font, UChar32 c) { | |
| 119 sk_sp<SkTypeface> typeface = | |
| 120 static_cast<PlatformFontLinux*>(font.platform_font())->typeface(); | |
| 121 std::unique_ptr<CachedFont>& cached_font = | |
| 122 g_fonts.Get()[typeface->uniqueID()]; | |
| 123 if (!cached_font) | |
| 124 cached_font = CachedFont::CreateForTypeface(typeface); | |
| 125 return cached_font->HasGlyphForCharacter(c); | |
| 126 } | |
| 127 | |
| 128 } // namespace | |
| 129 | |
| 12 std::vector<Font> GetFallbackFonts(const Font& font) { | 130 std::vector<Font> GetFallbackFonts(const Font& font) { |
| 13 return std::vector<Font>(); | 131 return std::vector<Font>(); |
| 14 } | 132 } |
| 15 | 133 |
| 134 std::string GetFallbackFontNameForChar(const Font& default_font, | |
| 135 UChar32 c, | |
| 136 const std::string& locale) { | |
| 137 if (FontSupportsChar(default_font, c)) | |
| 138 return std::string(); | |
| 139 CachedFontSet& cached_font_set = g_cached_font_set.Get(); | |
| 140 cached_font_set.SetLocale(locale); | |
| 141 return cached_font_set.GetFallbackFontNameForChar(c); | |
| 142 } | |
| 143 | |
| 16 } // namespace gfx | 144 } // namespace gfx |
| OLD | NEW |