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 SkFontScanner::VariationPosition current;
258 if (!fontScanner.scanInstance(stream.get(),
259 args.getCollectionIndex(),
260 0,
261 &name,
262 &style,
263 &isFixedPitch,
264 &axisDefinitions,
265 ¤t)) {
266 return nullptr;
267 }
268
269 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
270 AutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.size());
271 const SkFontArguments::VariationPosition currentPos{current.data(), current.size()};
272 SkFontScanner_FreeType::computeAxisValues(axisDefinitions, currentPos, position, axisValues,
273 name, &style);
274
275 auto fontData = std::make_unique<SkFontData>(
276 std::move(stream), args.getCollectionIndex(), args.getPalette().index,
277 axisValues.get(), axisDefinitions.size(),
278 args.getPalette().overrides, args.getPalette().overrideCount);
279 return sk_make_sp<SkTypeface_Fuchsia>(std::move(fontData), style, isFixedPitch, name, id);
280 }
281
CreateTypefaceFromSkData(sk_sp<SkData> data,TypefaceId id)282 sk_sp<SkTypeface> CreateTypefaceFromSkData(sk_sp<SkData> data, TypefaceId id) {
283 return CreateTypefaceFromSkStream(std::make_unique<SkMemoryStream>(std::move(data)),
284 SkFontArguments().setCollectionIndex(id.ttcIndex), id);
285 }
286
287 class SkFontMgr_Fuchsia final : public SkFontMgr {
288 public:
289 SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider);
290 ~SkFontMgr_Fuchsia() override;
291
292 protected:
293 // SkFontMgr overrides.
294 int onCountFamilies() const override;
295 void onGetFamilyName(int index, SkString* familyName) const override;
296 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override;
297 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override;
298 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[], const SkFontStyle&) const override;
299 sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
300 const char* bcp47[], int bcp47Count,
301 SkUnichar character) const override;
302 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
303 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
304 int ttcIndex) const override;
305 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
306 const SkFontArguments&) const override;
307 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
308 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
309
310 private:
311 friend class SkFontStyleSet_Fuchsia;
312
313 sk_sp<SkTypeface> FetchTypeface(const char familyName[], const SkFontStyle& style,
314 const char* bcp47[], int bcp47Count, SkUnichar character,
315 bool allow_fallback, bool exact_style_match) const;
316
317 sk_sp<SkTypeface> GetOrCreateTypeface(TypefaceId id, const fuchsia::mem::Buffer& buffer) const;
318
319 mutable fuchsia::fonts::ProviderSyncPtr fFontProvider;
320
321 sk_sp<SkFuchsiaFontDataCache> fBufferCache;
322
323 mutable SkMutex fCacheMutex;
324 mutable SkTypefaceCache fTypefaceCache SK_GUARDED_BY(fCacheMutex);
325 };
326
327 class SkFontStyleSet_Fuchsia : public SkFontStyleSet {
328 public:
SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager,std::string familyName,std::vector<SkFontStyle> styles)329 SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager, std::string familyName,
330 std::vector<SkFontStyle> styles)
331 : fFontManager(font_manager), fFamilyName(familyName), fStyles(styles) {}
332
333 ~SkFontStyleSet_Fuchsia() override = default;
334
count()335 int count() override { return fStyles.size(); }
336
getStyle(int index,SkFontStyle * style,SkString * styleName)337 void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
338 SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
339 if (style) *style = fStyles[index];
340
341 // We don't have style names. Return an empty name.
342 if (styleName) styleName->reset();
343 }
344
createTypeface(int index)345 sk_sp<SkTypeface> createTypeface(int index) override {
346 SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
347
348 if (fTypefaces.empty()) fTypefaces.resize(fStyles.size());
349
350 if (!fTypefaces[index]) {
351 fTypefaces[index] = fFontManager->FetchTypeface(
352 fFamilyName.c_str(), fStyles[index], /*bcp47=*/nullptr,
353 /*bcp47Count=*/0, /*character=*/0,
354 /*allow_fallback=*/false, /*exact_style_match=*/true);
355 }
356
357 return fTypefaces[index];
358 }
359
matchStyle(const SkFontStyle & pattern)360 sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
361 return matchStyleCSS3(pattern);
362 }
363
364 private:
365 sk_sp<SkFontMgr_Fuchsia> fFontManager;
366 std::string fFamilyName;
367 std::vector<SkFontStyle> fStyles;
368 std::vector<sk_sp<SkTypeface>> fTypefaces;
369 };
370
SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)371 SkFontMgr_Fuchsia::SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)
372 : fFontProvider(std::move(provider)), fBufferCache(sk_make_sp<SkFuchsiaFontDataCache>()) {}
373
374 SkFontMgr_Fuchsia::~SkFontMgr_Fuchsia() = default;
375
onCountFamilies() const376 int SkFontMgr_Fuchsia::onCountFamilies() const {
377 // Family enumeration is not supported.
378 return 0;
379 }
380
onGetFamilyName(int index,SkString * familyName) const381 void SkFontMgr_Fuchsia::onGetFamilyName(int index, SkString* familyName) const {
382 // Family enumeration is not supported.
383 familyName->reset();
384 }
385
onCreateStyleSet(int index) const386 sk_sp<SkFontStyleSet> SkFontMgr_Fuchsia::onCreateStyleSet(int index) const {
387 // Family enumeration is not supported.
388 return nullptr;
389 }
390
onMatchFamily(const char familyName[]) const391 sk_sp<SkFontStyleSet> SkFontMgr_Fuchsia::onMatchFamily(const char familyName[]) const {
392 fuchsia::fonts::FamilyName typedFamilyName;
393 typedFamilyName.name = familyName;
394
395 fuchsia::fonts::FontFamilyInfo familyInfo;
396 int result = fFontProvider->GetFontFamilyInfo(typedFamilyName, &familyInfo);
397 if (result != ZX_OK || !familyInfo.has_styles() || familyInfo.styles().empty()) return nullptr;
398
399 std::vector<SkFontStyle> styles;
400 for (auto& style : familyInfo.styles()) {
401 styles.push_back(SkFontStyle(style.weight(), FuchsiaToSkWidth(style.width()),
402 FuchsiaToSkSlant(style.slant())));
403 }
404
405 return sk_sp<SkFontStyleSet>(
406 new SkFontStyleSet_Fuchsia(sk_ref_sp(this), familyInfo.name().name, std::move(styles)));
407 }
408
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const409 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMatchFamilyStyle(const char familyName[],
410 const SkFontStyle& style) const {
411 return FetchTypeface(familyName, style, /*bcp47=*/nullptr, /*bcp47Count=*/0, /*character=*/0,
412 /*allow_fallback=*/false, /*exact_style_match=*/false);
413 }
414
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const415 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMatchFamilyStyleCharacter(
416 const char familyName[], const SkFontStyle& style,
417 const char* bcp47[], int bcp47Count,
418 SkUnichar character) const
419 {
420 return FetchTypeface(familyName, style, bcp47, bcp47Count, character,
421 /*allow_fallback=*/true, /*exact_style_match=*/false);
422 }
423
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const424 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const {
425 return makeFromStream(std::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
426 }
427
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> asset,int ttcIndex) const428 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> asset,
429 int ttcIndex) const {
430 return makeFromStream(std::move(asset), SkFontArguments().setCollectionIndex(ttcIndex));
431 }
432
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> asset,const SkFontArguments & args) const433 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> asset,
434 const SkFontArguments& args) const {
435 return CreateTypefaceFromSkStream(std::move(asset), args, kNullTypefaceId);
436 }
437
onMakeFromFile(const char path[],int ttcIndex) const438 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromFile(const char path[], int ttcIndex) const {
439 return makeFromStream(std::make_unique<SkFILEStream>(path), ttcIndex);
440 }
441
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const442 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onLegacyMakeTypeface(const char familyName[],
443 SkFontStyle style) const {
444 return sk_sp<SkTypeface>(matchFamilyStyle(familyName, style));
445 }
446
FetchTypeface(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character,bool allow_fallback,bool exact_style_match) const447 sk_sp<SkTypeface> SkFontMgr_Fuchsia::FetchTypeface(const char familyName[],
448 const SkFontStyle& style, const char* bcp47[],
449 int bcp47Count, SkUnichar character,
450 bool allow_fallback,
451 bool exact_style_match) const {
452 fuchsia::fonts::TypefaceQuery query;
453 query.set_style(SkToFuchsiaStyle(style));
454
455 if (bcp47Count > 0) {
456 std::vector<fuchsia::intl::LocaleId> languages{};
457 for (int i = 0; i < bcp47Count; i++) {
458 fuchsia::intl::LocaleId localeId;
459 localeId.id = bcp47[i];
460 languages.push_back(localeId);
461 }
462 query.set_languages(std::move(languages));
463 }
464
465 if (character) {
466 query.set_code_points({static_cast<uint32_t>(character)});
467 }
468
469 // If family name is not specified or is a generic family name (e.g. "serif"), then enable
470 // fallback; otherwise, pass the family name as is.
471 fuchsia::fonts::GenericFontFamily genericFontFamily =
472 fuchsia::fonts::GenericFontFamily::SANS_SERIF;
473 bool isGenericFontFamily = GetGenericFontFamilyByName(familyName, &genericFontFamily);
474 if (!familyName || *familyName == '\0' || isGenericFontFamily) {
475 if (isGenericFontFamily) {
476 query.set_fallback_family(genericFontFamily);
477 }
478 allow_fallback = true;
479 } else {
480 fuchsia::fonts::FamilyName typedFamilyName{};
481 typedFamilyName.name = familyName;
482 query.set_family(typedFamilyName);
483 }
484
485 fuchsia::fonts::TypefaceRequestFlags flags{};
486 if (!allow_fallback) flags |= fuchsia::fonts::TypefaceRequestFlags::EXACT_FAMILY;
487 if (exact_style_match) flags |= fuchsia::fonts::TypefaceRequestFlags::EXACT_STYLE;
488
489 fuchsia::fonts::TypefaceRequest request;
490 request.set_query(std::move(query));
491 request.set_flags(flags);
492
493 fuchsia::fonts::TypefaceResponse response;
494 int result = fFontProvider->GetTypeface(std::move(request), &response);
495 if (result != ZX_OK) return nullptr;
496
497 // The service may return an empty response if there is no font matching the request.
498 if (response.IsEmpty()) return nullptr;
499
500 return GetOrCreateTypeface(TypefaceId{response.buffer_id(), response.font_index()},
501 response.buffer());
502 }
503
FindByTypefaceId(SkTypeface * cachedTypeface,void * ctx)504 static bool FindByTypefaceId(SkTypeface* cachedTypeface, void* ctx) {
505 SkTypeface_Fuchsia* cachedFuchsiaTypeface = static_cast<SkTypeface_Fuchsia*>(cachedTypeface);
506 TypefaceId* id = static_cast<TypefaceId*>(ctx);
507
508 return cachedFuchsiaTypeface->id() == *id;
509 }
510
GetOrCreateTypeface(TypefaceId id,const fuchsia::mem::Buffer & buffer) const511 sk_sp<SkTypeface> SkFontMgr_Fuchsia::GetOrCreateTypeface(TypefaceId id,
512 const fuchsia::mem::Buffer& buffer) const {
513 SkAutoMutexExclusive mutexLock(fCacheMutex);
514
515 sk_sp<SkTypeface> cached = fTypefaceCache.findByProcAndRef(FindByTypefaceId, &id);
516 if (cached) return cached;
517
518 sk_sp<SkData> data = fBufferCache->GetOrCreateSkData(id.bufferId, buffer);
519 if (!data) return nullptr;
520
521 auto result = CreateTypefaceFromSkData(std::move(data), id);
522 fTypefaceCache.add(result);
523 return result;
524 }
525
SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)526 sk_sp<SkFontMgr> SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider) {
527 return sk_make_sp<SkFontMgr_Fuchsia>(std::move(provider));
528 }
529