blob: edbc0169af939781a4c0bfb426d8981a5f7e2c7f [file] [log] [blame]
djsollen@google.com60abb072012-02-15 18:49:15 +00001/* libs/graphics/ports/SkFontHost_android.cpp
djsollen@google.com58629292011-11-03 13:08:29 +00002**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
18#include "SkFontHost.h"
djsollen@google.come63793a2012-03-21 15:39:03 +000019#include "SkGraphics.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#include "SkDescriptor.h"
21#include "SkMMapStream.h"
22#include "SkPaint.h"
23#include "SkString.h"
24#include "SkStream.h"
25#include "SkThread.h"
26#include "SkTSearch.h"
djsollen@google.comff029602012-03-15 15:49:51 +000027#include "SkTypeface_android.h"
djsollen@google.com58629292011-11-03 13:08:29 +000028#include "FontHostConfiguration_android.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include <stdio.h>
djsollen@google.come63793a2012-03-21 15:39:03 +000030#include <string.h>
reed@android.com8a1c16f2008-12-17 15:59:43 +000031
djsollen@google.com60abb072012-02-15 18:49:15 +000032#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
33
reed@android.com8a1c16f2008-12-17 15:59:43 +000034#ifndef SK_FONT_FILE_PREFIX
35 #define SK_FONT_FILE_PREFIX "/fonts/"
36#endif
37
djsollen@google.com4dc686d2012-02-15 21:03:45 +000038bool find_name_and_attributes(SkStream* stream, SkString* name,
39 SkTypeface::Style* style, bool* isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
reed@android.comfcce6472009-03-20 12:23:07 +000041static void GetFullPathForSysFonts(SkString* full, const char name[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 full->set(getenv("ANDROID_ROOT"));
43 full->append(SK_FONT_FILE_PREFIX);
44 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.come63793a2012-03-21 15:39:03 +000078static SkTDArray<NameFamilyPair> gFallbackFilenameList;
djsollen@google.come4013992012-02-16 15:18:39 +000079
80static NameFamilyPairList& GetNameList() {
81 /*
82 * It is assumed that the caller has already acquired a lock on
83 * gFamilyHeadAndNameListMutex before calling this.
84 */
85 static NameFamilyPairList* gNameList;
86 if (NULL == gNameList) {
87 gNameList = SkNEW(NameFamilyPairList);
88 // register a delete proc with sk_atexit(..) when available
89 }
90 return *gNameList;
91}
reed@android.com8a1c16f2008-12-17 15:59:43 +000092
93struct FamilyRec {
94 FamilyRec* fNext;
95 SkTypeface* fFaces[4];
reed@google.com4f809512011-01-04 21:25:43 +000096
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 FamilyRec()
98 {
99 fNext = gFamilyHead;
100 memset(fFaces, 0, sizeof(fFaces));
101 gFamilyHead = this;
102 }
103};
104
105static SkTypeface* find_best_face(const FamilyRec* family,
reed@android.comfcce6472009-03-20 12:23:07 +0000106 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 SkTypeface* const* faces = family->fFaces;
108
109 if (faces[style] != NULL) { // exact match
110 return faces[style];
111 }
112 // look for a matching bold
113 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
114 if (faces[style] != NULL) {
115 return faces[style];
116 }
117 // look for the plain
118 if (faces[SkTypeface::kNormal] != NULL) {
119 return faces[SkTypeface::kNormal];
120 }
121 // look for anything
122 for (int i = 0; i < 4; i++) {
123 if (faces[i] != NULL) {
124 return faces[i];
125 }
126 }
127 // should never get here, since the faces list should not be empty
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000128 SkDEBUGFAIL("faces list is empty");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 return NULL;
130}
131
reed@android.comfcce6472009-03-20 12:23:07 +0000132static FamilyRec* find_family(const SkTypeface* member) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 FamilyRec* curr = gFamilyHead;
134 while (curr != NULL) {
135 for (int i = 0; i < 4; i++) {
136 if (curr->fFaces[i] == member) {
137 return curr;
138 }
139 }
140 curr = curr->fNext;
141 }
142 return NULL;
143}
144
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000145/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
146 is not modified.
147 */
reed@android.comfcce6472009-03-20 12:23:07 +0000148static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 FamilyRec* curr = gFamilyHead;
150 while (curr != NULL) {
151 for (int i = 0; i < 4; i++) {
152 SkTypeface* face = curr->fFaces[i];
153 if (face != NULL && face->uniqueID() == uniqueID) {
154 return face;
155 }
156 }
157 curr = curr->fNext;
158 }
159 return NULL;
160}
161
162/* Remove reference to this face from its family. If the resulting family
163 is empty (has no faces), return that family, otherwise return NULL
164*/
reed@android.comfcce6472009-03-20 12:23:07 +0000165static FamilyRec* remove_from_family(const SkTypeface* face) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 FamilyRec* family = find_family(face);
djsollen@google.com58629292011-11-03 13:08:29 +0000167 if (family) {
168 SkASSERT(family->fFaces[face->style()] == face);
169 family->fFaces[face->style()] = NULL;
reed@google.com4f809512011-01-04 21:25:43 +0000170
djsollen@google.com58629292011-11-03 13:08:29 +0000171 for (int i = 0; i < 4; i++) {
172 if (family->fFaces[i] != NULL) { // family is non-empty
173 return NULL;
174 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 }
djsollen@google.com58629292011-11-03 13:08:29 +0000176 } else {
177// SkDebugf("remove_from_family(%p) face not found", face);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 }
179 return family; // return the empty family
180}
181
182// maybe we should make FamilyRec be doubly-linked
reed@android.comfcce6472009-03-20 12:23:07 +0000183static void detach_and_delete_family(FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 FamilyRec* curr = gFamilyHead;
185 FamilyRec* prev = NULL;
186
187 while (curr != NULL) {
188 FamilyRec* next = curr->fNext;
189 if (curr == family) {
190 if (prev == NULL) {
191 gFamilyHead = next;
192 } else {
193 prev->fNext = next;
194 }
195 SkDELETE(family);
196 return;
197 }
198 prev = curr;
199 curr = next;
200 }
djsollen@google.com60abb072012-02-15 18:49:15 +0000201 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202}
203
djsollen@google.come4013992012-02-16 15:18:39 +0000204// gFamilyHeadAndNameListMutex must already be acquired
reed@android.comfcce6472009-03-20 12:23:07 +0000205static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
djsollen@google.come4013992012-02-16 15:18:39 +0000206 NameFamilyPairList& namelist = GetNameList();
207 NameFamilyPair* list = namelist.begin();
208 int count = namelist.count();
reed@google.com4f809512011-01-04 21:25:43 +0000209
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
211
212 if (index >= 0) {
213 return find_best_face(list[index].fFamily, style);
214 }
215 return NULL;
216}
217
djsollen@google.come4013992012-02-16 15:18:39 +0000218// gFamilyHeadAndNameListMutex must already be acquired
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219static SkTypeface* find_typeface(const SkTypeface* familyMember,
reed@android.comfcce6472009-03-20 12:23:07 +0000220 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 const FamilyRec* family = find_family(familyMember);
222 return family ? find_best_face(family, style) : NULL;
223}
224
djsollen@google.come4013992012-02-16 15:18:39 +0000225// gFamilyHeadAndNameListMutex must already be acquired
reed@android.comfcce6472009-03-20 12:23:07 +0000226static void add_name(const char name[], FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 SkAutoAsciiToLC tolc(name);
228 name = tolc.lc();
229
djsollen@google.come4013992012-02-16 15:18:39 +0000230 NameFamilyPairList& namelist = GetNameList();
231 NameFamilyPair* list = namelist.begin();
232 int count = namelist.count();
reed@google.com4f809512011-01-04 21:25:43 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
235
236 if (index < 0) {
djsollen@google.come4013992012-02-16 15:18:39 +0000237 list = namelist.insert(~index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 list->construct(name, family);
239 }
240}
241
djsollen@google.come4013992012-02-16 15:18:39 +0000242// gFamilyHeadAndNameListMutex must already be acquired
243static void remove_from_names(FamilyRec* emptyFamily) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244#ifdef SK_DEBUG
245 for (int i = 0; i < 4; i++) {
246 SkASSERT(emptyFamily->fFaces[i] == NULL);
247 }
248#endif
249
djsollen@google.come4013992012-02-16 15:18:39 +0000250 SkTDArray<NameFamilyPair>& list = GetNameList();
reed@google.com4f809512011-01-04 21:25:43 +0000251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 // must go backwards when removing
253 for (int i = list.count() - 1; i >= 0; --i) {
254 NameFamilyPair* pair = &list[i];
255 if (pair->fFamily == emptyFamily) {
256 pair->destruct();
257 list.remove(i);
258 }
259 }
260}
261
262///////////////////////////////////////////////////////////////////////////////
263
264class FamilyTypeface : public SkTypeface {
265public:
reed@google.com5b31b0f2011-02-23 14:41:42 +0000266 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
267 bool isFixedWidth)
268 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269 fIsSysFont = sysFont;
reed@google.com4f809512011-01-04 21:25:43 +0000270
djsollen@google.come4013992012-02-16 15:18:39 +0000271 // our caller has acquired the gFamilyHeadAndNameListMutex so this is safe
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 FamilyRec* rec = NULL;
273 if (familyMember) {
274 rec = find_family(familyMember);
275 SkASSERT(rec);
276 } else {
277 rec = SkNEW(FamilyRec);
278 }
279 rec->fFaces[style] = this;
280 }
reed@google.com4f809512011-01-04 21:25:43 +0000281
reed@android.comfcce6472009-03-20 12:23:07 +0000282 virtual ~FamilyTypeface() {
djsollen@google.come4013992012-02-16 15:18:39 +0000283 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@google.com4f809512011-01-04 21:25:43 +0000284
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 // remove us from our family. If the family is now empty, we return
286 // that and then remove that family from the name list
287 FamilyRec* family = remove_from_family(this);
288 if (NULL != family) {
289 remove_from_names(family);
290 detach_and_delete_family(family);
291 }
292 }
reed@google.com4f809512011-01-04 21:25:43 +0000293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 bool isSysFont() const { return fIsSysFont; }
reed@google.com4f809512011-01-04 21:25:43 +0000295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 virtual SkStream* openStream() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 virtual const char* getUniqueString() const = 0;
reed@android.comac981542009-07-31 16:17:01 +0000298 virtual const char* getFilePath() const = 0;
reed@google.com4f809512011-01-04 21:25:43 +0000299
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300private:
301 bool fIsSysFont;
reed@google.com4f809512011-01-04 21:25:43 +0000302
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 typedef SkTypeface INHERITED;
304};
305
306///////////////////////////////////////////////////////////////////////////////
307
308class StreamTypeface : public FamilyTypeface {
309public:
310 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
reed@google.com5b31b0f2011-02-23 14:41:42 +0000311 SkStream* stream, bool isFixedWidth)
312 : INHERITED(style, sysFont, familyMember, isFixedWidth) {
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000313 SkASSERT(stream);
314 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 fStream = stream;
316 }
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000317 virtual ~StreamTypeface() {
318 fStream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319 }
reed@google.com4f809512011-01-04 21:25:43 +0000320
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 // overrides
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000322 virtual SkStream* openStream() {
323 // we just ref our existing stream, since the caller will call unref()
324 // when they are through
325 fStream->ref();
reed@google.com4f809512011-01-04 21:25:43 +0000326 // must rewind each time, since the caller assumes a "new" stream
327 fStream->rewind();
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000328 return fStream;
329 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 virtual const char* getUniqueString() const { return NULL; }
reed@android.comac981542009-07-31 16:17:01 +0000331 virtual const char* getFilePath() const { return NULL; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332
333private:
334 SkStream* fStream;
reed@google.com4f809512011-01-04 21:25:43 +0000335
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 typedef FamilyTypeface INHERITED;
337};
338
339class FileTypeface : public FamilyTypeface {
340public:
341 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
reed@google.com5b31b0f2011-02-23 14:41:42 +0000342 const char path[], bool isFixedWidth)
343 : INHERITED(style, sysFont, familyMember, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 SkString fullpath;
reed@google.com4f809512011-01-04 21:25:43 +0000345
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 if (sysFont) {
347 GetFullPathForSysFonts(&fullpath, path);
348 path = fullpath.c_str();
349 }
350 fPath.set(path);
351 }
reed@google.com4f809512011-01-04 21:25:43 +0000352
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 // overrides
reed@android.comfcce6472009-03-20 12:23:07 +0000354 virtual SkStream* openStream() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
356
357 // check for failure
358 if (stream->getLength() <= 0) {
359 SkDELETE(stream);
360 // maybe MMAP isn't supported. try FILE
361 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
362 if (stream->getLength() <= 0) {
363 SkDELETE(stream);
364 stream = NULL;
365 }
366 }
367 return stream;
368 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 virtual const char* getUniqueString() const {
370 const char* str = strrchr(fPath.c_str(), '/');
371 if (str) {
372 str += 1; // skip the '/'
373 }
374 return str;
375 }
reed@android.comac981542009-07-31 16:17:01 +0000376 virtual const char* getFilePath() const {
377 return fPath.c_str();
378 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379
380private:
381 SkString fPath;
reed@google.com4f809512011-01-04 21:25:43 +0000382
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 typedef FamilyTypeface INHERITED;
384};
385
386///////////////////////////////////////////////////////////////////////////////
387///////////////////////////////////////////////////////////////////////////////
388
389static bool get_name_and_style(const char path[], SkString* name,
reed@google.com5b31b0f2011-02-23 14:41:42 +0000390 SkTypeface::Style* style,
391 bool* isFixedWidth, bool isExpected) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 SkString fullpath;
393 GetFullPathForSysFonts(&fullpath, path);
394
395 SkMMAPStream stream(fullpath.c_str());
396 if (stream.getLength() > 0) {
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000397 return find_name_and_attributes(&stream, name, style, isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398 }
399 else {
400 SkFILEStream stream(fullpath.c_str());
401 if (stream.getLength() > 0) {
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000402 return find_name_and_attributes(&stream, name, style, isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 }
404 }
405
reed@android.comfcce6472009-03-20 12:23:07 +0000406 if (isExpected) {
407 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
408 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 return false;
410}
411
reed@android.comfcce6472009-03-20 12:23:07 +0000412// used to record our notion of the pre-existing fonts
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413struct FontInitRec {
414 const char* fFileName;
415 const char* const* fNames; // null-terminated list
416};
417
reed@android.comfcce6472009-03-20 12:23:07 +0000418// deliberately empty, but we use the address to identify fallback fonts
reed@android.com8a1c16f2008-12-17 15:59:43 +0000419static const char* gFBNames[] = { NULL };
420
djsollen@google.comff029602012-03-15 15:49:51 +0000421static const struct {
422 const char* fFileName;
423 FallbackScripts fScript;
424} gFBFileNames[] = {
425 { "DroidNaskh-Regular.ttf", kArabic_FallbackScript },
426 { "DroidSansEthiopic-Regular.ttf", kEthiopic_FallbackScript },
427 { "DroidSansHebrew-Regular.ttf", kHebrewRegular_FallbackScript },
428 { "DroidSansHebrew-Bold.ttf", kHebrewBold_FallbackScript },
429 { "DroidSansThai.ttf", kThai_FallbackScript },
430 { "DroidSansArmenian.ttf", kArmenian_FallbackScript },
431 { "DroidSansGeorgian.ttf", kGeorgian_FallbackScript },
432 { "Lohit-Devanagari.ttf", kDevanagari_FallbackScript },
433 { "Lohit-Bengali.ttf", kBengali_FallbackScript },
434 { "Lohit-Tamil.ttf", kTamil_FallbackScript },
435};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436
djsollen@google.com58629292011-11-03 13:08:29 +0000437/* Fonts are grouped by family, with the first font in a family having the
438 list of names (even if that list is empty), and the following members having
439 null for the list. The names list must be NULL-terminated.
440*/
441static FontInitRec *gSystemFonts;
442static size_t gNumSystemFonts = 0;
443
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444// these globals are assigned (once) by load_system_fonts()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445static FamilyRec* gDefaultFamily;
446static SkTypeface* gDefaultNormal;
djsollen@google.com58629292011-11-03 13:08:29 +0000447static char** gDefaultNames = NULL;
448static uint32_t *gFallbackFonts;
djsollen@google.comff029602012-03-15 15:49:51 +0000449static uint32_t *gFallbackScriptsMap;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450
djsollen@google.come63793a2012-03-21 15:39:03 +0000451static void dump_globals() {
452 SkDebugf("gDefaultNormal=%p id=%u refCnt=%d", gDefaultNormal,
453 gDefaultNormal ? gDefaultNormal->uniqueID() : 0,
454 gDefaultNormal ? gDefaultNormal->getRefCnt() : 0);
455
456 if (gDefaultFamily) {
457 SkDebugf("gDefaultFamily=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
458 gDefaultFamily,
459 gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->uniqueID() : 0,
460 gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->uniqueID() : 0,
461 gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->uniqueID() : 0,
462 gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->uniqueID() : 0,
463 gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->getRefCnt() : 0,
464 gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->getRefCnt() : 0,
465 gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->getRefCnt() : 0,
466 gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->getRefCnt() : 0);
467 } else {
468 SkDebugf("gDefaultFamily=%p", gDefaultFamily);
469 }
470
471 SkDebugf("gNumSystemFonts=%d gSystemFonts=%p gFallbackFonts=%p",
472 gNumSystemFonts, gSystemFonts, gFallbackFonts);
473
474 for (size_t i = 0; i < gNumSystemFonts; ++i) {
475 SkDebugf("gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName);
476 size_t namesIndex = 0;
477 if (gSystemFonts[i].fNames)
478 for (const char* fontName = gSystemFonts[i].fNames[namesIndex];
479 fontName != 0;
480 fontName = gSystemFonts[i].fNames[++namesIndex]) {
481 SkDebugf(" name[%u]=%s", namesIndex, fontName);
482 }
483 }
484
485 if (gFamilyHead) {
486 FamilyRec* rec = gFamilyHead;
487 int i=0;
488 while (rec) {
489 SkDebugf("gFamilyHead[%d]=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}",
490 i++, rec,
491 rec->fFaces[0] ? rec->fFaces[0]->uniqueID() : 0,
492 rec->fFaces[1] ? rec->fFaces[1]->uniqueID() : 0,
493 rec->fFaces[2] ? rec->fFaces[2]->uniqueID() : 0,
494 rec->fFaces[3] ? rec->fFaces[3]->uniqueID() : 0,
495 rec->fFaces[0] ? rec->fFaces[0]->getRefCnt() : 0,
496 rec->fFaces[1] ? rec->fFaces[1]->getRefCnt() : 0,
497 rec->fFaces[2] ? rec->fFaces[2]->getRefCnt() : 0,
498 rec->fFaces[3] ? rec->fFaces[3]->getRefCnt() : 0);
499 rec = rec->fNext;
500 }
501 } else {
502 SkDebugf("gFamilyHead=%p", gFamilyHead);
503 }
504
505}
506
507
djsollen@google.com58629292011-11-03 13:08:29 +0000508/* Load info from a configuration file that populates the system/fallback font structures
509*/
510static void load_font_info() {
djsollen@google.com58629292011-11-03 13:08:29 +0000511 SkTDArray<FontFamily*> fontFamilies;
512 getFontFamilies(fontFamilies);
513
514 SkTDArray<FontInitRec> fontInfo;
515 bool firstInFamily = false;
516 for (int i = 0; i < fontFamilies.count(); ++i) {
517 FontFamily *family = fontFamilies[i];
518 firstInFamily = true;
519 for (int j = 0; j < family->fFileNames.count(); ++j) {
520 FontInitRec fontInfoRecord;
521 fontInfoRecord.fFileName = family->fFileNames[j];
522 if (j == 0) {
523 if (family->fNames.count() == 0) {
524 // Fallback font
525 fontInfoRecord.fNames = (char **)gFBNames;
526 } else {
527 SkTDArray<const char*> names = family->fNames;
528 const char **nameList = (const char**)
529 malloc((names.count() + 1) * sizeof(char*));
530 if (nameList == NULL) {
531 // shouldn't get here
532 break;
533 }
534 if (gDefaultNames == NULL) {
535 gDefaultNames = (char**) nameList;
536 }
537 for (int i = 0; i < names.count(); ++i) {
538 nameList[i] = names[i];
539 }
540 nameList[names.count()] = NULL;
541 fontInfoRecord.fNames = nameList;
542 }
543 } else {
544 fontInfoRecord.fNames = NULL;
545 }
546 *fontInfo.append() = fontInfoRecord;
547 }
548 }
549 gNumSystemFonts = fontInfo.count();
550 gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
551 gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
djsollen@google.comff029602012-03-15 15:49:51 +0000552 gFallbackScriptsMap = (uint32_t*) calloc(kFallbackScriptNumber, sizeof(uint32_t));
djsollen@google.com58629292011-11-03 13:08:29 +0000553 if (gSystemFonts == NULL) {
554 // shouldn't get here
555 gNumSystemFonts = 0;
556 }
djsollen@google.com60abb072012-02-15 18:49:15 +0000557// SkDebugf("---- We have %d system fonts", gNumSystemFonts);
djsollen@google.com58629292011-11-03 13:08:29 +0000558 for (size_t i = 0; i < gNumSystemFonts; ++i) {
559 gSystemFonts[i].fFileName = fontInfo[i].fFileName;
560 gSystemFonts[i].fNames = fontInfo[i].fNames;
djsollen@google.com60abb072012-02-15 18:49:15 +0000561// SkDebugf("---- gSystemFonts[%d] fileName=%s", i, fontInfo[i].fFileName);
djsollen@google.com58629292011-11-03 13:08:29 +0000562 }
563 fontFamilies.deleteAll();
564}
reed@android.comfcce6472009-03-20 12:23:07 +0000565
djsollen@google.come4013992012-02-16 15:18:39 +0000566/*
567 * Called once (ensured by the sentinel check at the beginning of our body).
568 * Initializes all the globals, and register the system fonts.
569 *
570 * gFamilyHeadAndNameListMutex must already be acquired.
reed@android.comfcce6472009-03-20 12:23:07 +0000571 */
djsollen@google.come63793a2012-03-21 15:39:03 +0000572static void init_system_fonts() {
573 // check if we've already been called
574 if (gDefaultNormal) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575 return;
576 }
reed@google.com4f809512011-01-04 21:25:43 +0000577
djsollen@google.com58629292011-11-03 13:08:29 +0000578 load_font_info();
579
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 const FontInitRec* rec = gSystemFonts;
581 SkTypeface* firstInFamily = NULL;
reed@android.comfcce6472009-03-20 12:23:07 +0000582 int fallbackCount = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583
djsollen@google.com58629292011-11-03 13:08:29 +0000584 for (size_t i = 0; i < gNumSystemFonts; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585 // if we're the first in a new family, clear firstInFamily
586 if (rec[i].fNames != NULL) {
587 firstInFamily = NULL;
588 }
reed@google.com4f809512011-01-04 21:25:43 +0000589
reed@google.com5b31b0f2011-02-23 14:41:42 +0000590 bool isFixedWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 SkString name;
592 SkTypeface::Style style;
reed@android.comfcce6472009-03-20 12:23:07 +0000593
594 // we expect all the fonts, except the "fallback" fonts
595 bool isExpected = (rec[i].fNames != gFBNames);
reed@google.com5b31b0f2011-02-23 14:41:42 +0000596 if (!get_name_and_style(rec[i].fFileName, &name, &style,
597 &isFixedWidth, isExpected)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598 continue;
599 }
600
601 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
602 (style,
603 true, // system-font (cannot delete)
604 firstInFamily, // what family to join
reed@google.com5b31b0f2011-02-23 14:41:42 +0000605 rec[i].fFileName,
606 isFixedWidth) // filename
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607 );
608
djsollen@google.com60abb072012-02-15 18:49:15 +0000609// SkDebugf("---- SkTypeface[%d] %s fontID %d\n", i, rec[i].fFileName, tf->uniqueID());
610
djsollen@google.comb8ff6332012-03-15 16:04:27 +0000611 FallbackScripts fallbackScript = SkGetFallbackScriptFromID(rec[i].fFileName);
djsollen@google.comff029602012-03-15 15:49:51 +0000612 if (SkTypeface_ValidScript(fallbackScript)) {
613 gFallbackScriptsMap[fallbackScript] = tf->uniqueID();
614 }
615
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 if (rec[i].fNames != NULL) {
reed@android.comfcce6472009-03-20 12:23:07 +0000617 // see if this is one of our fallback fonts
618 if (rec[i].fNames == gFBNames) {
djsollen@google.com60abb072012-02-15 18:49:15 +0000619// SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
620// rec[i].fFileName, fallbackCount, tf->uniqueID());
reed@android.comfcce6472009-03-20 12:23:07 +0000621 gFallbackFonts[fallbackCount++] = tf->uniqueID();
622 }
623
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624 firstInFamily = tf;
reed@android.comfcce6472009-03-20 12:23:07 +0000625 FamilyRec* family = find_family(tf);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626 const char* const* names = rec[i].fNames;
627
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628 // record the default family if this is it
djsollen@google.com58629292011-11-03 13:08:29 +0000629 if (names == gDefaultNames) {
reed@android.comfcce6472009-03-20 12:23:07 +0000630 gDefaultFamily = family;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631 }
632 // add the names to map to this family
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 while (*names) {
634 add_name(*names, family);
635 names += 1;
636 }
637 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638 }
639
640 // do this after all fonts are loaded. This is our default font, and it
641 // acts as a sentinel so we only execute load_system_fonts() once
642 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
reed@android.comfcce6472009-03-20 12:23:07 +0000643 // now terminate our fallback list with the sentinel value
644 gFallbackFonts[fallbackCount] = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645}
646
djsollen@google.come63793a2012-03-21 15:39:03 +0000647static size_t find_uniqueID(const char* filename) {
648 // uniqueID is the index, offset by one, of the associated element in gSystemFonts[]
649 // return 0 if not found
650 const FontInitRec* rec = gSystemFonts;
651 for (size_t i = 0; i < gNumSystemFonts; i++) {
652 if (strcmp(rec[i].fFileName, filename) == 0) {
653 return i+1;
654 }
655 }
656 return 0;
657}
658
659static void reload_fallback_fonts() {
660 SkGraphics::PurgeFontCache();
661
662 SkTDArray<FontFamily*> fallbackFamilies;
663 getFallbackFontFamilies(fallbackFamilies);
664
665 for (int i = 0; i < fallbackFamilies.count(); ++i) {
666 FontFamily *family = fallbackFamilies[i];
667
668 for (int j = 0; j < family->fFileNames.count(); ++j) {
669 if (family->fFileNames[j]) {
670 size_t uniqueID = find_uniqueID(family->fFileNames[j]);
671 if (uniqueID != gFallbackFonts[i])
672 gFallbackFonts[i] = uniqueID;
673 break; // The fallback set contains only the first font of each family
674 }
675 }
676 }
677}
678
679static void load_system_fonts() {
680#if !defined(SK_BUILD_FOR_ANDROID_NDK)
681 static char prevLanguage[3];
682 static char prevRegion[3];
683 char language[3] = "";
684 char region[3] = "";
685
686 getLocale(language, region);
687
688 if (!gDefaultNormal) {
689 strncpy(prevLanguage, language, 2);
690 strncpy(prevRegion, region, 2);
691 init_system_fonts();
692 } else if (strncmp(language, prevLanguage, 2) || strncmp(region, prevRegion, 2)) {
693 strncpy(prevLanguage, language, 2);
694 strncpy(prevRegion, region, 2);
695 reload_fallback_fonts();
696 }
697#else
698 if (!gDefaultNormal) {
699 init_system_fonts();
700 reload_fallback_fonts();
701 }
702#endif
703}
704
705
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706///////////////////////////////////////////////////////////////////////////////
707
708void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
djsollen@google.com58629292011-11-03 13:08:29 +0000709 // lookup and record if the font is custom (i.e. not a system font)
710 bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
711 stream->writeBool(isCustomFont);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712
djsollen@google.com58629292011-11-03 13:08:29 +0000713 if (isCustomFont) {
714 SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715
djsollen@google.com58629292011-11-03 13:08:29 +0000716 // store the length of the custom font
717 uint32_t len = fontStream->getLength();
718 stream->write32(len);
719
720 // store the entire font in the serialized stream
721 void* fontData = malloc(len);
722
723 fontStream->read(fontData, len);
724 stream->write(fontData, len);
725
726 fontStream->unref();
727 free(fontData);
728// SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
729
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730 } else {
djsollen@google.com58629292011-11-03 13:08:29 +0000731 const char* name = ((FamilyTypeface*)face)->getUniqueString();
732
733 stream->write8((uint8_t)face->style());
734
735 if (NULL == name || 0 == *name) {
736 stream->writePackedUInt(0);
737// SkDebugf("--- fonthost serialize null\n");
738 } else {
739 uint32_t len = strlen(name);
740 stream->writePackedUInt(len);
741 stream->write(name, len);
742// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
743 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 }
745}
746
747SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
djsollen@google.come4013992012-02-16 15:18:39 +0000748 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
749
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 load_system_fonts();
751
djsollen@google.com58629292011-11-03 13:08:29 +0000752 // check if the font is a custom or system font
753 bool isCustomFont = stream->readBool();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754
djsollen@google.com58629292011-11-03 13:08:29 +0000755 if (isCustomFont) {
reed@google.com4f809512011-01-04 21:25:43 +0000756
djsollen@google.com58629292011-11-03 13:08:29 +0000757 // read the length of the custom font from the stream
758 uint32_t len = stream->readU32();
759
760 // generate a new stream to store the custom typeface
761 SkMemoryStream* fontStream = new SkMemoryStream(len);
762 stream->read((void*)fontStream->getMemoryBase(), len);
763
764 SkTypeface* face = CreateTypefaceFromStream(fontStream);
765
766 fontStream->unref();
767
768// SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
769 return face;
770
771 } else {
772 int style = stream->readU8();
773
774 int len = stream->readPackedUInt();
775 if (len > 0) {
776 SkString str;
777 str.resize(len);
778 stream->read(str.writable_str(), len);
779
780 const FontInitRec* rec = gSystemFonts;
781 for (size_t i = 0; i < gNumSystemFonts; i++) {
782 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
783 // backup until we hit the fNames
784 for (int j = i; j >= 0; --j) {
785 if (rec[j].fNames != NULL) {
786 return SkFontHost::CreateTypeface(NULL,
787 rec[j].fNames[0], NULL, 0,
788 (SkTypeface::Style)style);
789 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 }
791 }
792 }
793 }
794 }
reed@android.com62533ed2009-03-06 15:57:26 +0000795 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796}
797
798///////////////////////////////////////////////////////////////////////////////
799
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000800SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
801 const char familyName[],
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000802 const void* data, size_t bytelength,
reed@android.comfcce6472009-03-20 12:23:07 +0000803 SkTypeface::Style style) {
djsollen@google.come4013992012-02-16 15:18:39 +0000804 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805
djsollen@google.come4013992012-02-16 15:18:39 +0000806 load_system_fonts();
reed@google.com4f809512011-01-04 21:25:43 +0000807
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // clip to legal style bits
809 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
reed@google.com4f809512011-01-04 21:25:43 +0000810
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811 SkTypeface* tf = NULL;
812
813 if (NULL != familyFace) {
814 tf = find_typeface(familyFace, style);
815 } else if (NULL != familyName) {
816// SkDebugf("======= familyName <%s>\n", familyName);
817 tf = find_typeface(familyName, style);
818 }
819
820 if (NULL == tf) {
821 tf = find_best_face(gDefaultFamily, style);
822 }
823
djsollen@google.come63793a2012-03-21 15:39:03 +0000824 // we ref(), since the semantic is to return a new instance
reed@android.comfb12c3e2009-03-05 20:43:42 +0000825 tf->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 return tf;
827}
828
djsollen@google.comff029602012-03-15 15:49:51 +0000829SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) {
830 if (!SkTypeface_ValidScript(script)) {
831 return NULL;
832 }
833
834 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
835
836 load_system_fonts();
837
838 if (gFallbackScriptsMap[script] == 0) {
839 return NULL;
840 }
841
842 SkTypeface* tf = find_from_uniqueID(gFallbackScriptsMap[script]);
843 // we ref(), since the symantic is to return a new instance
844 tf->ref();
845 return tf;
846}
847
848const char* SkGetFallbackScriptID(FallbackScripts script) {
849 for (int i = 0; i < sizeof(gFBFileNames) / sizeof(gFBFileNames[0]); i++) {
850 if (gFBFileNames[i].fScript == script) {
851 return gFBFileNames[i].fFileName;
852 }
853 }
854 return NULL;
855}
856
857FallbackScripts SkGetFallbackScriptFromID(const char* fileName) {
858 for (int i = 0; i < sizeof(gFBFileNames) / sizeof(gFBFileNames[0]); i++) {
859 if (strcmp(gFBFileNames[i].fFileName, fileName) == 0) {
860 return gFBFileNames[i].fScript;
861 }
862 }
863 return kFallbackScriptNumber; // Use SkTypeface_ValidScript as an invalid value.
864}
865
reed@android.comfcce6472009-03-20 12:23:07 +0000866SkStream* SkFontHost::OpenStream(uint32_t fontID) {
djsollen@google.come4013992012-02-16 15:18:39 +0000867 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@google.com4f809512011-01-04 21:25:43 +0000868
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000869 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 SkStream* stream = tf ? tf->openStream() : NULL;
871
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000872 if (stream && stream->getLength() == 0) {
873 stream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 stream = NULL;
875 }
876 return stream;
877}
878
reed@android.comac981542009-07-31 16:17:01 +0000879size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
880 int32_t* index) {
djsollen@google.come4013992012-02-16 15:18:39 +0000881 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
reed@android.comac981542009-07-31 16:17:01 +0000882
883 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
884 const char* src = tf ? tf->getFilePath() : NULL;
885
886 if (src) {
887 size_t size = strlen(src);
888 if (path) {
889 memcpy(path, src, SkMin32(size, length));
890 }
891 if (index) {
892 *index = 0; // we don't have collections (yet)
893 }
894 return size;
895 } else {
896 return 0;
897 }
898}
899
reed@google.com7d26c592011-06-13 13:01:10 +0000900SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
djsollen@google.come4013992012-02-16 15:18:39 +0000901 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
902
reed@android.com8a1c16f2008-12-17 15:59:43 +0000903 load_system_fonts();
904
djsollen@google.com58629292011-11-03 13:08:29 +0000905 const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
906 const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
907
908 SkASSERT(origTypeface != 0);
909 SkASSERT(currTypeface != 0);
djsollen@google.come63793a2012-03-21 15:39:03 +0000910 SkASSERT(gFallbackFonts);
djsollen@google.com58629292011-11-03 13:08:29 +0000911
912 // Our fallback list always stores the id of the plain in each fallback
913 // family, so we transform currFontID to its plain equivalent.
914 currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
915
reed@android.comfcce6472009-03-20 12:23:07 +0000916 /* First see if fontID is already one of our fallbacks. If so, return
917 its successor. If fontID is not in our list, then return the first one
918 in our list. Note: list is zero-terminated, and returning zero means
919 we have no more fonts to use for fallbacks.
920 */
921 const uint32_t* list = gFallbackFonts;
922 for (int i = 0; list[i] != 0; i++) {
reed@google.com7d26c592011-06-13 13:01:10 +0000923 if (list[i] == currFontID) {
djsollen@google.com58629292011-11-03 13:08:29 +0000924 if (list[i+1] == 0)
925 return 0;
926 const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
927 return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
reed@android.comfcce6472009-03-20 12:23:07 +0000928 }
reed@android.coma14ea0e2009-03-17 17:59:53 +0000929 }
djsollen@google.com58629292011-11-03 13:08:29 +0000930
931 // If we get here, currFontID was not a fallback, so we start at the
932 // beginning of our list.
933 const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
934 return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935}
936
937///////////////////////////////////////////////////////////////////////////////
938
reed@android.comfcce6472009-03-20 12:23:07 +0000939SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000940 if (NULL == stream || stream->getLength() <= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941 return NULL;
942 }
reed@google.com4f809512011-01-04 21:25:43 +0000943
reed@google.com5b31b0f2011-02-23 14:41:42 +0000944 bool isFixedWidth;
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000945 SkTypeface::Style style;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000947 if (find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
djsollen@google.come4013992012-02-16 15:18:39 +0000948 SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
djsollen@google.com7b34ea62011-02-24 16:28:51 +0000949 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
950 } else {
951 return NULL;
952 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953}
954
reed@android.comfcce6472009-03-20 12:23:07 +0000955SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000956 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
957 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
958 // since we created the stream, we let go of our ref() here
959 stream->unref();
960 return face;
reed@android.com1550a422008-12-23 20:10:57 +0000961}