• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "font_collection.h"
18 
19 #include <algorithm>
20 #include <list>
21 #include <memory>
22 #include <mutex>
23 #include <set>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27 #ifdef OHOS_PLATFORM
28 #include "skia/src/ports/SkFontMgr_ohos.h"
29 #endif
30 #include "flutter/fml/logging.h"
31 #include "flutter/fml/trace_event.h"
32 #include "font_skia.h"
33 #include "txt/text_style.h"
34 
35 namespace txt {
36 
37 namespace {
38 
39 const std::shared_ptr<minikin::FontFamily> g_null_family;
40 
41 }  // anonymous namespace
42 
FamilyKey(const std::vector<std::string> & families,const std::string & loc)43 FontCollection::FamilyKey::FamilyKey(const std::vector<std::string>& families,
44                                      const std::string& loc) {
45   locale = loc;
46 
47   std::stringstream stream;
48   for_each(families.begin(), families.end(),
49            [&stream](const std::string& str) { stream << str << ','; });
50   font_families = stream.str();
51 }
52 
operator ==(const FontCollection::FamilyKey & other) const53 bool FontCollection::FamilyKey::operator==(
54     const FontCollection::FamilyKey& other) const {
55   return font_families == other.font_families && locale == other.locale;
56 }
57 
operator ()(const FontCollection::FamilyKey & key) const58 size_t FontCollection::FamilyKey::Hasher::operator()(
59     const FontCollection::FamilyKey& key) const {
60   return std::hash<std::string>()(key.font_families) ^
61          std::hash<std::string>()(key.locale);
62 }
63 
64 class TxtFallbackFontProvider
65     : public minikin::FontCollection::FallbackFontProvider {
66  public:
TxtFallbackFontProvider(std::shared_ptr<FontCollection> font_collection)67   TxtFallbackFontProvider(std::shared_ptr<FontCollection> font_collection)
68       : font_collection_(font_collection) {}
69 
matchFallbackFont(uint32_t ch,std::string locale)70   virtual const std::shared_ptr<minikin::FontFamily>& matchFallbackFont(
71       uint32_t ch,
72       std::string locale) {
73     std::shared_ptr<FontCollection> fc = font_collection_.lock();
74     if (fc) {
75       return fc->MatchFallbackFont(ch, locale);
76     } else {
77       return g_null_family;
78     }
79   }
80 
matchFallbackFontFromHwFont(uint32_t ch,std::string locale)81   virtual const std::shared_ptr<minikin::FontFamily>& matchFallbackFontFromHwFont(
82       uint32_t ch,
83       std::string locale) {
84 #if defined(OHOS_PLATFORM) && !defined(OHOS_STANDARD_SYSTEM)
85     std::shared_ptr<FontCollection> fc = font_collection_.lock();
86     if (fc) {
87       return fc->MatchFallbackFontFromHwFont(ch, locale);
88     } else {
89       return g_null_family;
90     }
91 #endif
92     return g_null_family;
93   }
94 
95  private:
96   std::weak_ptr<FontCollection> font_collection_;
97 };
98 
FontCollection()99 FontCollection::FontCollection() : enable_font_fallback_(true) {}
100 
101 FontCollection::~FontCollection() = default;
102 
GetFontManagersCount() const103 size_t FontCollection::GetFontManagersCount() const {
104   return GetFontManagerOrder().size();
105 }
106 
SetupDefaultFontManager()107 void FontCollection::SetupDefaultFontManager() {
108   std::lock_guard<std::mutex> lock(fontManagerMutex_);
109   default_font_manager_ = GetDefaultFontManager();
110 }
111 
SetDefaultFontManager(sk_sp<SkFontMgr> font_manager)112 void FontCollection::SetDefaultFontManager(sk_sp<SkFontMgr> font_manager) {
113   std::lock_guard<std::mutex> lock(fontManagerMutex_);
114   default_font_manager_ = font_manager;
115 }
116 
SetAssetFontManager(sk_sp<SkFontMgr> font_manager)117 void FontCollection::SetAssetFontManager(sk_sp<SkFontMgr> font_manager) {
118   asset_font_manager_ = font_manager;
119 }
120 
SetDynamicFontManager(sk_sp<SkFontMgr> font_manager)121 void FontCollection::SetDynamicFontManager(sk_sp<SkFontMgr> font_manager) {
122   dynamic_font_manager_ = font_manager;
123 }
124 
SetTestFontManager(sk_sp<SkFontMgr> font_manager)125 void FontCollection::SetTestFontManager(sk_sp<SkFontMgr> font_manager) {
126   test_font_manager_ = font_manager;
127 }
128 
GetDefaultFontManagerSafely() const129 sk_sp<SkFontMgr> FontCollection::GetDefaultFontManagerSafely() const {
130   std::lock_guard<std::mutex> lock(fontManagerMutex_);
131   return default_font_manager_;
132 }
133 
134 // Return the available font managers in the order they should be queried.
GetFontManagerOrder() const135 std::vector<sk_sp<SkFontMgr>> FontCollection::GetFontManagerOrder() const {
136   std::vector<sk_sp<SkFontMgr>> order;
137   if (dynamic_font_manager_)
138     order.push_back(dynamic_font_manager_);
139   if (asset_font_manager_)
140     order.push_back(asset_font_manager_);
141   if (test_font_manager_)
142     order.push_back(test_font_manager_);
143   auto defaultFontManager = GetDefaultFontManagerSafely();
144   if (defaultFontManager)
145     order.push_back(defaultFontManager);
146   return order;
147 }
148 
DisableFontFallback()149 void FontCollection::DisableFontFallback() {
150   enable_font_fallback_ = false;
151 }
152 
153 std::shared_ptr<minikin::FontCollection>
GetMinikinFontCollectionForFamilies(const std::vector<std::string> & font_families,const std::string & locale)154 FontCollection::GetMinikinFontCollectionForFamilies(
155     const std::vector<std::string>& font_families,
156     const std::string& locale) {
157 #if defined(OHOS_PLATFORM) && !defined(OHOS_STANDARD_SYSTEM)
158   return GetMinikinFontCollectionForFamiliesWithVariation(font_families, locale);
159 #endif
160   // Look inside the font collections cache first.
161   FamilyKey family_key(font_families, locale);
162   {
163     std::lock_guard<std::mutex> lock(mutex_);
164     auto cached = font_collections_cache_.find(family_key);
165     if (cached != font_collections_cache_.end()) {
166       return cached->second;
167     }
168   }
169 
170   std::vector<std::shared_ptr<minikin::FontFamily>> minikin_families;
171 
172   // Search for all user provided font families.
173   for (size_t fallback_index = 0; fallback_index < font_families.size();
174        fallback_index++) {
175     std::shared_ptr<minikin::FontFamily> minikin_family =
176         FindFontFamilyInManagers(font_families[fallback_index]);
177     if (minikin_family != nullptr) {
178       minikin_families.push_back(minikin_family);
179     }
180   }
181   // Search for default font family if no user font families were found.
182   if (minikin_families.empty()) {
183     const auto default_font_family = GetDefaultFontFamily();
184     std::shared_ptr<minikin::FontFamily> minikin_family =
185         FindFontFamilyInManagers(default_font_family);
186     if (minikin_family != nullptr) {
187       minikin_families.push_back(minikin_family);
188     }
189   }
190   // Default font family also not found. We fail to get a FontCollection.
191   if (minikin_families.empty()) {
192     std::shared_ptr<minikin::FontCollection> tmp_font_collection;
193     std::lock_guard<std::mutex> lock(mutex_);
194     std::swap(font_collections_cache_[family_key], tmp_font_collection);
195     return nullptr;
196   }
197   if (enable_font_fallback_) {
198     std::lock_guard<std::mutex> lock(mutex_);
199     for (std::string fallback_family : fallback_fonts_for_locale_[locale]) {
200       auto it = fallback_fonts_.find(fallback_family);
201       if (it != fallback_fonts_.end()) {
202         minikin_families.push_back(it->second);
203       }
204     }
205   }
206   // Create the minikin font collection.
207   auto font_collection =
208       std::make_shared<minikin::FontCollection>(std::move(minikin_families));
209   if (enable_font_fallback_) {
210     font_collection->set_fallback_font_provider(
211         std::make_unique<TxtFallbackFontProvider>(shared_from_this()));
212   }
213 
214   {
215     std::shared_ptr<minikin::FontCollection> tmp_font_collection =
216         font_collection;
217     std::lock_guard<std::mutex> lock(mutex_);
218     // Cache the font collection for future queries.
219     std::swap(font_collections_cache_[family_key], tmp_font_collection);
220   }
221 
222   return font_collection;
223 }
224 
FindFontFamilyInManagers(const std::string & family_name)225 std::shared_ptr<minikin::FontFamily> FontCollection::FindFontFamilyInManagers(
226     const std::string& family_name) {
227   TRACE_EVENT0("flutter", "FontCollection::FindFontFamilyInManagers");
228   // Search for the font family in each font manager.
229   for (sk_sp<SkFontMgr>& manager : GetFontManagerOrder()) {
230     std::shared_ptr<minikin::FontFamily> minikin_family =
231         CreateMinikinFontFamily(manager, family_name);
232     if (!minikin_family)
233       continue;
234     return minikin_family;
235   }
236   return nullptr;
237 }
238 
CreateMinikinFontFamily(const sk_sp<SkFontMgr> & manager,const std::string & family_name)239 std::shared_ptr<minikin::FontFamily> FontCollection::CreateMinikinFontFamily(
240     const sk_sp<SkFontMgr>& manager,
241     const std::string& family_name) {
242   TRACE_EVENT1("flutter", "FontCollection::CreateMinikinFontFamily",
243                "family_name", family_name.c_str());
244   sk_sp<SkFontStyleSet> font_style_set(
245       manager->matchFamily(family_name.c_str()));
246   if (font_style_set == nullptr || font_style_set->count() == 0) {
247     return nullptr;
248   }
249 
250   std::vector<sk_sp<SkTypeface>> skia_typefaces;
251   for (int i = 0; i < font_style_set->count(); ++i) {
252     TRACE_EVENT0("flutter", "CreateSkiaTypeface");
253     sk_sp<SkTypeface> skia_typeface(
254         sk_sp<SkTypeface>(font_style_set->createTypeface(i)));
255     if (skia_typeface != nullptr) {
256       skia_typefaces.emplace_back(std::move(skia_typeface));
257     }
258   }
259 
260   std::sort(skia_typefaces.begin(), skia_typefaces.end(),
261             [](const sk_sp<SkTypeface>& a, const sk_sp<SkTypeface>& b) {
262               SkFontStyle a_style = a->fontStyle();
263               SkFontStyle b_style = b->fontStyle();
264               return (a_style.weight() != b_style.weight())
265                          ? a_style.weight() < b_style.weight()
266                          : a_style.slant() < b_style.slant();
267             });
268 
269   std::vector<minikin::Font> minikin_fonts;
270   for (const sk_sp<SkTypeface>& skia_typeface : skia_typefaces) {
271     // Create the minikin font from the skia typeface.
272     // Divide by 100 because the weights are given as "100", "200", etc.
273     minikin_fonts.emplace_back(
274         std::make_shared<FontSkia>(skia_typeface),
275         minikin::FontStyle{skia_typeface->fontStyle().weight() / 100,
276                            skia_typeface->isItalic()});
277   }
278 
279   return std::make_shared<minikin::FontFamily>(std::move(minikin_fonts));
280 }
281 
MatchFallbackFont(uint32_t ch,std::string locale)282 const std::shared_ptr<minikin::FontFamily>& FontCollection::MatchFallbackFont(
283     uint32_t ch,
284     std::string locale) {
285 #if defined(OHOS_PLATFORM) && !defined(OHOS_STANDARD_SYSTEM)
286   return MatchFallbackFontWithVariation(ch, locale);
287 #endif
288   // Check if the ch's matched font has been cached. We cache the results of
289   // this method as repeated matchFamilyStyleCharacter calls can become
290   // extremely laggy when typing a large number of complex emojis.
291   {
292     std::lock_guard<std::mutex> lock(mutex_);
293     auto lookup = fallback_match_cache_.find(ch);
294     if (lookup != fallback_match_cache_.end()) {
295       return *lookup->second;
296     }
297   }
298   const std::shared_ptr<minikin::FontFamily>* match =
299       &DoMatchFallbackFont(ch, locale);
300   {
301     std::lock_guard<std::mutex> lock(mutex_);
302     fallback_match_cache_.insert(std::make_pair(ch, match));
303   }
304   return *match;
305 }
306 
DoMatchFallbackFont(uint32_t ch,std::string locale)307 const std::shared_ptr<minikin::FontFamily>& FontCollection::DoMatchFallbackFont(
308     uint32_t ch,
309     std::string locale) {
310   for (const sk_sp<SkFontMgr>& manager : GetFontManagerOrder()) {
311     std::vector<const char*> bcp47;
312     if (!locale.empty())
313       bcp47.push_back(locale.c_str());
314     sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
315         0, SkFontStyle(), bcp47.data(), bcp47.size(), ch));
316     if (!typeface)
317       continue;
318 
319     SkString sk_family_name;
320     typeface->getFamilyName(&sk_family_name);
321     std::string family_name(sk_family_name.c_str());
322 
323     {
324       std::lock_guard<std::mutex> lock(mutex_);
325       fallback_fonts_for_locale_[locale].insert(family_name);
326     }
327 
328     return GetFallbackFontFamily(manager, family_name);
329   }
330   return g_null_family;
331 }
332 
333 const std::shared_ptr<minikin::FontFamily>&
GetFallbackFontFamily(const sk_sp<SkFontMgr> & manager,const std::string & family_name)334 FontCollection::GetFallbackFontFamily(const sk_sp<SkFontMgr>& manager,
335                                       const std::string& family_name) {
336   TRACE_EVENT0("flutter", "FontCollection::GetFallbackFontFamily");
337   {
338     std::lock_guard<std::mutex> lock(mutex_);
339     auto fallback_it = fallback_fonts_.find(family_name);
340     if (fallback_it != fallback_fonts_.end()) {
341       return fallback_it->second;
342     }
343   }
344 
345   std::shared_ptr<minikin::FontFamily> minikin_family =
346       CreateMinikinFontFamily(manager, family_name);
347   if (!minikin_family)
348     return g_null_family;
349 
350   {
351     decltype(font_collections_cache_) font_collections_cache;
352     std::lock_guard<std::mutex> lock(mutex_);
353     auto insert_it =
354         fallback_fonts_.insert(std::make_pair(family_name, minikin_family));
355 
356     // Clear the cache to force creation of new font collections that will
357     // include this fallback font.
358     std::swap(font_collections_cache_, font_collections_cache);
359 
360     return insert_it.first->second;
361   }
362 }
363 
ClearFontFamilyCache()364 void FontCollection::ClearFontFamilyCache() {
365   decltype(font_collections_cache_) font_collections_cache;
366   std::lock_guard<std::mutex> lock(mutex_);
367   std::swap(font_collections_cache_, font_collections_cache);
368 }
369 
VaryFontCollectionWithFontWeightScale(float font_weight_scale)370 void FontCollection::VaryFontCollectionWithFontWeightScale(float font_weight_scale) {
371   if (font_weight_scale > 0.0f && font_weight_scale != font_weight_scale_) {
372     decltype(fallback_fonts_) fallback_fonts;
373     std::lock_guard<std::mutex> lock(mutex_);
374     font_weight_scale_ = font_weight_scale;
375     varied_fonts_.clear();
376     fallback_fonts = std::move(fallback_fonts_);
377     fallback_match_cache_.clear();
378     fallback_fonts_for_locale_.clear();
379   }
380 }
381 
LoadSystemFont()382 void FontCollection::LoadSystemFont() {
383 #if defined(OHOS_PLATFORM) && !defined(OHOS_STANDARD_SYSTEM)
384   {
385     decltype(fallback_fonts_) fallback_fonts;
386     std::lock_guard<std::mutex> lock(mutex_);
387     varied_fonts_.clear();
388     fallback_fonts = std::move(fallback_fonts_);
389     fallback_match_cache_.clear();
390     fallback_fonts_for_locale_.clear();
391   }
392 
393   SetupDefaultFontManager();
394 
395 #endif
396 }
397 
SetIsZawgyiMyanmar(bool is_zawgyi_myanmar)398 void FontCollection::SetIsZawgyiMyanmar(bool is_zawgyi_myanmar) {
399   if (is_zawgyi_myanmar_ == is_zawgyi_myanmar) {
400     return;
401   }
402   is_zawgyi_myanmar_ = is_zawgyi_myanmar;
403   LoadSystemFont();
404 }
405 
406 #if defined(OHOS_PLATFORM) && !defined(OHOS_STANDARD_SYSTEM)
407 // Return the available font managers in the order they should be queried with
408 // type.
409 std::vector<std::pair<sk_sp<SkFontMgr>, txt::FontManagerType>>
GetFontManagerOrderWithType() const410 FontCollection::GetFontManagerOrderWithType() const {
411   std::vector<std::pair<sk_sp<SkFontMgr>, txt::FontManagerType>> order;
412   if (dynamic_font_manager_)
413     order.push_back(
414         std::make_pair(dynamic_font_manager_, txt::FontManagerType::DYNAMIC));
415   if (asset_font_manager_)
416     order.push_back(
417         std::make_pair(asset_font_manager_, txt::FontManagerType::ASSET));
418   if (test_font_manager_)
419     order.push_back(
420         std::make_pair(test_font_manager_, txt::FontManagerType::TEST));
421   auto defaultFontManager = GetDefaultFontManagerSafely();
422   if (defaultFontManager)
423     order.push_back(
424         std::make_pair(defaultFontManager, GetDefaultFontManagerType()));
425   return order;
426 }
427 
428 std::shared_ptr<minikin::FontCollection>
GetMinikinFontCollectionForFamiliesWithVariation(const std::vector<std::string> & font_families,const std::string & locale)429 FontCollection::GetMinikinFontCollectionForFamiliesWithVariation(
430     const std::vector<std::string>& font_families,
431     const std::string& locale) {
432   // Look inside the font collections cache first.
433   FamilyKey family_key(font_families, locale);
434   {
435     std::lock_guard<std::mutex> lock(mutex_);
436     auto iter = std::find(varied_fonts_.begin(), varied_fonts_.end(), family_key);
437     if (iter != varied_fonts_.end()) {
438       auto cached = font_collections_cache_.find(family_key);
439       if (cached != font_collections_cache_.end()) {
440         return cached->second;
441       }
442       varied_fonts_.erase(iter);
443     }
444   }
445 
446   std::vector<std::shared_ptr<minikin::FontFamily>> minikin_families;
447   // Search for all user provided font families.
448   for (size_t fallback_index = 0; fallback_index < font_families.size();
449        fallback_index++) {
450     std::shared_ptr<minikin::FontFamily> minikin_family =
451         FindFontFamilyInManagersWithType(font_families[fallback_index]);
452     if (minikin_family != nullptr) {
453       minikin_families.push_back(minikin_family);
454     }
455   }
456   // Search for default font family if no user font families were found.
457   if (minikin_families.empty()) {
458     const auto default_font_family = GetDefaultFontFamily();
459     std::shared_ptr<minikin::FontFamily> minikin_family =
460         FindFontFamilyInManagersWithType(default_font_family);
461     if (minikin_family != nullptr) {
462       minikin_families.push_back(minikin_family);
463     }
464   }
465   // Default font family also not found. We fail to get a FontCollection.
466   if (minikin_families.empty()) {
467     std::shared_ptr<minikin::FontCollection> tmp_font_collection;
468     std::lock_guard<std::mutex> lock(mutex_);
469     std::swap(font_collections_cache_[family_key], tmp_font_collection);
470     return nullptr;
471   }
472   if (enable_font_fallback_) {
473     std::lock_guard<std::mutex> lock(mutex_);
474     for (std::string fallback_family : fallback_fonts_for_locale_[locale]) {
475       auto it = fallback_fonts_.find(fallback_family);
476       if (it != fallback_fonts_.end()) {
477         minikin_families.push_back(it->second);
478       }
479     }
480   }
481   // Create the minikin font collection.
482   auto font_collection =
483       std::make_shared<minikin::FontCollection>(std::move(minikin_families));
484   font_collection->SetIsZawgyiMyanmar(is_zawgyi_myanmar_);
485 
486   if (enable_font_fallback_) {
487     font_collection->set_fallback_font_provider(
488         std::make_unique<TxtFallbackFontProvider>(shared_from_this()));
489   }
490 
491   {
492     std::shared_ptr<minikin::FontCollection> tmp_font_collection =
493         font_collection;
494     std::lock_guard<std::mutex> lock(mutex_);
495     // Cache the font collection for future queries.
496     std::swap(font_collections_cache_[family_key], tmp_font_collection);
497     varied_fonts_.emplace_back(family_key);
498   }
499 
500   return font_collection;
501 }
502 
503 std::shared_ptr<minikin::FontFamily>
FindFontFamilyInManagersWithType(const std::string & family_name)504 FontCollection::FindFontFamilyInManagersWithType(
505     const std::string& family_name) {
506   TRACE_EVENT0("flutter", "FontCollection::FindFontFamilyInManagersWithType");
507   // Search for the font family in each font manager.
508   for (std::pair<sk_sp<SkFontMgr>, FontManagerType>& managerPair :
509        GetFontManagerOrderWithType()) {
510     std::shared_ptr<minikin::FontFamily> minikin_family;
511     if (managerPair.second == FontManagerType::DEFAULT_OHOS) {
512       minikin_family =
513           CreateMinikinFontFamilyForOHOS(managerPair.first, family_name);
514     } else {
515       minikin_family =
516           CreateMinikinFontFamilyExceptOHOS(managerPair.first, family_name);
517     }
518     if (!minikin_family)
519       continue;
520     return minikin_family;
521   }
522   return nullptr;
523 }
524 
525 std::shared_ptr<minikin::FontFamily>
CreateMinikinFontFamilyForOHOS(const sk_sp<SkFontMgr> & manager,const std::string & family_name)526 FontCollection::CreateMinikinFontFamilyForOHOS(
527     const sk_sp<SkFontMgr>& manager,
528     const std::string& family_name) {
529   TRACE_EVENT1("flutter", "FontCollection::CreateMinikinFontFamilyForOHOS",
530                "family_name", family_name.c_str());
531   sk_sp<SkFontStyleSet> font_style_set(
532       manager->matchFamily(family_name.c_str()));
533   if (font_style_set == nullptr || font_style_set->count() == 0) {
534     return nullptr;
535   }
536 
537   auto font_style_set_ohos =
538       reinterpret_cast<SkFontStyleSet_OHOS*>(font_style_set.get());
539   if (font_style_set_ohos == nullptr) {
540     return CreateMinikinFontFamilyExceptOHOS(manager, family_name);
541   }
542 
543   std::vector<sk_sp<SkTypeface>> skia_typefaces;
544   for (int i = 0; i < font_style_set_ohos->count(); ++i) {
545     TRACE_EVENT0("flutter", "CreateSkiaTypeface");
546     sk_sp<SkTypeface> skia_typeface(
547         sk_sp<SkTypeface>(font_style_set_ohos->createTypeface(i)));
548     float wghtValue = font_style_set_ohos->getWghtValue(i);
549     if (wghtValue <= 0.0f) {
550       wghtValue = font_style_set_ohos->getFontWeight(i);
551     }
552     VaryTypeface(skia_typeface, wghtValue);
553     if (skia_typeface != nullptr) {
554       skia_typefaces.emplace_back(std::move(skia_typeface));
555     }
556   }
557 
558   int index = 0;
559   std::vector<minikin::Font> minikin_fonts;
560   for (const sk_sp<SkTypeface>& skia_typeface : skia_typefaces) {
561     // Create the minikin font from the skia typeface.
562     // Divide by 100 because the weights are given as "100", "200", etc.
563     minikin_fonts.emplace_back(
564         std::make_shared<FontSkia>(skia_typeface),
565         minikin::FontStyle{font_style_set_ohos->getFontWeight(index++) / 100,
566                            skia_typeface->isItalic()});
567   }
568 
569   return std::make_shared<minikin::FontFamily>(std::move(minikin_fonts));
570 }
571 
572 std::shared_ptr<minikin::FontFamily>
CreateMinikinFontFamilyExceptOHOS(const sk_sp<SkFontMgr> & manager,const std::string & family_name)573 FontCollection::CreateMinikinFontFamilyExceptOHOS(
574     const sk_sp<SkFontMgr>& manager,
575     const std::string& family_name) {
576   TRACE_EVENT1("flutter",
577                "FontCollection::CreateMinikinFontFamilyExceptOHOS",
578                "family_name", family_name.c_str());
579   sk_sp<SkFontStyleSet> font_style_set(
580       manager->matchFamily(family_name.c_str()));
581   if (font_style_set == nullptr || font_style_set->count() == 0) {
582     return nullptr;
583   }
584 
585   std::vector<sk_sp<SkTypeface>> skia_typefaces;
586   for (int i = 0; i < font_style_set->count(); ++i) {
587     TRACE_EVENT0("flutter", "CreateSkiaTypeface");
588     sk_sp<SkTypeface> skia_typeface(
589         sk_sp<SkTypeface>(font_style_set->createTypeface(i)));
590     VaryTypeface(skia_typeface, skia_typeface->fontStyle().weight());
591     if (skia_typeface != nullptr) {
592       skia_typefaces.emplace_back(std::move(skia_typeface));
593     }
594   }
595 
596   std::sort(skia_typefaces.begin(), skia_typefaces.end(),
597             [](const sk_sp<SkTypeface>& a, const sk_sp<SkTypeface>& b) {
598               SkFontStyle a_style = a->fontStyle();
599               SkFontStyle b_style = b->fontStyle();
600               return (a_style.weight() != b_style.weight())
601                          ? a_style.weight() < b_style.weight()
602                          : a_style.slant() < b_style.slant();
603             });
604 
605   std::vector<minikin::Font> minikin_fonts;
606   for (const sk_sp<SkTypeface>& skia_typeface : skia_typefaces) {
607     // Create the minikin font from the skia typeface.
608     // Divide by 100 because the weights are given as "100", "200", etc.
609     minikin_fonts.emplace_back(
610         std::make_shared<FontSkia>(skia_typeface),
611         minikin::FontStyle{skia_typeface->fontStyle().weight() / 100,
612                            skia_typeface->isItalic()});
613   }
614 
615   return std::make_shared<minikin::FontFamily>(std::move(minikin_fonts));
616 }
617 
VaryTypeface(sk_sp<SkTypeface> & typeface,float wght)618 void FontCollection::VaryTypeface(sk_sp<SkTypeface>& typeface, float wght) {
619   if (font_weight_scale_ <= 0.0f) {
620     return;
621   }
622   // Value of wght is between 0.0f and 1000.0f, and must be greater than 0.0f,
623   // default value is 400.0f.
624   if (wght <= 0.0) {
625     wght = 400.0f;
626   }
627   float wghtValue = std::min(wght * font_weight_scale_, 1000.0f);
628   SkFontArguments params;
629   int ttcIndex;
630   std::unique_ptr<SkStreamAsset> stream(typeface->openStream(&ttcIndex));
631   params.setCollectionIndex(ttcIndex);
632   std::vector<minikin::FontVariation> variations = {
633       {minikin::MinikinFont::MakeTag('w', 'g', 'h', 't'), wghtValue}};
634   std::vector<SkFontArguments::Axis> skAxes;
635   skAxes.resize(variations.size());
636   for (size_t i = 0; i < variations.size(); i++) {
637     skAxes[i].fTag = variations[i].axisTag;
638     skAxes[i].fStyleValue = variations[i].value;
639   }
640   params.setAxes(skAxes.data(), skAxes.size());
641   sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
642   typeface = fm->makeFromStream(std::move(stream), params);
643 }
644 
645 const std::shared_ptr<minikin::FontFamily>&
MatchFallbackFontWithVariation(uint32_t ch,std::string locale)646 FontCollection::MatchFallbackFontWithVariation(uint32_t ch,
647                                                std::string locale) {
648   {
649     std::lock_guard<std::mutex> lock(mutex_);
650     auto lookup = fallback_match_cache_.find(ch);
651     if (lookup != fallback_match_cache_.end()) {
652       return *lookup->second;
653     }
654   }
655   const std::shared_ptr<minikin::FontFamily>* match =
656       &DoMatchFallbackFontWithVariation(ch, locale);
657   {
658     std::lock_guard<std::mutex> lock(mutex_);
659     fallback_match_cache_.insert(std::make_pair(ch, match));
660   }
661   return *match;
662 }
663 
664 const std::shared_ptr<minikin::FontFamily>&
DoMatchFallbackFontWithVariation(uint32_t ch,std::string locale)665 FontCollection::DoMatchFallbackFontWithVariation(uint32_t ch,
666                                                  std::string locale) {
667   for (const std::pair<sk_sp<SkFontMgr>, FontManagerType>& managerPair :
668        GetFontManagerOrderWithType()) {
669     std::vector<const char*> bcp47;
670     if (!locale.empty())
671       bcp47.push_back(locale.c_str());
672 
673     if (managerPair.second == FontManagerType::DEFAULT_OHOS) {
674       auto ohosManager = reinterpret_cast<SkFontMgr_OHOS*>(managerPair.first.get());
675       if (ohosManager == nullptr)
676         continue;
677 
678       SkString sk_family_name = ohosManager->onMatchFamilyStyleCharacterOHOS(
679         0, SkFontStyle(), bcp47.data(), bcp47.size(), ch);
680       if(sk_family_name.isEmpty())
681         continue;
682 
683       return GetFallbackFontFamilyForOHOS(managerPair.first, std::string(sk_family_name.c_str()));
684     } else {
685       sk_sp<SkTypeface> typeface(managerPair.first->matchFamilyStyleCharacter(
686         0, SkFontStyle(), bcp47.data(), bcp47.size(), ch));
687       if (!typeface)
688         continue;
689 
690       SkString sk_family_name;
691       typeface->getFamilyName(&sk_family_name);
692       std::string family_name(sk_family_name.c_str());
693 
694       {
695         std::lock_guard<std::mutex> lock(mutex_);
696         fallback_fonts_for_locale_[locale].insert(family_name);
697       }
698 
699       return GetFallbackFontFamily(managerPair.first, family_name);
700     }
701   }
702   return g_null_family;
703 }
704 
705 const std::shared_ptr<minikin::FontFamily>&
GetFallbackFontFamilyForOHOS(const sk_sp<SkFontMgr> & manager,const std::string & family_name)706 FontCollection::GetFallbackFontFamilyForOHOS(
707     const sk_sp<SkFontMgr>& manager,
708     const std::string& family_name) {
709   TRACE_EVENT0("flutter", "FontCollection::GetFallbackFontFamily");
710   {
711     std::lock_guard<std::mutex> lock(mutex_);
712     auto fallback_it = fallback_fonts_.find(family_name);
713     if (fallback_it != fallback_fonts_.end()) {
714       return fallback_it->second;
715     }
716   }
717 
718   std::shared_ptr<minikin::FontFamily> minikin_family =
719       CreateMinikinFontFamilyForOHOS(manager, family_name);
720   if (!minikin_family) {
721     minikin_family = CreateMinikinFontFamilyExceptOHOS(manager, family_name);
722   }
723   if (!minikin_family)
724     return g_null_family;
725 
726   {
727     decltype(font_collections_cache_) font_collections_cache;
728     std::lock_guard<std::mutex> lock(mutex_);
729     auto insert_it =
730         fallback_fonts_.insert(std::make_pair(family_name, minikin_family));
731 
732     // Clear the cache to force creation of new font collections that will
733     // include this fallback font.
734     std::swap(font_collections_cache_, font_collections_cache);
735 
736     return insert_it.first->second;
737   }
738 }
739 
MatchFallbackFontFromHwFont(uint32_t ch,std::string locale)740 const std::shared_ptr<minikin::FontFamily>& FontCollection::MatchFallbackFontFromHwFont(
741     uint32_t ch,
742     std::string locale) {
743   const std::shared_ptr<minikin::FontFamily>* match =
744       &DoMatchFallbackFontFromHwFont(ch, locale);
745   return *match;
746 }
747 
748 const std::shared_ptr<minikin::FontFamily>&
DoMatchFallbackFontFromHwFont(uint32_t ch,std::string locale)749 FontCollection::DoMatchFallbackFontFromHwFont(uint32_t ch,
750                                               std::string locale) {
751   for (const std::pair<sk_sp<SkFontMgr>, FontManagerType>& managerPair :
752   GetFontManagerOrderWithType()) {
753     std::vector<const char*> bcp47;
754     if (!locale.empty())
755       bcp47.push_back(locale.c_str());
756 
757     if (managerPair.second == FontManagerType::DEFAULT_OHOS) {
758       auto ohosManager = reinterpret_cast<SkFontMgr_OHOS*>(managerPair.first.get());
759       if (ohosManager == nullptr)
760         continue;
761 
762       SkString sk_family_name = ohosManager->onMatchFamilyStyleCharacterHwFont(
763           0, SkFontStyle(), bcp47.data(), bcp47.size(), ch);
764       if(sk_family_name.isEmpty())
765         continue;
766 
767       return GetFallbackFontFamilyForOHOS(managerPair.first, std::string(sk_family_name.c_str()));
768     }
769   }
770   return g_null_family;
771 }
772 #endif
773 
774 #if FLUTTER_ENABLE_SKSHAPER
775 
776 sk_sp<skia::textlayout::FontCollection>
CreateSktFontCollection()777 FontCollection::CreateSktFontCollection() {
778   sk_sp<skia::textlayout::FontCollection> skt_collection =
779       sk_make_sp<skia::textlayout::FontCollection>();
780 
781   skt_collection->setDefaultFontManager(GetDefaultFontManagerSafely(),
782                                         GetDefaultFontFamily().c_str());
783   skt_collection->setAssetFontManager(asset_font_manager_);
784   skt_collection->setDynamicFontManager(dynamic_font_manager_);
785   skt_collection->setTestFontManager(test_font_manager_);
786   if (!enable_font_fallback_) {
787     skt_collection->disableFontFallback();
788   }
789 
790   return skt_collection;
791 }
792 
793 #endif  // FLUTTER_ENABLE_SKSHAPER
794 
795 }  // namespace txt
796