blob: 416d61d6616e9ec29e2c972ab8d32758760e7f00 [file] [log] [blame]
reed@google.comdd335ae2012-12-13 19:24:05 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00007
8#include "SkFontHost.h"
reed@google.com0da48612013-03-19 16:06:52 +00009#include "SkFontHost_FreeType_common.h"
djsollen@google.com97145162012-05-31 19:55:08 +000010#include "SkFontDescriptor.h"
djsollen@google.come63793a2012-03-21 15:39:03 +000011#include "SkGraphics.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkDescriptor.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkPaint.h"
14#include "SkString.h"
15#include "SkStream.h"
16#include "SkThread.h"
17#include "SkTSearch.h"
djsollen@google.comff029602012-03-15 15:49:51 +000018#include "SkTypeface_android.h"
djsollen@google.com58629292011-11-03 13:08:29 +000019#include "FontHostConfiguration_android.h"
djsollen@google.com60abb072012-02-15 18:49:15 +000020
reed@android.com8a1c16f2008-12-17 15:59:43 +000021#ifndef SK_FONT_FILE_PREFIX
22 #define SK_FONT_FILE_PREFIX "/fonts/"
23#endif
24
djsollen@google.com6f1dbff2012-10-05 14:48:32 +000025#ifndef SK_DEBUG_FONTS
djsollen@google.com3f5d6822012-10-05 15:19:27 +000026 #define SK_DEBUG_FONTS 0
djsollen@google.com6f1dbff2012-10-05 14:48:32 +000027#endif
28
djsollen@google.com5df2a992012-06-25 13:58:22 +000029// For test only.
30static const char* gTestMainConfigFile = NULL;
31static const char* gTestFallbackConfigFile = NULL;
32static const char* gTestFontFilePrefix = NULL;
33
djsollen@google.com4dc686d2012-02-15 21:03:45 +000034bool find_name_and_attributes(SkStream* stream, SkString* name,
35 SkTypeface::Style* style, bool* isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +000036
reed@android.comfcce6472009-03-20 12:23:07 +000037static void GetFullPathForSysFonts(SkString* full, const char name[]) {
djsollen@google.com5df2a992012-06-25 13:58:22 +000038 if (gTestFontFilePrefix) {
39 full->set(gTestFontFilePrefix);
40 } else {
41 full->set(getenv("ANDROID_ROOT"));
42 full->append(SK_FONT_FILE_PREFIX);
43 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 full->append(name);
45}
46
47///////////////////////////////////////////////////////////////////////////////
48
49struct FamilyRec;
50
51/* This guy holds a mapping of a name -> family, used for looking up fonts.
52 Since it is stored in a stretchy array that doesn't preserve object
53 semantics, we don't use constructor/destructors, but just have explicit
54 helpers to manage our internal bookkeeping.
55*/
56struct NameFamilyPair {
57 const char* fName; // we own this
58 FamilyRec* fFamily; // we don't own this, we just reference it
reed@google.com4f809512011-01-04 21:25:43 +000059
reed@android.comfcce6472009-03-20 12:23:07 +000060 void construct(const char name[], FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 fName = strdup(name);
62 fFamily = family; // we don't own this, so just record the referene
63 }
reed@android.comfcce6472009-03-20 12:23:07 +000064
65 void destruct() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 free((char*)fName);
67 // we don't own family, so just ignore our reference
68 }
69};
djsollen@google.come4013992012-02-16 15:18:39 +000070typedef SkTDArray<NameFamilyPair> NameFamilyPairList;
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
72// we use atomic_inc to grow this for each typeface we create
73static int32_t gUniqueFontID;
74
djsollen@google.come4013992012-02-16 15:18:39 +000075// this is the mutex that protects gFamilyHead and GetNameList()
76SK_DECLARE_STATIC_MUTEX(gFamilyHeadAndNameListMutex);
reed@android.com8a1c16f2008-12-17 15:59:43 +000077static FamilyRec* gFamilyHead;
djsollen@google.come4013992012-02-16 15:18:39 +000078
79static NameFamilyPairList& GetNameList() {
80 /*
81 * It is assumed that the caller has already acquired a lock on
82 * gFamilyHeadAndNameListMutex before calling this.
83 */
84 static NameFamilyPairList* gNameList;
85 if (NULL == gNameList) {
86 gNameList = SkNEW(NameFamilyPairList);
87 // register a delete proc with sk_atexit(..) when available
88 }
89 return *gNameList;
90}
reed@android.com8a1c16f2008-12-17 15:59:43 +000091
92struct FamilyRec {
93 FamilyRec* fNext;
94 SkTypeface* fFaces[4];
reed@google.com4f809512011-01-04 21:25:43 +000095
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 FamilyRec()
97 {
98 fNext = gFamilyHead;
99 memset(fFaces, 0, sizeof(fFaces));
100 gFamilyHead = this;
101 }
102};
103
104static SkTypeface* find_best_face(const FamilyRec* family,
reed@android.comfcce6472009-03-20 12:23:07 +0000105 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 SkTypeface* const* faces = family->fFaces;
107
108 if (faces[style] != NULL) { // exact match
109 return faces[style];
110 }
111 // look for a matching bold
112 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
113 if (faces[style] != NULL) {
114 return faces[style];
115 }
116 // look for the plain
117 if (faces[SkTypeface::kNormal] != NULL) {
118 return faces[SkTypeface::kNormal];
119 }
120 // look for anything
121 for (int i = 0; i < 4; i++) {
122 if (faces[i] != NULL) {
123 return faces[i];
124 }
125 }
126 // should never get here, since the faces list should not be empty
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000127 SkDEBUGFAIL("faces list is empty");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 return NULL;
129}
130
reed@android.comfcce6472009-03-20 12:23:07 +0000131static FamilyRec* find_family(const SkTypeface* member) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 FamilyRec* curr = gFamilyHead;
133 while (curr != NULL) {
134 for (int i = 0; i < 4; i++) {
135 if (curr->fFaces[i] == member) {
136 return curr;
137 }
138 }
139 curr = curr->fNext;
140 }
141 return NULL;
142}
143
djsollen@google.comb0d416c2012-06-01 15:36:39 +0000144// gFamilyHeadAndNameListMutex must already be acquired
145static const char* find_family_name(const SkTypeface* member) {
146 FamilyRec* family = find_family(member);
147 if (NULL == family) {
148 return NULL;
149 }
150
151 NameFamilyPairList& namelist = GetNameList();
152 NameFamilyPair* list = namelist.begin();
153 int count = namelist.count();
154
155 for (int i = 0; i < count; i++) {
156 NameFamilyPair* pair = &list[i];
157 if (pair->fFamily == family) {
158 return pair->fName;
159 }
160 }
161
162 return NULL;
163}
164
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000165/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
166 is not modified.
167 */
reed@android.comfcce6472009-03-20 12:23:07 +0000168static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 FamilyRec* curr = gFamilyHead;
170 while (curr != NULL) {
171 for (int i = 0; i < 4; i++) {
172 SkTypeface* face = curr->fFaces[i];
173 if (face != NULL && face->uniqueID() == uniqueID) {
174 return face;
175 }
176 }
177 curr = curr->fNext;
178 }
179 return NULL;
180}
181
182/* Remove reference to this face from its family. If the resulting family
183 is empty (has no faces), return that family, otherwise return NULL
184*/
reed@android.comfcce6472009-03-20 12:23:07 +0000185static FamilyRec* remove_from_family(const SkTypeface* face) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 FamilyRec* family = find_family(face);
djsollen@google.com58629292011-11-03 13:08:29 +0000187 if (family) {
188 SkASSERT(family->fFaces[face->style()] == face);
189 family->fFaces[face->style()] = NULL;
reed@google.com4f809512011-01-04 21:25:43 +0000190
djsollen@google.com58629292011-11-03 13:08:29 +0000191 for (int i = 0; i < 4; i++) {
192 if (family->fFaces[i] != NULL) { // family is non-empty
193 return NULL;
194 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 }
djsollen@google.com58629292011-11-03 13:08:29 +0000196 } else {
197// SkDebugf("remove_from_family(%p) face not found", face);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 }
199 return family; // return the empty family
200}
201
202// maybe we should make FamilyRec be doubly-linked
reed@android.comfcce6472009-03-20 12:23:07 +0000203static void detach_and_delete_family(FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 FamilyRec* curr = gFamilyHead;
205 FamilyRec* prev = NULL;
206
207 while (curr != NULL) {
208 FamilyRec* next = curr->fNext;
209 if (curr == family) {
210 if (prev == NULL) {
211 gFamilyHead = next;
212 } else {
213 prev->fNext = next;
214 }
215 SkDELETE(family);
216 return;
217 }
218 prev = curr;
219 curr = next;
220 }
djsollen@google.com60abb072012-02-15 18:49:15 +0000221 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222}
223
djsollen@google.come4013992012-02-16 15:18:39 +0000224// gFamilyHeadAndNameListMutex must already be acquired
reed@android.comfcce6472009-03-20 12:23:07 +0000225static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
djsollen@google.come4013992012-02-16 15:18:39 +0000226 NameFamilyPairList& namelist = GetNameList();
227 NameFamilyPair* list = namelist.begin();
228 int count = namelist.count();
reed@google.com4f809512011-01-04 21:25:43 +0000229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
231
232 if (index >= 0) {
233 return find_best_face(list[index].fFamily, style);
234 }
235 return NULL;
236}
237
djsollen@google.come4013992012-02-16 15:18:39 +0000238// gFamilyHeadAndNameListMutex must already be acquired
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239static SkTypeface* find_typeface(const SkTypeface* familyMember,
reed@android.comfcce6472009-03-20 12:23:07 +0000240 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 const FamilyRec* family = find_family(familyMember);
242 return family ? find_best_face(family, style) : NULL;
243}
244
djsollen@google.come4013992012-02-16 15:18:39 +0000245// gFamilyHeadAndNameListMutex must already be acquired
reed@android.comfcce6472009-03-20 12:23:07 +0000246static void add_name(const char name[], FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 SkAutoAsciiToLC tolc(name);
248 name = tolc.lc();
249
djsollen@google.come4013992012-02-16 15:18:39 +0000250 NameFamilyPairList& namelist = GetNameList();
251 NameFamilyPair* list = namelist.begin();
252 int count = namelist.count();
reed@google.com4f809512011-01-04 21:25:43 +0000253
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
255
256 if (index < 0) {
djsollen@google.come4013992012-02-16 15:18:39 +0000257 list = namelist.insert(~index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 list->construct(name, family);
259 }
260}
261
djsollen@google.come4013992012-02-16 15:18:39 +0000262// gFamilyHeadAndNameListMutex must already be acquired
263static void remove_from_names(FamilyRec* emptyFamily) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264#ifdef SK_DEBUG
265 for (int i = 0; i < 4; i++) {
266 SkASSERT(emptyFamily->fFaces[i] == NULL);
267 }
268#endif
269
djsollen@google.come4013992012-02-16 15:18:39 +0000270 SkTDArray<NameFamilyPair>& list = GetNameList();
reed@google.com4f809512011-01-04 21:25:43 +0000271
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 // must go backwards when removing
273 for (int i = list.count() - 1; i >= 0; --i) {
274 NameFamilyPair* pair = &list[i];
275 if (pair->fFamily == emptyFamily) {
276 pair->destruct();
277 list.remove(i);
278 }
279 }
280}
281
282///////////////////////////////////////////////////////////////////////////////
283
reed@google.com0da48612013-03-19 16:06:52 +0000284class FamilyTypeface : public SkTypeface_FreeType {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285public:
reed@google.com5b31b0f2011-02-23 14:41:42 +0000286 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
287 bool isFixedWidth)
reed@google.com0da48612013-03-19 16:06:52 +0000288 : INHERITED(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 fIsSysFont = sysFont;
reed@google.com4f809512011-01-04 21:25:43 +0000290
djsollen@google.come4013992012-02-16 15:18:39 +0000291 // our caller has acquired the gFamilyHeadAndNameListMutex so this is safe
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 FamilyRec* rec = NULL;
293 if (familyMember) {
294 rec = find_family(familyMember);
295 SkASSERT(rec);
296 } else {
297 rec = SkNEW(FamilyRec);
298 }
299 rec->fFaces[style] = this;
300 }
reed@google.com4f809512011-01-04 21:25:43 +0000301
reed@android.comfcce6472009-03-20 12:23:07 +0000302 virtual ~FamilyTypeface() {
djsollen@google.come4013992012-02-16 15:18:39 +0000303 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@google.com4f809512011-01-04 21:25:43 +0000304
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 // remove us from our family. If the family is now empty, we return
306 // that and then remove that family from the name list
307 FamilyRec* family = remove_from_family(this);
308 if (NULL != family) {
309 remove_from_names(family);
310 detach_and_delete_family(family);
311 }
312 }
reed@google.com4f809512011-01-04 21:25:43 +0000313
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 bool isSysFont() const { return fIsSysFont; }
reed@google.com4f809512011-01-04 21:25:43 +0000315
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 virtual SkStream* openStream() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317 virtual const char* getUniqueString() const = 0;
reed@android.comac981542009-07-31 16:17:01 +0000318 virtual const char* getFilePath() const = 0;
reed@google.com4f809512011-01-04 21:25:43 +0000319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320private:
321 bool fIsSysFont;
reed@google.com4f809512011-01-04 21:25:43 +0000322
reed@google.com0da48612013-03-19 16:06:52 +0000323 typedef SkTypeface_FreeType INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324};
325
326///////////////////////////////////////////////////////////////////////////////
327
328class StreamTypeface : public FamilyTypeface {
329public:
330 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
reed@google.com5b31b0f2011-02-23 14:41:42 +0000331 SkStream* stream, bool isFixedWidth)
332 : INHERITED(style, sysFont, familyMember, isFixedWidth) {
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000333 SkASSERT(stream);
334 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 fStream = stream;
336 }
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000337 virtual ~StreamTypeface() {
338 fStream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
reed@google.com4f809512011-01-04 21:25:43 +0000340
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 // overrides
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000342 virtual SkStream* openStream() {
343 // we just ref our existing stream, since the caller will call unref()
344 // when they are through
345 fStream->ref();
reed@google.com4f809512011-01-04 21:25:43 +0000346 // must rewind each time, since the caller assumes a "new" stream
347 fStream->rewind();
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000348 return fStream;
349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 virtual const char* getUniqueString() const { return NULL; }
reed@android.comac981542009-07-31 16:17:01 +0000351 virtual const char* getFilePath() const { return NULL; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352
353private:
354 SkStream* fStream;
reed@google.com4f809512011-01-04 21:25:43 +0000355
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 typedef FamilyTypeface INHERITED;
357};
358
359class FileTypeface : public FamilyTypeface {
360public:
361 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
reed@google.com5b31b0f2011-02-23 14:41:42 +0000362 const char path[], bool isFixedWidth)
363 : INHERITED(style, sysFont, familyMember, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 SkString fullpath;
reed@google.com4f809512011-01-04 21:25:43 +0000365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366 if (sysFont) {
367 GetFullPathForSysFonts(&fullpath, path);
368 path = fullpath.c_str();
369 }
370 fPath.set(path);
371 }
reed@google.com4f809512011-01-04 21:25:43 +0000372
reed@google.come1575aa2013-03-18 21:08:46 +0000373 virtual SkStream* openStream() SK_OVERRIDE {
374 return SkStream::NewFromFile(fPath.c_str());
reed@google.com070235e2013-03-18 20:53:49 +0000375 }
reed@google.come1575aa2013-03-18 21:08:46 +0000376
377 virtual const char* getUniqueString() const SK_OVERRIDE {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const char* str = strrchr(fPath.c_str(), '/');
379 if (str) {
380 str += 1; // skip the '/'
381 }
382 return str;
383 }
reed@google.come1575aa2013-03-18 21:08:46 +0000384
385 virtual const char* getFilePath() const SK_OVERRIDE {
reed@android.comac981542009-07-31 16:17:01 +0000386 return fPath.c_str();
387 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388
389private:
390 SkString fPath;
reed@google.com4f809512011-01-04 21:25:43 +0000391
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 typedef FamilyTypeface INHERITED;
393};
394
395///////////////////////////////////////////////////////////////////////////////
396///////////////////////////////////////////////////////////////////////////////
397
398static bool get_name_and_style(const char path[], SkString* name,
reed@google.com5b31b0f2011-02-23 14:41:42 +0000399 SkTypeface::Style* style,
400 bool* isFixedWidth, bool isExpected) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 SkString fullpath;
402 GetFullPathForSysFonts(&fullpath, path);
403
reed@google.come1575aa2013-03-18 21:08:46 +0000404 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(fullpath.c_str()));
405 if (stream.get()) {
406 return find_name_and_attributes(stream, name, style, isFixedWidth);
407 } else {
408 if (isExpected) {
409 SkDebugf("---- failed to open <%s> as a font", fullpath.c_str());
reed@google.com070235e2013-03-18 20:53:49 +0000410 }
reed@google.come1575aa2013-03-18 21:08:46 +0000411 return false;
reed@google.com070235e2013-03-18 20:53:49 +0000412 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413}
414
reed@android.comfcce6472009-03-20 12:23:07 +0000415// used to record our notion of the pre-existing fonts
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416struct FontInitRec {
417 const char* fFileName;
418 const char* const* fNames; // null-terminated list
419};
420
reed@android.comfcce6472009-03-20 12:23:07 +0000421// deliberately empty, but we use the address to identify fallback fonts
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422static const char* gFBNames[] = { NULL };
423
djsollen@google.com58629292011-11-03 13:08:29 +0000424/* Fonts are grouped by family, with the first font in a family having the
425 list of names (even if that list is empty), and the following members having
426 null for the list. The names list must be NULL-terminated.
427*/
428static FontInitRec *gSystemFonts;
429static size_t gNumSystemFonts = 0;
430
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431// these globals are assigned (once) by load_system_fonts()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432static FamilyRec* gDefaultFamily;
433static SkTypeface* gDefaultNormal;
djsollen@google.com58629292011-11-03 13:08:29 +0000434static char** gDefaultNames = NULL;
435static uint32_t *gFallbackFonts;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436
djsollen@google.comefbe8e92013-02-07 18:58:35 +0000437#if SK_DEBUG_FONTS
djsollen@google.come63793a2012-03-21 15:39:03 +0000438static void dump_globals() {
439 SkDebugf("gDefaultNormal=%p id=%u refCnt=%d", gDefaultNormal,
440 gDefaultNormal ? gDefaultNormal->uniqueID() : 0,
441 gDefaultNormal ? gDefaultNormal->getRefCnt() : 0);
442
443 if (gDefaultFamily) {
444 SkDebugf("gDefaultFamily=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
445 gDefaultFamily,
446 gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->uniqueID() : 0,
447 gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->uniqueID() : 0,
448 gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->uniqueID() : 0,
449 gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->uniqueID() : 0,
450 gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->getRefCnt() : 0,
451 gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->getRefCnt() : 0,
452 gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->getRefCnt() : 0,
453 gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->getRefCnt() : 0);
454 } else {
455 SkDebugf("gDefaultFamily=%p", gDefaultFamily);
456 }
457
458 SkDebugf("gNumSystemFonts=%d gSystemFonts=%p gFallbackFonts=%p",
459 gNumSystemFonts, gSystemFonts, gFallbackFonts);
460
461 for (size_t i = 0; i < gNumSystemFonts; ++i) {
462 SkDebugf("gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName);
463 size_t namesIndex = 0;
464 if (gSystemFonts[i].fNames)
465 for (const char* fontName = gSystemFonts[i].fNames[namesIndex];
466 fontName != 0;
467 fontName = gSystemFonts[i].fNames[++namesIndex]) {
468 SkDebugf(" name[%u]=%s", namesIndex, fontName);
469 }
470 }
471
472 if (gFamilyHead) {
473 FamilyRec* rec = gFamilyHead;
474 int i=0;
475 while (rec) {
476 SkDebugf("gFamilyHead[%d]=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
477 i++, rec,
478 rec->fFaces[0] ? rec->fFaces[0]->uniqueID() : 0,
479 rec->fFaces[1] ? rec->fFaces[1]->uniqueID() : 0,
480 rec->fFaces[2] ? rec->fFaces[2]->uniqueID() : 0,
481 rec->fFaces[3] ? rec->fFaces[3]->uniqueID() : 0,
482 rec->fFaces[0] ? rec->fFaces[0]->getRefCnt() : 0,
483 rec->fFaces[1] ? rec->fFaces[1]->getRefCnt() : 0,
484 rec->fFaces[2] ? rec->fFaces[2]->getRefCnt() : 0,
485 rec->fFaces[3] ? rec->fFaces[3]->getRefCnt() : 0);
486 rec = rec->fNext;
487 }
488 } else {
489 SkDebugf("gFamilyHead=%p", gFamilyHead);
490 }
491
492}
djsollen@google.comefbe8e92013-02-07 18:58:35 +0000493#endif
djsollen@google.come63793a2012-03-21 15:39:03 +0000494
495
djsollen@google.com58629292011-11-03 13:08:29 +0000496/* Load info from a configuration file that populates the system/fallback font structures
497*/
498static void load_font_info() {
djsollen@google.com58629292011-11-03 13:08:29 +0000499 SkTDArray<FontFamily*> fontFamilies;
djsollen@google.com5df2a992012-06-25 13:58:22 +0000500 if (gTestMainConfigFile) {
501 getTestFontFamilies(fontFamilies, gTestMainConfigFile, gTestFallbackConfigFile);
502 } else {
503 getFontFamilies(fontFamilies);
504 }
djsollen@google.com58629292011-11-03 13:08:29 +0000505
506 SkTDArray<FontInitRec> fontInfo;
djsollen@google.com58629292011-11-03 13:08:29 +0000507 for (int i = 0; i < fontFamilies.count(); ++i) {
508 FontFamily *family = fontFamilies[i];
djsollen@google.com58629292011-11-03 13:08:29 +0000509 for (int j = 0; j < family->fFileNames.count(); ++j) {
510 FontInitRec fontInfoRecord;
511 fontInfoRecord.fFileName = family->fFileNames[j];
512 if (j == 0) {
513 if (family->fNames.count() == 0) {
514 // Fallback font
515 fontInfoRecord.fNames = (char **)gFBNames;
516 } else {
517 SkTDArray<const char*> names = family->fNames;
518 const char **nameList = (const char**)
519 malloc((names.count() + 1) * sizeof(char*));
520 if (nameList == NULL) {
521 // shouldn't get here
djsollen@google.combae17122012-10-09 19:26:59 +0000522 SkDEBUGFAIL("Failed to allocate nameList");
djsollen@google.com58629292011-11-03 13:08:29 +0000523 break;
524 }
525 if (gDefaultNames == NULL) {
526 gDefaultNames = (char**) nameList;
527 }
528 for (int i = 0; i < names.count(); ++i) {
529 nameList[i] = names[i];
530 }
531 nameList[names.count()] = NULL;
532 fontInfoRecord.fNames = nameList;
533 }
534 } else {
535 fontInfoRecord.fNames = NULL;
536 }
537 *fontInfo.append() = fontInfoRecord;
538 }
539 }
540 gNumSystemFonts = fontInfo.count();
541 gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
542 gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
543 if (gSystemFonts == NULL) {
544 // shouldn't get here
djsollen@google.com548674f2012-05-04 12:03:48 +0000545 SkDEBUGFAIL("No system fonts were found");
djsollen@google.com58629292011-11-03 13:08:29 +0000546 gNumSystemFonts = 0;
547 }
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000548
549#if SK_DEBUG_FONTS
550 SkDebugf("---- We have %d system fonts", gNumSystemFonts);
551#endif
djsollen@google.com58629292011-11-03 13:08:29 +0000552 for (size_t i = 0; i < gNumSystemFonts; ++i) {
553 gSystemFonts[i].fFileName = fontInfo[i].fFileName;
554 gSystemFonts[i].fNames = fontInfo[i].fNames;
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000555#if SK_DEBUG_FONTS
djsollen@google.com3f5d6822012-10-05 15:19:27 +0000556 SkDebugf("---- gSystemFonts[%d] fileName=%s", i, fontInfo[i].fFileName);
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000557#endif
djsollen@google.com58629292011-11-03 13:08:29 +0000558 }
559 fontFamilies.deleteAll();
560}
reed@android.comfcce6472009-03-20 12:23:07 +0000561
djsollen@google.come4013992012-02-16 15:18:39 +0000562/*
563 * Called once (ensured by the sentinel check at the beginning of our body).
564 * Initializes all the globals, and register the system fonts.
565 *
566 * gFamilyHeadAndNameListMutex must already be acquired.
reed@android.comfcce6472009-03-20 12:23:07 +0000567 */
djsollen@google.come63793a2012-03-21 15:39:03 +0000568static void init_system_fonts() {
569 // check if we've already been called
570 if (gDefaultNormal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571 return;
572 }
reed@google.com4f809512011-01-04 21:25:43 +0000573
djsollen@google.com548674f2012-05-04 12:03:48 +0000574 SkASSERT(gUniqueFontID == 0);
575
djsollen@google.com58629292011-11-03 13:08:29 +0000576 load_font_info();
577
djsollen@google.combae17122012-10-09 19:26:59 +0000578 FontInitRec* rec = gSystemFonts;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579 SkTypeface* firstInFamily = NULL;
reed@android.comfcce6472009-03-20 12:23:07 +0000580 int fallbackCount = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581
djsollen@google.com58629292011-11-03 13:08:29 +0000582 for (size_t i = 0; i < gNumSystemFonts; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583 // if we're the first in a new family, clear firstInFamily
584 if (rec[i].fNames != NULL) {
585 firstInFamily = NULL;
586 }
reed@google.com4f809512011-01-04 21:25:43 +0000587
reed@google.com5b31b0f2011-02-23 14:41:42 +0000588 bool isFixedWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000589 SkString name;
590 SkTypeface::Style style;
reed@android.comfcce6472009-03-20 12:23:07 +0000591
592 // we expect all the fonts, except the "fallback" fonts
593 bool isExpected = (rec[i].fNames != gFBNames);
reed@google.com5b31b0f2011-02-23 14:41:42 +0000594 if (!get_name_and_style(rec[i].fFileName, &name, &style,
595 &isFixedWidth, isExpected)) {
djsollen@google.com548674f2012-05-04 12:03:48 +0000596 // We need to increase gUniqueFontID here so that the unique id of
597 // each font matches its index in gSystemFonts array, as expected
598 // by find_uniqueID.
599 sk_atomic_inc(&gUniqueFontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 continue;
601 }
602
603 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
604 (style,
605 true, // system-font (cannot delete)
606 firstInFamily, // what family to join
reed@google.com5b31b0f2011-02-23 14:41:42 +0000607 rec[i].fFileName,
608 isFixedWidth) // filename
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609 );
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000610#if SK_DEBUG_FONTS
611 SkDebugf("---- SkTypeface[%d] %s fontID %d",
612 i, rec[i].fFileName, tf->uniqueID());
613#endif
djsollen@google.com60abb072012-02-15 18:49:15 +0000614
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 if (rec[i].fNames != NULL) {
reed@android.comfcce6472009-03-20 12:23:07 +0000616 // see if this is one of our fallback fonts
617 if (rec[i].fNames == gFBNames) {
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000618#if SK_DEBUG_FONTS
619 SkDebugf("---- adding %s as fallback[%d] fontID %d",
620 rec[i].fFileName, fallbackCount, tf->uniqueID());
621#endif
reed@android.comfcce6472009-03-20 12:23:07 +0000622 gFallbackFonts[fallbackCount++] = tf->uniqueID();
djsollen@google.combae17122012-10-09 19:26:59 +0000623
624 // Use the font file name as the name of the typeface.
625 const char **nameList = (const char**)malloc(2 * sizeof(char*));
626 if (nameList == NULL) {
627 // shouldn't get here
628 SkDEBUGFAIL("Failed to allocate nameList");
629 break;
630 }
631 nameList[0] = rec[i].fFileName;
632 nameList[1] = NULL;
633 rec[i].fNames = nameList;
reed@android.comfcce6472009-03-20 12:23:07 +0000634 }
635
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636 firstInFamily = tf;
reed@android.comfcce6472009-03-20 12:23:07 +0000637 FamilyRec* family = find_family(tf);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638 const char* const* names = rec[i].fNames;
639
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640 // record the default family if this is it
djsollen@google.com58629292011-11-03 13:08:29 +0000641 if (names == gDefaultNames) {
reed@android.comfcce6472009-03-20 12:23:07 +0000642 gDefaultFamily = family;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 }
644 // add the names to map to this family
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645 while (*names) {
646 add_name(*names, family);
647 names += 1;
648 }
649 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650 }
651
652 // do this after all fonts are loaded. This is our default font, and it
653 // acts as a sentinel so we only execute load_system_fonts() once
654 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
reed@android.comfcce6472009-03-20 12:23:07 +0000655 // now terminate our fallback list with the sentinel value
656 gFallbackFonts[fallbackCount] = 0;
djsollen@google.com548674f2012-05-04 12:03:48 +0000657
djsollen@google.comefbe8e92013-02-07 18:58:35 +0000658#if SK_DEBUG_FONTS
659 SkDEBUGCODE(dump_globals());
660#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
djsollen@google.come63793a2012-03-21 15:39:03 +0000663static size_t find_uniqueID(const char* filename) {
djsollen@google.com548674f2012-05-04 12:03:48 +0000664 // uniqueID is the index, offset by one, of the associated element in
665 // gSystemFonts[] (assumes system fonts are loaded before external fonts)
djsollen@google.come63793a2012-03-21 15:39:03 +0000666 // return 0 if not found
667 const FontInitRec* rec = gSystemFonts;
668 for (size_t i = 0; i < gNumSystemFonts; i++) {
669 if (strcmp(rec[i].fFileName, filename) == 0) {
670 return i+1;
671 }
672 }
673 return 0;
674}
675
676static void reload_fallback_fonts() {
djsollen@google.com5df2a992012-06-25 13:58:22 +0000677 if (gTestFallbackConfigFile) {
678 // No need to reload fallback fonts in test environment.
679 return;
680 }
681
djsollen@google.come63793a2012-03-21 15:39:03 +0000682 SkGraphics::PurgeFontCache();
683
684 SkTDArray<FontFamily*> fallbackFamilies;
685 getFallbackFontFamilies(fallbackFamilies);
686
djsollen@google.com548674f2012-05-04 12:03:48 +0000687 int fallbackCount = 0;
djsollen@google.come63793a2012-03-21 15:39:03 +0000688 for (int i = 0; i < fallbackFamilies.count(); ++i) {
689 FontFamily *family = fallbackFamilies[i];
690
691 for (int j = 0; j < family->fFileNames.count(); ++j) {
692 if (family->fFileNames[j]) {
djsollen@google.com548674f2012-05-04 12:03:48 +0000693
694 // ensure the fallback font exists before adding it to the list
695 bool isFixedWidth;
696 SkString name;
697 SkTypeface::Style style;
698 if (!get_name_and_style(family->fFileNames[j], &name, &style,
699 &isFixedWidth, false)) {
700 continue;
701 }
702
djsollen@google.come63793a2012-03-21 15:39:03 +0000703 size_t uniqueID = find_uniqueID(family->fFileNames[j]);
djsollen@google.com548674f2012-05-04 12:03:48 +0000704 SkASSERT(uniqueID != 0);
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000705#if SK_DEBUG_FONTS
706 SkDebugf("---- reload %s as fallback[%d] fontID %d oldFontID %d",
djsollen@google.com548674f2012-05-04 12:03:48 +0000707 family->fFileNames[j], fallbackCount, uniqueID,
djsollen@google.com6f1dbff2012-10-05 14:48:32 +0000708 gFallbackFonts[fallbackCount]);
709#endif
djsollen@google.com548674f2012-05-04 12:03:48 +0000710 gFallbackFonts[fallbackCount++] = uniqueID;
djsollen@google.come63793a2012-03-21 15:39:03 +0000711 break; // The fallback set contains only the first font of each family
712 }
713 }
714 }
djsollen@google.com548674f2012-05-04 12:03:48 +0000715 // reset the sentinel the end of the newly ordered array
716 gFallbackFonts[fallbackCount] = 0;
djsollen@google.come63793a2012-03-21 15:39:03 +0000717}
718
719static void load_system_fonts() {
djsollen@google.comfc9054d2012-05-10 16:13:38 +0000720 static AndroidLocale prevLocale;
721 AndroidLocale locale;
djsollen@google.come63793a2012-03-21 15:39:03 +0000722
djsollen@google.comfc9054d2012-05-10 16:13:38 +0000723 getLocale(locale);
djsollen@google.come63793a2012-03-21 15:39:03 +0000724
725 if (!gDefaultNormal) {
djsollen@google.comfc9054d2012-05-10 16:13:38 +0000726 prevLocale = locale;
djsollen@google.come63793a2012-03-21 15:39:03 +0000727 init_system_fonts();
djsollen@google.comfc9054d2012-05-10 16:13:38 +0000728 } else if (strncmp(locale.language, prevLocale.language, 2) ||
729 strncmp(locale.region, prevLocale.region, 2)) {
730 prevLocale = locale;
djsollen@google.come63793a2012-03-21 15:39:03 +0000731 reload_fallback_fonts();
732 }
djsollen@google.come63793a2012-03-21 15:39:03 +0000733}
734
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735///////////////////////////////////////////////////////////////////////////////
736
737void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738
djsollen@google.com97145162012-05-31 19:55:08 +0000739 SkFontDescriptor descriptor;
djsollen@google.comb0d416c2012-06-01 15:36:39 +0000740 {
741 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
742 descriptor.setFamilyName(find_family_name(face));
743 descriptor.setStyle(face->style());
744 descriptor.setFontFileName(((FamilyTypeface*)face)->getUniqueString());
745 }
djsollen@google.com97145162012-05-31 19:55:08 +0000746
747 descriptor.serialize(stream);
748
749 const bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
djsollen@google.com58629292011-11-03 13:08:29 +0000750 if (isCustomFont) {
djsollen@google.com97145162012-05-31 19:55:08 +0000751 // store the entire font in the fontData
djsollen@google.com58629292011-11-03 13:08:29 +0000752 SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
djsollen@google.com97145162012-05-31 19:55:08 +0000753 const uint32_t length = fontStream->getLength();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754
djsollen@google.com97145162012-05-31 19:55:08 +0000755 stream->writePackedUInt(length);
756 stream->writeStream(fontStream, length);
djsollen@google.com58629292011-11-03 13:08:29 +0000757
758 fontStream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759 } else {
djsollen@google.com97145162012-05-31 19:55:08 +0000760 stream->writePackedUInt(0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761 }
762}
763
764SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
djsollen@google.com4cccc6b2012-03-30 12:42:12 +0000765 {
766 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
767 load_system_fonts();
768 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769
djsollen@google.com97145162012-05-31 19:55:08 +0000770 SkFontDescriptor descriptor(stream);
djsollen@google.comb0d416c2012-06-01 15:36:39 +0000771 const char* familyName = descriptor.getFamilyName();
djsollen@google.com97145162012-05-31 19:55:08 +0000772 const char* fontFileName = descriptor.getFontFileName();
djsollen@google.comb0d416c2012-06-01 15:36:39 +0000773 const SkTypeface::Style style = descriptor.getStyle();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774
djsollen@google.com97145162012-05-31 19:55:08 +0000775 const uint32_t customFontDataLength = stream->readPackedUInt();
776 if (customFontDataLength > 0) {
djsollen@google.com58629292011-11-03 13:08:29 +0000777
778 // generate a new stream to store the custom typeface
djsollen@google.com97145162012-05-31 19:55:08 +0000779 SkMemoryStream* fontStream = new SkMemoryStream(customFontDataLength - 1);
780 stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1);
djsollen@google.com58629292011-11-03 13:08:29 +0000781
782 SkTypeface* face = CreateTypefaceFromStream(fontStream);
783
784 fontStream->unref();
djsollen@google.com58629292011-11-03 13:08:29 +0000785 return face;
djsollen@google.com97145162012-05-31 19:55:08 +0000786 }
djsollen@google.com58629292011-11-03 13:08:29 +0000787
djsollen@google.com97145162012-05-31 19:55:08 +0000788 if (NULL != fontFileName && 0 != *fontFileName) {
789 const FontInitRec* rec = gSystemFonts;
790 for (size_t i = 0; i < gNumSystemFonts; i++) {
791 if (strcmp(rec[i].fFileName, fontFileName) == 0) {
792 // backup until we hit the fNames
793 for (int j = i; j >= 0; --j) {
794 if (rec[j].fNames != NULL) {
795 return SkFontHost::CreateTypeface(NULL,
796 rec[j].fNames[0], style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797 }
798 }
799 }
800 }
801 }
djsollen@google.com97145162012-05-31 19:55:08 +0000802
803 return SkFontHost::CreateTypeface(NULL, familyName, style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804}
805
806///////////////////////////////////////////////////////////////////////////////
807
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000808SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
809 const char familyName[],
reed@android.comfcce6472009-03-20 12:23:07 +0000810 SkTypeface::Style style) {
djsollen@google.come4013992012-02-16 15:18:39 +0000811 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812
djsollen@google.come4013992012-02-16 15:18:39 +0000813 load_system_fonts();
reed@google.com4f809512011-01-04 21:25:43 +0000814
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 // clip to legal style bits
816 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
reed@google.com4f809512011-01-04 21:25:43 +0000817
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 SkTypeface* tf = NULL;
819
820 if (NULL != familyFace) {
821 tf = find_typeface(familyFace, style);
822 } else if (NULL != familyName) {
823// SkDebugf("======= familyName <%s>\n", familyName);
824 tf = find_typeface(familyName, style);
825 }
826
827 if (NULL == tf) {
828 tf = find_best_face(gDefaultFamily, style);
829 }
830
djsollen@google.come63793a2012-03-21 15:39:03 +0000831 // we ref(), since the semantic is to return a new instance
reed@android.comfb12c3e2009-03-05 20:43:42 +0000832 tf->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 return tf;
834}
835
reed@android.comfcce6472009-03-20 12:23:07 +0000836SkStream* SkFontHost::OpenStream(uint32_t fontID) {
djsollen@google.come4013992012-02-16 15:18:39 +0000837 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@google.com4f809512011-01-04 21:25:43 +0000838
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000839 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840 SkStream* stream = tf ? tf->openStream() : NULL;
841
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000842 if (stream && stream->getLength() == 0) {
843 stream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844 stream = NULL;
845 }
846 return stream;
847}
848
reed@android.comac981542009-07-31 16:17:01 +0000849size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
850 int32_t* index) {
djsollen@google.come4013992012-02-16 15:18:39 +0000851 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@android.comac981542009-07-31 16:17:01 +0000852
853 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
854 const char* src = tf ? tf->getFilePath() : NULL;
855
856 if (src) {
857 size_t size = strlen(src);
858 if (path) {
859 memcpy(path, src, SkMin32(size, length));
860 }
861 if (index) {
862 *index = 0; // we don't have collections (yet)
863 }
864 return size;
865 } else {
866 return 0;
867 }
868}
869
reed@google.com0da48612013-03-19 16:06:52 +0000870SkTypeface* SkFontHost::NextLogicalTypeface(SkFontID currFontID, SkFontID origFontID) {
commit-bot@chromium.org059a4c72013-03-13 12:48:26 +0000871#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
djsollen@google.combae17122012-10-09 19:26:59 +0000872 // Skia does not support font fallback for ndk applications in order to
873 // enable clients such as WebKit to customize their font selection.
874 // Clients can use GetFallbackFamilyNameForChar() to get the fallback
875 // font for individual characters.
reed@google.com0da48612013-03-19 16:06:52 +0000876 return NULL;
djsollen@google.combae17122012-10-09 19:26:59 +0000877#else
djsollen@google.come4013992012-02-16 15:18:39 +0000878 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
879
reed@android.com8a1c16f2008-12-17 15:59:43 +0000880 load_system_fonts();
881
djsollen@google.com58629292011-11-03 13:08:29 +0000882 const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
883 const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
884
885 SkASSERT(origTypeface != 0);
886 SkASSERT(currTypeface != 0);
djsollen@google.come63793a2012-03-21 15:39:03 +0000887 SkASSERT(gFallbackFonts);
djsollen@google.com58629292011-11-03 13:08:29 +0000888
889 // Our fallback list always stores the id of the plain in each fallback
890 // family, so we transform currFontID to its plain equivalent.
891 currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
892
reed@android.comfcce6472009-03-20 12:23:07 +0000893 /* First see if fontID is already one of our fallbacks. If so, return
894 its successor. If fontID is not in our list, then return the first one
895 in our list. Note: list is zero-terminated, and returning zero means
896 we have no more fonts to use for fallbacks.
897 */
898 const uint32_t* list = gFallbackFonts;
899 for (int i = 0; list[i] != 0; i++) {
reed@google.com7d26c592011-06-13 13:01:10 +0000900 if (list[i] == currFontID) {
djsollen@google.com58629292011-11-03 13:08:29 +0000901 if (list[i+1] == 0)
reed@google.com0da48612013-03-19 16:06:52 +0000902 return NULL;
djsollen@google.com58629292011-11-03 13:08:29 +0000903 const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
reed@google.com0da48612013-03-19 16:06:52 +0000904 return SkRef(find_typeface(nextTypeface, origTypeface->style()));
reed@android.comfcce6472009-03-20 12:23:07 +0000905 }
reed@android.coma14ea0e2009-03-17 17:59:53 +0000906 }
djsollen@google.com58629292011-11-03 13:08:29 +0000907
908 // If we get here, currFontID was not a fallback, so we start at the
djsollen@google.com5df2a992012-06-25 13:58:22 +0000909 // beginning of our list. Assuming there is at least one fallback font,
910 // i.e. gFallbackFonts[0] != 0.
djsollen@google.com58629292011-11-03 13:08:29 +0000911 const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
reed@google.com0da48612013-03-19 16:06:52 +0000912 return SkRef(find_typeface(firstTypeface, origTypeface->style()));
djsollen@google.combae17122012-10-09 19:26:59 +0000913#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000914}
915
916///////////////////////////////////////////////////////////////////////////////
917
reed@android.comfcce6472009-03-20 12:23:07 +0000918SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 if (NULL == stream || stream->getLength() <= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000920 return NULL;
921 }
reed@google.com4f809512011-01-04 21:25:43 +0000922
reed@google.com5b31b0f2011-02-23 14:41:42 +0000923 bool isFixedWidth;
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000924 SkTypeface::Style style;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000925
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000926 if (find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
djsollen@google.come4013992012-02-16 15:18:39 +0000927 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
tomhudson@google.comb9e4c5d2012-09-04 16:37:09 +0000928 // Make sure system fonts are loaded to comply with the assumption of
929 // unique id offset by one in find_uniqueID.
930 load_system_fonts();
djsollen@google.com7b34ea62011-02-24 16:28:51 +0000931 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
932 } else {
933 return NULL;
934 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935}
936
reed@android.comfcce6472009-03-20 12:23:07 +0000937SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
reed@google.come1575aa2013-03-18 21:08:46 +0000938 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
939 return stream.get() ? SkFontHost::CreateTypefaceFromStream(stream) : NULL;
reed@android.com1550a422008-12-23 20:10:57 +0000940}
djsollen@google.com15eeca02012-06-01 12:52:26 +0000941
942///////////////////////////////////////////////////////////////////////////////
943// Function from SkTypeface_android.h
944///////////////////////////////////////////////////////////////////////////////
945
946struct FBScriptInfo {
947 const FallbackScripts fScript;
948 const char* fScriptID;
949 const SkTypeface::Style fStyle;
950 const SkUnichar fChar; // representative character for that script type
951 SkFontID fFontID;
952};
953
954#define SK_DEFINE_SCRIPT_ENTRY(script, style, unichar) \
955 { script, #script, style, unichar, 0 }
956
957static FBScriptInfo gFBScriptInfo[] = {
djsollen@google.com57cdcc02012-08-29 19:08:50 +0000958 SK_DEFINE_SCRIPT_ENTRY(kArabic_FallbackScript, SkTypeface::kNormal, 0x0627),
djsollen@google.com15eeca02012-06-01 12:52:26 +0000959 SK_DEFINE_SCRIPT_ENTRY(kArmenian_FallbackScript, SkTypeface::kNormal, 0x0531),
960 SK_DEFINE_SCRIPT_ENTRY(kBengali_FallbackScript, SkTypeface::kNormal, 0x0981),
961 SK_DEFINE_SCRIPT_ENTRY(kDevanagari_FallbackScript, SkTypeface::kNormal, 0x0901),
962 SK_DEFINE_SCRIPT_ENTRY(kEthiopic_FallbackScript, SkTypeface::kNormal, 0x1200),
963 SK_DEFINE_SCRIPT_ENTRY(kGeorgian_FallbackScript, SkTypeface::kNormal, 0x10A0),
964 SK_DEFINE_SCRIPT_ENTRY(kHebrewRegular_FallbackScript, SkTypeface::kNormal, 0x0591),
965 SK_DEFINE_SCRIPT_ENTRY(kHebrewBold_FallbackScript, SkTypeface::kBold, 0x0591),
966 SK_DEFINE_SCRIPT_ENTRY(kKannada_FallbackScript, SkTypeface::kNormal, 0x0C90),
967 SK_DEFINE_SCRIPT_ENTRY(kMalayalam_FallbackScript, SkTypeface::kNormal, 0x0D10),
968 SK_DEFINE_SCRIPT_ENTRY(kTamilRegular_FallbackScript, SkTypeface::kNormal, 0x0B82),
969 SK_DEFINE_SCRIPT_ENTRY(kTamilBold_FallbackScript, SkTypeface::kBold, 0x0B82),
970 SK_DEFINE_SCRIPT_ENTRY(kThai_FallbackScript, SkTypeface::kNormal, 0x0E01),
971 SK_DEFINE_SCRIPT_ENTRY(kTelugu_FallbackScript, SkTypeface::kNormal, 0x0C10),
972};
973
974static bool gFBScriptInitialized = false;
975static const int gFBScriptInfoCount = sizeof(gFBScriptInfo) / sizeof(FBScriptInfo);
976
977// ensure that if any value is added to the public enum it is also added here
978SK_COMPILE_ASSERT(gFBScriptInfoCount == kFallbackScriptNumber, FBScript_count_mismatch);
979
djsollen@google.com77465f92012-10-15 16:03:41 +0000980// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
djsollen@google.combae17122012-10-09 19:26:59 +0000981static bool typefaceContainsChar(SkTypeface* face, SkUnichar uni) {
djsollen@google.com15eeca02012-06-01 12:52:26 +0000982 SkPaint paint;
983 paint.setTypeface(face);
984 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
985
djsollen@google.combae17122012-10-09 19:26:59 +0000986 uint16_t glyphID;
987 paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
988 return glyphID != 0;
989}
djsollen@google.com15eeca02012-06-01 12:52:26 +0000990
djsollen@google.com77465f92012-10-15 16:03:41 +0000991// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
djsollen@google.combae17122012-10-09 19:26:59 +0000992static SkTypeface* findFallbackTypefaceForChar(SkUnichar uni) {
993 SkASSERT(gFallbackFonts);
994 const uint32_t* list = gFallbackFonts;
995 for (int i = 0; list[i] != 0; i++) {
djsollen@google.com77465f92012-10-15 16:03:41 +0000996 SkTypeface* face;
997 {
998 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
999 face = find_from_uniqueID(list[i]);
1000 }
djsollen@google.combae17122012-10-09 19:26:59 +00001001 if (typefaceContainsChar(face, uni)) {
1002 return face;
1003 }
djsollen@google.com15eeca02012-06-01 12:52:26 +00001004 }
1005 return 0;
1006}
1007
djsollen@google.com77465f92012-10-15 16:03:41 +00001008// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
djsollen@google.combae17122012-10-09 19:26:59 +00001009static SkFontID findFallbackFontIDForChar(SkUnichar uni, SkTypeface::Style style) {
1010 const SkTypeface* tf = findFallbackTypefaceForChar(uni);
1011 if (!tf) {
1012 return 0;
1013 }
1014 return find_typeface(tf, style)->uniqueID();
1015}
1016
djsollen@google.com15eeca02012-06-01 12:52:26 +00001017// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
1018static void initFBScriptInfo() {
djsollen@google.com15eeca02012-06-01 12:52:26 +00001019 if (gFBScriptInitialized) {
1020 return;
1021 }
1022
1023 // ensure the system fonts are loaded
1024 gFamilyHeadAndNameListMutex.acquire();
1025 load_system_fonts();
1026 gFamilyHeadAndNameListMutex.release();
1027
1028 for (int i = 0; i < gFBScriptInfoCount; i++) {
1029 FBScriptInfo& scriptInfo = gFBScriptInfo[i];
1030 // selects the best available style for the desired font. However, if
1031 // bold is requested and no bold font exists for the typeface containing
1032 // the character the next best style is chosen (e.g. normal).
djsollen@google.combae17122012-10-09 19:26:59 +00001033 scriptInfo.fFontID = findFallbackFontIDForChar(scriptInfo.fChar, scriptInfo.fStyle);
djsollen@google.com6f1dbff2012-10-05 14:48:32 +00001034#if SK_DEBUG_FONTS
1035 SkDebugf("gFBScriptInfo[%s] --> %d", scriptInfo.fScriptID, scriptInfo.fFontID);
1036#endif
djsollen@google.com15eeca02012-06-01 12:52:26 +00001037 }
1038 // mark the value as initialized so we don't repeat our work unnecessarily
1039 gFBScriptInitialized = true;
1040}
1041
1042SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) {
1043 if (!SkTypeface_ValidScript(script)) {
1044 return NULL;
1045 }
1046
1047 // ensure that our table is populated
1048 initFBScriptInfo();
1049
1050 FBScriptInfo& scriptInfo = gFBScriptInfo[script];
1051
1052 // ensure the element with that index actually maps to the correct script
1053 SkASSERT(scriptInfo.fScript == script);
1054
1055 // if a suitable script could not be found then return NULL
1056 if (scriptInfo.fFontID == 0) {
1057 return NULL;
1058 }
1059
1060 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
1061
1062 // retrieve the typeface the corresponds to this fontID
1063 SkTypeface* tf = find_from_uniqueID(scriptInfo.fFontID);
1064 // we ref(), since the semantic is to return a new instance
1065 tf->ref();
1066 return tf;
1067}
1068
1069const char* SkGetFallbackScriptID(FallbackScripts script) {
1070 for (int i = 0; i < gFBScriptInfoCount; i++) {
1071 if (gFBScriptInfo[i].fScript == script) {
1072 return gFBScriptInfo[i].fScriptID;
1073 }
1074 }
1075 return NULL;
1076}
1077
1078FallbackScripts SkGetFallbackScriptFromID(const char* id) {
1079 for (int i = 0; i < gFBScriptInfoCount; i++) {
1080 if (strcmp(gFBScriptInfo[i].fScriptID, id) == 0) {
1081 return gFBScriptInfo[i].fScript;
1082 }
1083 }
1084 return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value.
1085}
djsollen@google.com5df2a992012-06-25 13:58:22 +00001086
djsollen@google.combae17122012-10-09 19:26:59 +00001087SkTypeface* SkCreateFallbackTypefaceForChar(SkUnichar uni,
1088 SkTypeface::Style style) {
djsollen@google.com77465f92012-10-15 16:03:41 +00001089 {
1090 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
1091 load_system_fonts();
1092 }
djsollen@google.combae17122012-10-09 19:26:59 +00001093
1094 SkTypeface* tf = findFallbackTypefaceForChar(uni);
1095 if (!tf) {
1096 return NULL;
1097 }
djsollen@google.com77465f92012-10-15 16:03:41 +00001098 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
djsollen@google.combae17122012-10-09 19:26:59 +00001099 tf = find_typeface(tf, style);
1100 // we ref(), since the semantic is to return a new instance
1101 tf->ref();
1102 return tf;
1103}
1104
1105bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
1106 SkASSERT(name);
djsollen@google.com77465f92012-10-15 16:03:41 +00001107 {
1108 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
1109 load_system_fonts();
1110 }
djsollen@google.combae17122012-10-09 19:26:59 +00001111
1112 const SkTypeface* tf = findFallbackTypefaceForChar(uni);
1113 if (!tf) {
1114 return false;
1115 }
djsollen@google.com77465f92012-10-15 16:03:41 +00001116 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
djsollen@google.combae17122012-10-09 19:26:59 +00001117 name->set(find_family_name(tf));
1118 return true;
1119}
1120
djsollen@google.com5df2a992012-06-25 13:58:22 +00001121void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
1122 const char* fontsdir) {
1123 gTestMainConfigFile = mainconf;
1124 gTestFallbackConfigFile = fallbackconf;
1125 gTestFontFilePrefix = fontsdir;
1126 SkASSERT(gTestMainConfigFile);
1127 SkASSERT(gTestFallbackConfigFile);
1128 SkASSERT(gTestFontFilePrefix);
1129 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
1130 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
1131}