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