blob: 1ab2f29642a1147be1bc0404e43faf951f3af113 [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"
17#include "SkTypefaceCache.h"
18
19#include <limits>
20#include <stdlib.h>
21
22#ifndef SK_FONT_FILE_PREFIX
23# define SK_FONT_FILE_PREFIX "/fonts/"
24#endif
25
26#ifndef SK_DEBUG_FONTS
27 #define SK_DEBUG_FONTS 0
28#endif
29
30#if SK_DEBUG_FONTS
31# define DEBUG_FONT(args) SkDebugf args
32#else
33# define DEBUG_FONT(args)
34#endif
35
36class SkTypeface_Android : public SkTypeface_FreeType {
37public:
38 SkTypeface_Android(int index,
39 Style style,
40 bool isFixedPitch,
41 const SkString familyName)
42 : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
43 , fIndex(index)
tomhudson3a914242014-07-29 06:52:38 -070044 , fFamilyName(familyName) { }
bungeman8d84c992014-07-24 08:05:09 -070045
46 const SkString& name() const { return fFamilyName; }
47
48protected:
49 int fIndex;
50 SkString fFamilyName;
51
52private:
53 typedef SkTypeface_FreeType INHERITED;
54};
55
56class SkTypeface_AndroidSystem : public SkTypeface_Android {
57public:
58 SkTypeface_AndroidSystem(const SkString pathName,
59 int index,
60 Style style,
61 bool isFixedPitch,
bungeman65fcd3d2014-08-06 11:12:20 -070062 const SkString familyName,
63 const SkLanguage& lang,
Derek Sollenbergerda7a9442014-08-06 16:34:40 -040064 uint32_t variantStyle)
bungeman8d84c992014-07-24 08:05:09 -070065 : INHERITED(index, style, isFixedPitch, familyName)
bungeman65fcd3d2014-08-06 11:12:20 -070066 , fPathName(pathName)
67 , fLang(lang)
68 , fVariantStyle(variantStyle) { }
bungeman8d84c992014-07-24 08:05:09 -070069
70 virtual void onGetFontDescriptor(SkFontDescriptor* desc,
tomhudson3a914242014-07-29 06:52:38 -070071 bool* serialize) const SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -070072 SkASSERT(desc);
73 SkASSERT(serialize);
74 desc->setFamilyName(fFamilyName.c_str());
75 desc->setFontFileName(fPathName.c_str());
76 *serialize = false;
77 }
78 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
79 *ttcIndex = fIndex;
80 return SkStream::NewFromFile(fPathName.c_str());
81 }
82
bungeman65fcd3d2014-08-06 11:12:20 -070083 const SkString fPathName;
84 const SkLanguage fLang;
Derek Sollenbergerda7a9442014-08-06 16:34:40 -040085 const uint32_t fVariantStyle;
bungeman8d84c992014-07-24 08:05:09 -070086
87 typedef SkTypeface_Android INHERITED;
88};
89
90class SkTypeface_AndroidStream : public SkTypeface_Android {
91public:
92 SkTypeface_AndroidStream(SkStream* stream,
93 int index,
94 Style style,
95 bool isFixedPitch,
96 const SkString familyName)
97 : INHERITED(index, style, isFixedPitch, familyName)
bungeman8560cd52014-08-06 13:20:59 -070098 , fStream(SkRef(stream)) { }
bungeman8d84c992014-07-24 08:05:09 -070099
100 virtual void onGetFontDescriptor(SkFontDescriptor* desc,
101 bool* serialize) const SK_OVERRIDE {
102 SkASSERT(desc);
103 SkASSERT(serialize);
104 desc->setFamilyName(fFamilyName.c_str());
105 desc->setFontFileName(NULL);
106 *serialize = true;
107 }
108
109 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
110 *ttcIndex = fIndex;
111 return fStream->duplicate();
112 }
113
114private:
115 SkAutoTUnref<SkStream> fStream;
116
117 typedef SkTypeface_Android INHERITED;
118};
119
120void get_path_for_sys_fonts(SkString* full, const SkString& name) {
121 full->set(getenv("ANDROID_ROOT"));
122 full->append(SK_FONT_FILE_PREFIX);
123 full->append(name);
124}
125
126class SkFontStyleSet_Android : public SkFontStyleSet {
127public:
bungeman65fcd3d2014-08-06 11:12:20 -0700128 explicit SkFontStyleSet_Android(const FontFamily& family) {
129 const SkString* cannonicalFamilyName = NULL;
130 if (family.fNames.count() > 0) {
131 cannonicalFamilyName = &family.fNames[0];
132 }
bungeman8d84c992014-07-24 08:05:09 -0700133 // TODO? make this lazy
bungeman65fcd3d2014-08-06 11:12:20 -0700134 for (int i = 0; i < family.fFontFiles.count(); ++i) {
135 const FontFileInfo& fontFile = family.fFontFiles[i];
bungeman8d84c992014-07-24 08:05:09 -0700136
137 SkString pathName;
bungeman65fcd3d2014-08-06 11:12:20 -0700138 get_path_for_sys_fonts(&pathName, fontFile.fFileName);
bungeman8d84c992014-07-24 08:05:09 -0700139
140 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str()));
141 if (!stream.get()) {
bungeman65fcd3d2014-08-06 11:12:20 -0700142 DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, pathName.c_str()));
bungeman8d84c992014-07-24 08:05:09 -0700143 continue;
144 }
145
bungeman65fcd3d2014-08-06 11:12:20 -0700146 const int ttcIndex = fontFile.fIndex;
147 SkString familyName;
bungeman8d84c992014-07-24 08:05:09 -0700148 SkTypeface::Style style;
149 bool isFixedWidth;
bungeman07cfb202014-07-30 11:05:22 -0700150 if (!SkTypeface_FreeType::ScanFont(stream.get(), ttcIndex,
bungeman65fcd3d2014-08-06 11:12:20 -0700151 &familyName, &style, &isFixedWidth)) {
152 DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, pathName.c_str()));
bungeman8d84c992014-07-24 08:05:09 -0700153 continue;
154 }
155
Derek Sollenbergerda7a9442014-08-06 16:34:40 -0400156 const SkLanguage& lang = fontFile.fPaintOptions.getLanguage();
157 uint32_t variant = fontFile.fPaintOptions.getFontVariant();
158 if (SkPaintOptionsAndroid::kDefault_Variant == variant) {
159 variant = SkPaintOptionsAndroid::kCompact_Variant |
160 SkPaintOptionsAndroid::kElegant_Variant;
bungeman65fcd3d2014-08-06 11:12:20 -0700161 }
162
163 // The first specified family name overrides the family name found in the font.
164 // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
165 // all of the specified family names in addition to the names found in the font.
166 if (cannonicalFamilyName != NULL) {
167 familyName = *cannonicalFamilyName;
168 }
169
bungeman8d84c992014-07-24 08:05:09 -0700170 fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem,
bungeman07cfb202014-07-30 11:05:22 -0700171 (pathName, ttcIndex,
bungeman65fcd3d2014-08-06 11:12:20 -0700172 style, isFixedWidth, familyName,
173 lang, variant)));
bungeman8d84c992014-07-24 08:05:09 -0700174 }
175 }
176
177 virtual int count() SK_OVERRIDE {
178 return fStyles.count();
179 }
180 virtual void getStyle(int index, SkFontStyle* style, SkString* name) SK_OVERRIDE {
181 if (index < 0 || fStyles.count() <= index) {
182 return;
183 }
184 if (style) {
185 *style = this->style(index);
186 }
187 if (name) {
188 name->reset();
189 }
190 }
bungeman65fcd3d2014-08-06 11:12:20 -0700191 virtual SkTypeface_AndroidSystem* createTypeface(int index) SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -0700192 if (index < 0 || fStyles.count() <= index) {
193 return NULL;
194 }
195 return SkRef(fStyles[index].get());
196 }
197
198 /** Find the typeface in this style set that most closely matches the given pattern.
199 * TODO: consider replacing with SkStyleSet_Indirect::matchStyle();
200 * this simpler version using match_score() passes all our tests.
201 */
bungeman65fcd3d2014-08-06 11:12:20 -0700202 virtual SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -0700203 if (0 == fStyles.count()) {
204 return NULL;
205 }
bungeman65fcd3d2014-08-06 11:12:20 -0700206 SkTypeface_AndroidSystem* closest = fStyles[0];
bungeman8d84c992014-07-24 08:05:09 -0700207 int minScore = std::numeric_limits<int>::max();
208 for (int i = 0; i < fStyles.count(); ++i) {
209 SkFontStyle style = this->style(i);
210 int score = match_score(pattern, style);
211 if (score < minScore) {
212 closest = fStyles[i];
213 minScore = score;
214 }
215 }
216 return SkRef(closest);
217 }
218
219private:
220 SkFontStyle style(int index) {
221 return SkFontStyle(this->weight(index), SkFontStyle::kNormal_Width,
222 this->slant(index));
223 }
224 SkFontStyle::Weight weight(int index) {
225 if (fStyles[index]->isBold()) return SkFontStyle::kBold_Weight;
226 return SkFontStyle::kNormal_Weight;
227 }
228 SkFontStyle::Slant slant(int index) {
229 if (fStyles[index]->isItalic()) return SkFontStyle::kItalic_Slant;
230 return SkFontStyle::kUpright_Slant;
231 }
232 static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
233 int score = 0;
234 score += abs((pattern.width() - candidate.width()) * 100);
235 score += abs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
236 score += abs(pattern.weight() - candidate.weight());
237 return score;
238 }
239
bungeman65fcd3d2014-08-06 11:12:20 -0700240 SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles;
bungeman8d84c992014-07-24 08:05:09 -0700241
242 friend struct NameToFamily;
243 friend class SkFontMgr_Android;
244
245 typedef SkFontStyleSet INHERITED;
246};
247
248/** On Android a single family can have many names, but our API assumes unique names.
249 * Map names to the back end so that all names for a given family refer to the same
250 * (non-replicated) set of typefaces.
251 * SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
252 */
253struct NameToFamily {
254 SkString name;
255 SkFontStyleSet_Android* styleSet;
256};
257
258class SkFontMgr_Android : public SkFontMgr {
259public:
260 SkFontMgr_Android() {
261 SkTDArray<FontFamily*> fontFamilies;
262 SkFontConfigParser::GetFontFamilies(fontFamilies);
263 this->buildNameToFamilyMap(fontFamilies);
264 this->findDefaultFont();
265 }
266
267protected:
268 /** Returns not how many families we have, but how many unique names
269 * exist among the families.
270 */
271 virtual int onCountFamilies() const SK_OVERRIDE {
272 return fNameToFamilyMap.count();
273 }
274
275 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
276 if (index < 0 || fNameToFamilyMap.count() <= index) {
277 familyName->reset();
278 return;
279 }
280 familyName->set(fNameToFamilyMap[index].name);
281 }
282
283 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
284 if (index < 0 || fNameToFamilyMap.count() <= index) {
285 return NULL;
286 }
287 return SkRef(fNameToFamilyMap[index].styleSet);
288 }
289
290 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
291 if (!familyName) {
292 return NULL;
293 }
294 SkAutoAsciiToLC tolc(familyName);
295 for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
296 if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
297 return SkRef(fNameToFamilyMap[i].styleSet);
298 }
299 }
bungeman65fcd3d2014-08-06 11:12:20 -0700300 // TODO: eventually we should not need to name fallback families.
301 for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
302 if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
303 return SkRef(fFallbackNameToFamilyMap[i].styleSet);
304 }
305 }
bungeman8d84c992014-07-24 08:05:09 -0700306 return NULL;
307 }
308
309 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
310 const SkFontStyle& style) const SK_OVERRIDE {
311 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
312 return sset->matchStyle(style);
313 }
314
315 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
316 const SkFontStyle& style) const SK_OVERRIDE {
317 for (int i = 0; i < fFontStyleSets.count(); ++i) {
318 for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
319 if (fFontStyleSets[i]->fStyles[j] == typeface) {
320 return fFontStyleSets[i]->matchStyle(style);
321 }
322 }
323 }
324 return NULL;
325 }
326
bungeman65fcd3d2014-08-06 11:12:20 -0700327 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
328 const SkFontStyle& style,
329 const char bpc47[],
330 uint32_t character) const SK_OVERRIDE
331 {
332 // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
333 // The variant 'default' means 'compact and elegant'.
334 // As a result, it is not possible to know the variant context from the font alone.
335 // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
336
337 // For compatibility, try 'elegant' fonts first in fallback.
Derek Sollenbergerda7a9442014-08-06 16:34:40 -0400338 uint32_t variantMask = SkPaintOptionsAndroid::kElegant_Variant;
bungeman65fcd3d2014-08-06 11:12:20 -0700339
340 // The first time match anything in the mask, second time anything not in the mask.
341 for (bool maskMatches = true; maskMatches != false; maskMatches = false) {
342 SkLanguage lang(bpc47);
343 // Match against the language, removing a segment each time.
344 // The last time through the loop, the language will be empty.
345 // The empty language is special, and matches all languages.
346 do {
347 const SkString& langTag = lang.getTag();
348 for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
349 SkFontStyleSet_Android* family = fFallbackNameToFamilyMap[i].styleSet;
350 SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
351
352 if (!langTag.isEmpty() && langTag != face->fLang.getTag()) {
353 continue;
354 }
355
356 if (SkToBool(face->fVariantStyle & variantMask) != maskMatches) {
357 continue;
358 }
359
360 SkPaint paint;
361 paint.setTypeface(face);
362 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
363
364 uint16_t glyphID;
365 paint.textToGlyphs(&character, sizeof(character), &glyphID);
366 if (glyphID != 0) {
367 return face.detach();
368 }
369 }
370 } while (!lang.getTag().isEmpty() && (lang = lang.getParent(), true));
371 }
372 return NULL;
373 }
374
bungeman8d84c992014-07-24 08:05:09 -0700375 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
376 SkAutoTUnref<SkStream> stream(new SkMemoryStream(data));
377 return this->createFromStream(stream, ttcIndex);
378 }
379
380 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
381 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
382 return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
383 }
384
bungeman8560cd52014-08-06 13:20:59 -0700385 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
bungeman8d84c992014-07-24 08:05:09 -0700386 bool isFixedPitch;
387 SkTypeface::Style style;
388 SkString name;
389 if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) {
390 return NULL;
391 }
bungeman8560cd52014-08-06 13:20:59 -0700392 return SkNEW_ARGS(SkTypeface_AndroidStream, (stream, ttcIndex,
bungeman8d84c992014-07-24 08:05:09 -0700393 style, isFixedPitch, name));
394 }
395
396
397 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
398 unsigned styleBits) const SK_OVERRIDE {
399 SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
400 SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
401 ? SkFontStyle::kBold_Weight
402 : SkFontStyle::kNormal_Weight,
403 SkFontStyle::kNormal_Width,
404 oldStyle & SkTypeface::kItalic
405 ? SkFontStyle::kItalic_Slant
406 : SkFontStyle::kUpright_Slant);
bungeman8d84c992014-07-24 08:05:09 -0700407
408 if (NULL != familyName) {
409 // On Android, we must return NULL when we can't find the requested
410 // named typeface so that the system/app can provide their own recovery
411 // mechanism. On other platforms we'd provide a typeface from the
412 // default family instead.
bungeman07cfb202014-07-30 11:05:22 -0700413 return this->onMatchFamilyStyle(familyName, style);
bungeman8d84c992014-07-24 08:05:09 -0700414 }
bungeman07cfb202014-07-30 11:05:22 -0700415 return fDefaultFamily->matchStyle(style);
bungeman8d84c992014-07-24 08:05:09 -0700416 }
417
418
419private:
420
421 SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
422 SkFontStyleSet* fDefaultFamily;
423 SkTypeface* fDefaultTypeface;
424
425 SkTDArray<NameToFamily> fNameToFamilyMap;
bungeman65fcd3d2014-08-06 11:12:20 -0700426 SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
bungeman8d84c992014-07-24 08:05:09 -0700427
428 void buildNameToFamilyMap(SkTDArray<FontFamily*> families) {
429 for (int i = 0; i < families.count(); i++) {
bungeman65fcd3d2014-08-06 11:12:20 -0700430 FontFamily& family = *families[i];
431
432 SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
433 if (family.fIsFallbackFont) {
434 nameToFamily = &fFallbackNameToFamilyMap;
435
436 if (0 == family.fNames.count()) {
437 SkString& fallbackName = family.fNames.push_back();
438 fallbackName.printf("%.2x##fallback", i);
439 }
440 }
441
442 SkFontStyleSet_Android* newSet = SkNEW_ARGS(SkFontStyleSet_Android, (family));
443 if (0 == newSet->count()) {
444 SkDELETE(newSet);
445 continue;
446 }
447 fFontStyleSets.push_back().reset(newSet);
448
449 for (int j = 0; j < family.fNames.count(); j++) {
450 NameToFamily* nextEntry = nameToFamily->append();
451 SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j]));
452 nextEntry->styleSet = newSet;
bungeman8d84c992014-07-24 08:05:09 -0700453 }
454 }
455 }
456
457 void findDefaultFont() {
458 SkASSERT(!fFontStyleSets.empty());
459
460 static const char* gDefaultNames[] = { "sans-serif" };
461 for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
462 SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
463 if (NULL == set) {
464 continue;
465 }
466 SkTypeface* tf = set->matchStyle(SkFontStyle());
467 if (NULL == tf) {
468 continue;
469 }
470 fDefaultFamily = set;
471 fDefaultTypeface = tf;
472 break;
473 }
474 if (NULL == fDefaultTypeface) {
475 fDefaultFamily = fFontStyleSets[0];
476 fDefaultTypeface = fDefaultFamily->createTypeface(0);
477 }
478 SkASSERT(fDefaultFamily);
479 SkASSERT(fDefaultTypeface);
480 }
481
482 typedef SkFontMgr INHERITED;
483};
484
485///////////////////////////////////////////////////////////////////////////////
486
487SkFontMgr* SkFontMgr::Factory() {
488 return SkNEW(SkFontMgr_Android);
489}