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