Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 From 6982ad469adcdfa2b7bdbf8bbd843bc22d3832fc Mon Sep 17 00:00:00 2001
2 From: George Wright <gwright@mozilla.com>
3 Date: Fri, 18 May 2012 14:52:40 -0400
4 Subject: [PATCH 07/10] Bug 755869 - [10] Re-apply bug 719872 - Fix crash
5 on Android by reverting to older FontHost impl
6 r=mattwoodrow
8 ---
9 gfx/skia/Makefile.in | 5 +-
10 gfx/skia/src/ports/SkFontHost_android_old.cpp | 664 +++++++++++++++++++++++++
11 2 files changed, 668 insertions(+), 1 deletions(-)
12 create mode 100644 gfx/skia/src/ports/SkFontHost_android_old.cpp
14 diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in
15 index 9da098a..8184f1c 100644
16 --- a/gfx/skia/Makefile.in
17 +++ b/gfx/skia/Makefile.in
18 @@ -327,7 +327,10 @@ endif
19 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
20 CPPSRCS += \
21 SkDebug_android.cpp \
22 - SkFontHost_none.cpp \
23 + SkFontHost_android_old.cpp \
24 + SkFontHost_gamma.cpp \
25 + SkFontHost_FreeType.cpp \
26 + SkFontHost_tables.cpp \
27 SkMMapStream.cpp \
28 SkTime_Unix.cpp \
29 SkThread_pthread.cpp \
30 diff --git a/gfx/skia/src/ports/SkFontHost_android_old.cpp b/gfx/skia/src/ports/SkFontHost_android_old.cpp
31 new file mode 100644
32 index 0000000..b5c4f3c
33 --- /dev/null
34 +++ b/gfx/skia/src/ports/SkFontHost_android_old.cpp
35 @@ -0,0 +1,664 @@
36 +
37 +/*
38 + * Copyright 2006 The Android Open Source Project
39 + *
40 + * Use of this source code is governed by a BSD-style license that can be
41 + * found in the LICENSE file.
42 + */
43 +
44 +
45 +#include "SkFontHost.h"
46 +#include "SkDescriptor.h"
47 +#include "SkMMapStream.h"
48 +#include "SkPaint.h"
49 +#include "SkString.h"
50 +#include "SkStream.h"
51 +#include "SkThread.h"
52 +#include "SkTSearch.h"
53 +#include <stdio.h>
54 +
55 +#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
56 +
57 +#ifndef SK_FONT_FILE_PREFIX
58 + #define SK_FONT_FILE_PREFIX "/fonts/"
59 +#endif
60 +
61 +bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style,
62 + bool* isFixedWidth);
63 +
64 +static void GetFullPathForSysFonts(SkString* full, const char name[]) {
65 + full->set(getenv("ANDROID_ROOT"));
66 + full->append(SK_FONT_FILE_PREFIX);
67 + full->append(name);
68 +}
69 +
70 +///////////////////////////////////////////////////////////////////////////////
71 +
72 +struct FamilyRec;
73 +
74 +/* This guy holds a mapping of a name -> family, used for looking up fonts.
75 + Since it is stored in a stretchy array that doesn't preserve object
76 + semantics, we don't use constructor/destructors, but just have explicit
77 + helpers to manage our internal bookkeeping.
78 +*/
79 +struct NameFamilyPair {
80 + const char* fName; // we own this
81 + FamilyRec* fFamily; // we don't own this, we just reference it
82 +
83 + void construct(const char name[], FamilyRec* family) {
84 + fName = strdup(name);
85 + fFamily = family; // we don't own this, so just record the referene
86 + }
87 +
88 + void destruct() {
89 + free((char*)fName);
90 + // we don't own family, so just ignore our reference
91 + }
92 +};
93 +
94 +// we use atomic_inc to grow this for each typeface we create
95 +static int32_t gUniqueFontID;
96 +
97 +// this is the mutex that protects these globals
98 +static SkMutex gFamilyMutex;
99 +static FamilyRec* gFamilyHead;
100 +static SkTDArray<NameFamilyPair> gNameList;
101 +
102 +struct FamilyRec {
103 + FamilyRec* fNext;
104 + SkTypeface* fFaces[4];
105 +
106 + FamilyRec()
107 + {
108 + fNext = gFamilyHead;
109 + memset(fFaces, 0, sizeof(fFaces));
110 + gFamilyHead = this;
111 + }
112 +};
113 +
114 +static SkTypeface* find_best_face(const FamilyRec* family,
115 + SkTypeface::Style style) {
116 + SkTypeface* const* faces = family->fFaces;
117 +
118 + if (faces[style] != NULL) { // exact match
119 + return faces[style];
120 + }
121 + // look for a matching bold
122 + style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
123 + if (faces[style] != NULL) {
124 + return faces[style];
125 + }
126 + // look for the plain
127 + if (faces[SkTypeface::kNormal] != NULL) {
128 + return faces[SkTypeface::kNormal];
129 + }
130 + // look for anything
131 + for (int i = 0; i < 4; i++) {
132 + if (faces[i] != NULL) {
133 + return faces[i];
134 + }
135 + }
136 + // should never get here, since the faces list should not be empty
137 + SkASSERT(!"faces list is empty");
138 + return NULL;
139 +}
140 +
141 +static FamilyRec* find_family(const SkTypeface* member) {
142 + FamilyRec* curr = gFamilyHead;
143 + while (curr != NULL) {
144 + for (int i = 0; i < 4; i++) {
145 + if (curr->fFaces[i] == member) {
146 + return curr;
147 + }
148 + }
149 + curr = curr->fNext;
150 + }
151 + return NULL;
152 +}
153 +
154 +/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
155 + is not modified.
156 + */
157 +static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
158 + FamilyRec* curr = gFamilyHead;
159 + while (curr != NULL) {
160 + for (int i = 0; i < 4; i++) {
161 + SkTypeface* face = curr->fFaces[i];
162 + if (face != NULL && face->uniqueID() == uniqueID) {
163 + return face;
164 + }
165 + }
166 + curr = curr->fNext;
167 + }
168 + return NULL;
169 +}
170 +
171 +/* Remove reference to this face from its family. If the resulting family
172 + is empty (has no faces), return that family, otherwise return NULL
173 +*/
174 +static FamilyRec* remove_from_family(const SkTypeface* face) {
175 + FamilyRec* family = find_family(face);
176 + SkASSERT(family->fFaces[face->style()] == face);
177 + family->fFaces[face->style()] = NULL;
178 +
179 + for (int i = 0; i < 4; i++) {
180 + if (family->fFaces[i] != NULL) { // family is non-empty
181 + return NULL;
182 + }
183 + }
184 + return family; // return the empty family
185 +}
186 +
187 +// maybe we should make FamilyRec be doubly-linked
188 +static void detach_and_delete_family(FamilyRec* family) {
189 + FamilyRec* curr = gFamilyHead;
190 + FamilyRec* prev = NULL;
191 +
192 + while (curr != NULL) {
193 + FamilyRec* next = curr->fNext;
194 + if (curr == family) {
195 + if (prev == NULL) {
196 + gFamilyHead = next;
197 + } else {
198 + prev->fNext = next;
199 + }
200 + SkDELETE(family);
201 + return;
202 + }
203 + prev = curr;
204 + curr = next;
205 + }
206 + SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
207 +}
208 +
209 +static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
210 + NameFamilyPair* list = gNameList.begin();
211 + int count = gNameList.count();
212 +
213 + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
214 +
215 + if (index >= 0) {
216 + return find_best_face(list[index].fFamily, style);
217 + }
218 + return NULL;
219 +}
220 +
221 +static SkTypeface* find_typeface(const SkTypeface* familyMember,
222 + SkTypeface::Style style) {
223 + const FamilyRec* family = find_family(familyMember);
224 + return family ? find_best_face(family, style) : NULL;
225 +}
226 +
227 +static void add_name(const char name[], FamilyRec* family) {
228 + SkAutoAsciiToLC tolc(name);
229 + name = tolc.lc();
230 +
231 + NameFamilyPair* list = gNameList.begin();
232 + int count = gNameList.count();
233 +
234 + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
235 +
236 + if (index < 0) {
237 + list = gNameList.insert(~index);
238 + list->construct(name, family);
239 + }
240 +}
241 +
242 +static void remove_from_names(FamilyRec* emptyFamily)
243 +{
244 +#ifdef SK_DEBUG
245 + for (int i = 0; i < 4; i++) {
246 + SkASSERT(emptyFamily->fFaces[i] == NULL);
247 + }
248 +#endif
249 +
250 + SkTDArray<NameFamilyPair>& list = gNameList;
251 +
252 + // 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 +
264 +class FamilyTypeface : public SkTypeface {
265 +public:
266 + FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
267 + bool isFixedWidth)
268 + : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
269 + fIsSysFont = sysFont;
270 +
271 + SkAutoMutexAcquire ac(gFamilyMutex);
272 +
273 + FamilyRec* rec = NULL;
274 + if (familyMember) {
275 + rec = find_family(familyMember);
276 + SkASSERT(rec);
277 + } else {
278 + rec = SkNEW(FamilyRec);
279 + }
280 + rec->fFaces[style] = this;
281 + }
282 +
283 + virtual ~FamilyTypeface() {
284 + SkAutoMutexAcquire ac(gFamilyMutex);
285 +
286 + // remove us from our family. If the family is now empty, we return
287 + // that and then remove that family from the name list
288 + FamilyRec* family = remove_from_family(this);
289 + if (NULL != family) {
290 + remove_from_names(family);
291 + detach_and_delete_family(family);
292 + }
293 + }
294 +
295 + bool isSysFont() const { return fIsSysFont; }
296 +
297 + virtual SkStream* openStream() = 0;
298 + virtual const char* getUniqueString() const = 0;
299 + virtual const char* getFilePath() const = 0;
300 +
301 +private:
302 + bool fIsSysFont;
303 +
304 + typedef SkTypeface INHERITED;
305 +};
306 +
307 +///////////////////////////////////////////////////////////////////////////////
308 +
309 +class StreamTypeface : public FamilyTypeface {
310 +public:
311 + StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
312 + SkStream* stream, bool isFixedWidth)
313 + : INHERITED(style, sysFont, familyMember, isFixedWidth) {
314 + SkASSERT(stream);
315 + stream->ref();
316 + fStream = stream;
317 + }
318 + virtual ~StreamTypeface() {
319 + fStream->unref();
320 + }
321 +
322 + // overrides
323 + virtual SkStream* openStream() {
324 + // we just ref our existing stream, since the caller will call unref()
325 + // when they are through
326 + fStream->ref();
327 + // must rewind each time, since the caller assumes a "new" stream
328 + fStream->rewind();
329 + return fStream;
330 + }
331 + virtual const char* getUniqueString() const { return NULL; }
332 + virtual const char* getFilePath() const { return NULL; }
333 +
334 +private:
335 + SkStream* fStream;
336 +
337 + typedef FamilyTypeface INHERITED;
338 +};
339 +
340 +class FileTypeface : public FamilyTypeface {
341 +public:
342 + FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
343 + const char path[], bool isFixedWidth)
344 + : INHERITED(style, sysFont, familyMember, isFixedWidth) {
345 + SkString fullpath;
346 +
347 + if (sysFont) {
348 + GetFullPathForSysFonts(&fullpath, path);
349 + path = fullpath.c_str();
350 + }
351 + fPath.set(path);
352 + }
353 +
354 + // overrides
355 + virtual SkStream* openStream() {
356 + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
357 +
358 + // check for failure
359 + if (stream->getLength() <= 0) {
360 + SkDELETE(stream);
361 + // maybe MMAP isn't supported. try FILE
362 + stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
363 + if (stream->getLength() <= 0) {
364 + SkDELETE(stream);
365 + stream = NULL;
366 + }
367 + }
368 + return stream;
369 + }
370 + virtual const char* getUniqueString() const {
371 + const char* str = strrchr(fPath.c_str(), '/');
372 + if (str) {
373 + str += 1; // skip the '/'
374 + }
375 + return str;
376 + }
377 + virtual const char* getFilePath() const {
378 + return fPath.c_str();
379 + }
380 +
381 +private:
382 + SkString fPath;
383 +
384 + typedef FamilyTypeface INHERITED;
385 +};
386 +
387 +///////////////////////////////////////////////////////////////////////////////
388 +///////////////////////////////////////////////////////////////////////////////
389 +
390 +static bool get_name_and_style(const char path[], SkString* name,
391 + SkTypeface::Style* style,
392 + bool* isFixedWidth, bool isExpected) {
393 + SkString fullpath;
394 + GetFullPathForSysFonts(&fullpath, path);
395 +
396 + SkMMAPStream stream(fullpath.c_str());
397 + if (stream.getLength() > 0) {
398 + find_name_and_attributes(&stream, name, style, isFixedWidth);
399 + return true;
400 + }
401 + else {
402 + SkFILEStream stream(fullpath.c_str());
403 + if (stream.getLength() > 0) {
404 + find_name_and_attributes(&stream, name, style, isFixedWidth);
405 + return true;
406 + }
407 + }
408 +
409 + if (isExpected) {
410 + SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
411 + }
412 + return false;
413 +}
414 +
415 +// used to record our notion of the pre-existing fonts
416 +struct FontInitRec {
417 + const char* fFileName;
418 + const char* const* fNames; // null-terminated list
419 +};
420 +
421 +static const char* gSansNames[] = {
422 + "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
423 +};
424 +
425 +static const char* gSerifNames[] = {
426 + "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
427 + "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
428 +};
429 +
430 +static const char* gMonoNames[] = {
431 + "monospace", "courier", "courier new", "monaco", NULL
432 +};
433 +
434 +// deliberately empty, but we use the address to identify fallback fonts
435 +static const char* gFBNames[] = { NULL };
436 +
437 +/* Fonts must be 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 +*/
441 +static const FontInitRec gSystemFonts[] = {
442 + { "DroidSans.ttf", gSansNames },
443 + { "DroidSans-Bold.ttf", NULL },
444 + { "DroidSerif-Regular.ttf", gSerifNames },
445 + { "DroidSerif-Bold.ttf", NULL },
446 + { "DroidSerif-Italic.ttf", NULL },
447 + { "DroidSerif-BoldItalic.ttf", NULL },
448 + { "DroidSansMono.ttf", gMonoNames },
449 + /* These are optional, and can be ignored if not found in the file system.
450 + These are appended to gFallbackFonts[] as they are seen, so we list
451 + them in the order we want them to be accessed by NextLogicalFont().
452 + */
453 + { "DroidSansArabic.ttf", gFBNames },
454 + { "DroidSansHebrew.ttf", gFBNames },
455 + { "DroidSansThai.ttf", gFBNames },
456 + { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
457 + { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
458 + { "DroidSansJapanese.ttf", gFBNames },
459 + { "DroidSansFallback.ttf", gFBNames }
460 +};
461 +
462 +#define DEFAULT_NAMES gSansNames
463 +
464 +// these globals are assigned (once) by load_system_fonts()
465 +static FamilyRec* gDefaultFamily;
466 +static SkTypeface* gDefaultNormal;
467 +
468 +/* This is sized conservatively, assuming that it will never be a size issue.
469 + It will be initialized in load_system_fonts(), and will be filled with the
470 + fontIDs that can be used for fallback consideration, in sorted order (sorted
471 + meaning element[0] should be used first, then element[1], etc. When we hit
472 + a fontID==0 in the array, the list is done, hence our allocation size is
473 + +1 the total number of possible system fonts. Also see NextLogicalFont().
474 + */
475 +static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
476 +
477 +/* Called once (ensured by the sentinel check at the beginning of our body).
478 + Initializes all the globals, and register the system fonts.
479 + */
480 +static void load_system_fonts() {
481 + // check if we've already be called
482 + if (NULL != gDefaultNormal) {
483 + return;
484 + }
485 +
486 + const FontInitRec* rec = gSystemFonts;
487 + SkTypeface* firstInFamily = NULL;
488 + int fallbackCount = 0;
489 +
490 + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
491 + // if we're the first in a new family, clear firstInFamily
492 + if (rec[i].fNames != NULL) {
493 + firstInFamily = NULL;
494 + }
495 +
496 + bool isFixedWidth;
497 + SkString name;
498 + SkTypeface::Style style;
499 +
500 + // we expect all the fonts, except the "fallback" fonts
501 + bool isExpected = (rec[i].fNames != gFBNames);
502 + if (!get_name_and_style(rec[i].fFileName, &name, &style,
503 + &isFixedWidth, isExpected)) {
504 + continue;
505 + }
506 +
507 + SkTypeface* tf = SkNEW_ARGS(FileTypeface,
508 + (style,
509 + true, // system-font (cannot delete)
510 + firstInFamily, // what family to join
511 + rec[i].fFileName,
512 + isFixedWidth) // filename
513 + );
514 +
515 + if (rec[i].fNames != NULL) {
516 + // see if this is one of our fallback fonts
517 + if (rec[i].fNames == gFBNames) {
518 + // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
519 + // rec[i].fFileName, fallbackCount, tf->uniqueID());
520 + gFallbackFonts[fallbackCount++] = tf->uniqueID();
521 + }
522 +
523 + firstInFamily = tf;
524 + FamilyRec* family = find_family(tf);
525 + const char* const* names = rec[i].fNames;
526 +
527 + // record the default family if this is it
528 + if (names == DEFAULT_NAMES) {
529 + gDefaultFamily = family;
530 + }
531 + // add the names to map to this family
532 + while (*names) {
533 + add_name(*names, family);
534 + names += 1;
535 + }
536 + }
537 + }
538 +
539 + // do this after all fonts are loaded. This is our default font, and it
540 + // acts as a sentinel so we only execute load_system_fonts() once
541 + gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
542 + // now terminate our fallback list with the sentinel value
543 + gFallbackFonts[fallbackCount] = 0;
544 +}
545 +
546 +///////////////////////////////////////////////////////////////////////////////
547 +
548 +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
549 + const char* name = ((FamilyTypeface*)face)->getUniqueString();
550 +
551 + stream->write8((uint8_t)face->style());
552 +
553 + if (NULL == name || 0 == *name) {
554 + stream->writePackedUInt(0);
555 +// SkDebugf("--- fonthost serialize null\n");
556 + } else {
557 + uint32_t len = strlen(name);
558 + stream->writePackedUInt(len);
559 + stream->write(name, len);
560 +// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
561 + }
562 +}
563 +
564 +SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
565 + load_system_fonts();
566 +
567 + int style = stream->readU8();
568 +
569 + int len = stream->readPackedUInt();
570 + if (len > 0) {
571 + SkString str;
572 + str.resize(len);
573 + stream->read(str.writable_str(), len);
574 +
575 + const FontInitRec* rec = gSystemFonts;
576 + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
577 + if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
578 + // backup until we hit the fNames
579 + for (int j = i; j >= 0; --j) {
580 + if (rec[j].fNames != NULL) {
581 + return SkFontHost::CreateTypeface(NULL,
582 + rec[j].fNames[0], (SkTypeface::Style)style);
583 + }
584 + }
585 + }
586 + }
587 + }
588 + return NULL;
589 +}
590 +
591 +///////////////////////////////////////////////////////////////////////////////
592 +
593 +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
594 + const char familyName[],
595 + SkTypeface::Style style) {
596 + load_system_fonts();
597 +
598 + SkAutoMutexAcquire ac(gFamilyMutex);
599 +
600 + // clip to legal style bits
601 + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
602 +
603 + SkTypeface* tf = NULL;
604 +
605 + if (NULL != familyFace) {
606 + tf = find_typeface(familyFace, style);
607 + } else if (NULL != familyName) {
608 +// SkDebugf("======= familyName <%s>\n", familyName);
609 + tf = find_typeface(familyName, style);
610 + }
611 +
612 + if (NULL == tf) {
613 + tf = find_best_face(gDefaultFamily, style);
614 + }
615 +
616 + // we ref(), since the symantic is to return a new instance
617 + tf->ref();
618 + return tf;
619 +}
620 +
621 +SkStream* SkFontHost::OpenStream(uint32_t fontID) {
622 + SkAutoMutexAcquire ac(gFamilyMutex);
623 +
624 + FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
625 + SkStream* stream = tf ? tf->openStream() : NULL;
626 +
627 + if (stream && stream->getLength() == 0) {
628 + stream->unref();
629 + stream = NULL;
630 + }
631 + return stream;
632 +}
633 +
634 +size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
635 + int32_t* index) {
636 + SkAutoMutexAcquire ac(gFamilyMutex);
637 +
638 + FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
639 + const char* src = tf ? tf->getFilePath() : NULL;
640 +
641 + if (src) {
642 + size_t size = strlen(src);
643 + if (path) {
644 + memcpy(path, src, SkMin32(size, length));
645 + }
646 + if (index) {
647 + *index = 0; // we don't have collections (yet)
648 + }
649 + return size;
650 + } else {
651 + return 0;
652 + }
653 +}
654 +
655 +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
656 + load_system_fonts();
657 +
658 + /* First see if fontID is already one of our fallbacks. If so, return
659 + its successor. If fontID is not in our list, then return the first one
660 + in our list. Note: list is zero-terminated, and returning zero means
661 + we have no more fonts to use for fallbacks.
662 + */
663 + const uint32_t* list = gFallbackFonts;
664 + for (int i = 0; list[i] != 0; i++) {
665 + if (list[i] == currFontID) {
666 + return list[i+1];
667 + }
668 + }
669 + return list[0];
670 +}
671 +
672 +///////////////////////////////////////////////////////////////////////////////
673 +
674 +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
675 + if (NULL == stream || stream->getLength() <= 0) {
676 + return NULL;
677 + }
678 +
679 + bool isFixedWidth;
680 + SkString name;
681 + SkTypeface::Style style;
682 + find_name_and_attributes(stream, &name, &style, &isFixedWidth);
683 +
684 + if (!name.isEmpty()) {
685 + return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
686 + } else {
687 + return NULL;
688 + }
689 +}
690 +
691 +SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
692 + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
693 + SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
694 + // since we created the stream, we let go of our ref() here
695 + stream->unref();
696 + return face;
697 +}
698 +
699 +///////////////////////////////////////////////////////////////////////////////
700 --
701 1.7.5.4