1 /*
2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
31
32 #include <limits>
33 #include <memory>
34
35 #include "base/debug/alias.h"
36 #include "base/feature_list.h"
37 #include "base/memory/ptr_util.h"
38 #include "base/trace_event/process_memory_dump.h"
39 #include "base/trace_event/trace_event.h"
40 #include "build/build_config.h"
41 #include "third_party/blink/public/platform/platform.h"
42 #include "third_party/blink/renderer/platform/font_family_names.h"
43 #include "third_party/blink/renderer/platform/fonts/alternate_font_family.h"
44 #include "third_party/blink/renderer/platform/fonts/font_cache_client.h"
45 #include "third_party/blink/renderer/platform/fonts/font_cache_key.h"
46 #include "third_party/blink/renderer/platform/fonts/font_data_cache.h"
47 #include "third_party/blink/renderer/platform/fonts/font_description.h"
48 #include "third_party/blink/renderer/platform/fonts/font_fallback_map.h"
49 #include "third_party/blink/renderer/platform/fonts/font_global_context.h"
50 #include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
51 #include "third_party/blink/renderer/platform/fonts/font_smoothing_mode.h"
52 #include "third_party/blink/renderer/platform/fonts/font_unique_name_lookup.h"
53 #include "third_party/blink/renderer/platform/fonts/shaping/shape_cache.h"
54 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
55 #include "third_party/blink/renderer/platform/fonts/text_rendering_mode.h"
56 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
57 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h"
58 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
59 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
60 #include "third_party/blink/renderer/platform/text/layout_locale.h"
61 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
62 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
63 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
64 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
65 #include "third_party/blink/renderer/platform/wtf/vector.h"
66 #include "ui/gfx/font_list.h"
67
68 #if defined(OS_WIN)
69 #include "third_party/skia/include/ports/SkTypeface_win.h"
70 #endif
71
72 namespace blink {
73
74 namespace {
75 const base::Feature kFontCacheNoSizeInKey{"FontCacheNoSizeInKey",
76 base::FEATURE_DISABLED_BY_DEFAULT};
77 }
78
79 const char kColorEmojiLocale[] = "und-Zsye";
80
81 SkFontMgr* FontCache::static_font_manager_ = nullptr;
82
83 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
84 float FontCache::device_scale_factor_ = 1.0;
85 #endif
86
87 #if defined(OS_WIN)
88 bool FontCache::antialiased_text_enabled_ = false;
89 bool FontCache::lcd_text_enabled_ = false;
90 bool FontCache::use_skia_font_fallback_ = false;
91 #endif // defined(OS_WIN)
92
GetFontCache(CreateIfNeeded create)93 FontCache* FontCache::GetFontCache(CreateIfNeeded create) {
94 return FontGlobalContext::GetFontCache(create);
95 }
96
FontCache()97 FontCache::FontCache()
98 : no_size_in_key_(base::FeatureList::IsEnabled(kFontCacheNoSizeInKey)),
99 purge_prevent_count_(0),
100 font_manager_(sk_ref_sp(static_font_manager_)),
101 font_size_limit_(std::nextafter(
102 (static_cast<float>(std::numeric_limits<unsigned>::max()) - 2.f) /
103 static_cast<float>(blink::FontCacheKey::PrecisionMultiplier()),
104 0.f)) {
105 #if defined(OS_WIN)
106 if (!font_manager_) {
107 // This code path is only for unit tests. This SkFontMgr does not work in
108 // sandboxed environments, but injecting this initialization code to all
109 // unit tests isn't easy.
110 font_manager_ = SkFontMgr_New_DirectWrite();
111 // Set |is_test_font_mgr_| to capture if this is not happening in the
112 // production code. crbug.com/561873
113 is_test_font_mgr_ = true;
114 }
115 DCHECK(font_manager_.get());
116 #endif
117 }
118
119 #if !defined(OS_MAC)
SystemFontPlatformData(const FontDescription & font_description)120 FontPlatformData* FontCache::SystemFontPlatformData(
121 const FontDescription& font_description) {
122 const AtomicString& family = FontCache::SystemFontFamily();
123 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA) || defined(OS_BSD)
124 if (family.IsEmpty() || family == font_family_names::kSystemUi)
125 return nullptr;
126 #else
127 DCHECK(!family.IsEmpty() && family != font_family_names::kSystemUi);
128 #endif
129 return GetFontPlatformData(font_description, FontFaceCreationParams(family),
130 AlternateFontName::kNoAlternate);
131 }
132 #endif
133
GetFontPlatformData(const FontDescription & font_description,const FontFaceCreationParams & creation_params,AlternateFontName alternate_font_name)134 FontPlatformData* FontCache::GetFontPlatformData(
135 const FontDescription& font_description,
136 const FontFaceCreationParams& creation_params,
137 AlternateFontName alternate_font_name) {
138 TRACE_EVENT0("fonts", "FontCache::GetFontPlatformData");
139
140 if (!platform_init_) {
141 platform_init_ = true;
142 PlatformInit();
143 }
144
145 #if !defined(OS_MAC)
146 if (creation_params.CreationType() == kCreateFontByFamily &&
147 creation_params.Family() == font_family_names::kSystemUi) {
148 return SystemFontPlatformData(font_description);
149 }
150 #endif
151
152 float size = font_description.EffectiveFontSize();
153 size = std::min(size, font_size_limit_);
154
155 unsigned rounded_size = size * FontCacheKey::PrecisionMultiplier();
156
157 // Assert that the computed hash map key rounded_size value does not hit
158 // the empty (max()) or deleted (max()-1) sentinel values of the hash map,
159 // compare UnsignedWithZeroKeyHashTraits() in hash_traits.h.
160 DCHECK_LT(rounded_size, std::numeric_limits<unsigned>::max() - 1);
161 // Assert that rounded_size was not reset to 0 due to an integer overflow,
162 // i.e. if size was non-zero, rounded_size can't be zero, but if size was 0,
163 // it may be 0.
164 DCHECK_EQ(!!size, !!rounded_size);
165
166 bool is_unique_match =
167 alternate_font_name == AlternateFontName::kLocalUniqueFace;
168 FontCacheKey key =
169 font_description.CacheKey(creation_params, is_unique_match);
170 DCHECK(!key.IsHashTableDeletedValue());
171
172 if (no_size_in_key_) {
173 // Clear font size from they key. Size is not required in the primary key
174 // because per-size FontPlatformData are held in a nested map.
175 key.ClearFontSize();
176 }
177
178 // Remove the font size from the cache key, and handle the font size
179 // separately in the inner HashMap. So that different size of FontPlatformData
180 // can share underlying SkTypeface.
181 FontPlatformData* result;
182 bool found_result;
183
184 {
185 // addResult's scope must end before we recurse for alternate family names
186 // below, to avoid triggering its dtor hash-changed asserts.
187 SizedFontPlatformDataSet* sized_fonts =
188 &font_platform_data_cache_.insert(key, SizedFontPlatformDataSet())
189 .stored_value->value;
190 bool was_empty = sized_fonts->IsEmpty();
191
192 // Take a different size instance of the same font before adding an entry to
193 // |sizedFont|.
194 FontPlatformData* another_size =
195 was_empty ? nullptr : sized_fonts->begin()->value.get();
196 auto add_result = sized_fonts->insert(rounded_size, nullptr);
197 std::unique_ptr<FontPlatformData>* found = &add_result.stored_value->value;
198 if (add_result.is_new_entry) {
199 if (was_empty) {
200 *found = CreateFontPlatformData(font_description, creation_params, size,
201 alternate_font_name);
202 } else if (another_size) {
203 *found = ScaleFontPlatformData(*another_size, font_description,
204 creation_params, size);
205 }
206 }
207
208 result = found->get();
209 found_result = result || !add_result.is_new_entry;
210 }
211
212 if (!found_result &&
213 alternate_font_name == AlternateFontName::kAllowAlternate &&
214 creation_params.CreationType() == kCreateFontByFamily) {
215 // We were unable to find a font. We have a small set of fonts that we alias
216 // to other names, e.g., Arial/Helvetica, Courier/Courier New, etc. Try
217 // looking up the font under the aliased name.
218 const AtomicString& alternate_name =
219 AlternateFamilyName(creation_params.Family());
220 if (!alternate_name.IsEmpty()) {
221 FontFaceCreationParams create_by_alternate_family(alternate_name);
222 result = GetFontPlatformData(font_description, create_by_alternate_family,
223 AlternateFontName::kNoAlternate);
224 }
225 if (result) {
226 // Cache the result under the old name.
227 auto* adding =
228 &font_platform_data_cache_.insert(key, SizedFontPlatformDataSet())
229 .stored_value->value;
230 adding->Set(rounded_size, std::make_unique<FontPlatformData>(*result));
231 }
232 }
233
234 return result;
235 }
236
ScaleFontPlatformData(const FontPlatformData & font_platform_data,const FontDescription & font_description,const FontFaceCreationParams & creation_params,float font_size)237 std::unique_ptr<FontPlatformData> FontCache::ScaleFontPlatformData(
238 const FontPlatformData& font_platform_data,
239 const FontDescription& font_description,
240 const FontFaceCreationParams& creation_params,
241 float font_size) {
242 TRACE_EVENT0("fonts,ui", "FontCache::ScaleFontPlatformData");
243
244 #if defined(OS_MAC)
245 return CreateFontPlatformData(font_description, creation_params, font_size);
246 #else
247 return std::make_unique<FontPlatformData>(font_platform_data, font_size);
248 #endif
249 }
250
GetShapeCache(const FallbackListCompositeKey & key)251 ShapeCache* FontCache::GetShapeCache(const FallbackListCompositeKey& key) {
252 FallbackListShaperCache::iterator it = fallback_list_shaper_cache_.find(key);
253 ShapeCache* result = nullptr;
254 if (it == fallback_list_shaper_cache_.end()) {
255 result = new ShapeCache();
256 fallback_list_shaper_cache_.Set(key, base::WrapUnique(result));
257 } else {
258 result = it->value.get();
259 }
260
261 DCHECK(result);
262 return result;
263 }
264
SetFontManager(sk_sp<SkFontMgr> font_manager)265 void FontCache::SetFontManager(sk_sp<SkFontMgr> font_manager) {
266 DCHECK(!static_font_manager_);
267 static_font_manager_ = font_manager.release();
268 }
269
AcceptLanguagesChanged(const String & accept_languages)270 void FontCache::AcceptLanguagesChanged(const String& accept_languages) {
271 LayoutLocale::AcceptLanguagesChanged(accept_languages);
272 GetFontCache()->InvalidateShapeCache();
273 }
274
GetFontData(const FontDescription & font_description,const AtomicString & family,AlternateFontName altername_font_name,ShouldRetain should_retain)275 scoped_refptr<SimpleFontData> FontCache::GetFontData(
276 const FontDescription& font_description,
277 const AtomicString& family,
278 AlternateFontName altername_font_name,
279 ShouldRetain should_retain) {
280 if (FontPlatformData* platform_data = GetFontPlatformData(
281 font_description,
282 FontFaceCreationParams(
283 AdjustFamilyNameToAvoidUnsupportedFonts(family)),
284 altername_font_name)) {
285 return FontDataFromFontPlatformData(
286 platform_data, should_retain, font_description.SubpixelAscentDescent());
287 }
288
289 return nullptr;
290 }
291
FontDataFromFontPlatformData(const FontPlatformData * platform_data,ShouldRetain should_retain,bool subpixel_ascent_descent)292 scoped_refptr<SimpleFontData> FontCache::FontDataFromFontPlatformData(
293 const FontPlatformData* platform_data,
294 ShouldRetain should_retain,
295 bool subpixel_ascent_descent) {
296 #if DCHECK_IS_ON()
297 if (should_retain == kDoNotRetain)
298 DCHECK(purge_prevent_count_);
299 #endif
300
301 return font_data_cache_.Get(platform_data, should_retain,
302 subpixel_ascent_descent);
303 }
304
IsPlatformFamilyMatchAvailable(const FontDescription & font_description,const AtomicString & family)305 bool FontCache::IsPlatformFamilyMatchAvailable(
306 const FontDescription& font_description,
307 const AtomicString& family) {
308 return GetFontPlatformData(
309 font_description,
310 FontFaceCreationParams(AdjustFamilyNameToAvoidUnsupportedFonts(family)),
311 AlternateFontName::kNoAlternate);
312 }
313
IsPlatformFontUniqueNameMatchAvailable(const FontDescription & font_description,const AtomicString & unique_font_name)314 bool FontCache::IsPlatformFontUniqueNameMatchAvailable(
315 const FontDescription& font_description,
316 const AtomicString& unique_font_name) {
317 return GetFontPlatformData(font_description,
318 FontFaceCreationParams(unique_font_name),
319 AlternateFontName::kLocalUniqueFace);
320 }
321
FirstAvailableOrFirst(const String & families)322 String FontCache::FirstAvailableOrFirst(const String& families) {
323 // The conversions involve at least two string copies, and more if non-ASCII.
324 // For now we prefer shared code over the cost because a) inputs are
325 // only from grd/xtb and all ASCII, and b) at most only a few times per
326 // setting change/script.
327 return String::FromUTF8(
328 gfx::FontList::FirstAvailableOrFirst(families.Utf8().c_str()));
329 }
330
GetNonRetainedLastResortFallbackFont(const FontDescription & font_description)331 SimpleFontData* FontCache::GetNonRetainedLastResortFallbackFont(
332 const FontDescription& font_description) {
333 auto font = GetLastResortFallbackFont(font_description, kDoNotRetain);
334 if (font)
335 font->AddRef();
336 return font.get();
337 }
338
FallbackFontForCharacter(const FontDescription & description,UChar32 lookup_char,const SimpleFontData * font_data_to_substitute,FontFallbackPriority fallback_priority)339 scoped_refptr<SimpleFontData> FontCache::FallbackFontForCharacter(
340 const FontDescription& description,
341 UChar32 lookup_char,
342 const SimpleFontData* font_data_to_substitute,
343 FontFallbackPriority fallback_priority) {
344 TRACE_EVENT0("fonts", "FontCache::FallbackFontForCharacter");
345
346 // In addition to PUA, do not perform fallback for non-characters either. Some
347 // of these are sentinel characters to detect encodings and do appear on
348 // websites. More details on
349 // http://www.unicode.org/faq/private_use.html#nonchar1 - See also
350 // crbug.com/862352 where performing fallback for U+FFFE causes a memory
351 // regression.
352 if (Character::IsPrivateUse(lookup_char) ||
353 Character::IsNonCharacter(lookup_char))
354 return nullptr;
355 return PlatformFallbackFontForCharacter(
356 description, lookup_char, font_data_to_substitute, fallback_priority);
357 }
358
ReleaseFontData(const SimpleFontData * font_data)359 void FontCache::ReleaseFontData(const SimpleFontData* font_data) {
360 font_data_cache_.Release(font_data);
361 }
362
PurgePlatformFontDataCache()363 void FontCache::PurgePlatformFontDataCache() {
364 TRACE_EVENT0("fonts,ui", "FontCache::PurgePlatformFontDataCache");
365 Vector<FontCacheKey> keys_to_remove;
366 keys_to_remove.ReserveInitialCapacity(font_platform_data_cache_.size());
367 for (auto& sized_fonts : font_platform_data_cache_) {
368 Vector<unsigned> sizes_to_remove;
369 sizes_to_remove.ReserveInitialCapacity(sized_fonts.value.size());
370 for (const auto& platform_data : sized_fonts.value) {
371 if (platform_data.value &&
372 !font_data_cache_.Contains(platform_data.value.get()))
373 sizes_to_remove.push_back(platform_data.key);
374 }
375 sized_fonts.value.RemoveAll(sizes_to_remove);
376 if (sized_fonts.value.IsEmpty())
377 keys_to_remove.push_back(sized_fonts.key);
378 }
379 font_platform_data_cache_.RemoveAll(keys_to_remove);
380 }
381
PurgeFallbackListShaperCache()382 void FontCache::PurgeFallbackListShaperCache() {
383 TRACE_EVENT0("fonts,ui", "FontCache::PurgeFallbackListShaperCache");
384 unsigned items = 0;
385 FallbackListShaperCache::iterator iter;
386 for (iter = fallback_list_shaper_cache_.begin();
387 iter != fallback_list_shaper_cache_.end(); ++iter) {
388 items += iter->value->size();
389 }
390 fallback_list_shaper_cache_.clear();
391 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, shape_cache_histogram,
392 ("Blink.Fonts.ShapeCache", 1, 1000000, 50));
393 shape_cache_histogram.Count(items);
394 }
395
InvalidateShapeCache()396 void FontCache::InvalidateShapeCache() {
397 PurgeFallbackListShaperCache();
398 }
399
Purge(PurgeSeverity purge_severity)400 void FontCache::Purge(PurgeSeverity purge_severity) {
401 // Ideally we should never be forcing the purge while the
402 // FontCachePurgePreventer is in scope, but we call purge() at any timing
403 // via MemoryPressureListenerRegistry.
404 if (purge_prevent_count_)
405 return;
406
407 if (!font_data_cache_.Purge(purge_severity))
408 return;
409
410 PurgePlatformFontDataCache();
411 PurgeFallbackListShaperCache();
412 }
413
AddClient(FontCacheClient * client)414 void FontCache::AddClient(FontCacheClient* client) {
415 CHECK(client);
416 if (!font_cache_clients_) {
417 font_cache_clients_ =
418 MakeGarbageCollected<HeapHashSet<WeakMember<FontCacheClient>>>();
419 font_cache_clients_.RegisterAsStaticReference();
420 }
421 DCHECK(!font_cache_clients_->Contains(client));
422 font_cache_clients_->insert(client);
423 }
424
Generation()425 uint16_t FontCache::Generation() {
426 return generation_;
427 }
428
Invalidate()429 void FontCache::Invalidate() {
430 TRACE_EVENT0("fonts,ui", "FontCache::Invalidate");
431 font_platform_data_cache_.clear();
432 generation_++;
433
434 if (font_cache_clients_) {
435 for (const auto& client : *font_cache_clients_)
436 client->FontCacheInvalidated();
437 }
438
439 Purge(kForcePurge);
440 }
441
CrashWithFontInfo(const FontDescription * font_description)442 void FontCache::CrashWithFontInfo(const FontDescription* font_description) {
443 FontCache* font_cache = nullptr;
444 SkFontMgr* font_mgr = nullptr;
445 int num_families = std::numeric_limits<int>::min();
446 bool is_test_font_mgr = false;
447 if (FontGlobalContext::Get(kDoNotCreate)) {
448 font_cache = FontCache::GetFontCache();
449 if (font_cache) {
450 #if defined(OS_WIN)
451 is_test_font_mgr = font_cache->is_test_font_mgr_;
452 #endif
453 font_mgr = font_cache->font_manager_.get();
454 if (font_mgr)
455 num_families = font_mgr->countFamilies();
456 }
457 }
458
459 // In production, these 3 font managers must match.
460 // They don't match in unit tests or in single process mode.
461 SkFontMgr* static_font_mgr = static_font_manager_;
462 SkFontMgr* skia_default_font_mgr = SkFontMgr::RefDefault().get();
463 base::debug::Alias(&font_mgr);
464 base::debug::Alias(&static_font_mgr);
465 base::debug::Alias(&skia_default_font_mgr);
466
467 FontDescription font_description_copy = *font_description;
468 base::debug::Alias(&font_description_copy);
469 base::debug::Alias(&is_test_font_mgr);
470 base::debug::Alias(&num_families);
471
472 CHECK(false);
473 }
474
DumpFontPlatformDataCache(base::trace_event::ProcessMemoryDump * memory_dump)475 void FontCache::DumpFontPlatformDataCache(
476 base::trace_event::ProcessMemoryDump* memory_dump) {
477 DCHECK(IsMainThread());
478 base::trace_event::MemoryAllocatorDump* dump =
479 memory_dump->CreateAllocatorDump("font_caches/font_platform_data_cache");
480 size_t font_platform_data_objects_size =
481 font_platform_data_cache_.size() * sizeof(FontPlatformData);
482 dump->AddScalar("size", "bytes", font_platform_data_objects_size);
483 memory_dump->AddSuballocation(dump->guid(),
484 WTF::Partitions::kAllocatedObjectPoolName);
485 }
486
DumpShapeResultCache(base::trace_event::ProcessMemoryDump * memory_dump)487 void FontCache::DumpShapeResultCache(
488 base::trace_event::ProcessMemoryDump* memory_dump) {
489 DCHECK(IsMainThread());
490 base::trace_event::MemoryAllocatorDump* dump =
491 memory_dump->CreateAllocatorDump("font_caches/shape_caches");
492 size_t shape_result_cache_size = 0;
493 FallbackListShaperCache::iterator iter;
494 for (iter = fallback_list_shaper_cache_.begin();
495 iter != fallback_list_shaper_cache_.end(); ++iter) {
496 shape_result_cache_size += iter->value->ByteSize();
497 }
498 dump->AddScalar("size", "bytes", shape_result_cache_size);
499 memory_dump->AddSuballocation(dump->guid(),
500 WTF::Partitions::kAllocatedObjectPoolName);
501 }
502
CreateTypefaceFromUniqueName(const FontFaceCreationParams & creation_params)503 sk_sp<SkTypeface> FontCache::CreateTypefaceFromUniqueName(
504 const FontFaceCreationParams& creation_params) {
505 FontUniqueNameLookup* unique_name_lookup =
506 FontGlobalContext::Get()->GetFontUniqueNameLookup();
507 DCHECK(unique_name_lookup);
508 sk_sp<SkTypeface> uniquely_identified_font =
509 unique_name_lookup->MatchUniqueName(creation_params.Family());
510 if (uniquely_identified_font) {
511 return uniquely_identified_font;
512 }
513 return nullptr;
514 }
515
516 // static
GetBcp47LocaleForRequest(const FontDescription & font_description,FontFallbackPriority fallback_priority)517 FontCache::Bcp47Vector FontCache::GetBcp47LocaleForRequest(
518 const FontDescription& font_description,
519 FontFallbackPriority fallback_priority) {
520 Bcp47Vector result;
521
522 // Fill in the list of locales in the reverse priority order.
523 // Skia expects the highest array index to be the first priority.
524 const LayoutLocale* content_locale = font_description.Locale();
525 if (const LayoutLocale* han_locale =
526 LayoutLocale::LocaleForHan(content_locale)) {
527 result.push_back(han_locale->LocaleForHanForSkFontMgr());
528 }
529 result.push_back(LayoutLocale::GetDefault().LocaleForSkFontMgr());
530 if (content_locale)
531 result.push_back(content_locale->LocaleForSkFontMgr());
532
533 if (fallback_priority == FontFallbackPriority::kEmojiEmoji)
534 result.push_back(kColorEmojiLocale);
535 return result;
536 }
537
GetFontFallbackMap()538 FontFallbackMap& FontCache::GetFontFallbackMap() {
539 if (!font_fallback_map_) {
540 font_fallback_map_ = MakeGarbageCollected<FontFallbackMap>(nullptr);
541 AddClient(font_fallback_map_);
542 }
543 return *font_fallback_map_;
544 }
545
546 } // namespace blink
547