xref: /aosp_15_r20/external/skia/src/ports/SkFontMgr_fuchsia.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/ports/SkFontMgr_fuchsia.h"
9 
10 #include <fuchsia/fonts/cpp/fidl.h>
11 #include <lib/zx/vmar.h>
12 #include <strings.h>
13 #include <memory>
14 #include <unordered_map>
15 
16 #include "src/core/SkFontDescriptor.h"
17 #include "src/ports/SkFontMgr_custom.h"
18 #include "src/ports/SkFontScanner_FreeType_priv.h"
19 #include "src/ports/SkTypeface_FreeType.h"
20 
21 #include "include/core/SkFontMgr.h"
22 #include "include/core/SkStream.h"
23 #include "include/core/SkTypeface.h"
24 #include "include/private/base/SkThreadAnnotations.h"
25 #include "src/core/SkTypefaceCache.h"
26 
27 using namespace skia_private;
28 
29 // SkFuchsiaFontDataCache keep track of SkData created from `fuchsia::mem::Buffer` where each buffer
30 // is identified with a unique identifier. It allows to share the same SkData instances between all
31 // SkTypeface instances created from the same buffer.
32 class SkFuchsiaFontDataCache : public SkRefCnt {
33 public:
34     SkFuchsiaFontDataCache() = default;
~SkFuchsiaFontDataCache()35     ~SkFuchsiaFontDataCache() { SkASSERT(fBuffers.empty()); }
36 
37     sk_sp<SkData> GetOrCreateSkData(int bufferId, const fuchsia::mem::Buffer& buffer);
38 
39 private:
40     struct ReleaseSkDataContext {
41         sk_sp<SkFuchsiaFontDataCache> fCache;
42         int fBufferId;
43     };
44 
45     static void ReleaseSkData(const void* buffer, void* context);
46     void OnBufferDeleted(int bufferId);
47 
48     SkMutex fMutex;
49     std::unordered_map<int, SkData*> fBuffers SK_GUARDED_BY(fMutex);
50 };
51 
GetOrCreateSkData(int bufferId,const fuchsia::mem::Buffer & buffer)52 sk_sp<SkData> SkFuchsiaFontDataCache::GetOrCreateSkData(int bufferId,
53                                                         const fuchsia::mem::Buffer& buffer) {
54     SkAutoMutexExclusive mutexLock(fMutex);
55 
56     auto iter = fBuffers.find(bufferId);
57     if (iter != fBuffers.end()) {
58         return sk_ref_sp(iter->second);
59     }
60     auto font_mgr = sk_ref_sp(this);
61 
62     uint64_t size = buffer.size;
63     uintptr_t mapped_addr = 0;
64     zx_status_t status =
65             zx::vmar::root_self()->map(ZX_VM_PERM_READ, 0, buffer.vmo, 0, size, &mapped_addr);
66     if (status != ZX_OK) return nullptr;
67 
68     auto context = new ReleaseSkDataContext{sk_ref_sp(this), bufferId};
69     auto data = SkData::MakeWithProc(
70             reinterpret_cast<void*>(mapped_addr), size, ReleaseSkData, context);
71     SkASSERT(data);
72 
73     fBuffers[bufferId] = data.get();
74     return data;
75 }
76 
OnBufferDeleted(int bufferId)77 void SkFuchsiaFontDataCache::OnBufferDeleted(int bufferId) {
78     zx_vaddr_t unmap_addr;
79     size_t unmap_size;
80     {
81         SkAutoMutexExclusive mutexLock(fMutex);
82         auto it = fBuffers.find(bufferId);
83         SkASSERT(it != fBuffers.end());
84         unmap_addr = reinterpret_cast<zx_vaddr_t>(it->second->data());
85         unmap_size = it->second->size();
86         fBuffers.erase(it);
87     }
88 
89     zx::vmar::root_self()->unmap(unmap_addr, unmap_size);
90 }
91 
92 // static
ReleaseSkData(const void * buffer,void * context)93 void SkFuchsiaFontDataCache::ReleaseSkData(const void* buffer, void* context) {
94     auto releaseSkDataContext = reinterpret_cast<ReleaseSkDataContext*>(context);
95     releaseSkDataContext->fCache->OnBufferDeleted(releaseSkDataContext->fBufferId);
96     delete releaseSkDataContext;
97 }
98 
SkToFuchsiaSlant(SkFontStyle::Slant slant)99 fuchsia::fonts::Slant SkToFuchsiaSlant(SkFontStyle::Slant slant) {
100     switch (slant) {
101         case SkFontStyle::kOblique_Slant:
102             return fuchsia::fonts::Slant::OBLIQUE;
103         case SkFontStyle::kItalic_Slant:
104             return fuchsia::fonts::Slant::ITALIC;
105         case SkFontStyle::kUpright_Slant:
106         default:
107             return fuchsia::fonts::Slant::UPRIGHT;
108     }
109 }
110 
FuchsiaToSkSlant(fuchsia::fonts::Slant slant)111 SkFontStyle::Slant FuchsiaToSkSlant(fuchsia::fonts::Slant slant) {
112     switch (slant) {
113         case fuchsia::fonts::Slant::OBLIQUE:
114             return SkFontStyle::kOblique_Slant;
115         case fuchsia::fonts::Slant::ITALIC:
116             return SkFontStyle::kItalic_Slant;
117         case fuchsia::fonts::Slant::UPRIGHT:
118         default:
119             return SkFontStyle::kUpright_Slant;
120     }
121 }
122 
SkToFuchsiaWidth(SkFontStyle::Width width)123 fuchsia::fonts::Width SkToFuchsiaWidth(SkFontStyle::Width width) {
124     switch (width) {
125         case SkFontStyle::Width::kUltraCondensed_Width:
126             return fuchsia::fonts::Width::ULTRA_CONDENSED;
127         case SkFontStyle::Width::kExtraCondensed_Width:
128             return fuchsia::fonts::Width::EXTRA_CONDENSED;
129         case SkFontStyle::Width::kCondensed_Width:
130             return fuchsia::fonts::Width::CONDENSED;
131         case SkFontStyle::Width::kSemiCondensed_Width:
132             return fuchsia::fonts::Width::SEMI_CONDENSED;
133         case SkFontStyle::Width::kNormal_Width:
134             return fuchsia::fonts::Width::NORMAL;
135         case SkFontStyle::Width::kSemiExpanded_Width:
136             return fuchsia::fonts::Width::SEMI_EXPANDED;
137         case SkFontStyle::Width::kExpanded_Width:
138             return fuchsia::fonts::Width::EXPANDED;
139         case SkFontStyle::Width::kExtraExpanded_Width:
140             return fuchsia::fonts::Width::EXTRA_EXPANDED;
141         case SkFontStyle::Width::kUltraExpanded_Width:
142             return fuchsia::fonts::Width::ULTRA_EXPANDED;
143     }
144 }
145 
146 // Tries to convert the given integer Skia style width value to the Fuchsia equivalent.
147 //
148 // On success, returns true. On failure, returns false, and `outFuchsiaWidth` is left untouched.
SkToFuchsiaWidth(int skWidth,fuchsia::fonts::Width * outFuchsiaWidth)149 bool SkToFuchsiaWidth(int skWidth, fuchsia::fonts::Width* outFuchsiaWidth) {
150     if (skWidth < SkFontStyle::Width::kUltraCondensed_Width ||
151         skWidth > SkFontStyle::Width::kUltraExpanded_Width) {
152         return false;
153     }
154     auto typedSkWidth = static_cast<SkFontStyle::Width>(skWidth);
155     *outFuchsiaWidth = SkToFuchsiaWidth(typedSkWidth);
156     return true;
157 }
158 
FuchsiaToSkWidth(fuchsia::fonts::Width width)159 SkFontStyle::Width FuchsiaToSkWidth(fuchsia::fonts::Width width) {
160     switch (width) {
161         case fuchsia::fonts::Width::ULTRA_CONDENSED:
162             return SkFontStyle::Width::kUltraCondensed_Width;
163         case fuchsia::fonts::Width::EXTRA_CONDENSED:
164             return SkFontStyle::Width::kExtraCondensed_Width;
165         case fuchsia::fonts::Width::CONDENSED:
166             return SkFontStyle::Width::kCondensed_Width;
167         case fuchsia::fonts::Width::SEMI_CONDENSED:
168             return SkFontStyle::Width::kSemiCondensed_Width;
169         case fuchsia::fonts::Width::NORMAL:
170             return SkFontStyle::Width::kNormal_Width;
171         case fuchsia::fonts::Width::SEMI_EXPANDED:
172             return SkFontStyle::Width::kSemiExpanded_Width;
173         case fuchsia::fonts::Width::EXPANDED:
174             return SkFontStyle::Width::kExpanded_Width;
175         case fuchsia::fonts::Width::EXTRA_EXPANDED:
176             return SkFontStyle::Width::kExtraExpanded_Width;
177         case fuchsia::fonts::Width::ULTRA_EXPANDED:
178             return SkFontStyle::Width::kUltraExpanded_Width;
179     }
180 }
181 
SkToFuchsiaStyle(const SkFontStyle & style)182 fuchsia::fonts::Style2 SkToFuchsiaStyle(const SkFontStyle& style) {
183     fuchsia::fonts::Style2 fuchsiaStyle;
184     fuchsiaStyle.set_slant(SkToFuchsiaSlant(style.slant())).set_weight(style.weight());
185 
186     fuchsia::fonts::Width fuchsiaWidth = fuchsia::fonts::Width::NORMAL;
187     if (SkToFuchsiaWidth(style.width(), &fuchsiaWidth)) {
188         fuchsiaStyle.set_width(fuchsiaWidth);
189     }
190 
191     return fuchsiaStyle;
192 }
193 
194 constexpr struct {
195     const char* fName;
196     fuchsia::fonts::GenericFontFamily fGenericFontFamily;
197 } kGenericFontFamiliesByName[] = {{"serif", fuchsia::fonts::GenericFontFamily::SERIF},
198                                   {"sans", fuchsia::fonts::GenericFontFamily::SANS_SERIF},
199                                   {"sans-serif", fuchsia::fonts::GenericFontFamily::SANS_SERIF},
200                                   {"mono", fuchsia::fonts::GenericFontFamily::MONOSPACE},
201                                   {"monospace", fuchsia::fonts::GenericFontFamily::MONOSPACE},
202                                   {"cursive", fuchsia::fonts::GenericFontFamily::CURSIVE},
203                                   {"fantasy", fuchsia::fonts::GenericFontFamily::FANTASY},
204                                   {"system-ui", fuchsia::fonts::GenericFontFamily::SYSTEM_UI},
205                                   {"emoji", fuchsia::fonts::GenericFontFamily::EMOJI},
206                                   {"math", fuchsia::fonts::GenericFontFamily::MATH},
207                                   {"fangsong", fuchsia::fonts::GenericFontFamily::FANGSONG}};
208 
209 // Tries to find a generic font family with the given name. If none is found, returns false.
GetGenericFontFamilyByName(const char * name,fuchsia::fonts::GenericFontFamily * outGenericFamily)210 bool GetGenericFontFamilyByName(const char* name,
211                                 fuchsia::fonts::GenericFontFamily* outGenericFamily) {
212     if (!name) return false;
213     for (auto& genericFamily : kGenericFontFamiliesByName) {
214         if (strcasecmp(genericFamily.fName, name) == 0) {
215             *outGenericFamily = genericFamily.fGenericFontFamily;
216             return true;
217         }
218     }
219     return false;
220 }
221 
222 struct TypefaceId {
223     uint32_t bufferId;
224     uint32_t ttcIndex;
225 
operator ==TypefaceId226     bool operator==(TypefaceId& other) const {
227         return std::tie(bufferId, ttcIndex) == std::tie(other.bufferId, other.ttcIndex);
228     }
229 }
230 
231 constexpr kNullTypefaceId = {0xFFFFFFFF, 0xFFFFFFFF};
232 
233 class SkTypeface_Fuchsia : public SkTypeface_FreeTypeStream {
234 public:
SkTypeface_Fuchsia(std::unique_ptr<SkFontData> fontData,const SkFontStyle & style,bool isFixedPitch,const SkString familyName,TypefaceId id)235     SkTypeface_Fuchsia(std::unique_ptr<SkFontData> fontData, const SkFontStyle& style,
236                        bool isFixedPitch, const SkString familyName, TypefaceId id)
237             : SkTypeface_FreeTypeStream(std::move(fontData), familyName, style, isFixedPitch)
238             , fId(id) {}
239 
id()240     TypefaceId id() { return fId; }
241 
242 private:
243     TypefaceId fId;
244 };
245 
CreateTypefaceFromSkStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args,TypefaceId id)246 sk_sp<SkTypeface> CreateTypefaceFromSkStream(std::unique_ptr<SkStreamAsset> stream,
247                                              const SkFontArguments& args, TypefaceId id) {
248     SkFontScanner_FreeType fontScanner;
249     int numInstances;
250     if (!fontScanner.scanFace(stream.get(), args.getCollectionIndex(), &numInstances)) {
251         return nullptr;
252     }
253     bool isFixedPitch;
254     SkFontStyle style;
255     SkString name;
256     SkFontScanner::AxisDefinitions axisDefinitions;
257     if (!fontScanner.scanInstance(stream.get(),
258                                   args.getCollectionIndex(),
259                                   0,
260                                   &name,
261                                   &style,
262                                   &isFixedPitch,
263                                   &axisDefinitions)) {
264         return nullptr;
265     }
266 
267     const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
268     AutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.size());
269     SkFontScanner_FreeType::computeAxisValues(axisDefinitions, position, axisValues, name, &style);
270 
271     auto fontData = std::make_unique<SkFontData>(
272         std::move(stream), args.getCollectionIndex(), args.getPalette().index,
273         axisValues.get(), axisDefinitions.size(),
274         args.getPalette().overrides, args.getPalette().overrideCount);
275     return sk_make_sp<SkTypeface_Fuchsia>(std::move(fontData), style, isFixedPitch, name, id);
276 }
277 
CreateTypefaceFromSkData(sk_sp<SkData> data,TypefaceId id)278 sk_sp<SkTypeface> CreateTypefaceFromSkData(sk_sp<SkData> data, TypefaceId id) {
279     return CreateTypefaceFromSkStream(std::make_unique<SkMemoryStream>(std::move(data)),
280                                       SkFontArguments().setCollectionIndex(id.ttcIndex), id);
281 }
282 
283 class SkFontMgr_Fuchsia final : public SkFontMgr {
284 public:
285     SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider);
286     ~SkFontMgr_Fuchsia() override;
287 
288 protected:
289     // SkFontMgr overrides.
290     int onCountFamilies() const override;
291     void onGetFamilyName(int index, SkString* familyName) const override;
292     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override;
293     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override;
294     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[], const SkFontStyle&) const override;
295     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
296                                             const char* bcp47[], int bcp47Count,
297                                             SkUnichar character) const override;
298     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
299     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
300                                             int ttcIndex) const override;
301     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
302                                            const SkFontArguments&) const override;
303     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
304     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
305 
306 private:
307     friend class SkFontStyleSet_Fuchsia;
308 
309     sk_sp<SkTypeface> FetchTypeface(const char familyName[], const SkFontStyle& style,
310                                     const char* bcp47[], int bcp47Count, SkUnichar character,
311                                     bool allow_fallback, bool exact_style_match) const;
312 
313     sk_sp<SkTypeface> GetOrCreateTypeface(TypefaceId id, const fuchsia::mem::Buffer& buffer) const;
314 
315     mutable fuchsia::fonts::ProviderSyncPtr fFontProvider;
316 
317     sk_sp<SkFuchsiaFontDataCache> fBufferCache;
318 
319     mutable SkMutex fCacheMutex;
320     mutable SkTypefaceCache fTypefaceCache SK_GUARDED_BY(fCacheMutex);
321 };
322 
323 class SkFontStyleSet_Fuchsia : public SkFontStyleSet {
324 public:
SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager,std::string familyName,std::vector<SkFontStyle> styles)325     SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager, std::string familyName,
326                  std::vector<SkFontStyle> styles)
327             : fFontManager(font_manager), fFamilyName(familyName), fStyles(styles) {}
328 
329     ~SkFontStyleSet_Fuchsia() override = default;
330 
count()331     int count() override { return fStyles.size(); }
332 
getStyle(int index,SkFontStyle * style,SkString * styleName)333     void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
334         SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
335         if (style) *style = fStyles[index];
336 
337         // We don't have style names. Return an empty name.
338         if (styleName) styleName->reset();
339     }
340 
createTypeface(int index)341     sk_sp<SkTypeface> createTypeface(int index) override {
342         SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
343 
344         if (fTypefaces.empty()) fTypefaces.resize(fStyles.size());
345 
346         if (!fTypefaces[index]) {
347             fTypefaces[index] = fFontManager->FetchTypeface(
348                     fFamilyName.c_str(), fStyles[index], /*bcp47=*/nullptr,
349                     /*bcp47Count=*/0, /*character=*/0,
350                     /*allow_fallback=*/false, /*exact_style_match=*/true);
351         }
352 
353         return fTypefaces[index];
354     }
355 
matchStyle(const SkFontStyle & pattern)356     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
357         return matchStyleCSS3(pattern);
358     }
359 
360 private:
361     sk_sp<SkFontMgr_Fuchsia> fFontManager;
362     std::string fFamilyName;
363     std::vector<SkFontStyle> fStyles;
364     std::vector<sk_sp<SkTypeface>> fTypefaces;
365 };
366 
SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)367 SkFontMgr_Fuchsia::SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)
368         : fFontProvider(std::move(provider)), fBufferCache(sk_make_sp<SkFuchsiaFontDataCache>()) {}
369 
370 SkFontMgr_Fuchsia::~SkFontMgr_Fuchsia() = default;
371 
onCountFamilies() const372 int SkFontMgr_Fuchsia::onCountFamilies() const {
373     // Family enumeration is not supported.
374     return 0;
375 }
376 
onGetFamilyName(int index,SkString * familyName) const377 void SkFontMgr_Fuchsia::onGetFamilyName(int index, SkString* familyName) const {
378     // Family enumeration is not supported.
379     familyName->reset();
380 }
381 
onCreateStyleSet(int index) const382 sk_sp<SkFontStyleSet> SkFontMgr_Fuchsia::onCreateStyleSet(int index) const {
383     // Family enumeration is not supported.
384     return nullptr;
385 }
386 
onMatchFamily(const char familyName[]) const387 sk_sp<SkFontStyleSet> SkFontMgr_Fuchsia::onMatchFamily(const char familyName[]) const {
388     fuchsia::fonts::FamilyName typedFamilyName;
389     typedFamilyName.name = familyName;
390 
391     fuchsia::fonts::FontFamilyInfo familyInfo;
392     int result = fFontProvider->GetFontFamilyInfo(typedFamilyName, &familyInfo);
393     if (result != ZX_OK || !familyInfo.has_styles() || familyInfo.styles().empty()) return nullptr;
394 
395     std::vector<SkFontStyle> styles;
396     for (auto& style : familyInfo.styles()) {
397         styles.push_back(SkFontStyle(style.weight(), FuchsiaToSkWidth(style.width()),
398                                      FuchsiaToSkSlant(style.slant())));
399     }
400 
401     return sk_sp<SkFontStyleSet>(
402         new SkFontStyleSet_Fuchsia(sk_ref_sp(this), familyInfo.name().name, std::move(styles)));
403 }
404 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const405 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMatchFamilyStyle(const char familyName[],
406                                                         const SkFontStyle& style) const {
407     return FetchTypeface(familyName, style, /*bcp47=*/nullptr, /*bcp47Count=*/0, /*character=*/0,
408                          /*allow_fallback=*/false, /*exact_style_match=*/false);
409 }
410 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const411 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMatchFamilyStyleCharacter(
412     const char familyName[], const SkFontStyle& style,
413     const char* bcp47[], int bcp47Count,
414     SkUnichar character) const
415 {
416     return FetchTypeface(familyName, style, bcp47, bcp47Count, character,
417                          /*allow_fallback=*/true, /*exact_style_match=*/false);
418 }
419 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const420 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const {
421     return makeFromStream(std::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
422 }
423 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> asset,int ttcIndex) const424 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> asset,
425                                                            int ttcIndex) const {
426     return makeFromStream(std::move(asset), SkFontArguments().setCollectionIndex(ttcIndex));
427 }
428 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> asset,const SkFontArguments & args) const429 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> asset,
430                                                           const SkFontArguments& args) const {
431     return CreateTypefaceFromSkStream(std::move(asset), args, kNullTypefaceId);
432 }
433 
onMakeFromFile(const char path[],int ttcIndex) const434 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromFile(const char path[], int ttcIndex) const {
435     return makeFromStream(std::make_unique<SkFILEStream>(path), ttcIndex);
436 }
437 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const438 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onLegacyMakeTypeface(const char familyName[],
439                                                           SkFontStyle style) const {
440     return sk_sp<SkTypeface>(matchFamilyStyle(familyName, style));
441 }
442 
FetchTypeface(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character,bool allow_fallback,bool exact_style_match) const443 sk_sp<SkTypeface> SkFontMgr_Fuchsia::FetchTypeface(const char familyName[],
444                                                    const SkFontStyle& style, const char* bcp47[],
445                                                    int bcp47Count, SkUnichar character,
446                                                    bool allow_fallback,
447                                                    bool exact_style_match) const {
448     fuchsia::fonts::TypefaceQuery query;
449     query.set_style(SkToFuchsiaStyle(style));
450 
451     if (bcp47Count > 0) {
452         std::vector<fuchsia::intl::LocaleId> languages{};
453         for (int i = 0; i < bcp47Count; i++) {
454             fuchsia::intl::LocaleId localeId;
455             localeId.id = bcp47[i];
456             languages.push_back(localeId);
457         }
458         query.set_languages(std::move(languages));
459     }
460 
461     if (character) {
462         query.set_code_points({static_cast<uint32_t>(character)});
463     }
464 
465     // If family name is not specified or is a generic family name (e.g. "serif"), then enable
466     // fallback; otherwise, pass the family name as is.
467     fuchsia::fonts::GenericFontFamily genericFontFamily =
468             fuchsia::fonts::GenericFontFamily::SANS_SERIF;
469     bool isGenericFontFamily = GetGenericFontFamilyByName(familyName, &genericFontFamily);
470     if (!familyName || *familyName == '\0' || isGenericFontFamily) {
471         if (isGenericFontFamily) {
472             query.set_fallback_family(genericFontFamily);
473         }
474         allow_fallback = true;
475     } else {
476         fuchsia::fonts::FamilyName typedFamilyName{};
477         typedFamilyName.name = familyName;
478         query.set_family(typedFamilyName);
479     }
480 
481     fuchsia::fonts::TypefaceRequestFlags flags{};
482     if (!allow_fallback) flags |= fuchsia::fonts::TypefaceRequestFlags::EXACT_FAMILY;
483     if (exact_style_match) flags |= fuchsia::fonts::TypefaceRequestFlags::EXACT_STYLE;
484 
485     fuchsia::fonts::TypefaceRequest request;
486     request.set_query(std::move(query));
487     request.set_flags(flags);
488 
489     fuchsia::fonts::TypefaceResponse response;
490     int result = fFontProvider->GetTypeface(std::move(request), &response);
491     if (result != ZX_OK) return nullptr;
492 
493     // The service may return an empty response if there is no font matching the request.
494     if (response.IsEmpty()) return nullptr;
495 
496     return GetOrCreateTypeface(TypefaceId{response.buffer_id(), response.font_index()},
497                                response.buffer());
498 }
499 
FindByTypefaceId(SkTypeface * cachedTypeface,void * ctx)500 static bool FindByTypefaceId(SkTypeface* cachedTypeface, void* ctx) {
501     SkTypeface_Fuchsia* cachedFuchsiaTypeface = static_cast<SkTypeface_Fuchsia*>(cachedTypeface);
502     TypefaceId* id = static_cast<TypefaceId*>(ctx);
503 
504     return cachedFuchsiaTypeface->id() == *id;
505 }
506 
GetOrCreateTypeface(TypefaceId id,const fuchsia::mem::Buffer & buffer) const507 sk_sp<SkTypeface> SkFontMgr_Fuchsia::GetOrCreateTypeface(TypefaceId id,
508                                                          const fuchsia::mem::Buffer& buffer) const {
509     SkAutoMutexExclusive mutexLock(fCacheMutex);
510 
511     sk_sp<SkTypeface> cached = fTypefaceCache.findByProcAndRef(FindByTypefaceId, &id);
512     if (cached) return cached;
513 
514     sk_sp<SkData> data = fBufferCache->GetOrCreateSkData(id.bufferId, buffer);
515     if (!data) return nullptr;
516 
517     auto result = CreateTypefaceFromSkData(std::move(data), id);
518     fTypefaceCache.add(result);
519     return result;
520 }
521 
SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)522 sk_sp<SkFontMgr> SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider) {
523     return sk_make_sp<SkFontMgr_Fuchsia>(std::move(provider));
524 }
525