blob: 733b0cc6801f1bb2cbdf43b8fd634dd1c7ccceff [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 The Android Open Source Project
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com9d3a9852010-01-08 14:07:42 +000010#include "SkFontHost.h"
11#include "SkDescriptor.h"
12#include "SkMMapStream.h"
13#include "SkPaint.h"
14#include "SkString.h"
15#include "SkStream.h"
16#include "SkThread.h"
17#include "SkTSearch.h"
18#include <stdio.h>
19
reed@google.com60169622011-03-14 15:08:44 +000020#ifdef SK_BUILD_FOR_MAC
21 #define SK_FONT_FILE_PREFIX "/Library/Fonts/"
22#else
23 #define SK_FONT_FILE_PREFIX "/skimages/"
24#endif
reed@android.com9d3a9852010-01-08 14:07:42 +000025
djsollen@google.com4dc686d2012-02-15 21:03:45 +000026bool find_name_and_attributes(SkStream* stream, SkString* name,
27 SkTypeface::Style* style, bool* isFixedWidth);
reed@android.com9d3a9852010-01-08 14:07:42 +000028
29static void GetFullPathForSysFonts(SkString* full, const char name[]) {
30 full->set(SK_FONT_FILE_PREFIX);
31 full->append(name);
32}
33
34///////////////////////////////////////////////////////////////////////////////
35
36struct FamilyRec;
37
38/* This guy holds a mapping of a name -> family, used for looking up fonts.
39 Since it is stored in a stretchy array that doesn't preserve object
40 semantics, we don't use constructor/destructors, but just have explicit
41 helpers to manage our internal bookkeeping.
42*/
43struct NameFamilyPair {
44 const char* fName; // we own this
45 FamilyRec* fFamily; // we don't own this, we just reference it
reed@google.com60169622011-03-14 15:08:44 +000046
reed@android.com9d3a9852010-01-08 14:07:42 +000047 void construct(const char name[], FamilyRec* family) {
48 fName = strdup(name);
49 fFamily = family; // we don't own this, so just record the referene
50 }
51
52 void destruct() {
53 free((char*)fName);
54 // we don't own family, so just ignore our reference
55 }
56};
57
58// we use atomic_inc to grow this for each typeface we create
59static int32_t gUniqueFontID;
60
61// this is the mutex that protects these globals
digit@google.com1771cbf2012-01-26 21:26:40 +000062SK_DECLARE_STATIC_MUTEX(gFamilyMutex);
reed@android.com9d3a9852010-01-08 14:07:42 +000063static FamilyRec* gFamilyHead;
64static SkTDArray<NameFamilyPair> gNameList;
65
66struct FamilyRec {
67 FamilyRec* fNext;
68 SkTypeface* fFaces[4];
reed@google.com60169622011-03-14 15:08:44 +000069
reed@android.com9d3a9852010-01-08 14:07:42 +000070 FamilyRec()
71 {
72 fNext = gFamilyHead;
73 memset(fFaces, 0, sizeof(fFaces));
74 gFamilyHead = this;
75 }
76};
77
78static SkTypeface* find_best_face(const FamilyRec* family,
79 SkTypeface::Style style) {
80 SkTypeface* const* faces = family->fFaces;
81
82 if (faces[style] != NULL) { // exact match
83 return faces[style];
84 }
85 // look for a matching bold
86 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
87 if (faces[style] != NULL) {
88 return faces[style];
89 }
90 // look for the plain
91 if (faces[SkTypeface::kNormal] != NULL) {
92 return faces[SkTypeface::kNormal];
93 }
94 // look for anything
95 for (int i = 0; i < 4; i++) {
96 if (faces[i] != NULL) {
97 return faces[i];
98 }
99 }
100 // should never get here, since the faces list should not be empty
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000101 SkDEBUGFAIL("faces list is empty");
reed@android.com9d3a9852010-01-08 14:07:42 +0000102 return NULL;
103}
104
105static FamilyRec* find_family(const SkTypeface* member) {
106 FamilyRec* curr = gFamilyHead;
107 while (curr != NULL) {
108 for (int i = 0; i < 4; i++) {
109 if (curr->fFaces[i] == member) {
110 return curr;
111 }
112 }
113 curr = curr->fNext;
114 }
115 return NULL;
116}
117
118/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
119 is not modified.
120 */
121static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
122 FamilyRec* curr = gFamilyHead;
123 while (curr != NULL) {
124 for (int i = 0; i < 4; i++) {
125 SkTypeface* face = curr->fFaces[i];
126 if (face != NULL && face->uniqueID() == uniqueID) {
127 return face;
128 }
129 }
130 curr = curr->fNext;
131 }
132 return NULL;
133}
134
135/* Remove reference to this face from its family. If the resulting family
136 is empty (has no faces), return that family, otherwise return NULL
137*/
138static FamilyRec* remove_from_family(const SkTypeface* face) {
139 FamilyRec* family = find_family(face);
140 SkASSERT(family->fFaces[face->style()] == face);
141 family->fFaces[face->style()] = NULL;
reed@google.com60169622011-03-14 15:08:44 +0000142
reed@android.com9d3a9852010-01-08 14:07:42 +0000143 for (int i = 0; i < 4; i++) {
144 if (family->fFaces[i] != NULL) { // family is non-empty
145 return NULL;
146 }
147 }
148 return family; // return the empty family
149}
150
151// maybe we should make FamilyRec be doubly-linked
152static void detach_and_delete_family(FamilyRec* family) {
153 FamilyRec* curr = gFamilyHead;
154 FamilyRec* prev = NULL;
155
156 while (curr != NULL) {
157 FamilyRec* next = curr->fNext;
158 if (curr == family) {
159 if (prev == NULL) {
160 gFamilyHead = next;
161 } else {
162 prev->fNext = next;
163 }
164 SkDELETE(family);
165 return;
166 }
167 prev = curr;
168 curr = next;
169 }
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000170 SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
reed@android.com9d3a9852010-01-08 14:07:42 +0000171}
172
173static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
174 NameFamilyPair* list = gNameList.begin();
175 int count = gNameList.count();
reed@google.com60169622011-03-14 15:08:44 +0000176
reed@android.com9d3a9852010-01-08 14:07:42 +0000177 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
178
179 if (index >= 0) {
180 return find_best_face(list[index].fFamily, style);
181 }
182 return NULL;
183}
184
185static SkTypeface* find_typeface(const SkTypeface* familyMember,
186 SkTypeface::Style style) {
187 const FamilyRec* family = find_family(familyMember);
188 return family ? find_best_face(family, style) : NULL;
189}
190
191static void add_name(const char name[], FamilyRec* family) {
192 SkAutoAsciiToLC tolc(name);
193 name = tolc.lc();
194
195 NameFamilyPair* list = gNameList.begin();
196 int count = gNameList.count();
reed@google.com60169622011-03-14 15:08:44 +0000197
reed@android.com9d3a9852010-01-08 14:07:42 +0000198 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
199
200 if (index < 0) {
201 list = gNameList.insert(~index);
202 list->construct(name, family);
203 }
204}
205
206static void remove_from_names(FamilyRec* emptyFamily)
207{
208#ifdef SK_DEBUG
209 for (int i = 0; i < 4; i++) {
210 SkASSERT(emptyFamily->fFaces[i] == NULL);
211 }
212#endif
213
214 SkTDArray<NameFamilyPair>& list = gNameList;
reed@google.com60169622011-03-14 15:08:44 +0000215
reed@android.com9d3a9852010-01-08 14:07:42 +0000216 // must go backwards when removing
217 for (int i = list.count() - 1; i >= 0; --i) {
218 NameFamilyPair* pair = &list[i];
219 if (pair->fFamily == emptyFamily) {
220 pair->destruct();
221 list.remove(i);
222 }
223 }
224}
225
226///////////////////////////////////////////////////////////////////////////////
227
228class FamilyTypeface : public SkTypeface {
229public:
230 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember)
231 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) {
232 fIsSysFont = sysFont;
reed@google.com60169622011-03-14 15:08:44 +0000233
reed@android.com9d3a9852010-01-08 14:07:42 +0000234 SkAutoMutexAcquire ac(gFamilyMutex);
reed@google.com60169622011-03-14 15:08:44 +0000235
reed@android.com9d3a9852010-01-08 14:07:42 +0000236 FamilyRec* rec = NULL;
237 if (familyMember) {
238 rec = find_family(familyMember);
239 SkASSERT(rec);
240 } else {
241 rec = SkNEW(FamilyRec);
242 }
243 rec->fFaces[style] = this;
244 }
reed@google.com60169622011-03-14 15:08:44 +0000245
reed@android.com9d3a9852010-01-08 14:07:42 +0000246 virtual ~FamilyTypeface() {
247 SkAutoMutexAcquire ac(gFamilyMutex);
reed@google.com60169622011-03-14 15:08:44 +0000248
reed@android.com9d3a9852010-01-08 14:07:42 +0000249 // remove us from our family. If the family is now empty, we return
250 // that and then remove that family from the name list
251 FamilyRec* family = remove_from_family(this);
252 if (NULL != family) {
253 remove_from_names(family);
254 detach_and_delete_family(family);
255 }
256 }
reed@google.com60169622011-03-14 15:08:44 +0000257
reed@android.com9d3a9852010-01-08 14:07:42 +0000258 bool isSysFont() const { return fIsSysFont; }
reed@google.com60169622011-03-14 15:08:44 +0000259
reed@android.com9d3a9852010-01-08 14:07:42 +0000260 virtual SkStream* openStream() = 0;
261 virtual const char* getUniqueString() const = 0;
262 virtual const char* getFilePath() const = 0;
reed@google.com60169622011-03-14 15:08:44 +0000263
reed@android.com9d3a9852010-01-08 14:07:42 +0000264private:
265 bool fIsSysFont;
reed@google.com60169622011-03-14 15:08:44 +0000266
reed@android.com9d3a9852010-01-08 14:07:42 +0000267 typedef SkTypeface INHERITED;
268};
269
270///////////////////////////////////////////////////////////////////////////////
271
272class StreamTypeface : public FamilyTypeface {
273public:
274 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
275 SkStream* stream)
276 : INHERITED(style, sysFont, familyMember) {
277 SkASSERT(stream);
278 stream->ref();
279 fStream = stream;
280 }
281 virtual ~StreamTypeface() {
282 fStream->unref();
283 }
reed@google.com60169622011-03-14 15:08:44 +0000284
reed@android.com9d3a9852010-01-08 14:07:42 +0000285 // overrides
286 virtual SkStream* openStream() {
287 // we just ref our existing stream, since the caller will call unref()
288 // when they are through
289 fStream->ref();
290 return fStream;
291 }
292 virtual const char* getUniqueString() const { return NULL; }
293 virtual const char* getFilePath() const { return NULL; }
294
295private:
296 SkStream* fStream;
reed@google.com60169622011-03-14 15:08:44 +0000297
reed@android.com9d3a9852010-01-08 14:07:42 +0000298 typedef FamilyTypeface INHERITED;
299};
300
301class FileTypeface : public FamilyTypeface {
302public:
303 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
304 const char path[])
305 : INHERITED(style, sysFont, familyMember) {
306 SkString fullpath;
reed@google.com60169622011-03-14 15:08:44 +0000307
reed@android.com9d3a9852010-01-08 14:07:42 +0000308 if (sysFont) {
309 GetFullPathForSysFonts(&fullpath, path);
310 path = fullpath.c_str();
311 }
312 fPath.set(path);
313 }
reed@google.com60169622011-03-14 15:08:44 +0000314
reed@android.com9d3a9852010-01-08 14:07:42 +0000315 // overrides
316 virtual SkStream* openStream() {
317 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
318
319 // check for failure
320 if (stream->getLength() <= 0) {
321 SkDELETE(stream);
322 // maybe MMAP isn't supported. try FILE
323 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
324 if (stream->getLength() <= 0) {
325 SkDELETE(stream);
326 stream = NULL;
327 }
328 }
329 return stream;
330 }
331 virtual const char* getUniqueString() const {
332 const char* str = strrchr(fPath.c_str(), '/');
333 if (str) {
334 str += 1; // skip the '/'
335 }
336 return str;
337 }
338 virtual const char* getFilePath() const {
339 return fPath.c_str();
340 }
341
342private:
343 SkString fPath;
reed@google.com60169622011-03-14 15:08:44 +0000344
reed@android.com9d3a9852010-01-08 14:07:42 +0000345 typedef FamilyTypeface INHERITED;
346};
347
348///////////////////////////////////////////////////////////////////////////////
349///////////////////////////////////////////////////////////////////////////////
350
351static bool get_name_and_style(const char path[], SkString* name,
352 SkTypeface::Style* style, bool isExpected) {
353 SkString fullpath;
354 GetFullPathForSysFonts(&fullpath, path);
355
356 SkMMAPStream stream(fullpath.c_str());
357 if (stream.getLength() > 0) {
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000358 return find_name_and_attributes(&stream, name, style, NULL);
reed@android.com9d3a9852010-01-08 14:07:42 +0000359 }
360 else {
361 SkFILEStream stream(fullpath.c_str());
362 if (stream.getLength() > 0) {
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000363 return find_name_and_attributes(&stream, name, style, NULL);
reed@android.com9d3a9852010-01-08 14:07:42 +0000364 }
365 }
366
367 if (isExpected) {
368 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
369 }
370 return false;
371}
372
373// used to record our notion of the pre-existing fonts
374struct FontInitRec {
375 const char* fFileName;
376 const char* const* fNames; // null-terminated list
377};
378
379static const char* gSansNames[] = {
380 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
381};
382
383static const char* gSerifNames[] = {
384 "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
385 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
386};
387
388static const char* gMonoNames[] = {
389 "monospace", "courier", "courier new", "monaco", NULL
390};
391
392// deliberately empty, but we use the address to identify fallback fonts
393static const char* gFBNames[] = { NULL };
394
395/* Fonts must be grouped by family, with the first font in a family having the
396 list of names (even if that list is empty), and the following members having
397 null for the list. The names list must be NULL-terminated
398*/
399static const FontInitRec gSystemFonts[] = {
reed@google.com60169622011-03-14 15:08:44 +0000400 { "Arial.ttf", gSansNames },
401 { "Times.ttf", gSerifNames },
reed@android.com9d3a9852010-01-08 14:07:42 +0000402 { "samplefont.ttf", gSansNames },
403};
404
405#define DEFAULT_NAMES gSansNames
406
407// these globals are assigned (once) by load_system_fonts()
408static FamilyRec* gDefaultFamily;
409static SkTypeface* gDefaultNormal;
410
411/* This is sized conservatively, assuming that it will never be a size issue.
412 It will be initialized in load_system_fonts(), and will be filled with the
413 fontIDs that can be used for fallback consideration, in sorted order (sorted
414 meaning element[0] should be used first, then element[1], etc. When we hit
415 a fontID==0 in the array, the list is done, hence our allocation size is
416 +1 the total number of possible system fonts. Also see NextLogicalFont().
417 */
418static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
419
420/* Called once (ensured by the sentinel check at the beginning of our body).
421 Initializes all the globals, and register the system fonts.
422 */
423static void load_system_fonts() {
424 // check if we've already be called
425 if (NULL != gDefaultNormal) {
426 return;
427 }
reed@google.com60169622011-03-14 15:08:44 +0000428
reed@android.com9d3a9852010-01-08 14:07:42 +0000429 const FontInitRec* rec = gSystemFonts;
430 SkTypeface* firstInFamily = NULL;
431 int fallbackCount = 0;
432
433 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
434 // if we're the first in a new family, clear firstInFamily
435 if (rec[i].fNames != NULL) {
436 firstInFamily = NULL;
437 }
reed@google.com60169622011-03-14 15:08:44 +0000438
reed@android.com9d3a9852010-01-08 14:07:42 +0000439 SkString name;
440 SkTypeface::Style style;
441
442 // we expect all the fonts, except the "fallback" fonts
443 bool isExpected = (rec[i].fNames != gFBNames);
444 if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
445 continue;
446 }
447
448 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
449 (style,
450 true, // system-font (cannot delete)
451 firstInFamily, // what family to join
452 rec[i].fFileName) // filename
453 );
454
455 if (rec[i].fNames != NULL) {
456 // see if this is one of our fallback fonts
457 if (rec[i].fNames == gFBNames) {
458 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
459 // rec[i].fFileName, fallbackCount, tf->uniqueID());
460 gFallbackFonts[fallbackCount++] = tf->uniqueID();
461 }
462
463 firstInFamily = tf;
464 FamilyRec* family = find_family(tf);
465 const char* const* names = rec[i].fNames;
466
467 // record the default family if this is it
468 if (names == DEFAULT_NAMES) {
469 gDefaultFamily = family;
470 }
471 // add the names to map to this family
472 while (*names) {
473 add_name(*names, family);
474 names += 1;
475 }
476 }
477 }
478
479 // do this after all fonts are loaded. This is our default font, and it
480 // acts as a sentinel so we only execute load_system_fonts() once
481 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
482 // now terminate our fallback list with the sentinel value
483 gFallbackFonts[fallbackCount] = 0;
484}
485
486///////////////////////////////////////////////////////////////////////////////
487
488void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
489 const char* name = ((FamilyTypeface*)face)->getUniqueString();
490
491 stream->write8((uint8_t)face->style());
492
493 if (NULL == name || 0 == *name) {
494 stream->writePackedUInt(0);
495// SkDebugf("--- fonthost serialize null\n");
496 } else {
497 uint32_t len = strlen(name);
498 stream->writePackedUInt(len);
499 stream->write(name, len);
500// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
501 }
502}
503
504SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
505 load_system_fonts();
506
507 int style = stream->readU8();
508
509 int len = stream->readPackedUInt();
510 if (len > 0) {
511 SkString str;
512 str.resize(len);
513 stream->read(str.writable_str(), len);
reed@google.com60169622011-03-14 15:08:44 +0000514
reed@android.com9d3a9852010-01-08 14:07:42 +0000515 const FontInitRec* rec = gSystemFonts;
516 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
517 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
518 // backup until we hit the fNames
519 for (int j = i; j >= 0; --j) {
520 if (rec[j].fNames != NULL) {
521 return SkFontHost::CreateTypeface(NULL,
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000522 rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
reed@android.com9d3a9852010-01-08 14:07:42 +0000523 }
524 }
525 }
526 }
527 }
528 return NULL;
529}
530
531///////////////////////////////////////////////////////////////////////////////
532
533SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
534 const char familyName[],
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000535 const void* data, size_t bytelength,
reed@android.com9d3a9852010-01-08 14:07:42 +0000536 SkTypeface::Style style) {
537 load_system_fonts();
538
539 SkAutoMutexAcquire ac(gFamilyMutex);
reed@google.com60169622011-03-14 15:08:44 +0000540
reed@android.com9d3a9852010-01-08 14:07:42 +0000541 // clip to legal style bits
542 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
reed@google.com60169622011-03-14 15:08:44 +0000543
reed@android.com9d3a9852010-01-08 14:07:42 +0000544 SkTypeface* tf = NULL;
545
546 if (NULL != familyFace) {
547 tf = find_typeface(familyFace, style);
548 } else if (NULL != familyName) {
549// SkDebugf("======= familyName <%s>\n", familyName);
550 tf = find_typeface(familyName, style);
551 }
552
553 if (NULL == tf) {
554 tf = find_best_face(gDefaultFamily, style);
555 }
556
557 // we ref(), since the symantic is to return a new instance
558 tf->ref();
559 return tf;
560}
561
reed@android.com9d3a9852010-01-08 14:07:42 +0000562SkStream* SkFontHost::OpenStream(uint32_t fontID) {
563 SkAutoMutexAcquire ac(gFamilyMutex);
reed@google.com60169622011-03-14 15:08:44 +0000564
reed@android.com9d3a9852010-01-08 14:07:42 +0000565 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
566 SkStream* stream = tf ? tf->openStream() : NULL;
567
568 if (stream && stream->getLength() == 0) {
569 stream->unref();
570 stream = NULL;
571 }
572 return stream;
573}
574
reed@google.com60169622011-03-14 15:08:44 +0000575#if 0
vandebo@chromium.orgc48b2b32011-02-02 02:11:22 +0000576SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +0000577 uint32_t fontID,
tomhudson@google.comeebd62a2012-03-23 15:38:28 +0000578 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
579 const uint32_t* glyphIDs,
580 uint32_t glyphIDsCount) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000581 SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000582 return NULL;
583}
reed@google.com60169622011-03-14 15:08:44 +0000584#endif
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000585
reed@android.com9d3a9852010-01-08 14:07:42 +0000586size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
587 int32_t* index) {
588 SkAutoMutexAcquire ac(gFamilyMutex);
589
590 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
591 const char* src = tf ? tf->getFilePath() : NULL;
592
593 if (src) {
594 size_t size = strlen(src);
595 if (path) {
596 memcpy(path, src, SkMin32(size, length));
597 }
598 if (index) {
599 *index = 0; // we don't have collections (yet)
600 }
601 return size;
602 } else {
603 return 0;
604 }
605}
606
reed@google.com7d26c592011-06-13 13:01:10 +0000607SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
reed@android.com9d3a9852010-01-08 14:07:42 +0000608 load_system_fonts();
609
610 /* First see if fontID is already one of our fallbacks. If so, return
611 its successor. If fontID is not in our list, then return the first one
612 in our list. Note: list is zero-terminated, and returning zero means
613 we have no more fonts to use for fallbacks.
614 */
615 const uint32_t* list = gFallbackFonts;
616 for (int i = 0; list[i] != 0; i++) {
reed@google.com7d26c592011-06-13 13:01:10 +0000617 if (list[i] == currFontID) {
reed@android.com9d3a9852010-01-08 14:07:42 +0000618 return list[i+1];
619 }
620 }
621 return list[0];
622}
623
624///////////////////////////////////////////////////////////////////////////////
625
626SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
627 if (NULL == stream || stream->getLength() <= 0) {
628 return NULL;
629 }
reed@google.com60169622011-03-14 15:08:44 +0000630
djsollen@google.com4dc686d2012-02-15 21:03:45 +0000631 SkTypeface::Style style;
632 if (find_name_and_attributes(stream, NULL, &style, NULL)) {
633 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
634 } else {
635 return NULL;
636 }
reed@android.com9d3a9852010-01-08 14:07:42 +0000637}
638
639SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
640 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
641 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
642 // since we created the stream, we let go of our ref() here
643 stream->unref();
644 return face;
645}
646