blob: b0af791d300a974f2898d336b3a3eb767b1be7c0 [file] [log] [blame]
bungeman8d84c992014-07-24 08:05:09 -07001/*
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"
bungeman4e3523c2014-08-08 12:06:51 -070017#include "SkTypeface_android.h"
bungeman8d84c992014-07-24 08:05:09 -070018#include "SkTypefaceCache.h"
19
20#include <limits>
21#include <stdlib.h>
22
23#ifndef SK_FONT_FILE_PREFIX
24# define SK_FONT_FILE_PREFIX "/fonts/"
25#endif
26
27#ifndef SK_DEBUG_FONTS
28 #define SK_DEBUG_FONTS 0
29#endif
30
31#if SK_DEBUG_FONTS
32# define DEBUG_FONT(args) SkDebugf args
33#else
34# define DEBUG_FONT(args)
35#endif
36
37class SkTypeface_Android : public SkTypeface_FreeType {
38public:
39 SkTypeface_Android(int index,
40 Style style,
41 bool isFixedPitch,
42 const SkString familyName)
43 : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
44 , fIndex(index)
tomhudson3a914242014-07-29 06:52:38 -070045 , fFamilyName(familyName) { }
bungeman8d84c992014-07-24 08:05:09 -070046
47 const SkString& name() const { return fFamilyName; }
48
49protected:
50 int fIndex;
51 SkString fFamilyName;
52
53private:
54 typedef SkTypeface_FreeType INHERITED;
55};
56
57class SkTypeface_AndroidSystem : public SkTypeface_Android {
58public:
59 SkTypeface_AndroidSystem(const SkString pathName,
60 int index,
61 Style style,
62 bool isFixedPitch,
bungeman65fcd3d2014-08-06 11:12:20 -070063 const SkString familyName,
64 const SkLanguage& lang,
Derek Sollenbergerda7a9442014-08-06 16:34:40 -040065 uint32_t variantStyle)
bungeman8d84c992014-07-24 08:05:09 -070066 : INHERITED(index, style, isFixedPitch, familyName)
bungeman65fcd3d2014-08-06 11:12:20 -070067 , fPathName(pathName)
68 , fLang(lang)
69 , fVariantStyle(variantStyle) { }
bungeman8d84c992014-07-24 08:05:09 -070070
71 virtual void onGetFontDescriptor(SkFontDescriptor* desc,
tomhudson3a914242014-07-29 06:52:38 -070072 bool* serialize) const SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -070073 SkASSERT(desc);
74 SkASSERT(serialize);
75 desc->setFamilyName(fFamilyName.c_str());
76 desc->setFontFileName(fPathName.c_str());
77 *serialize = false;
78 }
79 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
80 *ttcIndex = fIndex;
81 return SkStream::NewFromFile(fPathName.c_str());
82 }
83
bungeman65fcd3d2014-08-06 11:12:20 -070084 const SkString fPathName;
85 const SkLanguage fLang;
Derek Sollenbergerda7a9442014-08-06 16:34:40 -040086 const uint32_t fVariantStyle;
bungeman8d84c992014-07-24 08:05:09 -070087
88 typedef SkTypeface_Android INHERITED;
89};
90
91class SkTypeface_AndroidStream : public SkTypeface_Android {
92public:
93 SkTypeface_AndroidStream(SkStream* stream,
94 int index,
95 Style style,
96 bool isFixedPitch,
97 const SkString familyName)
98 : INHERITED(index, style, isFixedPitch, familyName)
bungeman8560cd52014-08-06 13:20:59 -070099 , fStream(SkRef(stream)) { }
bungeman8d84c992014-07-24 08:05:09 -0700100
101 virtual void onGetFontDescriptor(SkFontDescriptor* desc,
102 bool* serialize) const SK_OVERRIDE {
103 SkASSERT(desc);
104 SkASSERT(serialize);
105 desc->setFamilyName(fFamilyName.c_str());
106 desc->setFontFileName(NULL);
107 *serialize = true;
108 }
109
110 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
111 *ttcIndex = fIndex;
112 return fStream->duplicate();
113 }
114
115private:
116 SkAutoTUnref<SkStream> fStream;
117
118 typedef SkTypeface_Android INHERITED;
119};
120
bungeman4e3523c2014-08-08 12:06:51 -0700121void get_path_for_sys_fonts(const char* basePath, const SkString& name, SkString* full) {
122 if (basePath) {
123 full->set(basePath);
124 } else {
125 full->set(getenv("ANDROID_ROOT"));
126 full->append(SK_FONT_FILE_PREFIX);
127 }
bungeman8d84c992014-07-24 08:05:09 -0700128 full->append(name);
129}
130
131class SkFontStyleSet_Android : public SkFontStyleSet {
132public:
bungeman4e3523c2014-08-08 12:06:51 -0700133 explicit SkFontStyleSet_Android(const FontFamily& family, const char* basePath) {
bungeman65fcd3d2014-08-06 11:12:20 -0700134 const SkString* cannonicalFamilyName = NULL;
135 if (family.fNames.count() > 0) {
136 cannonicalFamilyName = &family.fNames[0];
137 }
bungeman8d84c992014-07-24 08:05:09 -0700138 // TODO? make this lazy
bungeman65fcd3d2014-08-06 11:12:20 -0700139 for (int i = 0; i < family.fFontFiles.count(); ++i) {
140 const FontFileInfo& fontFile = family.fFontFiles[i];
bungeman8d84c992014-07-24 08:05:09 -0700141
142 SkString pathName;
bungeman4e3523c2014-08-08 12:06:51 -0700143 get_path_for_sys_fonts(basePath, fontFile.fFileName, &pathName);
bungeman8d84c992014-07-24 08:05:09 -0700144
145 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str()));
146 if (!stream.get()) {
bungeman65fcd3d2014-08-06 11:12:20 -0700147 DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, pathName.c_str()));
bungeman8d84c992014-07-24 08:05:09 -0700148 continue;
149 }
150
bungeman65fcd3d2014-08-06 11:12:20 -0700151 const int ttcIndex = fontFile.fIndex;
152 SkString familyName;
bungeman8d84c992014-07-24 08:05:09 -0700153 SkTypeface::Style style;
154 bool isFixedWidth;
bungeman07cfb202014-07-30 11:05:22 -0700155 if (!SkTypeface_FreeType::ScanFont(stream.get(), ttcIndex,
bungeman65fcd3d2014-08-06 11:12:20 -0700156 &familyName, &style, &isFixedWidth)) {
157 DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, pathName.c_str()));
bungeman8d84c992014-07-24 08:05:09 -0700158 continue;
159 }
160
Derek Sollenbergerda7a9442014-08-06 16:34:40 -0400161 const SkLanguage& lang = fontFile.fPaintOptions.getLanguage();
162 uint32_t variant = fontFile.fPaintOptions.getFontVariant();
163 if (SkPaintOptionsAndroid::kDefault_Variant == variant) {
164 variant = SkPaintOptionsAndroid::kCompact_Variant |
165 SkPaintOptionsAndroid::kElegant_Variant;
bungeman65fcd3d2014-08-06 11:12:20 -0700166 }
167
168 // The first specified family name overrides the family name found in the font.
169 // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
170 // all of the specified family names in addition to the names found in the font.
171 if (cannonicalFamilyName != NULL) {
172 familyName = *cannonicalFamilyName;
173 }
174
bungeman8d84c992014-07-24 08:05:09 -0700175 fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem,
bungeman07cfb202014-07-30 11:05:22 -0700176 (pathName, ttcIndex,
bungeman65fcd3d2014-08-06 11:12:20 -0700177 style, isFixedWidth, familyName,
178 lang, variant)));
bungeman8d84c992014-07-24 08:05:09 -0700179 }
180 }
181
182 virtual int count() SK_OVERRIDE {
183 return fStyles.count();
184 }
185 virtual void getStyle(int index, SkFontStyle* style, SkString* name) SK_OVERRIDE {
186 if (index < 0 || fStyles.count() <= index) {
187 return;
188 }
189 if (style) {
190 *style = this->style(index);
191 }
192 if (name) {
193 name->reset();
194 }
195 }
bungeman65fcd3d2014-08-06 11:12:20 -0700196 virtual SkTypeface_AndroidSystem* createTypeface(int index) SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -0700197 if (index < 0 || fStyles.count() <= index) {
198 return NULL;
199 }
200 return SkRef(fStyles[index].get());
201 }
202
203 /** Find the typeface in this style set that most closely matches the given pattern.
204 * TODO: consider replacing with SkStyleSet_Indirect::matchStyle();
205 * this simpler version using match_score() passes all our tests.
206 */
bungeman65fcd3d2014-08-06 11:12:20 -0700207 virtual SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -0700208 if (0 == fStyles.count()) {
209 return NULL;
210 }
bungeman65fcd3d2014-08-06 11:12:20 -0700211 SkTypeface_AndroidSystem* closest = fStyles[0];
bungeman8d84c992014-07-24 08:05:09 -0700212 int minScore = std::numeric_limits<int>::max();
213 for (int i = 0; i < fStyles.count(); ++i) {
214 SkFontStyle style = this->style(i);
215 int score = match_score(pattern, style);
216 if (score < minScore) {
217 closest = fStyles[i];
218 minScore = score;
219 }
220 }
221 return SkRef(closest);
222 }
223
224private:
225 SkFontStyle style(int index) {
226 return SkFontStyle(this->weight(index), SkFontStyle::kNormal_Width,
227 this->slant(index));
228 }
229 SkFontStyle::Weight weight(int index) {
230 if (fStyles[index]->isBold()) return SkFontStyle::kBold_Weight;
231 return SkFontStyle::kNormal_Weight;
232 }
233 SkFontStyle::Slant slant(int index) {
234 if (fStyles[index]->isItalic()) return SkFontStyle::kItalic_Slant;
235 return SkFontStyle::kUpright_Slant;
236 }
237 static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
238 int score = 0;
239 score += abs((pattern.width() - candidate.width()) * 100);
240 score += abs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
241 score += abs(pattern.weight() - candidate.weight());
242 return score;
243 }
244
bungeman65fcd3d2014-08-06 11:12:20 -0700245 SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles;
bungeman8d84c992014-07-24 08:05:09 -0700246
247 friend struct NameToFamily;
248 friend class SkFontMgr_Android;
249
250 typedef SkFontStyleSet INHERITED;
251};
252
253/** On Android a single family can have many names, but our API assumes unique names.
254 * Map names to the back end so that all names for a given family refer to the same
255 * (non-replicated) set of typefaces.
256 * SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
257 */
258struct NameToFamily {
259 SkString name;
260 SkFontStyleSet_Android* styleSet;
261};
262
263class SkFontMgr_Android : public SkFontMgr {
264public:
265 SkFontMgr_Android() {
266 SkTDArray<FontFamily*> fontFamilies;
267 SkFontConfigParser::GetFontFamilies(fontFamilies);
bungeman4e3523c2014-08-08 12:06:51 -0700268 this->buildNameToFamilyMap(fontFamilies, NULL);
269 this->findDefaultFont();
270 }
271 SkFontMgr_Android(const char* mainConfigFile, const char* fallbackConfigFile,
272 const char* basePath)
273 {
274 SkTDArray<FontFamily*> fontFamilies;
275 SkFontConfigParser::GetTestFontFamilies(fontFamilies, mainConfigFile, fallbackConfigFile);
276 this->buildNameToFamilyMap(fontFamilies, basePath);
bungeman8d84c992014-07-24 08:05:09 -0700277 this->findDefaultFont();
278 }
279
280protected:
281 /** Returns not how many families we have, but how many unique names
282 * exist among the families.
283 */
284 virtual int onCountFamilies() const SK_OVERRIDE {
285 return fNameToFamilyMap.count();
286 }
287
288 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
289 if (index < 0 || fNameToFamilyMap.count() <= index) {
290 familyName->reset();
291 return;
292 }
293 familyName->set(fNameToFamilyMap[index].name);
294 }
295
296 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
297 if (index < 0 || fNameToFamilyMap.count() <= index) {
298 return NULL;
299 }
300 return SkRef(fNameToFamilyMap[index].styleSet);
301 }
302
303 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
304 if (!familyName) {
305 return NULL;
306 }
307 SkAutoAsciiToLC tolc(familyName);
308 for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
309 if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
310 return SkRef(fNameToFamilyMap[i].styleSet);
311 }
312 }
bungeman65fcd3d2014-08-06 11:12:20 -0700313 // TODO: eventually we should not need to name fallback families.
314 for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
315 if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
316 return SkRef(fFallbackNameToFamilyMap[i].styleSet);
317 }
318 }
bungeman8d84c992014-07-24 08:05:09 -0700319 return NULL;
320 }
321
322 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
323 const SkFontStyle& style) const SK_OVERRIDE {
324 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
325 return sset->matchStyle(style);
326 }
327
328 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
329 const SkFontStyle& style) const SK_OVERRIDE {
330 for (int i = 0; i < fFontStyleSets.count(); ++i) {
331 for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
332 if (fFontStyleSets[i]->fStyles[j] == typeface) {
333 return fFontStyleSets[i]->matchStyle(style);
334 }
335 }
336 }
337 return NULL;
338 }
339
bungeman65fcd3d2014-08-06 11:12:20 -0700340 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
341 const SkFontStyle& style,
342 const char bpc47[],
343 uint32_t character) const SK_OVERRIDE
344 {
345 // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
346 // The variant 'default' means 'compact and elegant'.
347 // As a result, it is not possible to know the variant context from the font alone.
348 // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
349
350 // For compatibility, try 'elegant' fonts first in fallback.
Derek Sollenbergerda7a9442014-08-06 16:34:40 -0400351 uint32_t variantMask = SkPaintOptionsAndroid::kElegant_Variant;
bungeman65fcd3d2014-08-06 11:12:20 -0700352
353 // The first time match anything in the mask, second time anything not in the mask.
354 for (bool maskMatches = true; maskMatches != false; maskMatches = false) {
355 SkLanguage lang(bpc47);
356 // Match against the language, removing a segment each time.
357 // The last time through the loop, the language will be empty.
358 // The empty language is special, and matches all languages.
359 do {
360 const SkString& langTag = lang.getTag();
361 for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
362 SkFontStyleSet_Android* family = fFallbackNameToFamilyMap[i].styleSet;
363 SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
364
365 if (!langTag.isEmpty() && langTag != face->fLang.getTag()) {
366 continue;
367 }
368
369 if (SkToBool(face->fVariantStyle & variantMask) != maskMatches) {
370 continue;
371 }
372
373 SkPaint paint;
374 paint.setTypeface(face);
375 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
376
377 uint16_t glyphID;
378 paint.textToGlyphs(&character, sizeof(character), &glyphID);
379 if (glyphID != 0) {
380 return face.detach();
381 }
382 }
383 } while (!lang.getTag().isEmpty() && (lang = lang.getParent(), true));
384 }
385 return NULL;
386 }
387
bungeman8d84c992014-07-24 08:05:09 -0700388 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
389 SkAutoTUnref<SkStream> stream(new SkMemoryStream(data));
390 return this->createFromStream(stream, ttcIndex);
391 }
392
393 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
394 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
395 return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
396 }
397
bungeman8560cd52014-08-06 13:20:59 -0700398 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -0700399 bool isFixedPitch;
400 SkTypeface::Style style;
401 SkString name;
402 if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) {
403 return NULL;
404 }
bungeman8560cd52014-08-06 13:20:59 -0700405 return SkNEW_ARGS(SkTypeface_AndroidStream, (stream, ttcIndex,
bungeman8d84c992014-07-24 08:05:09 -0700406 style, isFixedPitch, name));
407 }
408
409
410 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
411 unsigned styleBits) const SK_OVERRIDE {
412 SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
413 SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
414 ? SkFontStyle::kBold_Weight
415 : SkFontStyle::kNormal_Weight,
416 SkFontStyle::kNormal_Width,
417 oldStyle & SkTypeface::kItalic
418 ? SkFontStyle::kItalic_Slant
419 : SkFontStyle::kUpright_Slant);
bungeman8d84c992014-07-24 08:05:09 -0700420
421 if (NULL != familyName) {
422 // On Android, we must return NULL when we can't find the requested
423 // named typeface so that the system/app can provide their own recovery
424 // mechanism. On other platforms we'd provide a typeface from the
425 // default family instead.
bungeman07cfb202014-07-30 11:05:22 -0700426 return this->onMatchFamilyStyle(familyName, style);
bungeman8d84c992014-07-24 08:05:09 -0700427 }
bungeman07cfb202014-07-30 11:05:22 -0700428 return fDefaultFamily->matchStyle(style);
bungeman8d84c992014-07-24 08:05:09 -0700429 }
430
431
432private:
433
434 SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
435 SkFontStyleSet* fDefaultFamily;
436 SkTypeface* fDefaultTypeface;
437
438 SkTDArray<NameToFamily> fNameToFamilyMap;
bungeman65fcd3d2014-08-06 11:12:20 -0700439 SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
bungeman8d84c992014-07-24 08:05:09 -0700440
bungeman4e3523c2014-08-08 12:06:51 -0700441 void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const char* basePath) {
bungeman8d84c992014-07-24 08:05:09 -0700442 for (int i = 0; i < families.count(); i++) {
bungeman65fcd3d2014-08-06 11:12:20 -0700443 FontFamily& family = *families[i];
444
445 SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
446 if (family.fIsFallbackFont) {
447 nameToFamily = &fFallbackNameToFamilyMap;
448
449 if (0 == family.fNames.count()) {
450 SkString& fallbackName = family.fNames.push_back();
451 fallbackName.printf("%.2x##fallback", i);
452 }
453 }
454
bungeman4e3523c2014-08-08 12:06:51 -0700455 SkFontStyleSet_Android* newSet = SkNEW_ARGS(SkFontStyleSet_Android, (family, basePath));
bungeman65fcd3d2014-08-06 11:12:20 -0700456 if (0 == newSet->count()) {
457 SkDELETE(newSet);
458 continue;
459 }
460 fFontStyleSets.push_back().reset(newSet);
461
462 for (int j = 0; j < family.fNames.count(); j++) {
463 NameToFamily* nextEntry = nameToFamily->append();
464 SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j]));
465 nextEntry->styleSet = newSet;
bungeman8d84c992014-07-24 08:05:09 -0700466 }
467 }
468 }
469
470 void findDefaultFont() {
471 SkASSERT(!fFontStyleSets.empty());
472
473 static const char* gDefaultNames[] = { "sans-serif" };
474 for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
475 SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
476 if (NULL == set) {
477 continue;
478 }
479 SkTypeface* tf = set->matchStyle(SkFontStyle());
480 if (NULL == tf) {
481 continue;
482 }
483 fDefaultFamily = set;
484 fDefaultTypeface = tf;
485 break;
486 }
487 if (NULL == fDefaultTypeface) {
488 fDefaultFamily = fFontStyleSets[0];
489 fDefaultTypeface = fDefaultFamily->createTypeface(0);
490 }
491 SkASSERT(fDefaultFamily);
492 SkASSERT(fDefaultTypeface);
493 }
494
495 typedef SkFontMgr INHERITED;
496};
497
498///////////////////////////////////////////////////////////////////////////////
499
500SkFontMgr* SkFontMgr::Factory() {
bungeman4e3523c2014-08-08 12:06:51 -0700501 // The call to SkGetTestFontConfiguration is so that Chromium can override the environment.
502 // TODO: these globals need to be removed, in favor of a constructor / separate Factory
503 // which can be used instead.
504 const char* mainConfigFile;
505 const char* fallbackConfigFile;
506 const char* basePath;
507 SkGetTestFontConfiguration(&mainConfigFile, &fallbackConfigFile, &basePath);
508 if (mainConfigFile) {
509 SkNEW_ARGS(SkFontMgr_Android, (mainConfigFile, fallbackConfigFile, basePath));
510 }
511
bungeman8d84c992014-07-24 08:05:09 -0700512 return SkNEW(SkFontMgr_Android);
513}