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