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