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 "SkOSFile.h" 22#include "SkPaint.h" 23#include "SkString.h" 24#include "SkStream.h" 25#include "SkThread.h" 26#include "SkTSearch.h" 27#include <stdio.h> 28 29#define FONT_CACHE_MEMORY_BUDGET (1 * 1024 * 1024) 30 31#ifndef SK_FONT_FILE_PREFIX 32 #define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/" 33#endif 34 35SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name, 36 bool* isFixedWidth); 37 38static void GetFullPathForSysFonts(SkString* full, const char name[]) 39{ 40 full->append(SK_FONT_FILE_PREFIX); 41 full->append(name); 42} 43 44/////////////////////////////////////////////////////////////////////////////// 45 46struct FamilyRec; 47 48/* This guy holds a mapping of a name -> family, used for looking up fonts. 49 Since it is stored in a stretchy array that doesn't preserve object 50 semantics, we don't use constructor/destructors, but just have explicit 51 helpers to manage our internal bookkeeping. 52 */ 53struct NameFamilyPair { 54 const char* fName; // we own this 55 FamilyRec* fFamily; // we don't own this, we just reference it 56 57 void construct(const char name[], FamilyRec* family) 58 { 59 fName = strdup(name); 60 fFamily = family; // we don't own this, so just record the referene 61 } 62 void destruct() 63 { 64 free((char*)fName); 65 // we don't own family, so just ignore our reference 66 } 67}; 68 69// we use atomic_inc to grow this for each typeface we create 70static int32_t gUniqueFontID; 71 72// this is the mutex that protects these globals 73static SkMutex gFamilyMutex; 74static FamilyRec* gFamilyHead; 75static SkTDArray<NameFamilyPair> gNameList; 76 77struct FamilyRec { 78 FamilyRec* fNext; 79 SkTypeface* fFaces[4]; 80 81 FamilyRec() 82 { 83 fNext = gFamilyHead; 84 memset(fFaces, 0, sizeof(fFaces)); 85 gFamilyHead = this; 86 } 87}; 88 89static SkTypeface* find_best_face(const FamilyRec* family, 90 SkTypeface::Style style) { 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 116static FamilyRec* find_family(const SkTypeface* member) { 117 FamilyRec* curr = gFamilyHead; 118 while (curr != NULL) { 119 for (int i = 0; i < 4; i++) { 120 if (curr->fFaces[i] == member) { 121 return curr; 122 } 123 } 124 curr = curr->fNext; 125 } 126 return NULL; 127} 128 129static 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 false; 141} 142 143static bool valid_uniqueID(uint32_t uniqueID) { 144 return find_from_uniqueID(uniqueID) != NULL; 145} 146 147/* Remove reference to this face from its family. If the resulting family 148 is empty (has no faces), return that family, otherwise return NULL 149 */ 150static FamilyRec* remove_from_family(const SkTypeface* face) { 151 FamilyRec* family = find_family(face); 152 SkASSERT(family->fFaces[face->style()] == face); 153 family->fFaces[face->style()] = NULL; 154 155 for (int i = 0; i < 4; i++) { 156 if (family->fFaces[i] != NULL) { // family is non-empty 157 return NULL; 158 } 159 } 160 return family; // return the empty family 161} 162 163// maybe we should make FamilyRec be doubly-linked 164static void detach_and_delete_family(FamilyRec* family) { 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 185static FamilyRec* find_familyrec(const char name[]) { 186 const NameFamilyPair* list = gNameList.begin(); 187 int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name, 188 sizeof(list[0])); 189 return index >= 0 ? list[index].fFamily : NULL; 190} 191 192static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { 193 FamilyRec* rec = find_familyrec(name); 194 return rec ? find_best_face(rec, style) : NULL; 195} 196 197static SkTypeface* find_typeface(const SkTypeface* familyMember, 198 SkTypeface::Style style) { 199 const FamilyRec* family = find_family(familyMember); 200 return family ? find_best_face(family, style) : NULL; 201} 202 203static void add_name(const char name[], FamilyRec* family) { 204 SkAutoAsciiToLC tolc(name); 205 name = tolc.lc(); 206 207 NameFamilyPair* list = gNameList.begin(); 208 int count = gNameList.count(); 209 210 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); 211 212 if (index < 0) { 213 list = gNameList.insert(~index); 214 list->construct(name, family); 215 } 216} 217 218static void remove_from_names(FamilyRec* emptyFamily) { 219#ifdef SK_DEBUG 220 for (int i = 0; i < 4; i++) { 221 SkASSERT(emptyFamily->fFaces[i] == NULL); 222 } 223#endif 224 225 SkTDArray<NameFamilyPair>& list = gNameList; 226 227 // must go backwards when removing 228 for (int i = list.count() - 1; i >= 0; --i) { 229 NameFamilyPair* pair = &list[i]; 230 if (pair->fFamily == emptyFamily) { 231 pair->destruct(); 232 list.remove(i); 233 } 234 } 235} 236 237/////////////////////////////////////////////////////////////////////////////// 238 239class FamilyTypeface : public SkTypeface { 240public: 241 FamilyTypeface(Style style, bool sysFont, FamilyRec* family, bool isFixedWidth) 242 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) { 243 fIsSysFont = sysFont; 244 245 SkAutoMutexAcquire ac(gFamilyMutex); 246 247 if (NULL == family) { 248 family = SkNEW(FamilyRec); 249 } 250 family->fFaces[style] = this; 251 fFamilyRec = family; // just record it so we can return it if asked 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 FamilyRec* getFamily() const { return fFamilyRec; } 268 // openStream returns a SkStream that has been ref-ed 269 virtual SkStream* openStream() = 0; 270 virtual const char* getUniqueString() const = 0; 271 272private: 273 FamilyRec* fFamilyRec; // we don't own this, just point to it 274 bool fIsSysFont; 275 276 typedef SkTypeface INHERITED; 277}; 278 279/////////////////////////////////////////////////////////////////////////////// 280 281/* This subclass is just a place holder for when we have no fonts available. 282 It exists so that our globals (e.g. gFamilyHead) that expect *something* 283 will not be null. 284 */ 285class EmptyTypeface : public FamilyTypeface { 286public: 287 EmptyTypeface() : INHERITED(SkTypeface::kNormal, true, NULL, false) {} 288 289 // overrides 290 virtual SkStream* openStream() { return NULL; } 291 virtual const char* getUniqueString() const { return NULL; } 292 293private: 294 typedef FamilyTypeface INHERITED; 295}; 296 297class StreamTypeface : public FamilyTypeface { 298public: 299 StreamTypeface(Style style, bool sysFont, FamilyRec* family, 300 SkStream* stream, bool isFixedWidth) 301 : INHERITED(style, sysFont, family, isFixedWidth) { 302 stream->ref(); 303 fStream = stream; 304 } 305 virtual ~StreamTypeface() { 306 fStream->unref(); 307 } 308 309 // overrides 310 virtual SkStream* openStream() 311 { 312 // openStream returns a refed stream. 313 fStream->ref(); 314 return fStream; 315 } 316 virtual const char* getUniqueString() const { return NULL; } 317 318private: 319 SkStream* fStream; 320 321 typedef FamilyTypeface INHERITED; 322}; 323 324class FileTypeface : public FamilyTypeface { 325public: 326 FileTypeface(Style style, bool sysFont, FamilyRec* family, 327 const char path[], bool isFixedWidth) 328 : INHERITED(style, sysFont, family, isFixedWidth) { 329 fPath.set(path); 330 } 331 332 // overrides 333 virtual SkStream* openStream() 334 { 335 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str())); 336 337 // check for failure 338 if (stream->getLength() <= 0) { 339 SkDELETE(stream); 340 // maybe MMAP isn't supported. try FILE 341 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str())); 342 if (stream->getLength() <= 0) { 343 SkDELETE(stream); 344 stream = NULL; 345 } 346 } 347 return stream; 348 } 349 350 virtual const char* getUniqueString() const { 351 const char* str = strrchr(fPath.c_str(), '/'); 352 if (str) { 353 str += 1; // skip the '/' 354 } 355 return str; 356 } 357 358private: 359 SkString fPath; 360 361 typedef FamilyTypeface INHERITED; 362}; 363 364/////////////////////////////////////////////////////////////////////////////// 365/////////////////////////////////////////////////////////////////////////////// 366 367static bool get_name_and_style(const char path[], SkString* name, 368 SkTypeface::Style* style, bool* isFixedWidth) { 369 SkMMAPStream stream(path); 370 if (stream.getLength() > 0) { 371 *style = find_name_and_attributes(&stream, name, isFixedWidth); 372 return true; 373 } 374 else { 375 SkFILEStream stream(path); 376 if (stream.getLength() > 0) { 377 *style = find_name_and_attributes(&stream, name, isFixedWidth); 378 return true; 379 } 380 } 381 382 SkDebugf("---- failed to open <%s> as a font\n", path); 383 return false; 384} 385 386// these globals are assigned (once) by load_system_fonts() 387static SkTypeface* gFallBackTypeface; 388static FamilyRec* gDefaultFamily; 389static SkTypeface* gDefaultNormal; 390 391static void load_system_fonts() { 392 // check if we've already be called 393 if (NULL != gDefaultNormal) { 394// printf("---- default font %p\n", gDefaultNormal); 395 return; 396 } 397 398 SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf"); 399 SkString name; 400 int count = 0; 401 402 while (iter.next(&name, false)) { 403 SkString filename; 404 GetFullPathForSysFonts(&filename, name.c_str()); 405 406 bool isFixedWidth; 407 SkString realname; 408 SkTypeface::Style style = SkTypeface::kNormal; // avoid uninitialized warning 409 410 if (!get_name_and_style(filename.c_str(), &realname, &style, &isFixedWidth)) { 411 SkDebugf("------ can't load <%s> as a font\n", filename.c_str()); 412 continue; 413 } 414 415// SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_str()); 416 417 FamilyRec* family = find_familyrec(realname.c_str()); 418 if (family && family->fFaces[style]) { 419// SkDebugf("---- skipping duplicate typeface %s style %d\n", 420// realname.c_str(), style); 421 continue; 422 } 423 424 // this constructor puts us into the global gFamilyHead llist 425 FamilyTypeface* tf = SkNEW_ARGS(FileTypeface, 426 (style, 427 true, // system-font (cannot delete) 428 family, // what family to join 429 filename.c_str(), 430 isFixedWidth) // filename 431 ); 432 433 if (NULL == family) { 434 add_name(realname.c_str(), tf->getFamily()); 435 } 436 count += 1; 437 } 438 439 if (0 == count) { 440 SkNEW(EmptyTypeface); 441 } 442 443 // do this after all fonts are loaded. This is our default font, and it 444 // acts as a sentinel so we only execute load_system_fonts() once 445 static const char* gDefaultNames[] = { 446 "Arial", "Verdana", "Times New Roman", NULL 447 }; 448 const char** names = gDefaultNames; 449 while (*names) { 450 SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal); 451 if (tf) { 452 gDefaultNormal = tf; 453 break; 454 } 455 } 456 // check if we found *something* 457 if (NULL == gDefaultNormal) { 458 if (NULL == gFamilyHead) { 459 sk_throw(); 460 } 461 for (int i = 0; i < 4; i++) { 462 if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) { 463 break; 464 } 465 } 466 } 467 if (NULL == gDefaultNormal) { 468 sk_throw(); 469 } 470 gFallBackTypeface = gDefaultNormal; 471 gDefaultFamily = find_family(gDefaultNormal); 472 473// SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHead, gDefaultFamily); 474} 475 476/////////////////////////////////////////////////////////////////////////////// 477 478void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { 479#if 0 480 const char* name = ((FamilyTypeface*)face)->getUniqueString(); 481 482 stream->write8((uint8_t)face->getStyle()); 483 484 if (NULL == name || 0 == *name) { 485 stream->writePackedUInt(0); 486 // SkDebugf("--- fonthost serialize null\n"); 487 } else { 488 uint32_t len = strlen(name); 489 stream->writePackedUInt(len); 490 stream->write(name, len); 491 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle()); 492 } 493#endif 494 sk_throw(); 495} 496 497SkTypeface* SkFontHost::Deserialize(SkStream* stream) { 498#if 0 499 load_system_fonts(); 500 501 int style = stream->readU8(); 502 503 int len = stream->readPackedUInt(); 504 if (len > 0) { 505 SkString str; 506 str.resize(len); 507 stream->read(str.writable_str(), len); 508 509 const FontInitRec* rec = gSystemFonts; 510 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { 511 if (strcmp(rec[i].fFileName, str.c_str()) == 0) { 512 // backup until we hit the fNames 513 for (int j = i; j >= 0; --j) { 514 if (rec[j].fNames != NULL) { 515 return SkFontHost::CreateTypeface(NULL, rec[j].fNames[0], NULL, 0, 516 (SkTypeface::Style)style); 517 } 518 } 519 } 520 } 521 } 522 return SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, (SkTypeface::Style)style); 523#endif 524 sk_throw(); 525 return NULL; 526} 527 528/////////////////////////////////////////////////////////////////////////////// 529 530SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 531 const char familyName[], 532 const void* data, size_t bytelength, 533 SkTypeface::Style style) { 534 load_system_fonts(); 535 536 SkAutoMutexAcquire ac(gFamilyMutex); 537 538 // clip to legal style bits 539 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); 540 541 SkTypeface* tf = NULL; 542 543 if (NULL != familyFace) { 544 tf = find_typeface(familyFace, style); 545 } else if (NULL != familyName) { 546 // SkDebugf("======= familyName <%s>\n", familyName); 547 tf = find_typeface(familyName, style); 548 } 549 550 if (NULL == tf) { 551 tf = find_best_face(gDefaultFamily, style); 552 } 553 554 SkSafeRef(tf); 555 return tf; 556} 557 558bool SkFontHost::ValidFontID(uint32_t fontID) { 559 SkAutoMutexAcquire ac(gFamilyMutex); 560 561 return valid_uniqueID(fontID); 562} 563 564SkStream* SkFontHost::OpenStream(uint32_t fontID) { 565 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID); 566 SkStream* stream = tf ? tf->openStream() : NULL; 567 568 if (stream && stream->getLength() == 0) { 569 stream->unref(); 570 stream = NULL; 571 } 572 return stream; 573} 574 575size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, 576 int32_t* index) { 577 SkDebugf("SkFontHost::GetFileName unimplemented\n"); 578 return 0; 579} 580 581SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { 582 return 0; 583} 584 585/////////////////////////////////////////////////////////////////////////////// 586 587SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 588 if (NULL == stream || stream->getLength() <= 0) { 589 SkDELETE(stream); 590 return NULL; 591 } 592 593 bool isFixedWidth; 594 SkString name; 595 SkTypeface::Style style = find_name_and_attributes(stream, &name, &isFixedWidth); 596 597 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth)); 598} 599 600SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 601 SkTypeface* face = NULL; 602 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path)); 603 604 if (stream->isValid()) { 605 face = CreateTypefaceFromStream(stream); 606 } 607 stream->unref(); 608 return face; 609} 610 611/////////////////////////////////////////////////////////////////////////////// 612 613size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { 614 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) 615 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; 616 else 617 return 0; // nothing to do 618} 619 620