|
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 |
|
7 |
|
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 |
|
13 |
|
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 |
|
702 |