1 | /* |
2 | * Copyright 2013 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/core/SkFontMgr.h" |
9 | #include "include/core/SkFontStyle.h" |
10 | #include "include/core/SkString.h" |
11 | #include "include/core/SkTypeface.h" |
12 | #include "include/ports/SkFontConfigInterface.h" |
13 | #include "include/ports/SkFontMgr_FontConfigInterface.h" |
14 | #include "include/private/SkMutex.h" |
15 | #include "src/core/SkFontDescriptor.h" |
16 | #include "src/core/SkResourceCache.h" |
17 | #include "src/core/SkTypefaceCache.h" |
18 | #include "src/ports/SkFontConfigTypeface.h" |
19 | #include <new> |
20 | |
21 | std::unique_ptr<SkStreamAsset> SkTypeface_FCI::onOpenStream(int* ttcIndex) const { |
22 | *ttcIndex = this->getIdentity().fTTCIndex; |
23 | |
24 | if (fFontData) { |
25 | SkStreamAsset* stream = fFontData->getStream(); |
26 | if (!stream) { |
27 | return nullptr; |
28 | } |
29 | return stream->duplicate(); |
30 | } |
31 | |
32 | return std::unique_ptr<SkStreamAsset>(fFCI->openStream(this->getIdentity())); |
33 | } |
34 | |
35 | std::unique_ptr<SkFontData> SkTypeface_FCI::onMakeFontData() const { |
36 | if (fFontData) { |
37 | return std::make_unique<SkFontData>(*fFontData); |
38 | } |
39 | |
40 | const SkFontConfigInterface::FontIdentity& id = this->getIdentity(); |
41 | return std::make_unique<SkFontData>(std::unique_ptr<SkStreamAsset>(fFCI->openStream(id)), |
42 | id.fTTCIndex, nullptr, 0); |
43 | } |
44 | |
45 | void SkTypeface_FCI::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalStream) const { |
46 | SkString name; |
47 | this->getFamilyName(&name); |
48 | desc->setFamilyName(name.c_str()); |
49 | desc->setStyle(this->fontStyle()); |
50 | *isLocalStream = SkToBool(fFontData); |
51 | } |
52 | |
53 | /////////////////////////////////////////////////////////////////////////////// |
54 | |
55 | class SkFontStyleSet_FCI : public SkFontStyleSet { |
56 | public: |
57 | SkFontStyleSet_FCI() {} |
58 | |
59 | int count() override { return 0; } |
60 | void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(false); } |
61 | SkTypeface* createTypeface(int index) override { SkASSERT(false); return nullptr; } |
62 | SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr; } |
63 | }; |
64 | |
65 | /////////////////////////////////////////////////////////////////////////////// |
66 | |
67 | class SkFontRequestCache { |
68 | public: |
69 | struct Request : public SkResourceCache::Key { |
70 | private: |
71 | Request(const char* name, size_t nameLen, const SkFontStyle& style) : fStyle(style) { |
72 | /** Pointer to just after the last field of this class. */ |
73 | char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle)); |
74 | |
75 | // No holes. |
76 | SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + keySize) == content); |
77 | |
78 | // Has a size divisible by size of uint32_t. |
79 | SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t) == 0); |
80 | |
81 | size_t contentLen = SkAlign4(nameLen); |
82 | sk_careful_memcpy(content, name, nameLen); |
83 | sk_bzero(content + nameLen, contentLen - nameLen); |
84 | this->init(nullptr, 0, keySize + contentLen); |
85 | } |
86 | const SkFontStyle fStyle; |
87 | /** The sum of the sizes of the fields of this class. */ |
88 | static const size_t keySize = sizeof(fStyle); |
89 | |
90 | public: |
91 | static Request* Create(const char* name, const SkFontStyle& style) { |
92 | size_t nameLen = name ? strlen(name) : 0; |
93 | size_t contentLen = SkAlign4(nameLen); |
94 | char* storage = new char[sizeof(Request) + contentLen]; |
95 | return new (storage) Request(name, nameLen, style); |
96 | } |
97 | void operator delete(void* storage) { |
98 | delete[] reinterpret_cast<char*>(storage); |
99 | } |
100 | }; |
101 | |
102 | |
103 | private: |
104 | struct Result : public SkResourceCache::Rec { |
105 | Result(Request* request, sk_sp<SkTypeface> typeface) |
106 | : fRequest(request), fFace(std::move(typeface)) {} |
107 | Result(Result&&) = default; |
108 | Result& operator=(Result&&) = default; |
109 | |
110 | const Key& getKey() const override { return *fRequest; } |
111 | size_t bytesUsed() const override { return fRequest->size() + sizeof(fFace); } |
112 | const char* getCategory() const override { return "request_cache" ; } |
113 | SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } |
114 | |
115 | std::unique_ptr<Request> fRequest; |
116 | sk_sp<SkTypeface> fFace; |
117 | }; |
118 | |
119 | SkResourceCache fCachedResults; |
120 | |
121 | public: |
122 | SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} |
123 | |
124 | /** Takes ownership of request. It will be deleted when no longer needed. */ |
125 | void add(sk_sp<SkTypeface> face, Request* request) { |
126 | fCachedResults.add(new Result(request, std::move(face))); |
127 | } |
128 | /** Does not take ownership of request. */ |
129 | sk_sp<SkTypeface> findAndRef(Request* request) { |
130 | sk_sp<SkTypeface> face; |
131 | fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void* context) -> bool { |
132 | const Result& result = static_cast<const Result&>(rec); |
133 | sk_sp<SkTypeface>* face = static_cast<sk_sp<SkTypeface>*>(context); |
134 | |
135 | *face = result.fFace; |
136 | return true; |
137 | }, &face); |
138 | return face; |
139 | } |
140 | }; |
141 | |
142 | /////////////////////////////////////////////////////////////////////////////// |
143 | |
144 | static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { |
145 | typedef SkFontConfigInterface::FontIdentity FontIdentity; |
146 | SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypeface); |
147 | FontIdentity* identity = static_cast<FontIdentity*>(ctx); |
148 | |
149 | return cachedFCTypeface->getIdentity() == *identity; |
150 | } |
151 | |
152 | /////////////////////////////////////////////////////////////////////////////// |
153 | |
154 | class SkFontMgr_FCI : public SkFontMgr { |
155 | sk_sp<SkFontConfigInterface> fFCI; |
156 | SkTypeface_FreeType::Scanner fScanner; |
157 | |
158 | mutable SkMutex fMutex; |
159 | mutable SkTypefaceCache fTFCache; |
160 | |
161 | // The value of maxSize here is a compromise between cache hits and cache size. |
162 | // See https://crbug.com/424082#63 for reason for current size. |
163 | static const size_t kMaxSize = 1 << 15; |
164 | mutable SkFontRequestCache fCache; |
165 | |
166 | public: |
167 | SkFontMgr_FCI(sk_sp<SkFontConfigInterface> fci) |
168 | : fFCI(std::move(fci)) |
169 | , fCache(kMaxSize) |
170 | {} |
171 | |
172 | protected: |
173 | int onCountFamilies() const override { |
174 | SK_ABORT("Not implemented." ); |
175 | } |
176 | |
177 | void onGetFamilyName(int index, SkString* familyName) const override { |
178 | SK_ABORT("Not implemented." ); |
179 | } |
180 | |
181 | SkFontStyleSet* onCreateStyleSet(int index) const override { |
182 | SK_ABORT("Not implemented." ); |
183 | } |
184 | |
185 | SkFontStyleSet* onMatchFamily(const char familyName[]) const override { |
186 | SK_ABORT("Not implemented." ); |
187 | } |
188 | |
189 | SkTypeface* onMatchFamilyStyle(const char requestedFamilyName[], |
190 | const SkFontStyle& requestedStyle) const override |
191 | { |
192 | SkAutoMutexExclusive ama(fMutex); |
193 | |
194 | SkFontConfigInterface::FontIdentity identity; |
195 | SkString outFamilyName; |
196 | SkFontStyle outStyle; |
197 | if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, |
198 | &identity, &outFamilyName, &outStyle)) |
199 | { |
200 | return nullptr; |
201 | } |
202 | |
203 | // Check if a typeface with this FontIdentity is already in the FontIdentity cache. |
204 | sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); |
205 | if (!face) { |
206 | face.reset(SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle)); |
207 | // Add this FontIdentity to the FontIdentity cache. |
208 | fTFCache.add(face); |
209 | } |
210 | return face.release(); |
211 | } |
212 | |
213 | SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, |
214 | const char* bcp47[], int bcp47Count, |
215 | SkUnichar character) const override { |
216 | SK_ABORT("Not implemented." ); |
217 | } |
218 | |
219 | SkTypeface* onMatchFaceStyle(const SkTypeface*, const SkFontStyle&) const override { |
220 | SK_ABORT("Not implemented." ); |
221 | } |
222 | |
223 | sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override { |
224 | return this->onMakeFromStreamIndex(SkMemoryStream::Make(std::move(data)), ttcIndex); |
225 | } |
226 | |
227 | sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, |
228 | int ttcIndex) const override { |
229 | const size_t length = stream->getLength(); |
230 | if (!length) { |
231 | return nullptr; |
232 | } |
233 | if (length >= 1024 * 1024 * 1024) { |
234 | return nullptr; // don't accept too large fonts (>= 1GB) for safety. |
235 | } |
236 | |
237 | // TODO should the caller give us the style or should we get it from freetype? |
238 | SkString name; |
239 | SkFontStyle style; |
240 | bool isFixedPitch = false; |
241 | if (!fScanner.scanFont(stream.get(), 0, &name, &style, &isFixedPitch, nullptr)) { |
242 | return nullptr; |
243 | } |
244 | |
245 | auto fontData = std::make_unique<SkFontData>(std::move(stream), ttcIndex, nullptr, 0); |
246 | return sk_sp<SkTypeface>(SkTypeface_FCI::Create(std::move(fontData), std::move(name), |
247 | style, isFixedPitch)); |
248 | } |
249 | |
250 | sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream, |
251 | const SkFontArguments& args) const override { |
252 | using Scanner = SkTypeface_FreeType::Scanner; |
253 | const size_t length = stream->getLength(); |
254 | if (!length) { |
255 | return nullptr; |
256 | } |
257 | if (length >= 1024 * 1024 * 1024) { |
258 | return nullptr; // don't accept too large fonts (>= 1GB) for safety. |
259 | } |
260 | |
261 | bool isFixedPitch; |
262 | SkFontStyle style; |
263 | SkString name; |
264 | Scanner::AxisDefinitions axisDefinitions; |
265 | if (!fScanner.scanFont(stream.get(), args.getCollectionIndex(), |
266 | &name, &style, &isFixedPitch, &axisDefinitions)) |
267 | { |
268 | return nullptr; |
269 | } |
270 | |
271 | SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); |
272 | Scanner::computeAxisValues(axisDefinitions, args.getVariationDesignPosition(), |
273 | axisValues, name); |
274 | |
275 | auto fontData = std::make_unique<SkFontData>(std::move(stream), |
276 | args.getCollectionIndex(), |
277 | axisValues.get(), |
278 | axisDefinitions.count()); |
279 | return sk_sp<SkTypeface>(SkTypeface_FCI::Create(std::move(fontData), std::move(name), |
280 | style, isFixedPitch)); |
281 | } |
282 | |
283 | sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override { |
284 | std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path); |
285 | return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr; |
286 | } |
287 | |
288 | sk_sp<SkTypeface> onLegacyMakeTypeface(const char requestedFamilyName[], |
289 | SkFontStyle requestedStyle) const override |
290 | { |
291 | SkAutoMutexExclusive ama(fMutex); |
292 | |
293 | // Check if this request is already in the request cache. |
294 | using Request = SkFontRequestCache::Request; |
295 | std::unique_ptr<Request> request(Request::Create(requestedFamilyName, requestedStyle)); |
296 | sk_sp<SkTypeface> face = fCache.findAndRef(request.get()); |
297 | if (face) { |
298 | return sk_sp<SkTypeface>(face); |
299 | } |
300 | |
301 | SkFontConfigInterface::FontIdentity identity; |
302 | SkString outFamilyName; |
303 | SkFontStyle outStyle; |
304 | if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, |
305 | &identity, &outFamilyName, &outStyle)) |
306 | { |
307 | return nullptr; |
308 | } |
309 | |
310 | // Check if a typeface with this FontIdentity is already in the FontIdentity cache. |
311 | face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); |
312 | if (!face) { |
313 | face.reset(SkTypeface_FCI::Create(fFCI, identity, std::move(outFamilyName), outStyle)); |
314 | // Add this FontIdentity to the FontIdentity cache. |
315 | fTFCache.add(face); |
316 | } |
317 | // Add this request to the request cache. |
318 | fCache.add(face, request.release()); |
319 | |
320 | return face; |
321 | } |
322 | }; |
323 | |
324 | SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci) { |
325 | SkASSERT(fci); |
326 | return sk_make_sp<SkFontMgr_FCI>(std::move(fci)); |
327 | } |
328 | |