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 "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 "third_party/skia/src/core/SkFontDescriptor.h"
17 #include "third_party/skia/src/ports/SkFontMgr_custom.h"
18
19 #include "SkFontMgr.h"
20 #include "SkStream.h"
21 #include "SkTypeface.h"
22 #include "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(0, data.vmo, 0, size, ZX_VM_PERM_READ, &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
79 constexpr struct {
80 const char* fName;
81 fuchsia::fonts::FallbackGroup fFallbackGroup;
82 } kFallbackGroupsByName[] = {
83 {"serif", fuchsia::fonts::FallbackGroup::SERIF},
84 {"sans", fuchsia::fonts::FallbackGroup::SANS_SERIF},
85 {"sans-serif", fuchsia::fonts::FallbackGroup::SANS_SERIF},
86 {"mono", fuchsia::fonts::FallbackGroup::MONOSPACE},
87 {"monospace", fuchsia::fonts::FallbackGroup::MONOSPACE},
88 {"cursive", fuchsia::fonts::FallbackGroup::CURSIVE},
89 {"fantasy", fuchsia::fonts::FallbackGroup::FANTASY},
90 };
91
GetFallbackGroupByName(const char * name)92 fuchsia::fonts::FallbackGroup GetFallbackGroupByName(const char* name) {
93 if (!name) return fuchsia::fonts::FallbackGroup::NONE;
94 for (auto& group : kFallbackGroupsByName) {
95 if (strcasecmp(group.fName, name) == 0) {
96 return group.fFallbackGroup;
97 }
98 }
99 return fuchsia::fonts::FallbackGroup::NONE;
100 }
101
102 struct TypefaceId {
103 uint32_t bufferId;
104 uint32_t ttcIndex;
105
operator ==TypefaceId106 bool operator==(TypefaceId& other) {
107 return std::tie(bufferId, ttcIndex) == std::tie(other.bufferId, other.ttcIndex);
108 }
109 }
110
111 constexpr kNullTypefaceId = {0xFFFFFFFF, 0xFFFFFFFF};
112
113 class SkTypeface_Fuchsia : public SkTypeface_Stream {
114 public:
SkTypeface_Fuchsia(std::unique_ptr<SkFontData> fontData,const SkFontStyle & style,bool isFixedPitch,const SkString familyName,TypefaceId id)115 SkTypeface_Fuchsia(std::unique_ptr<SkFontData> fontData, const SkFontStyle& style,
116 bool isFixedPitch, const SkString familyName, TypefaceId id)
117 : SkTypeface_Stream(std::move(fontData), style, isFixedPitch,
118 /*sys_font=*/true, familyName)
119 , fId(id) {}
120
id()121 TypefaceId id() { return fId; }
122
123 private:
124 TypefaceId fId;
125 };
126
CreateTypefaceFromSkStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args,TypefaceId id)127 sk_sp<SkTypeface> CreateTypefaceFromSkStream(std::unique_ptr<SkStreamAsset> stream,
128 const SkFontArguments& args, TypefaceId id) {
129 using Scanner = SkTypeface_FreeType::Scanner;
130 Scanner scanner;
131 bool isFixedPitch;
132 SkFontStyle style;
133 SkString name;
134 Scanner::AxisDefinitions axisDefinitions;
135 if (!scanner.scanFont(stream.get(), args.getCollectionIndex(), &name, &style, &isFixedPitch,
136 &axisDefinitions)) {
137 return nullptr;
138 }
139
140 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
141 SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
142 Scanner::computeAxisValues(axisDefinitions, position, axisValues, name);
143
144 auto fontData = std::make_unique<SkFontData>(std::move(stream), args.getCollectionIndex(),
145 axisValues.get(), axisDefinitions.count());
146 return sk_make_sp<SkTypeface_Fuchsia>(std::move(fontData), style, isFixedPitch, name, id);
147 }
148
CreateTypefaceFromSkData(sk_sp<SkData> data,TypefaceId id)149 sk_sp<SkTypeface> CreateTypefaceFromSkData(sk_sp<SkData> data, TypefaceId id) {
150 return CreateTypefaceFromSkStream(std::make_unique<SkMemoryStream>(std::move(data)),
151 SkFontArguments().setCollectionIndex(id.ttcIndex), id);
152 }
153
154 class SkFontMgr_Fuchsia final : public SkFontMgr {
155 public:
156 SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider);
157 ~SkFontMgr_Fuchsia() override;
158
159 protected:
160 // SkFontMgr overrides.
161 int onCountFamilies() const override;
162 void onGetFamilyName(int index, SkString* familyName) const override;
163 SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
164 SkFontStyleSet* onCreateStyleSet(int index) const override;
165 SkTypeface* onMatchFamilyStyle(const char familyName[], const SkFontStyle&) const override;
166 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
167 const char* bcp47[], int bcp47Count,
168 SkUnichar character) const override;
169 SkTypeface* onMatchFaceStyle(const SkTypeface*, const SkFontStyle&) const override;
170 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
171 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
172 int ttcIndex) const override;
173 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
174 const SkFontArguments&) const override;
175 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
176 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
177
178 private:
179 friend class SkFontStyleSet_Fuchsia;
180
181 sk_sp<SkTypeface> FetchTypeface(const char familyName[], const SkFontStyle& style,
182 const char* bcp47[], int bcp47Count, SkUnichar character,
183 bool allow_fallback, bool exact_style_match) const;
184
185 sk_sp<SkData> GetOrCreateSkData(int bufferId, const fuchsia::mem::Buffer& buffer) const;
186 void OnSkDataDeleted(int bufferId) const;
187
188 sk_sp<SkTypeface> GetOrCreateTypeface(TypefaceId id, const fuchsia::mem::Buffer& buffer) const;
189
190 mutable fuchsia::fonts::ProviderSyncPtr fFontProvider;
191
192 mutable SkMutex fCacheMutex;
193
194 // Must be accessed only with fCacheMutex acquired.
195 mutable std::unordered_map<int, SkData*> fBufferCache;
196 mutable SkTypefaceCache fTypefaceCache;
197 };
198
199 class SkFontStyleSet_Fuchsia : public SkFontStyleSet {
200 public:
SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager,std::string familyName,std::vector<SkFontStyle> styles)201 SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager, std::string familyName,
202 std::vector<SkFontStyle> styles)
203 : fFontManager(font_manager), fFamilyName(familyName), fStyles(styles) {}
204
205 ~SkFontStyleSet_Fuchsia() override = default;
206
count()207 int count() override { return fStyles.size(); }
208
getStyle(int index,SkFontStyle * style,SkString * styleName)209 void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
210 SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
211 if (style) *style = fStyles[index];
212
213 // We don't have style names. Return an empty name.
214 if (styleName) styleName->reset();
215 }
216
createTypeface(int index)217 SkTypeface* createTypeface(int index) override {
218 SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
219
220 if (fTypefaces.empty()) fTypefaces.resize(fStyles.size());
221
222 if (!fTypefaces[index]) {
223 fTypefaces[index] = fFontManager->FetchTypeface(
224 fFamilyName.c_str(), fStyles[index], /*bcp47=*/nullptr,
225 /*bcp47Count=*/0, /*character=*/0,
226 /*allow_fallback=*/false, /*exact_style_match=*/true);
227 }
228
229 return SkSafeRef(fTypefaces[index].get());
230 }
231
matchStyle(const SkFontStyle & pattern)232 SkTypeface* matchStyle(const SkFontStyle& pattern) override { return matchStyleCSS3(pattern); }
233
234 private:
235 sk_sp<SkFontMgr_Fuchsia> fFontManager;
236 std::string fFamilyName;
237 std::vector<SkFontStyle> fStyles;
238 std::vector<sk_sp<SkTypeface>> fTypefaces;
239 };
240
SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)241 SkFontMgr_Fuchsia::SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)
242 : fFontProvider(std::move(provider)) {}
243
244 SkFontMgr_Fuchsia::~SkFontMgr_Fuchsia() = default;
245
onCountFamilies() const246 int SkFontMgr_Fuchsia::onCountFamilies() const {
247 // Family enumeration is not supported.
248 return 0;
249 }
250
onGetFamilyName(int index,SkString * familyName) const251 void SkFontMgr_Fuchsia::onGetFamilyName(int index, SkString* familyName) const {
252 // Family enumeration is not supported.
253 familyName->reset();
254 }
255
onCreateStyleSet(int index) const256 SkFontStyleSet* SkFontMgr_Fuchsia::onCreateStyleSet(int index) const {
257 // Family enumeration is not supported.
258 return nullptr;
259 }
260
onMatchFamily(const char familyName[]) const261 SkFontStyleSet* SkFontMgr_Fuchsia::onMatchFamily(const char familyName[]) const {
262 fuchsia::fonts::FamilyInfoPtr familyInfo;
263 int result = fFontProvider->GetFamilyInfo(familyName, &familyInfo);
264 if (result != ZX_OK || !familyInfo) return nullptr;
265
266 std::vector<SkFontStyle> styles;
267 #ifdef USE_STD_FOR_NON_NULLABLE_FIDL_FIELDS
268 for (auto& style : familyInfo->styles) {
269 #else
270 for (auto& style : *(familyInfo->styles)) {
271 #endif
272 styles.push_back(SkFontStyle(style.weight, style.width, FuchsiaToSkSlant(style.slant)));
273 }
274
275 return new SkFontStyleSet_Fuchsia(sk_ref_sp(this), familyInfo->name, std::move(styles));
276 }
277
278 SkTypeface* SkFontMgr_Fuchsia::onMatchFamilyStyle(const char familyName[],
279 const SkFontStyle& style) const {
280 sk_sp<SkTypeface> typeface =
281 FetchTypeface(familyName, style, /*bcp47=*/nullptr,
282 /*bcp47Count=*/0, /*character=*/0,
283 /*allow_fallback=*/false, /*exact_style_match=*/false);
284 return typeface.release();
285 }
286
287 SkTypeface* SkFontMgr_Fuchsia::onMatchFamilyStyleCharacter(const char familyName[],
288 const SkFontStyle& style,
289 const char* bcp47[], int bcp47Count,
290 SkUnichar character) const {
291 sk_sp<SkTypeface> typeface =
292 FetchTypeface(familyName, style, bcp47, bcp47Count, character, /*allow_fallback=*/true,
293 /*exact_style_match=*/false);
294 return typeface.release();
295 }
296
297 SkTypeface* SkFontMgr_Fuchsia::onMatchFaceStyle(const SkTypeface*, const SkFontStyle&) const {
298 return nullptr;
299 }
300
301 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromData(sk_sp<SkData>, int ttcIndex) const {
302 SkASSERT(false);
303 return nullptr;
304 }
305
306 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> asset,
307 int ttcIndex) const {
308 return makeFromStream(std::move(asset), SkFontArguments().setCollectionIndex(ttcIndex));
309 }
310
311 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> asset,
312 const SkFontArguments& args) const {
313 return CreateTypefaceFromSkStream(std::move(asset), args, kNullTypefaceId);
314 }
315
316 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromFile(const char path[], int ttcIndex) const {
317 return makeFromStream(std::make_unique<SkFILEStream>(path), ttcIndex);
318 }
319
320 sk_sp<SkTypeface> SkFontMgr_Fuchsia::onLegacyMakeTypeface(const char familyName[],
321 SkFontStyle style) const {
322 return sk_sp<SkTypeface>(matchFamilyStyle(familyName, style));
323 }
324
325 sk_sp<SkTypeface> SkFontMgr_Fuchsia::FetchTypeface(const char familyName[],
326 const SkFontStyle& style, const char* bcp47[],
327 int bcp47Count, SkUnichar character,
328 bool allow_fallback,
329 bool exact_style_match) const {
330 fuchsia::fonts::Request request;
331 request.weight = style.weight();
332 request.width = style.width();
333 request.slant = SkToFuchsiaSlant(style.slant());
334 #ifdef USE_STD_FOR_NON_NULLABLE_FIDL_FIELDS
335 request.language.reset(std::vector<std::string>(bcp47, bcp47 + bcp47Count));
336 #else
337 request.language.reset(std::vector<fidl::StringPtr>(bcp47, bcp47 + bcp47Count));
338 #endif
339 request.character = character;
340 request.fallback_group = GetFallbackGroupByName(familyName);
341
342 // If family name is not specified or it is a generic fallback group name (e.g. "serif") then
343 // enable fallback, otherwise pass the family name as is.
344 if (!familyName || *familyName == '\0' ||
345 request.fallback_group != fuchsia::fonts::FallbackGroup::NONE) {
346 request.family = "";
347 allow_fallback = true;
348 } else {
349 request.family = familyName;
350 }
351
352 request.flags = 0;
353 if (!allow_fallback) request.flags |= fuchsia::fonts::REQUEST_FLAG_NO_FALLBACK;
354 if (exact_style_match) request.flags |= fuchsia::fonts::REQUEST_FLAG_EXACT_MATCH;
355
356 fuchsia::fonts::ResponsePtr response;
357 int result = fFontProvider->GetFont(std::move(request), &response);
358 if (result != ZX_OK) return nullptr;
359
360 // The service may return null response if there is no font matching the request.
361 if (!response) return nullptr;
362
363 return GetOrCreateTypeface(TypefaceId{response->buffer_id, response->font_index},
364 response->buffer);
365 }
366
367 sk_sp<SkData> SkFontMgr_Fuchsia::GetOrCreateSkData(int bufferId,
368 const fuchsia::mem::Buffer& buffer) const {
369 fCacheMutex.assertHeld();
370
371 auto iter = fBufferCache.find(bufferId);
372 if (iter != fBufferCache.end()) {
373 return sk_ref_sp(iter->second);
374 }
375 auto font_mgr = sk_ref_sp(this);
376 auto data = MakeSkDataFromBuffer(buffer,
377 [font_mgr, bufferId]() { font_mgr->OnSkDataDeleted(bufferId); });
378 if (!data) {
379 return nullptr;
380 }
381 fBufferCache[bufferId] = data.get();
382 return data;
383 }
384
385 void SkFontMgr_Fuchsia::OnSkDataDeleted(int bufferId) const {
386 SK_UNUSED bool wasFound = fBufferCache.erase(bufferId) != 0;
387 SkASSERT(wasFound);
388 }
389
390 static bool FindByTypefaceId(SkTypeface* cachedTypeface, void* ctx) {
391 SkTypeface_Fuchsia* cachedFuchsiaTypeface = static_cast<SkTypeface_Fuchsia*>(cachedTypeface);
392 TypefaceId* id = static_cast<TypefaceId*>(ctx);
393
394 return cachedFuchsiaTypeface->id() == *id;
395 }
396
397 sk_sp<SkTypeface> SkFontMgr_Fuchsia::GetOrCreateTypeface(TypefaceId id,
398 const fuchsia::mem::Buffer& buffer) const {
399 SkAutoMutexAcquire mutexLock(fCacheMutex);
400
401 SkTypeface* cached = fTypefaceCache.findByProcAndRef(FindByTypefaceId, &id);
402 if (cached) return sk_sp<SkTypeface>(cached);
403
404 sk_sp<SkData> data = GetOrCreateSkData(id.bufferId, buffer);
405 if (!data) return nullptr;
406
407 auto result = CreateTypefaceFromSkData(std::move(data), id);
408 fTypefaceCache.add(result.get());
409 return result;
410 }
411
412 SK_API sk_sp<SkFontMgr> SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider) {
413 return sk_make_sp<SkFontMgr_Fuchsia>(std::move(provider));
414 }
415