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 "SkFontConfigInterface.h" |
9 #include "SkFontConfigTypeface.h" | 9 #include "SkFontConfigTypeface.h" |
| 10 #include "SkFontDescriptor.h" |
10 #include "SkFontMgr.h" | 11 #include "SkFontMgr.h" |
11 #include "SkFontStyle.h" | 12 #include "SkFontStyle.h" |
12 #include "SkMath.h" | |
13 #include "SkMutex.h" | 13 #include "SkMutex.h" |
14 #include "SkString.h" | 14 #include "SkString.h" |
15 #include "SkTDArray.h" | 15 #include "SkTypeface.h" |
| 16 #include "SkTypefaceCache.h" |
| 17 #include "SkResourceCache.h" |
16 | 18 |
17 // for now we pull these in directly. eventually we will solely rely on the | 19 SkStreamAsset* SkTypeface_FCI::onOpenStream(int* ttcIndex) const { |
18 // SkFontConfigInterface instance. | 20 *ttcIndex = this->getIdentity().fTTCIndex; |
19 #include <fontconfig/fontconfig.h> | |
20 #include <unistd.h> | |
21 | 21 |
22 namespace { | 22 SkStreamAsset* stream = this->getLocalStream(); |
23 | 23 if (stream) { |
24 // Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a glo
bal mutex. | 24 return stream->duplicate(); |
25 // See skia:1497 for background. | |
26 SK_DECLARE_STATIC_MUTEX(gFCMutex); | |
27 static bool gFCSafeToUse; | |
28 | |
29 struct FCLocker { | |
30 FCLocker() { | |
31 if (FcGetVersion() < 21091) { // We assume FcGetVersion() has always be
en thread safe. | |
32 gFCMutex.acquire(); | |
33 fUnlock = true; | |
34 } else { | |
35 fUnlock = false; | |
36 } | |
37 gFCSafeToUse = true; | |
38 } | 25 } |
39 | 26 |
40 ~FCLocker() { | 27 return fFCI->openStream(this->getIdentity()); |
41 if (fUnlock) { | 28 } |
42 gFCSafeToUse = false; | 29 |
43 gFCMutex.release(); | 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 *isLocalStream = SkToBool(this->getLocalStream()); |
| 35 } |
| 36 |
| 37 /////////////////////////////////////////////////////////////////////////////// |
| 38 |
| 39 class SkFontStyleSet_FCI : public SkFontStyleSet { |
| 40 public: |
| 41 SkFontStyleSet_FCI() {} |
| 42 |
| 43 int count() override { return 0; } |
| 44 void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(
false); } |
| 45 SkTypeface* createTypeface(int index) override { SkASSERT(false); return nul
lptr; } |
| 46 SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr
; } |
| 47 }; |
| 48 |
| 49 /////////////////////////////////////////////////////////////////////////////// |
| 50 |
| 51 class SkFontRequestCache { |
| 52 public: |
| 53 struct Request : public SkResourceCache::Key { |
| 54 private: |
| 55 Request(const char* name, size_t nameLen, const SkFontStyle& style) : fS
tyle(style) { |
| 56 /** Pointer to just after the last field of this class. */ |
| 57 char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle
)); |
| 58 |
| 59 // No holes. |
| 60 SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + key
Size) == content); |
| 61 |
| 62 // Has a size divisible by size of uint32_t. |
| 63 SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t
) == 0); |
| 64 |
| 65 size_t contentLen = SkAlign4(nameLen); |
| 66 sk_careful_memcpy(content, name, nameLen); |
| 67 sk_bzero(content + nameLen, contentLen - nameLen); |
| 68 this->init(nullptr, 0, keySize + contentLen); |
44 } | 69 } |
45 } | 70 const SkFontStyle fStyle; |
| 71 /** The sum of the sizes of the fields of this class. */ |
| 72 static const size_t keySize = sizeof(fStyle); |
| 73 |
| 74 public: |
| 75 static Request* Create(const char* name, const SkFontStyle& style) { |
| 76 size_t nameLen = name ? strlen(name) : 0; |
| 77 size_t contentLen = SkAlign4(nameLen); |
| 78 char* storage = new char[sizeof(Request) + contentLen]; |
| 79 return new (storage) Request(name, nameLen, style); |
| 80 } |
| 81 void operator delete(void* storage) { |
| 82 delete[] reinterpret_cast<char*>(storage); |
| 83 } |
| 84 }; |
| 85 |
46 | 86 |
47 private: | 87 private: |
48 bool fUnlock; | 88 struct Result : public SkResourceCache::Rec { |
| 89 Result(Request* request, SkTypeface* typeface) |
| 90 : fRequest(request) |
| 91 , fFace(SkSafeRef(typeface)) {} |
| 92 Result(Result&&) = default; |
| 93 Result& operator=(Result&&) = default; |
| 94 |
| 95 const Key& getKey() const override { return *fRequest; } |
| 96 size_t bytesUsed() const override { return fRequest->size() + sizeof(fFa
ce); } |
| 97 const char* getCategory() const override { return "request_cache"; } |
| 98 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { r
eturn nullptr; } |
| 99 |
| 100 SkAutoTDelete<Request> fRequest; |
| 101 SkAutoTUnref<SkTypeface> fFace; |
| 102 }; |
| 103 |
| 104 SkResourceCache fCachedResults; |
| 105 |
| 106 public: |
| 107 SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} |
| 108 |
| 109 /** Takes ownership of request. It will be deleted when no longer needed. */ |
| 110 void add(SkTypeface* face, Request* request) { |
| 111 fCachedResults.add(new Result(request, face)); |
| 112 } |
| 113 /** Does not take ownership of request. */ |
| 114 SkTypeface* findAndRef(Request* request) { |
| 115 SkTypeface* face = nullptr; |
| 116 fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void*
context) -> bool { |
| 117 const Result& result = static_cast<const Result&>(rec); |
| 118 SkTypeface** face = static_cast<SkTypeface**>(context); |
| 119 |
| 120 *face = result.fFace; |
| 121 return true; |
| 122 }, &face); |
| 123 return SkSafeRef(face); |
| 124 } |
49 }; | 125 }; |
50 | 126 |
51 } // namespace | 127 /////////////////////////////////////////////////////////////////////////////// |
52 | 128 |
53 // borrow this global from SkFontHost_fontconfig. eventually that file should | 129 static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { |
54 // go away, and be replaced with this one. | 130 typedef SkFontConfigInterface::FontIdentity FontIdentity; |
55 extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); | 131 SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypefa
ce); |
56 static SkFontConfigInterface* RefFCI() { | 132 FontIdentity* identity = static_cast<FontIdentity*>(ctx); |
57 return SkFontHost_fontconfig_ref_global(); | 133 |
| 134 return cachedFCTypeface->getIdentity() == *identity; |
58 } | 135 } |
59 | 136 |
60 // look for the last substring after a '/' and return that, or return null. | 137 /////////////////////////////////////////////////////////////////////////////// |
61 static const char* find_just_name(const char* str) { | |
62 const char* last = strrchr(str, '/'); | |
63 return last ? last + 1 : nullptr; | |
64 } | |
65 | 138 |
66 static bool is_lower(char c) { | 139 class SkFontMgr_FCI : public SkFontMgr { |
67 return c >= 'a' && c <= 'z'; | |
68 } | |
69 | |
70 static int get_int(FcPattern* pattern, const char field[]) { | |
71 SkASSERT(gFCSafeToUse); | |
72 int value; | |
73 if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) { | |
74 value = SK_MinS32; | |
75 } | |
76 return value; | |
77 } | |
78 | |
79 static const char* get_name(FcPattern* pattern, const char field[]) { | |
80 SkASSERT(gFCSafeToUse); | |
81 const char* name; | |
82 if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch
) { | |
83 name = ""; | |
84 } | |
85 return name; | |
86 } | |
87 | |
88 static bool valid_pattern(FcPattern* pattern) { | |
89 SkASSERT(gFCSafeToUse); | |
90 FcBool is_scalable; | |
91 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
|| !is_scalable) { | |
92 return false; | |
93 } | |
94 | |
95 // fontconfig can also return fonts which are unreadable | |
96 const char* c_filename = get_name(pattern, FC_FILE); | |
97 if (0 == *c_filename) { | |
98 return false; | |
99 } | |
100 if (access(c_filename, R_OK) != 0) { | |
101 return false; | |
102 } | |
103 return true; | |
104 } | |
105 | |
106 static bool match_name(FcPattern* pattern, const char family_name[]) { | |
107 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); | |
108 } | |
109 | |
110 static FcPattern** MatchFont(FcFontSet* font_set, | |
111 const char post_config_family[], | |
112 int* count) { | |
113 // Older versions of fontconfig have a bug where they cannot select | |
114 // only scalable fonts so we have to manually filter the results. | |
115 | |
116 FcPattern** iter = font_set->fonts; | |
117 FcPattern** stop = iter + font_set->nfont; | |
118 // find the first good match | |
119 for (; iter < stop; ++iter) { | |
120 if (valid_pattern(*iter)) { | |
121 break; | |
122 } | |
123 } | |
124 | |
125 if (iter == stop || !match_name(*iter, post_config_family)) { | |
126 return nullptr; | |
127 } | |
128 | |
129 FcPattern** firstIter = iter++; | |
130 for (; iter < stop; ++iter) { | |
131 if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) { | |
132 break; | |
133 } | |
134 } | |
135 | |
136 *count = iter - firstIter; | |
137 return firstIter; | |
138 } | |
139 | |
140 class SkFontStyleSet_FC : public SkFontStyleSet { | |
141 public: | |
142 SkFontStyleSet_FC(FcPattern** matches, int count); | |
143 virtual ~SkFontStyleSet_FC(); | |
144 | |
145 int count() override { return fRecCount; } | |
146 void getStyle(int index, SkFontStyle*, SkString* style) override; | |
147 SkTypeface* createTypeface(int index) override; | |
148 SkTypeface* matchStyle(const SkFontStyle& pattern) override; | |
149 | |
150 private: | |
151 struct Rec { | |
152 SkString fStyleName; | |
153 SkString fFileName; | |
154 SkFontStyle fStyle; | |
155 }; | |
156 Rec* fRecs; | |
157 int fRecCount; | |
158 }; | |
159 | |
160 static int map_range(int value, | |
161 int old_min, int old_max, int new_min, int new_max) { | |
162 SkASSERT(old_min < old_max); | |
163 SkASSERT(new_min < new_max); | |
164 return new_min + SkMulDiv(value - old_min, | |
165 new_max - new_min, old_max - old_min); | |
166 } | |
167 | |
168 static SkFontStyle make_fontconfig_style(FcPattern* match) { | |
169 int weight = get_int(match, FC_WEIGHT); | |
170 int width = get_int(match, FC_WIDTH); | |
171 int fcSlant = get_int(match, FC_SLANT); | |
172 | |
173 // fontconfig weight seems to be 0..200 or so, so we remap it here | |
174 weight = map_range(weight, 0, 80, 0, 400); | |
175 width = map_range(width, 0, 200, 0, 9); | |
176 SkFontStyle::Slant skSlant = SkFontStyle::kUpright_Slant; | |
177 switch (fcSlant) { | |
178 case FC_SLANT_ROMAN: skSlant = SkFontStyle::kUpright_Slant; break; | |
179 case FC_SLANT_ITALIC : skSlant = SkFontStyle::kItalic_Slant ; break; | |
180 case FC_SLANT_OBLIQUE: skSlant = SkFontStyle::kOblique_Slant; break; | |
181 default: SkASSERT(false); break; | |
182 } | |
183 return SkFontStyle(weight, width, skSlant); | |
184 } | |
185 | |
186 SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) { | |
187 fRecCount = count; | |
188 fRecs = new Rec[count]; | |
189 for (int i = 0; i < count; ++i) { | |
190 fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE)); | |
191 fRecs[i].fFileName.set(get_name(matches[i], FC_FILE)); | |
192 fRecs[i].fStyle = make_fontconfig_style(matches[i]); | |
193 } | |
194 } | |
195 | |
196 SkFontStyleSet_FC::~SkFontStyleSet_FC() { delete[] fRecs; } | |
197 | |
198 void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style, | |
199 SkString* styleName) { | |
200 SkASSERT((unsigned)index < (unsigned)fRecCount); | |
201 if (style) { | |
202 *style = fRecs[index].fStyle; | |
203 } | |
204 if (styleName) { | |
205 *styleName = fRecs[index].fStyleName; | |
206 } | |
207 } | |
208 | |
209 SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { | |
210 return nullptr; | |
211 } | |
212 | |
213 SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { | |
214 return nullptr; | |
215 } | |
216 | |
217 class SkFontMgr_fontconfig : public SkFontMgr { | |
218 SkAutoTUnref<SkFontConfigInterface> fFCI; | 140 SkAutoTUnref<SkFontConfigInterface> fFCI; |
219 SkDataTable* fFamilyNames; | 141 SkAutoTUnref<SkDataTable> fFamilyNames; |
220 SkTypeface_FreeType::Scanner fScanner; | 142 SkTypeface_FreeType::Scanner fScanner; |
221 | 143 |
| 144 mutable SkMutex fMutex; |
| 145 mutable SkTypefaceCache fTFCache; |
| 146 |
| 147 // The value of maxSize here is a compromise between cache hits and cache si
ze. |
| 148 // See https://crbug.com/424082#63 for reason for current size. |
| 149 static const size_t kMaxSize = 1 << 15; |
| 150 mutable SkFontRequestCache fCache; |
| 151 |
222 public: | 152 public: |
223 SkFontMgr_fontconfig(SkFontConfigInterface* fci) | 153 SkFontMgr_FCI(SkFontConfigInterface* fci) |
224 : fFCI(fci) | 154 : fFCI(fci) |
225 , fFamilyNames(fFCI->getFamilyNames()) {} | 155 , fFamilyNames(fFCI->getFamilyNames()) |
226 | 156 , fCache(kMaxSize) |
227 virtual ~SkFontMgr_fontconfig() { | 157 {} |
228 SkSafeUnref(fFamilyNames); | |
229 } | |
230 | 158 |
231 protected: | 159 protected: |
232 int onCountFamilies() const override { | 160 int onCountFamilies() const override { |
233 return fFamilyNames->count(); | 161 return fFamilyNames->count(); |
234 } | 162 } |
235 | 163 |
236 void onGetFamilyName(int index, SkString* familyName) const override { | 164 void onGetFamilyName(int index, SkString* familyName) const override { |
237 familyName->set(fFamilyNames->atStr(index)); | 165 familyName->set(fFamilyNames->atStr(index)); |
238 } | 166 } |
239 | 167 |
240 SkFontStyleSet* onCreateStyleSet(int index) const override { | 168 SkFontStyleSet* onCreateStyleSet(int index) const override { |
241 return this->onMatchFamily(fFamilyNames->atStr(index)); | 169 return this->onMatchFamily(fFamilyNames->atStr(index)); |
242 } | 170 } |
243 | 171 |
244 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { | 172 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { |
245 FCLocker lock; | 173 return new SkFontStyleSet_FCI(); |
246 | |
247 FcPattern* pattern = FcPatternCreate(); | |
248 | |
249 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); | |
250 #if 0 | |
251 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); | |
252 #endif | |
253 FcConfigSubstitute(nullptr, pattern, FcMatchPattern); | |
254 FcDefaultSubstitute(pattern); | |
255 | |
256 const char* post_config_family = get_name(pattern, FC_FAMILY); | |
257 | |
258 FcResult result; | |
259 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); | |
260 if (!font_set) { | |
261 FcPatternDestroy(pattern); | |
262 return nullptr; | |
263 } | |
264 | |
265 int count; | |
266 FcPattern** match = MatchFont(font_set, post_config_family, &count); | |
267 if (!match) { | |
268 FcPatternDestroy(pattern); | |
269 FcFontSetDestroy(font_set); | |
270 return nullptr; | |
271 } | |
272 | |
273 FcPatternDestroy(pattern); | |
274 | |
275 SkTDArray<FcPattern*> trimmedMatches; | |
276 for (int i = 0; i < count; ++i) { | |
277 const char* justName = find_just_name(get_name(match[i], FC_FILE)); | |
278 if (!is_lower(*justName)) { | |
279 *trimmedMatches.append() = match[i]; | |
280 } | |
281 } | |
282 | |
283 SkFontStyleSet_FC* sset = | |
284 new SkFontStyleSet_FC(trimmedMatches.begin(), trimmedMatches.cou
nt()); | |
285 return sset; | |
286 } | 174 } |
287 | 175 |
288 SkTypeface* onMatchFamilyStyle(const char familyName[], | 176 SkTypeface* onMatchFamilyStyle(const char familyName[], |
289 const SkFontStyle&) const override { return n
ullptr; } | 177 const SkFontStyle&) const override { return n
ullptr; } |
290 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFon
tStyle&, | 178 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFon
tStyle&, |
291 const char* bcp47[], int bcp47Count, | 179 const char* bcp47[], int bcp47Count, |
292 SkUnichar character) const override
{ | 180 SkUnichar character) const override
{ |
293 return nullptr; | 181 return nullptr; |
294 } | 182 } |
295 SkTypeface* onMatchFaceStyle(const SkTypeface*, | 183 SkTypeface* onMatchFaceStyle(const SkTypeface*, |
(...skipping 11 matching lines...) Expand all Loading... |
307 return nullptr; // don't accept too large fonts (>= 1GB) for safety
. | 195 return nullptr; // don't accept too large fonts (>= 1GB) for safety
. |
308 } | 196 } |
309 | 197 |
310 // TODO should the caller give us the style or should we get it from fre
etype? | 198 // TODO should the caller give us the style or should we get it from fre
etype? |
311 SkFontStyle style; | 199 SkFontStyle style; |
312 bool isFixedWidth = false; | 200 bool isFixedWidth = false; |
313 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullpt
r)) { | 201 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullpt
r)) { |
314 return nullptr; | 202 return nullptr; |
315 } | 203 } |
316 | 204 |
317 SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, strea
m.release()); | 205 return SkTypeface_FCI::Create(style, isFixedWidth, stream.release(), ttc
Index); |
318 return face; | |
319 } | 206 } |
320 | 207 |
321 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override
{ | 208 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override
{ |
322 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); | 209 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); |
323 return stream.get() ? this->createFromStream(stream.release(), ttcIndex)
: nullptr; | 210 return stream.get() ? this->createFromStream(stream.release(), ttcIndex)
: nullptr; |
324 } | 211 } |
325 | 212 |
326 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle styl
e) const override { | 213 SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], |
327 FCLocker lock; | 214 SkFontStyle requestedStyle) const overrid
e |
328 return FontConfigTypeface::LegacyCreateTypeface(familyName, style); | 215 { |
| 216 SkAutoMutexAcquire ama(fMutex); |
| 217 |
| 218 // Check if this request is already in the request cache. |
| 219 using Request = SkFontRequestCache::Request; |
| 220 SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requ
estedStyle)); |
| 221 SkTypeface* face = fCache.findAndRef(request); |
| 222 if (face) { |
| 223 return face; |
| 224 } |
| 225 |
| 226 SkFontConfigInterface::FontIdentity identity; |
| 227 SkString outFamilyName; |
| 228 SkFontStyle outStyle; |
| 229 if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, |
| 230 &identity, &outFamilyName, &outStyle)) |
| 231 { |
| 232 return nullptr; |
| 233 } |
| 234 |
| 235 // Check if a typeface with this FontIdentity is already in the FontIden
tity cache. |
| 236 face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); |
| 237 if (!face) { |
| 238 face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyl
e); |
| 239 // Add this FontIdentity to the FontIdentity cache. |
| 240 fTFCache.add(face); |
| 241 } |
| 242 // Add this request to the request cache. |
| 243 fCache.add(face, request.release()); |
| 244 |
| 245 return face; |
329 } | 246 } |
330 }; | 247 }; |
331 | 248 |
332 SkFontMgr* SkFontMgr::Factory() { | 249 SK_API SkFontMgr* SkFontMgr_New_FCI(SkFontConfigInterface* fci) { |
333 SkFontConfigInterface* fci = RefFCI(); | 250 SkASSERT(fci); |
334 return fci ? new SkFontMgr_fontconfig(fci) : nullptr; | 251 return new SkFontMgr_FCI(fci); |
335 } | 252 } |
OLD | NEW |