OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkFontConfigInterface.h" | 8 #include "../ports/SkFontMgr_FontConfigInterface.cpp" |
9 #include "SkFontConfigTypeface.h" | |
10 #include "SkFontDescriptor.h" | |
11 #include "SkFontMgr.h" | |
12 #include "SkFontStyle.h" | |
13 #include "SkMutex.h" | |
14 #include "SkString.h" | |
15 #include "SkTypeface.h" | |
16 #include "SkTypefaceCache.h" | |
17 #include "SkResourceCache.h" | |
18 | |
19 SkStreamAsset* SkTypeface_FCI::onOpenStream(int* ttcIndex) const { | |
20 *ttcIndex = this->getIdentity().fTTCIndex; | |
21 | |
22 SkStreamAsset* stream = this->getLocalStream(); | |
23 if (stream) { | |
24 return stream->duplicate(); | |
25 } | |
26 | |
27 return fFCI->openStream(this->getIdentity()); | |
28 } | |
29 | |
30 void SkTypeface_FCI::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalSt
ream) const { | |
31 SkString name; | |
32 this->getFamilyName(&name); | |
33 desc->setFamilyName(name.c_str()); | |
34 desc->setStyle(this->fontStyle()); | |
35 *isLocalStream = SkToBool(this->getLocalStream()); | |
36 } | |
37 | |
38 /////////////////////////////////////////////////////////////////////////////// | |
39 | |
40 class SkFontStyleSet_FCI : public SkFontStyleSet { | |
41 public: | |
42 SkFontStyleSet_FCI() {} | |
43 | |
44 int count() override { return 0; } | |
45 void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(
false); } | |
46 SkTypeface* createTypeface(int index) override { SkASSERT(false); return nul
lptr; } | |
47 SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr
; } | |
48 }; | |
49 | |
50 /////////////////////////////////////////////////////////////////////////////// | |
51 | |
52 class SkFontRequestCache { | |
53 public: | |
54 struct Request : public SkResourceCache::Key { | |
55 private: | |
56 Request(const char* name, size_t nameLen, const SkFontStyle& style) : fS
tyle(style) { | |
57 /** Pointer to just after the last field of this class. */ | |
58 char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle
)); | |
59 | |
60 // No holes. | |
61 SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + key
Size) == content); | |
62 | |
63 // Has a size divisible by size of uint32_t. | |
64 SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t
) == 0); | |
65 | |
66 size_t contentLen = SkAlign4(nameLen); | |
67 sk_careful_memcpy(content, name, nameLen); | |
68 sk_bzero(content + nameLen, contentLen - nameLen); | |
69 this->init(nullptr, 0, keySize + contentLen); | |
70 } | |
71 const SkFontStyle fStyle; | |
72 /** The sum of the sizes of the fields of this class. */ | |
73 static const size_t keySize = sizeof(fStyle); | |
74 | |
75 public: | |
76 static Request* Create(const char* name, const SkFontStyle& style) { | |
77 size_t nameLen = name ? strlen(name) : 0; | |
78 size_t contentLen = SkAlign4(nameLen); | |
79 char* storage = new char[sizeof(Request) + contentLen]; | |
80 return new (storage) Request(name, nameLen, style); | |
81 } | |
82 void operator delete(void* storage) { | |
83 delete[] reinterpret_cast<char*>(storage); | |
84 } | |
85 }; | |
86 | |
87 | |
88 private: | |
89 struct Result : public SkResourceCache::Rec { | |
90 Result(Request* request, SkTypeface* typeface) | |
91 : fRequest(request) | |
92 , fFace(SkSafeRef(typeface)) {} | |
93 Result(Result&&) = default; | |
94 Result& operator=(Result&&) = default; | |
95 | |
96 const Key& getKey() const override { return *fRequest; } | |
97 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFa
ce); } | |
98 const char* getCategory() const override { return "request_cache"; } | |
99 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { r
eturn nullptr; } | |
100 | |
101 SkAutoTDelete<Request> fRequest; | |
102 SkAutoTUnref<SkTypeface> fFace; | |
103 }; | |
104 | |
105 SkResourceCache fCachedResults; | |
106 | |
107 public: | |
108 SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} | |
109 | |
110 /** Takes ownership of request. It will be deleted when no longer needed. */ | |
111 void add(SkTypeface* face, Request* request) { | |
112 fCachedResults.add(new Result(request, face)); | |
113 } | |
114 /** Does not take ownership of request. */ | |
115 SkTypeface* findAndRef(Request* request) { | |
116 SkTypeface* face = nullptr; | |
117 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void*
context) -> bool { | |
118 const Result& result = static_cast<const Result&>(rec); | |
119 SkTypeface** face = static_cast<SkTypeface**>(context); | |
120 | |
121 *face = result.fFace; | |
122 return true; | |
123 }, &face); | |
124 return SkSafeRef(face); | |
125 } | |
126 }; | |
127 | |
128 /////////////////////////////////////////////////////////////////////////////// | |
129 | |
130 static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { | |
131 typedef SkFontConfigInterface::FontIdentity FontIdentity; | |
132 SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypefa
ce); | |
133 FontIdentity* identity = static_cast<FontIdentity*>(ctx); | |
134 | |
135 return cachedFCTypeface->getIdentity() == *identity; | |
136 } | |
137 | |
138 /////////////////////////////////////////////////////////////////////////////// | |
139 | |
140 class SkFontMgr_FCI : public SkFontMgr { | |
141 SkAutoTUnref<SkFontConfigInterface> fFCI; | |
142 SkAutoTUnref<SkDataTable> fFamilyNames; | |
143 SkTypeface_FreeType::Scanner fScanner; | |
144 | |
145 mutable SkMutex fMutex; | |
146 mutable SkTypefaceCache fTFCache; | |
147 | |
148 // The value of maxSize here is a compromise between cache hits and cache si
ze. | |
149 // See https://crbug.com/424082#63 for reason for current size. | |
150 static const size_t kMaxSize = 1 << 15; | |
151 mutable SkFontRequestCache fCache; | |
152 | |
153 public: | |
154 SkFontMgr_FCI(SkFontConfigInterface* fci) | |
155 : fFCI(fci) | |
156 , fFamilyNames(fFCI->getFamilyNames()) | |
157 , fCache(kMaxSize) | |
158 {} | |
159 | |
160 protected: | |
161 int onCountFamilies() const override { | |
162 return fFamilyNames->count(); | |
163 } | |
164 | |
165 void onGetFamilyName(int index, SkString* familyName) const override { | |
166 familyName->set(fFamilyNames->atStr(index)); | |
167 } | |
168 | |
169 SkFontStyleSet* onCreateStyleSet(int index) const override { | |
170 return this->onMatchFamily(fFamilyNames->atStr(index)); | |
171 } | |
172 | |
173 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { | |
174 return new SkFontStyleSet_FCI(); | |
175 } | |
176 | |
177 SkTypeface* onMatchFamilyStyle(const char familyName[], | |
178 const SkFontStyle&) const override { return n
ullptr; } | |
179 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFon
tStyle&, | |
180 const char* bcp47[], int bcp47Count, | |
181 SkUnichar character) const override
{ | |
182 return nullptr; | |
183 } | |
184 SkTypeface* onMatchFaceStyle(const SkTypeface*, | |
185 const SkFontStyle&) const override { return nul
lptr; } | |
186 | |
187 SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { return
nullptr; } | |
188 | |
189 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) cons
t override { | |
190 SkAutoTDelete<SkStreamAsset> stream(bareStream); | |
191 const size_t length = stream->getLength(); | |
192 if (!length) { | |
193 return nullptr; | |
194 } | |
195 if (length >= 1024 * 1024 * 1024) { | |
196 return nullptr; // don't accept too large fonts (>= 1GB) for safety
. | |
197 } | |
198 | |
199 // TODO should the caller give us the style or should we get it from fre
etype? | |
200 SkFontStyle style; | |
201 bool isFixedWidth = false; | |
202 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullpt
r)) { | |
203 return nullptr; | |
204 } | |
205 | |
206 return SkTypeface_FCI::Create(style, isFixedWidth, stream.release(), ttc
Index); | |
207 } | |
208 | |
209 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override
{ | |
210 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); | |
211 return stream.get() ? this->createFromStream(stream.release(), ttcIndex)
: nullptr; | |
212 } | |
213 | |
214 SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], | |
215 SkFontStyle requestedStyle) const overrid
e | |
216 { | |
217 SkAutoMutexAcquire ama(fMutex); | |
218 | |
219 // Check if this request is already in the request cache. | |
220 using Request = SkFontRequestCache::Request; | |
221 SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requ
estedStyle)); | |
222 SkTypeface* face = fCache.findAndRef(request); | |
223 if (face) { | |
224 return face; | |
225 } | |
226 | |
227 SkFontConfigInterface::FontIdentity identity; | |
228 SkString outFamilyName; | |
229 SkFontStyle outStyle; | |
230 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, | |
231 &identity, &outFamilyName, &outStyle)) | |
232 { | |
233 return nullptr; | |
234 } | |
235 | |
236 // Check if a typeface with this FontIdentity is already in the FontIden
tity cache. | |
237 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); | |
238 if (!face) { | |
239 face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyl
e); | |
240 // Add this FontIdentity to the FontIdentity cache. | |
241 fTFCache.add(face); | |
242 } | |
243 // Add this request to the request cache. | |
244 fCache.add(face, request.release()); | |
245 | |
246 return face; | |
247 } | |
248 }; | |
249 | |
250 SK_API SkFontMgr* SkFontMgr_New_FCI(SkFontConfigInterface* fci) { | |
251 SkASSERT(fci); | |
252 return new SkFontMgr_FCI(fci); | |
253 } | |
OLD | NEW |