|
1 # HG changeset patch |
|
2 # Parent 9ee29e4aace683ddf6cf8ddb2893cd34fcfc772c |
|
3 # User James Willcox <jwillcox@mozilla.com> |
|
4 diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in |
|
5 --- a/gfx/skia/Makefile.in |
|
6 +++ b/gfx/skia/Makefile.in |
|
7 @@ -305,21 +305,20 @@ CPPSRCS += \ |
|
8 SkFontHost_mac_coretext.cpp \ |
|
9 SkTime_Unix.cpp \ |
|
10 $(NULL) |
|
11 endif |
|
12 |
|
13 ifeq (android,$(MOZ_WIDGET_TOOLKIT)) |
|
14 CPPSRCS += \ |
|
15 SkFontHost_FreeType.cpp \ |
|
16 SkFontHost_android.cpp \ |
|
17 SkFontHost_gamma.cpp \ |
|
18 - FontHostConfiguration_android.cpp \ |
|
19 SkMMapStream.cpp \ |
|
20 SkTime_Unix.cpp \ |
|
21 $(NULL) |
|
22 |
|
23 DEFINES += -DSK_BUILD_FOR_ANDROID_NDK |
|
24 OS_CXXFLAGS += $(CAIRO_FT_CFLAGS) |
|
25 endif |
|
26 |
|
27 ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT)) |
|
28 CPPSRCS += \ |
|
29 diff --git a/gfx/skia/src/ports/SkFontHost_android.cpp b/gfx/skia/src/ports/SkFontHost_android.cpp |
|
30 --- a/gfx/skia/src/ports/SkFontHost_android.cpp |
|
31 +++ b/gfx/skia/src/ports/SkFontHost_android.cpp |
|
32 @@ -1,38 +1,31 @@ |
|
33 + |
|
34 /* |
|
35 -** |
|
36 -** Copyright 2006, The Android Open Source Project |
|
37 -** |
|
38 -** Licensed under the Apache License, Version 2.0 (the "License"); |
|
39 -** you may not use this file except in compliance with the License. |
|
40 -** You may obtain a copy of the License at |
|
41 -** |
|
42 -** http://www.apache.org/licenses/LICENSE-2.0 |
|
43 -** |
|
44 -** Unless required by applicable law or agreed to in writing, software |
|
45 -** distributed under the License is distributed on an "AS IS" BASIS, |
|
46 -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
47 -** See the License for the specific language governing permissions and |
|
48 -** limitations under the License. |
|
49 -*/ |
|
50 + * Copyright 2006 The Android Open Source Project |
|
51 + * |
|
52 + * Use of this source code is governed by a BSD-style license that can be |
|
53 + * found in the LICENSE file. |
|
54 + */ |
|
55 + |
|
56 |
|
57 #include "SkFontHost.h" |
|
58 #include "SkDescriptor.h" |
|
59 #include "SkMMapStream.h" |
|
60 #include "SkPaint.h" |
|
61 #include "SkString.h" |
|
62 #include "SkStream.h" |
|
63 #include "SkThread.h" |
|
64 #include "SkTSearch.h" |
|
65 -#include "FontHostConfiguration_android.h" |
|
66 #include <stdio.h> |
|
67 |
|
68 +#define FONT_CACHE_MEMORY_BUDGET (768 * 1024) |
|
69 + |
|
70 #ifndef SK_FONT_FILE_PREFIX |
|
71 #define SK_FONT_FILE_PREFIX "/fonts/" |
|
72 #endif |
|
73 |
|
74 SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name, |
|
75 bool* isFixedWidth); |
|
76 |
|
77 static void GetFullPathForSysFonts(SkString* full, const char name[]) { |
|
78 full->set(getenv("ANDROID_ROOT")); |
|
79 full->append(SK_FONT_FILE_PREFIX); |
|
80 @@ -99,21 +92,21 @@ static SkTypeface* find_best_face(const |
|
81 if (faces[SkTypeface::kNormal] != NULL) { |
|
82 return faces[SkTypeface::kNormal]; |
|
83 } |
|
84 // look for anything |
|
85 for (int i = 0; i < 4; i++) { |
|
86 if (faces[i] != NULL) { |
|
87 return faces[i]; |
|
88 } |
|
89 } |
|
90 // should never get here, since the faces list should not be empty |
|
91 - SkDEBUGFAIL("faces list is empty"); |
|
92 + SkASSERT(!"faces list is empty"); |
|
93 return NULL; |
|
94 } |
|
95 |
|
96 static FamilyRec* find_family(const SkTypeface* member) { |
|
97 FamilyRec* curr = gFamilyHead; |
|
98 while (curr != NULL) { |
|
99 for (int i = 0; i < 4; i++) { |
|
100 if (curr->fFaces[i] == member) { |
|
101 return curr; |
|
102 } |
|
103 @@ -138,31 +131,27 @@ static SkTypeface* find_from_uniqueID(ui |
|
104 curr = curr->fNext; |
|
105 } |
|
106 return NULL; |
|
107 } |
|
108 |
|
109 /* Remove reference to this face from its family. If the resulting family |
|
110 is empty (has no faces), return that family, otherwise return NULL |
|
111 */ |
|
112 static FamilyRec* remove_from_family(const SkTypeface* face) { |
|
113 FamilyRec* family = find_family(face); |
|
114 - if (family) { |
|
115 - SkASSERT(family->fFaces[face->style()] == face); |
|
116 - family->fFaces[face->style()] = NULL; |
|
117 + SkASSERT(family->fFaces[face->style()] == face); |
|
118 + family->fFaces[face->style()] = NULL; |
|
119 |
|
120 - for (int i = 0; i < 4; i++) { |
|
121 - if (family->fFaces[i] != NULL) { // family is non-empty |
|
122 - return NULL; |
|
123 - } |
|
124 + for (int i = 0; i < 4; i++) { |
|
125 + if (family->fFaces[i] != NULL) { // family is non-empty |
|
126 + return NULL; |
|
127 } |
|
128 - } else { |
|
129 -// SkDebugf("remove_from_family(%p) face not found", face); |
|
130 } |
|
131 return family; // return the empty family |
|
132 } |
|
133 |
|
134 // maybe we should make FamilyRec be doubly-linked |
|
135 static void detach_and_delete_family(FamilyRec* family) { |
|
136 FamilyRec* curr = gFamilyHead; |
|
137 FamilyRec* prev = NULL; |
|
138 |
|
139 while (curr != NULL) { |
|
140 @@ -172,21 +161,21 @@ static void detach_and_delete_family(Fam |
|
141 gFamilyHead = next; |
|
142 } else { |
|
143 prev->fNext = next; |
|
144 } |
|
145 SkDELETE(family); |
|
146 return; |
|
147 } |
|
148 prev = curr; |
|
149 curr = next; |
|
150 } |
|
151 - SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete"); |
|
152 + SkASSERT(!"Yikes, couldn't find family in our list to remove/delete"); |
|
153 } |
|
154 |
|
155 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { |
|
156 NameFamilyPair* list = gNameList.begin(); |
|
157 int count = gNameList.count(); |
|
158 |
|
159 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); |
|
160 |
|
161 if (index >= 0) { |
|
162 return find_best_face(list[index].fFamily, style); |
|
163 @@ -387,111 +376,90 @@ static bool get_name_and_style(const cha |
|
164 } |
|
165 return false; |
|
166 } |
|
167 |
|
168 // used to record our notion of the pre-existing fonts |
|
169 struct FontInitRec { |
|
170 const char* fFileName; |
|
171 const char* const* fNames; // null-terminated list |
|
172 }; |
|
173 |
|
174 +static const char* gSansNames[] = { |
|
175 + "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL |
|
176 +}; |
|
177 + |
|
178 +static const char* gSerifNames[] = { |
|
179 + "serif", "times", "times new roman", "palatino", "georgia", "baskerville", |
|
180 + "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL |
|
181 +}; |
|
182 + |
|
183 +static const char* gMonoNames[] = { |
|
184 + "monospace", "courier", "courier new", "monaco", NULL |
|
185 +}; |
|
186 + |
|
187 // deliberately empty, but we use the address to identify fallback fonts |
|
188 static const char* gFBNames[] = { NULL }; |
|
189 |
|
190 +/* Fonts must be grouped by family, with the first font in a family having the |
|
191 + list of names (even if that list is empty), and the following members having |
|
192 + null for the list. The names list must be NULL-terminated |
|
193 +*/ |
|
194 +static const FontInitRec gSystemFonts[] = { |
|
195 + { "DroidSans.ttf", gSansNames }, |
|
196 + { "DroidSans-Bold.ttf", NULL }, |
|
197 + { "DroidSerif-Regular.ttf", gSerifNames }, |
|
198 + { "DroidSerif-Bold.ttf", NULL }, |
|
199 + { "DroidSerif-Italic.ttf", NULL }, |
|
200 + { "DroidSerif-BoldItalic.ttf", NULL }, |
|
201 + { "DroidSansMono.ttf", gMonoNames }, |
|
202 + /* These are optional, and can be ignored if not found in the file system. |
|
203 + These are appended to gFallbackFonts[] as they are seen, so we list |
|
204 + them in the order we want them to be accessed by NextLogicalFont(). |
|
205 + */ |
|
206 + { "DroidSansArabic.ttf", gFBNames }, |
|
207 + { "DroidSansHebrew.ttf", gFBNames }, |
|
208 + { "DroidSansThai.ttf", gFBNames }, |
|
209 + { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font |
|
210 + { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font |
|
211 + { "DroidSansJapanese.ttf", gFBNames }, |
|
212 + { "DroidSansFallback.ttf", gFBNames } |
|
213 +}; |
|
214 |
|
215 -/* Fonts are grouped by family, with the first font in a family having the |
|
216 - list of names (even if that list is empty), and the following members having |
|
217 - null for the list. The names list must be NULL-terminated. |
|
218 -*/ |
|
219 -static FontInitRec *gSystemFonts; |
|
220 -static size_t gNumSystemFonts = 0; |
|
221 - |
|
222 -#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg" |
|
223 +#define DEFAULT_NAMES gSansNames |
|
224 |
|
225 // these globals are assigned (once) by load_system_fonts() |
|
226 static FamilyRec* gDefaultFamily; |
|
227 static SkTypeface* gDefaultNormal; |
|
228 -static char** gDefaultNames = NULL; |
|
229 -static uint32_t *gFallbackFonts; |
|
230 |
|
231 -/* Load info from a configuration file that populates the system/fallback font structures |
|
232 -*/ |
|
233 -static void load_font_info() { |
|
234 -// load_font_info_xml("/system/etc/system_fonts.xml"); |
|
235 - SkTDArray<FontFamily*> fontFamilies; |
|
236 - getFontFamilies(fontFamilies); |
|
237 - |
|
238 - SkTDArray<FontInitRec> fontInfo; |
|
239 - bool firstInFamily = false; |
|
240 - for (int i = 0; i < fontFamilies.count(); ++i) { |
|
241 - FontFamily *family = fontFamilies[i]; |
|
242 - firstInFamily = true; |
|
243 - for (int j = 0; j < family->fFileNames.count(); ++j) { |
|
244 - FontInitRec fontInfoRecord; |
|
245 - fontInfoRecord.fFileName = family->fFileNames[j]; |
|
246 - if (j == 0) { |
|
247 - if (family->fNames.count() == 0) { |
|
248 - // Fallback font |
|
249 - fontInfoRecord.fNames = (char **)gFBNames; |
|
250 - } else { |
|
251 - SkTDArray<const char*> names = family->fNames; |
|
252 - const char **nameList = (const char**) |
|
253 - malloc((names.count() + 1) * sizeof(char*)); |
|
254 - if (nameList == NULL) { |
|
255 - // shouldn't get here |
|
256 - break; |
|
257 - } |
|
258 - if (gDefaultNames == NULL) { |
|
259 - gDefaultNames = (char**) nameList; |
|
260 - } |
|
261 - for (int i = 0; i < names.count(); ++i) { |
|
262 - nameList[i] = names[i]; |
|
263 - } |
|
264 - nameList[names.count()] = NULL; |
|
265 - fontInfoRecord.fNames = nameList; |
|
266 - } |
|
267 - } else { |
|
268 - fontInfoRecord.fNames = NULL; |
|
269 - } |
|
270 - *fontInfo.append() = fontInfoRecord; |
|
271 - } |
|
272 - } |
|
273 - gNumSystemFonts = fontInfo.count(); |
|
274 - gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec)); |
|
275 - gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t)); |
|
276 - if (gSystemFonts == NULL) { |
|
277 - // shouldn't get here |
|
278 - gNumSystemFonts = 0; |
|
279 - } |
|
280 - for (size_t i = 0; i < gNumSystemFonts; ++i) { |
|
281 - gSystemFonts[i].fFileName = fontInfo[i].fFileName; |
|
282 - gSystemFonts[i].fNames = fontInfo[i].fNames; |
|
283 - } |
|
284 - fontFamilies.deleteAll(); |
|
285 -} |
|
286 +/* This is sized conservatively, assuming that it will never be a size issue. |
|
287 + It will be initialized in load_system_fonts(), and will be filled with the |
|
288 + fontIDs that can be used for fallback consideration, in sorted order (sorted |
|
289 + meaning element[0] should be used first, then element[1], etc. When we hit |
|
290 + a fontID==0 in the array, the list is done, hence our allocation size is |
|
291 + +1 the total number of possible system fonts. Also see NextLogicalFont(). |
|
292 + */ |
|
293 +static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1]; |
|
294 |
|
295 /* Called once (ensured by the sentinel check at the beginning of our body). |
|
296 Initializes all the globals, and register the system fonts. |
|
297 */ |
|
298 static void load_system_fonts() { |
|
299 // check if we've already be called |
|
300 if (NULL != gDefaultNormal) { |
|
301 return; |
|
302 } |
|
303 |
|
304 - load_font_info(); |
|
305 - |
|
306 const FontInitRec* rec = gSystemFonts; |
|
307 SkTypeface* firstInFamily = NULL; |
|
308 int fallbackCount = 0; |
|
309 |
|
310 - for (size_t i = 0; i < gNumSystemFonts; i++) { |
|
311 + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { |
|
312 // if we're the first in a new family, clear firstInFamily |
|
313 if (rec[i].fNames != NULL) { |
|
314 firstInFamily = NULL; |
|
315 } |
|
316 |
|
317 bool isFixedWidth; |
|
318 SkString name; |
|
319 SkTypeface::Style style; |
|
320 |
|
321 // we expect all the fonts, except the "fallback" fonts |
|
322 @@ -515,120 +483,75 @@ static void load_system_fonts() { |
|
323 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n", |
|
324 // rec[i].fFileName, fallbackCount, tf->uniqueID()); |
|
325 gFallbackFonts[fallbackCount++] = tf->uniqueID(); |
|
326 } |
|
327 |
|
328 firstInFamily = tf; |
|
329 FamilyRec* family = find_family(tf); |
|
330 const char* const* names = rec[i].fNames; |
|
331 |
|
332 // record the default family if this is it |
|
333 - if (names == gDefaultNames) { |
|
334 + if (names == DEFAULT_NAMES) { |
|
335 gDefaultFamily = family; |
|
336 } |
|
337 // add the names to map to this family |
|
338 while (*names) { |
|
339 add_name(*names, family); |
|
340 names += 1; |
|
341 } |
|
342 } |
|
343 } |
|
344 |
|
345 // do this after all fonts are loaded. This is our default font, and it |
|
346 // acts as a sentinel so we only execute load_system_fonts() once |
|
347 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); |
|
348 // now terminate our fallback list with the sentinel value |
|
349 gFallbackFonts[fallbackCount] = 0; |
|
350 } |
|
351 |
|
352 /////////////////////////////////////////////////////////////////////////////// |
|
353 |
|
354 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { |
|
355 - // lookup and record if the font is custom (i.e. not a system font) |
|
356 - bool isCustomFont = !((FamilyTypeface*)face)->isSysFont(); |
|
357 - stream->writeBool(isCustomFont); |
|
358 + const char* name = ((FamilyTypeface*)face)->getUniqueString(); |
|
359 |
|
360 - if (isCustomFont) { |
|
361 - SkStream* fontStream = ((FamilyTypeface*)face)->openStream(); |
|
362 + stream->write8((uint8_t)face->style()); |
|
363 |
|
364 - // store the length of the custom font |
|
365 - uint32_t len = fontStream->getLength(); |
|
366 - stream->write32(len); |
|
367 - |
|
368 - // store the entire font in the serialized stream |
|
369 - void* fontData = malloc(len); |
|
370 - |
|
371 - fontStream->read(fontData, len); |
|
372 - stream->write(fontData, len); |
|
373 - |
|
374 - fontStream->unref(); |
|
375 - free(fontData); |
|
376 -// SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len); |
|
377 - |
|
378 + if (NULL == name || 0 == *name) { |
|
379 + stream->writePackedUInt(0); |
|
380 +// SkDebugf("--- fonthost serialize null\n"); |
|
381 } else { |
|
382 - const char* name = ((FamilyTypeface*)face)->getUniqueString(); |
|
383 - |
|
384 - stream->write8((uint8_t)face->style()); |
|
385 - |
|
386 - if (NULL == name || 0 == *name) { |
|
387 - stream->writePackedUInt(0); |
|
388 -// SkDebugf("--- fonthost serialize null\n"); |
|
389 - } else { |
|
390 - uint32_t len = strlen(name); |
|
391 - stream->writePackedUInt(len); |
|
392 - stream->write(name, len); |
|
393 -// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style()); |
|
394 - } |
|
395 + uint32_t len = strlen(name); |
|
396 + stream->writePackedUInt(len); |
|
397 + stream->write(name, len); |
|
398 +// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style()); |
|
399 } |
|
400 } |
|
401 |
|
402 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { |
|
403 load_system_fonts(); |
|
404 |
|
405 - // check if the font is a custom or system font |
|
406 - bool isCustomFont = stream->readBool(); |
|
407 + int style = stream->readU8(); |
|
408 |
|
409 - if (isCustomFont) { |
|
410 + int len = stream->readPackedUInt(); |
|
411 + if (len > 0) { |
|
412 + SkString str; |
|
413 + str.resize(len); |
|
414 + stream->read(str.writable_str(), len); |
|
415 |
|
416 - // read the length of the custom font from the stream |
|
417 - uint32_t len = stream->readU32(); |
|
418 - |
|
419 - // generate a new stream to store the custom typeface |
|
420 - SkMemoryStream* fontStream = new SkMemoryStream(len); |
|
421 - stream->read((void*)fontStream->getMemoryBase(), len); |
|
422 - |
|
423 - SkTypeface* face = CreateTypefaceFromStream(fontStream); |
|
424 - |
|
425 - fontStream->unref(); |
|
426 - |
|
427 -// SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len); |
|
428 - return face; |
|
429 - |
|
430 - } else { |
|
431 - int style = stream->readU8(); |
|
432 - |
|
433 - int len = stream->readPackedUInt(); |
|
434 - if (len > 0) { |
|
435 - SkString str; |
|
436 - str.resize(len); |
|
437 - stream->read(str.writable_str(), len); |
|
438 - |
|
439 - const FontInitRec* rec = gSystemFonts; |
|
440 - for (size_t i = 0; i < gNumSystemFonts; i++) { |
|
441 - if (strcmp(rec[i].fFileName, str.c_str()) == 0) { |
|
442 - // backup until we hit the fNames |
|
443 - for (int j = i; j >= 0; --j) { |
|
444 - if (rec[j].fNames != NULL) { |
|
445 - return SkFontHost::CreateTypeface(NULL, |
|
446 - rec[j].fNames[0], NULL, 0, |
|
447 - (SkTypeface::Style)style); |
|
448 - } |
|
449 + const FontInitRec* rec = gSystemFonts; |
|
450 + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { |
|
451 + if (strcmp(rec[i].fFileName, str.c_str()) == 0) { |
|
452 + // backup until we hit the fNames |
|
453 + for (int j = i; j >= 0; --j) { |
|
454 + if (rec[j].fNames != NULL) { |
|
455 + return SkFontHost::CreateTypeface(NULL, |
|
456 + rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style); |
|
457 } |
|
458 } |
|
459 } |
|
460 } |
|
461 } |
|
462 return NULL; |
|
463 } |
|
464 |
|
465 /////////////////////////////////////////////////////////////////////////////// |
|
466 |
|
467 @@ -697,49 +620,32 @@ size_t SkFontHost::GetFileName(SkFontID |
|
468 } |
|
469 return size; |
|
470 } else { |
|
471 return 0; |
|
472 } |
|
473 } |
|
474 |
|
475 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { |
|
476 load_system_fonts(); |
|
477 |
|
478 - const SkTypeface* origTypeface = find_from_uniqueID(origFontID); |
|
479 - const SkTypeface* currTypeface = find_from_uniqueID(currFontID); |
|
480 - |
|
481 - SkASSERT(origTypeface != 0); |
|
482 - SkASSERT(currTypeface != 0); |
|
483 - |
|
484 - // Our fallback list always stores the id of the plain in each fallback |
|
485 - // family, so we transform currFontID to its plain equivalent. |
|
486 - currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID(); |
|
487 - |
|
488 /* First see if fontID is already one of our fallbacks. If so, return |
|
489 its successor. If fontID is not in our list, then return the first one |
|
490 in our list. Note: list is zero-terminated, and returning zero means |
|
491 we have no more fonts to use for fallbacks. |
|
492 */ |
|
493 const uint32_t* list = gFallbackFonts; |
|
494 for (int i = 0; list[i] != 0; i++) { |
|
495 if (list[i] == currFontID) { |
|
496 - if (list[i+1] == 0) |
|
497 - return 0; |
|
498 - const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]); |
|
499 - return find_typeface(nextTypeface, origTypeface->style())->uniqueID(); |
|
500 + return list[i+1]; |
|
501 } |
|
502 } |
|
503 - |
|
504 - // If we get here, currFontID was not a fallback, so we start at the |
|
505 - // beginning of our list. |
|
506 - const SkTypeface* firstTypeface = find_from_uniqueID(list[0]); |
|
507 - return find_typeface(firstTypeface, origTypeface->style())->uniqueID(); |
|
508 + return list[0]; |
|
509 } |
|
510 |
|
511 /////////////////////////////////////////////////////////////////////////////// |
|
512 |
|
513 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { |
|
514 if (NULL == stream || stream->getLength() <= 0) { |
|
515 return NULL; |
|
516 } |
|
517 |
|
518 bool isFixedWidth; |
|
519 @@ -754,10 +660,11 @@ SkTypeface* SkFontHost::CreateTypefaceFr |
|
520 } |
|
521 |
|
522 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { |
|
523 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path)); |
|
524 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream); |
|
525 // since we created the stream, we let go of our ref() here |
|
526 stream->unref(); |
|
527 return face; |
|
528 } |
|
529 |
|
530 +/////////////////////////////////////////////////////////////////////////////// |