Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: skia/ports/SkFontHost_android.cpp

Issue 113827: Remove the remainder of the skia source code from the Chromium repo.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/ports/SkFontHost_FreeType.cpp ('k') | skia/ports/SkFontHost_ascender.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* libs/graphics/ports/SkFontHost_android.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkFontHost.h"
19 #include "SkDescriptor.h"
20 #include "SkMMapStream.h"
21 #include "SkPaint.h"
22 #include "SkString.h"
23 #include "SkStream.h"
24 #include "SkThread.h"
25 #include "SkTSearch.h"
26 #include <stdio.h>
27
28 #define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
29
30 #ifndef SK_FONT_FILE_PREFIX
31 #define SK_FONT_FILE_PREFIX "/fonts/"
32 #endif
33
34 SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
35
36 static void GetFullPathForSysFonts(SkString* full, const char name[])
37 {
38 full->set(getenv("ANDROID_ROOT"));
39 full->append(SK_FONT_FILE_PREFIX);
40 full->append(name);
41 }
42
43 ///////////////////////////////////////////////////////////////////////////////
44
45 struct FamilyRec;
46
47 /* This guy holds a mapping of a name -> family, used for looking up fonts.
48 Since it is stored in a stretchy array that doesn't preserve object
49 semantics, we don't use constructor/destructors, but just have explicit
50 helpers to manage our internal bookkeeping.
51 */
52 struct NameFamilyPair {
53 const char* fName; // we own this
54 FamilyRec* fFamily; // we don't own this, we just reference it
55
56 void construct(const char name[], FamilyRec* family)
57 {
58 fName = strdup(name);
59 fFamily = family; // we don't own this, so just record the referene
60 }
61 void destruct()
62 {
63 free((char*)fName);
64 // we don't own family, so just ignore our reference
65 }
66 };
67
68 // we use atomic_inc to grow this for each typeface we create
69 static int32_t gUniqueFontID;
70
71 // this is the mutex that protects these globals
72 static SkMutex gFamilyMutex;
73 static FamilyRec* gFamilyHead;
74 static SkTDArray<NameFamilyPair> gNameList;
75
76 struct FamilyRec {
77 FamilyRec* fNext;
78 SkTypeface* fFaces[4];
79
80 FamilyRec()
81 {
82 fNext = gFamilyHead;
83 memset(fFaces, 0, sizeof(fFaces));
84 gFamilyHead = this;
85 }
86 };
87
88 static SkTypeface* find_best_face(const FamilyRec* family,
89 SkTypeface::Style style)
90 {
91 SkTypeface* const* faces = family->fFaces;
92
93 if (faces[style] != NULL) { // exact match
94 return faces[style];
95 }
96 // look for a matching bold
97 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
98 if (faces[style] != NULL) {
99 return faces[style];
100 }
101 // look for the plain
102 if (faces[SkTypeface::kNormal] != NULL) {
103 return faces[SkTypeface::kNormal];
104 }
105 // look for anything
106 for (int i = 0; i < 4; i++) {
107 if (faces[i] != NULL) {
108 return faces[i];
109 }
110 }
111 // should never get here, since the faces list should not be empty
112 SkASSERT(!"faces list is empty");
113 return NULL;
114 }
115
116 static FamilyRec* find_family(const SkTypeface* member)
117 {
118 FamilyRec* curr = gFamilyHead;
119 while (curr != NULL) {
120 for (int i = 0; i < 4; i++) {
121 if (curr->fFaces[i] == member) {
122 return curr;
123 }
124 }
125 curr = curr->fNext;
126 }
127 return NULL;
128 }
129
130 static SkTypeface* resolve_uniqueID(uint32_t uniqueID)
131 {
132 FamilyRec* curr = gFamilyHead;
133 while (curr != NULL) {
134 for (int i = 0; i < 4; i++) {
135 SkTypeface* face = curr->fFaces[i];
136 if (face != NULL && face->uniqueID() == uniqueID) {
137 return face;
138 }
139 }
140 curr = curr->fNext;
141 }
142 return NULL;
143 }
144
145 /* Remove reference to this face from its family. If the resulting family
146 is empty (has no faces), return that family, otherwise return NULL
147 */
148 static FamilyRec* remove_from_family(const SkTypeface* face)
149 {
150 FamilyRec* family = find_family(face);
151 SkASSERT(family->fFaces[face->style()] == face);
152 family->fFaces[face->style()] = NULL;
153
154 for (int i = 0; i < 4; i++) {
155 if (family->fFaces[i] != NULL) { // family is non-empty
156 return NULL;
157 }
158 }
159 return family; // return the empty family
160 }
161
162 // maybe we should make FamilyRec be doubly-linked
163 static void detach_and_delete_family(FamilyRec* family)
164 {
165 FamilyRec* curr = gFamilyHead;
166 FamilyRec* prev = NULL;
167
168 while (curr != NULL) {
169 FamilyRec* next = curr->fNext;
170 if (curr == family) {
171 if (prev == NULL) {
172 gFamilyHead = next;
173 } else {
174 prev->fNext = next;
175 }
176 SkDELETE(family);
177 return;
178 }
179 prev = curr;
180 curr = next;
181 }
182 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
183 }
184
185 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style)
186 {
187 NameFamilyPair* list = gNameList.begin();
188 int count = gNameList.count();
189
190 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
191
192 if (index >= 0) {
193 return find_best_face(list[index].fFamily, style);
194 }
195 return NULL;
196 }
197
198 static SkTypeface* find_typeface(const SkTypeface* familyMember,
199 SkTypeface::Style style)
200 {
201 const FamilyRec* family = find_family(familyMember);
202 return family ? find_best_face(family, style) : NULL;
203 }
204
205 static void add_name(const char name[], FamilyRec* family)
206 {
207 SkAutoAsciiToLC tolc(name);
208 name = tolc.lc();
209
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 list = gNameList.insert(~index);
217 list->construct(name, family);
218 }
219 }
220
221 static void remove_from_names(FamilyRec* emptyFamily)
222 {
223 #ifdef SK_DEBUG
224 for (int i = 0; i < 4; i++) {
225 SkASSERT(emptyFamily->fFaces[i] == NULL);
226 }
227 #endif
228
229 SkTDArray<NameFamilyPair>& list = gNameList;
230
231 // must go backwards when removing
232 for (int i = list.count() - 1; i >= 0; --i) {
233 NameFamilyPair* pair = &list[i];
234 if (pair->fFamily == emptyFamily) {
235 pair->destruct();
236 list.remove(i);
237 }
238 }
239 }
240
241 ///////////////////////////////////////////////////////////////////////////////
242
243 class FamilyTypeface : public SkTypeface {
244 public:
245 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember)
246 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1)
247 {
248 fIsSysFont = sysFont;
249
250 SkAutoMutexAcquire ac(gFamilyMutex);
251
252 FamilyRec* rec = NULL;
253 if (familyMember) {
254 rec = find_family(familyMember);
255 SkASSERT(rec);
256 } else {
257 rec = SkNEW(FamilyRec);
258 }
259 rec->fFaces[style] = this;
260 }
261
262 virtual ~FamilyTypeface()
263 {
264 SkAutoMutexAcquire ac(gFamilyMutex);
265
266 // remove us from our family. If the family is now empty, we return
267 // that and then remove that family from the name list
268 FamilyRec* family = remove_from_family(this);
269 if (NULL != family) {
270 remove_from_names(family);
271 detach_and_delete_family(family);
272 }
273 }
274
275 bool isSysFont() const { return fIsSysFont; }
276
277 virtual SkStream* openStream() = 0;
278 virtual void closeStream(SkStream*) = 0;
279 virtual const char* getUniqueString() const = 0;
280
281 private:
282 bool fIsSysFont;
283
284 typedef SkTypeface INHERITED;
285 };
286
287 ///////////////////////////////////////////////////////////////////////////////
288
289 class StreamTypeface : public FamilyTypeface {
290 public:
291 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
292 SkStream* stream)
293 : INHERITED(style, sysFont, familyMember)
294 {
295 fStream = stream;
296 }
297 virtual ~StreamTypeface()
298 {
299 SkDELETE(fStream);
300 }
301
302 // overrides
303 virtual SkStream* openStream() { return fStream; }
304 virtual void closeStream(SkStream*) {}
305 virtual const char* getUniqueString() const { return NULL; }
306
307 private:
308 SkStream* fStream;
309
310 typedef FamilyTypeface INHERITED;
311 };
312
313 class FileTypeface : public FamilyTypeface {
314 public:
315 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
316 const char path[])
317 : INHERITED(style, sysFont, familyMember)
318 {
319 SkString fullpath;
320
321 if (sysFont) {
322 GetFullPathForSysFonts(&fullpath, path);
323 path = fullpath.c_str();
324 }
325 fPath.set(path);
326 }
327
328 // overrides
329 virtual SkStream* openStream()
330 {
331 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
332
333 // check for failure
334 if (stream->getLength() <= 0) {
335 SkDELETE(stream);
336 // maybe MMAP isn't supported. try FILE
337 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
338 if (stream->getLength() <= 0) {
339 SkDELETE(stream);
340 stream = NULL;
341 }
342 }
343 return stream;
344 }
345 virtual void closeStream(SkStream* stream)
346 {
347 SkDELETE(stream);
348 }
349 virtual const char* getUniqueString() const {
350 const char* str = strrchr(fPath.c_str(), '/');
351 if (str) {
352 str += 1; // skip the '/'
353 }
354 return str;
355 }
356
357 private:
358 SkString fPath;
359
360 typedef FamilyTypeface INHERITED;
361 };
362
363 ///////////////////////////////////////////////////////////////////////////////
364 ///////////////////////////////////////////////////////////////////////////////
365
366 static bool get_name_and_style(const char path[], SkString* name,
367 SkTypeface::Style* style)
368 {
369 SkString fullpath;
370 GetFullPathForSysFonts(&fullpath, path);
371
372 SkMMAPStream stream(fullpath.c_str());
373 if (stream.getLength() > 0) {
374 *style = find_name_and_style(&stream, name);
375 return true;
376 }
377 else {
378 SkFILEStream stream(fullpath.c_str());
379 if (stream.getLength() > 0) {
380 *style = find_name_and_style(&stream, name);
381 return true;
382 }
383 }
384
385 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
386 return false;
387 }
388
389 struct FontInitRec {
390 const char* fFileName;
391 const char* const* fNames; // null-terminated list
392 };
393
394 static const char* gSansNames[] = {
395 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
396 };
397
398 static const char* gSerifNames[] = {
399 "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
400 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
401 };
402
403 static const char* gMonoNames[] = {
404 "monospace", "courier", "courier new", "monaco", NULL
405 };
406
407 static const char* gFBNames[] = { NULL };
408
409 /* Fonts must be grouped by family, with the first font in a family having the
410 list of names (even if that list is empty), and the following members having
411 null for the list. The names list must be NULL-terminated
412 */
413 static const FontInitRec gSystemFonts[] = {
414 { "DroidSans.ttf", gSansNames },
415 { "DroidSans-Bold.ttf", NULL },
416 { "DroidSerif-Regular.ttf", gSerifNames },
417 { "DroidSerif-Bold.ttf", NULL },
418 { "DroidSerif-Italic.ttf", NULL },
419 { "DroidSerif-BoldItalic.ttf", NULL },
420 { "DroidSansMono.ttf", gMonoNames },
421 { "DroidSansFallback.ttf", gFBNames }
422 };
423
424 #define DEFAULT_NAMES gSansNames
425
426 // these globals are assigned (once) by load_system_fonts()
427 static SkTypeface* gFallBackTypeface;
428 static FamilyRec* gDefaultFamily;
429 static SkTypeface* gDefaultNormal;
430
431 static void load_system_fonts()
432 {
433 // check if we've already be called
434 if (NULL != gDefaultNormal) {
435 return;
436 }
437
438 const FontInitRec* rec = gSystemFonts;
439 SkTypeface* firstInFamily = NULL;
440
441 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
442 // if we're the first in a new family, clear firstInFamily
443 if (rec[i].fNames != NULL) {
444 firstInFamily = NULL;
445 }
446
447 SkString name;
448 SkTypeface::Style style;
449
450 if (!get_name_and_style(rec[i].fFileName, &name, &style)) {
451 SkDebugf("------ can't load <%s> as a font\n", rec[i].fFileName);
452 continue;
453 }
454
455 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
456 (style,
457 true, // system-font (cannot delete)
458 firstInFamily, // what family to join
459 rec[i].fFileName) // filename
460 );
461
462 if (rec[i].fNames != NULL) {
463 firstInFamily = tf;
464 const char* const* names = rec[i].fNames;
465
466 // record the fallback if this is it
467 if (names == gFBNames) {
468 gFallBackTypeface = tf;
469 }
470 // record the default family if this is it
471 if (names == DEFAULT_NAMES) {
472 gDefaultFamily = find_family(tf);
473 }
474 // add the names to map to this family
475 FamilyRec* family = find_family(tf);
476 while (*names) {
477 add_name(*names, family);
478 names += 1;
479 }
480 }
481
482 }
483
484 // do this after all fonts are loaded. This is our default font, and it
485 // acts as a sentinel so we only execute load_system_fonts() once
486 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
487 }
488
489 ///////////////////////////////////////////////////////////////////////////////
490
491 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
492 const char* name = ((FamilyTypeface*)face)->getUniqueString();
493
494 stream->write8((uint8_t)face->getStyle());
495
496 if (NULL == name || 0 == *name) {
497 stream->writePackedUInt(0);
498 // SkDebugf("--- fonthost serialize null\n");
499 } else {
500 uint32_t len = strlen(name);
501 stream->writePackedUInt(len);
502 stream->write(name, len);
503 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle());
504 }
505 }
506
507 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
508 load_system_fonts();
509
510 int style = stream->readU8();
511
512 int len = stream->readPackedUInt();
513 if (len > 0) {
514 SkString str;
515 str.resize(len);
516 stream->read(str.writable_str(), len);
517
518 const FontInitRec* rec = gSystemFonts;
519 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
520 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
521 // backup until we hit the fNames
522 for (int j = i; j >= 0; --j) {
523 if (rec[j].fNames != NULL) {
524 return SkFontHost::FindTypeface(NULL, rec[j].fNames[0],
525 (SkTypeface::Style)style);
526 }
527 }
528 }
529 }
530 }
531 return SkFontHost::FindTypeface(NULL, NULL, (SkTypeface::Style)style);
532 }
533
534 ///////////////////////////////////////////////////////////////////////////////
535
536 SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace,
537 const char familyName[],
538 SkTypeface::Style style)
539 {
540 load_system_fonts();
541
542 SkAutoMutexAcquire ac(gFamilyMutex);
543
544 // clip to legal style bits
545 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
546
547 SkTypeface* tf = NULL;
548
549 if (NULL != familyFace) {
550 tf = find_typeface(familyFace, style);
551 } else if (NULL != familyName) {
552 // SkDebugf("======= familyName <%s>\n", familyName);
553 tf = find_typeface(familyName, style);
554 }
555
556 if (NULL == tf) {
557 tf = find_best_face(gDefaultFamily, style);
558 }
559
560 return tf;
561 }
562
563 SkTypeface* SkFontHost::ResolveTypeface(uint32_t fontID)
564 {
565 SkAutoMutexAcquire ac(gFamilyMutex);
566
567 return resolve_uniqueID(fontID);
568 }
569
570 SkStream* SkFontHost::OpenStream(uint32_t fontID)
571 {
572
573 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID);
574 SkStream* stream = tf ? tf->openStream() : NULL;
575
576 if (NULL == stream || stream->getLength() == 0) {
577 delete stream;
578 stream = NULL;
579 }
580 return stream;
581 }
582
583 void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream)
584 {
585 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID);
586 if (NULL != tf) {
587 tf->closeStream(stream);
588 }
589 }
590
591 SkScalerContext* SkFontHost::CreateFallbackScalerContext(
592 const SkScalerContext::Rec& rec)
593 {
594 load_system_fonts();
595
596 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
597 SkDescriptor* desc = ad.getDesc();
598
599 desc->init();
600 SkScalerContext::Rec* newRec =
601 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
602 sizeof(rec), &rec);
603 newRec->fFontID = gFallBackTypeface->uniqueID();
604 desc->computeChecksum();
605
606 return SkFontHost::CreateScalerContext(desc);
607 }
608
609 ///////////////////////////////////////////////////////////////////////////////
610
611 SkTypeface* SkFontHost::CreateTypeface(SkStream* stream)
612 {
613 if (NULL == stream || stream->getLength() <= 0) {
614 SkDELETE(stream);
615 return NULL;
616 }
617
618 SkString name;
619 SkTypeface::Style style = find_name_and_style(stream, &name);
620
621 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
622 }
623
624 ///////////////////////////////////////////////////////////////////////////////
625
626 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
627 {
628 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
629 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
630 else
631 return 0; // nothing to do
632 }
633
OLDNEW
« no previous file with comments | « skia/ports/SkFontHost_FreeType.cpp ('k') | skia/ports/SkFontHost_ascender.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698