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