Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Side by Side Diff: src/ports/SkFontMgr_android.cpp

Issue 384503002: WIP SkFontMgrAndroid (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Cleanup main file Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ports/SkFontConfigParser_android.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 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 "SkFontConfigParser_android.h"
9 #include "SkFontDescriptor.h"
10 #include "SkFontHost_FreeType_common.h"
11 #include "SkFontMgr.h"
12 #include "SkFontStyle.h"
13 #include "SkStream.h"
14 #include "SkTDArray.h"
15 #include "SkTSearch.h"
16 #include "SkTypeface.h"
17 #include "SkTypefaceCache.h"
18
19 #include <limits>
20 #include <stdlib.h>
21
22 // TODO: document isLocal in getFontDescriptor:
bungeman-skia 2014/07/21 15:48:00 We need to just change the name to 'shouldSerializ
bungeman-skia 2014/07/22 17:26:53 Acknowledged.
23 // isLocal TRUE: this is a copy of the font local to my installation,
24 // I need to serialize it.
25 // isLocal FALSE: this font is globally available - installed as part
26 // of the system image - so I can just refer to it and the recipient is
27 // guaranteed to have it available.
28
29 // TODO?
30 bool find_name_and_attributes(SkStream* stream, SkString* name,
bungeman-skia 2014/07/21 15:48:00 This is now gone, replaced by SkTypeface_FreeType:
bungeman-skia 2014/07/22 17:26:52 Done.
31 SkTypeface::Style* style, bool* isFixedPitch);
32
33 class SkTypeface_Android : public SkTypeface_FreeType {
34 public:
35 SkTypeface_Android(Style style,
36 bool isFixedPitch,
37 const SkString familyName)
38 : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
39 , fFamilyName(familyName) {
40 }
41
42 const SkString& name () const { return fFamilyName; }
bungeman-skia 2014/07/21 15:48:00 nit: name()
bungeman-skia 2014/07/22 17:26:53 Done.
43
44 protected:
45 SkString fFamilyName;
46
bungeman-skia 2014/07/21 15:48:00 We can put an fTtcIndex right here, and use it as
bungeman-skia 2014/07/22 17:26:53 Done.
47 private:
48 typedef SkTypeface_FreeType INHERITED;
49 };
50
51 /// On Android, system fonts are installed on the device; the XML catalogs
52 /// are read by SkFontConfigParser_android. We can't safely duplicate()
53 /// them, so re-open them every time we need a fresh stream
bungeman-skia 2014/07/21 15:48:00 This comment (or at least most of it) seems more a
bungeman-skia 2014/07/22 17:26:53 Done.
54 class SkTypeface_AndroidSystem : public SkTypeface_Android {
55 public:
56 SkTypeface_AndroidSystem(Style style,
57 bool isFixedPitch,
58 const SkString pathName,
59 const SkString familyName)
60 : INHERITED(style, isFixedPitch, familyName)
61 , fPathName(pathName) {
62 }
63
64 void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal)
65 const SK_OVERRIDE {
66 SkASSERT(desc);
67 SkASSERT(isLocal);
68 desc->setFamilyName(fFamilyName.c_str());
69 desc->setFontFileName(fPathName.c_str());
70 *isLocal = false;
71 }
72 SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
73 *ttcIndex = 0; // TODO
74 return SkStream::NewFromFile(fPathName.c_str());
75 }
76
77 private:
78 SkString fPathName;
79
80 typedef SkTypeface_Android INHERITED;
81 };
82
83 /// On Android, non-system fonts can be supplied through a SkStream,
84 /// which we can cache in memory and duplicate() when necessary. We
85 /// don't have a pathname for these fonts, however.
86 class SkTypeface_AndroidStream : public SkTypeface_Android {
87 public:
88 SkTypeface_AndroidStream(Style style,
89 bool isFixedPitch,
90 SkStream* stream,
91 const SkString familyName)
92 : INHERITED(style, isFixedPitch, familyName)
93 , fStream(stream) {
94 }
95
96 void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal)
97 const SK_OVERRIDE {
98 SkASSERT(desc);
99 SkASSERT(isLocal);
100 desc->setFamilyName(fFamilyName.c_str());
101 desc->setFontFileName(NULL);
102 *isLocal = true;
103 }
104
105 SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
106 *ttcIndex = 0; // TODO
107 return fStream->duplicate();
108 }
109
110 private:
111 SkAutoTUnref<SkStream> fStream;
112
113 typedef SkTypeface_Android INHERITED;
114 };
115
116 // TODO - need another implementation of Typeface_Android to hold faces
117 // created from Streams; that one can call duplicate().
bungeman-skia 2014/07/21 15:48:00 Looks like you've done this todo?
bungeman-skia 2014/07/22 17:26:53 Done.
118
119 namespace {
120
121 #ifndef SK_FONT_FILE_PREFIX
122 #define SK_FONT_FILE_PREFIX "/fonts/"
123 #endif
124
125 void get_path_for_sys_fonts(SkString* full, const SkString& name) {
126 full->set(getenv("ANDROID_ROOT"));
127 full->append(SK_FONT_FILE_PREFIX);
128 full->append(name);
129 }
130
131 }
132
133 class SkFontStyleSet_Android : public SkFontStyleSet {
134 public:
135 explicit SkFontStyleSet_Android(FontFamily* family) :
136 fFontFamily(family) {
137
138 // TODO? make this lazy
139
140 for (int i = 0; i < family->fFontFiles.count(); ++i) {
141 const SkString& fileName = family->fFontFiles[i].fFileName;
bungeman-skia 2014/07/21 15:48:00 We have SkTTCFHeader.h and can write some simple c
bungeman-skia 2014/07/22 17:26:53 Done.
142 SkString pathName;
143 get_path_for_sys_fonts(&pathName, fileName);
144
145 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str() ));
146 SkASSERT(stream.get());
147 bool isFixedWidth;
148 SkTypeface::Style style;
149 SkString fontName;
150 find_name_and_attributes(stream.get(), &fontName, &style, &isFixedWi dth);
bungeman-skia 2014/07/21 15:48:00 We should check (at least assert or message) the r
bungeman-skia 2014/07/22 17:26:53 Done.
151 fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem,
152 (style, isFixedWidth,
153 pathName, fontName)));
154 }
155 }
156
157 int count() SK_OVERRIDE {
158 return fStyles.count();
159 }
160 void getStyle(int index, SkFontStyle* style, SkString* name) SK_OVERRIDE {
161 SkASSERT(index >= 0 && index < fStyles.count());
bungeman-skia 2014/07/21 15:48:00 Since this is public API, I think we should probab
bungeman-skia 2014/07/22 17:26:52 Done.
162 SkASSERT(style);
163 SkASSERT(name);
bungeman-skia 2014/07/21 15:48:01 These need to be like 'if (style) ...'. Any subset
bungeman-skia 2014/07/22 17:26:53 Done.
164 *style = this->style(index);
165 name->reset(); // UNDEFINED SEMANTICS?
bungeman-skia 2014/07/21 15:48:00 I think this is right for when it isn't supported
bungeman-skia 2014/07/22 17:26:52 Acknowledged.
166 }
167 SkTypeface* createTypeface(int index) SK_OVERRIDE {
168 SkASSERT(index >= 0 && index < fStyles.count());
169 return SkRef(fStyles[index].get());
170 }
171
172 /// Find the typeface in this style set that most closely matches the given pattern.
173 /// TODO: consider replacing with SkStyleSet_Indirect::matchStyle(); this si mpler
174 /// version using match_score() passes all our tests.
175 SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
176 if (0 == fStyles.count()) {
177 return NULL;
178 }
179 SkTypeface* closest = fStyles[0];
180 int minScore = std::numeric_limits<int>::max();
181 for (int i = 0; i < fStyles.count(); ++i) {
182 SkFontStyle style = this->style(i);
183 int score = match_score(pattern, style);
184 if (score < minScore) {
185 closest = fStyles[i];
186 minScore = score;
187 }
188 }
189 return SkRef(closest);
190 }
191
192 private:
193 SkFontStyle style(int index) {
194 return SkFontStyle(this->weight(index), SkFontStyle::kNormal_Width,
195 this->slant(index));
196 }
197 SkFontStyle::Weight weight(int index) {
198 if (fStyles[index]->isBold()) return SkFontStyle::kBold_Weight;
199 return SkFontStyle::kNormal_Weight;
200 }
201 SkFontStyle::Slant slant(int index) {
202 if (fStyles[index]->isItalic()) return SkFontStyle::kItalic_Slant;
203 return SkFontStyle::kUpright_Slant;
204 }
205 static int match_score(const SkFontStyle& pattern, const SkFontStyle& candid ate) {
206 int score = 0;
207 score += abs((pattern.width() - candidate.width()) * 100);
208 score += abs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
209 score += abs(pattern.weight() - candidate.weight());
210 return score;
211 }
212
213
214 FontFamily* fFontFamily;
215 SkTArray<SkAutoTUnref<SkTypeface>, true> fStyles;
216
217 friend struct NameToFamily;
218 friend class SkFontMgr_Android;
219
220 typedef SkFontStyleSet INHERITED;
221 };
222
223 /** On Android a single family can have many names, but our API assumes unique n ames.
224 Map names to the back end so that all names for a given family refer to the same
225 (non-replicated) set of typefaces.
226 SkTDict<> doesn't let us do index-based lookup, so we write our own mapping. */
227 struct NameToFamily {
228 SkString name;
229 SkFontStyleSet_Android* styleSet;
230 };
231
232 class SkFontMgr_Android : public SkFontMgr {
233 public:
234 SkFontMgr_Android() {
235 SkTDArray<FontFamily*> fontFamilies;
236 SkFontConfigParser::GetFontFamilies(fontFamilies);
237 this->buildNameToFamilyMap(fontFamilies);
238 this->findDefaultFont();
239 }
240
241 protected:
242 /// On Android: Returns not how many families we have, but how many unique n ames
243 /// exist among the families.
244 virtual int onCountFamilies() const SK_OVERRIDE {
245 return fNameToFamilyMap.count();
246 }
247 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERR IDE {
248 SkASSERT(index >= 0 && index < fNameToFamilyMap.count());
249 familyName->set(fNameToFamilyMap[index].name);
250 }
251 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
252 SkASSERT(index >= 0 && index < fNameToFamilyMap.count());
253 return SkRef(fNameToFamilyMap[index].styleSet);
254 }
255
256 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVER RIDE {
257 if (!familyName) {
258 return NULL;
259 }
260 SkAutoAsciiToLC tolc(familyName);
261 for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
262 if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
263 return SkRef(fNameToFamilyMap[i].styleSet);
264 }
265 }
266 return NULL;
267 }
268
269 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
270 const SkFontStyle& style) const SK_OV ERRIDE {
271 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
272 return sset->matchStyle(style);
273 }
274
275 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
276 const SkFontStyle& style) const SK_OVER RIDE {
277 for (int i = 0; i < fFontStyleSets.count(); ++i) {
278 for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
279 if (fFontStyleSets[i]->fStyles[j] == typeface) {
280 return fFontStyleSets[i]->matchStyle(style);
281 }
282 }
283 }
284 return NULL;
285 }
286
287 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OV ERRIDE {
288 SkAutoTUnref<SkStream> stream(new SkMemoryStream(data));
289 return this->createFromStream(stream, ttcIndex);
290 }
291
292 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
293 if (NULL == stream || stream->getLength() <= 0) {
294 SkDELETE(stream);
295 return NULL;
296 }
297
298 bool isFixedPitch;
299 SkTypeface::Style style;
300 SkString name;
301 if (find_name_and_attributes(stream, &name, &style, &isFixedPitch)) {
302 return SkNEW_ARGS(SkTypeface_AndroidStream,
303 (style, isFixedPitch, stream, name));
304 } else {
305 return NULL;
306 }
307 }
308
309 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
310 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
311 return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
312 }
313
314 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
315 unsigned styleBits) const SK_OVER RIDE {
316 SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
317 SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
318 ? SkFontStyle::kBold_Weight
319 : SkFontStyle::kNormal_Weight,
320 SkFontStyle::kNormal_Width,
321 oldStyle & SkTypeface::kItalic
322 ? SkFontStyle::kItalic_Slant
323 : SkFontStyle::kUpright_Slant);
324 SkTypeface* tf = NULL;
325
326 if (NULL != familyName) {
327 // On Android, we must return NULL when we can't find the requested
328 // named typeface so that the system/app can provide their own recov ery
329 // mechanism. On other platforms we'd provide a typeface from the
330 // default family instead.
331 tf = this->onMatchFamilyStyle(familyName, style);
332 } else {
333 tf = gDefaultFamily->matchStyle(style);
334 }
335
336 // TODO: double ref? qv matchStyle()
337 return SkSafeRef(tf);
338 }
339
340
341 private:
342
343 SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
344 SkFontStyleSet* gDefaultFamily;
345 SkTypeface* gDefaultTypeface;
346
347 SkTDArray<NameToFamily> fNameToFamilyMap;
348
349 void buildNameToFamilyMap(SkTDArray<FontFamily*> families) {
350 for (int i = 0; i < families.count(); i++) {
351 fFontStyleSets.push_back().reset(SkNEW_ARGS(SkFontStyleSet_Android,
352 (families[i])));
353 for (int j = 0; j < families[i]->fNames.count(); j++) {
354 NameToFamily* nextEntry = fNameToFamilyMap.append();
355 SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (families[i]->f Names[j]));
356 nextEntry->styleSet = fFontStyleSets.back().get();
357 }
358 }
359 }
360
361 void findDefaultFont() {
362 SkASSERT(!fFontStyleSets.empty()); // TODO?
363
364 // TODO: hardwired list of names - should there be more?
365 // TODO: Previous version was NULL-terminated; why??
366 // Currently passing NULL to onMatchFamily crashes.
367 static const char* gDefaultNames[] = { "Droid Sans" };
368 for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
369 SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
370 if (NULL == set) {
371 continue;
372 }
373 SkTypeface* tf = set->matchStyle(SkFontStyle());
374 if (NULL == tf) {
375 continue;
376 }
377 gDefaultFamily = set;
378 gDefaultTypeface = tf;
379 break;
380 }
381 if (NULL == gDefaultTypeface) {
382 gDefaultFamily = fFontStyleSets[0];
383 gDefaultTypeface = gDefaultFamily->createTypeface(0);
384 }
385 SkASSERT(gDefaultFamily);
386 SkASSERT(gDefaultTypeface);
387 }
388
389 typedef SkFontMgr INHERITED;
390 };
391
392 ///////////////////////////////////////////////////////////////////////////////
393
394 SkFontMgr* SkFontMgr::Factory() {
395 return SkNEW(SkFontMgr_Android);
396 }
397
398
399
OLDNEW
« no previous file with comments | « src/ports/SkFontConfigParser_android.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698