1 /* 2 * Copyright 2001-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 /*! Manages font families and styles */ 11 12 13 #include "FontFamily.h" 14 #include "FontManager.h" 15 #include "ServerConfig.h" 16 #include "ServerFont.h" 17 18 #include <Autolock.h> 19 #include <Directory.h> 20 #include <Entry.h> 21 #include <File.h> 22 #include <FindDirectory.h> 23 #include <Message.h> 24 #include <NodeMonitor.h> 25 #include <Path.h> 26 #include <String.h> 27 28 #include <new> 29 30 //#define TRACE_FONT_MANAGER 31 #ifdef TRACE_FONT_MANAGER 32 # define FTRACE(x) printf x 33 #else 34 # define FTRACE(x) ; 35 #endif 36 37 38 // TODO: needs some more work for multi-user support 39 40 FT_Library gFreeTypeLibrary; 41 FontManager *gFontManager = NULL; 42 43 struct FontManager::font_directory { 44 node_ref directory; 45 uid_t user; 46 gid_t group; 47 uint32 revision; 48 BObjectList<FontStyle> styles; 49 50 bool AlreadyScanned() const { return revision != 0; } 51 FontStyle* FindStyle(const node_ref& nodeRef) const; 52 }; 53 54 struct FontManager::font_mapping { 55 BString family; 56 BString style; 57 entry_ref ref; 58 }; 59 60 61 FontStyle* 62 FontManager::font_directory::FindStyle(const node_ref& nodeRef) const 63 { 64 for (int32 i = styles.CountItems(); i-- > 0;) { 65 FontStyle* style = styles.ItemAt(i); 66 67 if (nodeRef == style->NodeRef()) 68 return style; 69 } 70 71 return NULL; 72 } 73 74 75 static status_t 76 set_entry(node_ref& nodeRef, const char* name, BEntry& entry) 77 { 78 entry_ref ref; 79 ref.device = nodeRef.device; 80 ref.directory = nodeRef.node; 81 82 status_t status = ref.set_name(name); 83 if (status != B_OK) 84 return status; 85 86 return entry.SetTo(&ref); 87 } 88 89 90 static int 91 compare_font_families(const FontFamily* a, const FontFamily* b) 92 { 93 return strcmp(a->Name(), b->Name()); 94 } 95 96 97 // #pragma mark - 98 99 100 //! Does basic set up so that directories can be scanned 101 FontManager::FontManager() 102 : BLooper("Font Manager"), 103 fDirectories(10, true), 104 fMappings(10, true), 105 fFamilies(20), 106 107 fDefaultPlainFont(NULL), 108 fDefaultBoldFont(NULL), 109 fDefaultFixedFont(NULL), 110 111 fScanned(false), 112 fNextID(0) 113 { 114 fInitStatus = FT_Init_FreeType(&gFreeTypeLibrary) == 0 ? B_OK : B_ERROR; 115 116 if (fInitStatus == B_OK) { 117 _AddSystemPaths(); 118 _LoadRecentFontMappings(); 119 120 fInitStatus = _SetDefaultFonts(); 121 122 if (fInitStatus == B_OK) { 123 // Precache the plain and bold fonts 124 _PrecacheFontFile(fDefaultPlainFont); 125 _PrecacheFontFile(fDefaultBoldFont); 126 } 127 } 128 } 129 130 131 //! Frees items allocated in the constructor and shuts down FreeType 132 FontManager::~FontManager() 133 { 134 delete fDefaultPlainFont; 135 delete fDefaultBoldFont; 136 delete fDefaultFixedFont; 137 138 // free families before we're done with FreeType 139 140 for (int32 i = fFamilies.CountItems(); i-- > 0;) { 141 delete fFamilies.ItemAt(i); 142 } 143 144 FT_Done_FreeType(gFreeTypeLibrary); 145 } 146 147 148 void 149 FontManager::MessageReceived(BMessage* message) 150 { 151 switch (message->what) { 152 case B_NODE_MONITOR: 153 { 154 // TODO: support removing fonts! 155 156 int32 opcode; 157 if (message->FindInt32("opcode", &opcode) != B_OK) 158 return; 159 160 switch (opcode) { 161 case B_ENTRY_CREATED: 162 { 163 const char* name; 164 node_ref nodeRef; 165 if (message->FindInt32("device", &nodeRef.device) != B_OK 166 || message->FindInt64("directory", &nodeRef.node) != B_OK 167 || message->FindString("name", &name) != B_OK) 168 break; 169 170 // TODO: make this better (possible under Haiku) 171 snooze(100000); 172 // let the font be written completely before trying to open it 173 174 BEntry entry; 175 if (set_entry(nodeRef, name, entry) != B_OK) 176 break; 177 178 if (entry.IsDirectory()) { 179 // a new directory to watch for us 180 _AddPath(entry); 181 } else { 182 // a new font 183 font_directory* directory = _FindDirectory(nodeRef); 184 if (directory == NULL) { 185 // unknown directory? how come? 186 break; 187 } 188 189 _AddFont(*directory, entry); 190 } 191 break; 192 } 193 194 case B_ENTRY_MOVED: 195 { 196 // has the entry been moved into a monitored directory or has 197 // it been removed from one? 198 const char* name; 199 node_ref nodeRef; 200 uint64 fromNode; 201 uint64 node; 202 if (message->FindInt32("device", &nodeRef.device) != B_OK 203 || message->FindInt64("to directory", &nodeRef.node) != B_OK 204 || message->FindInt64("from directory", (int64 *)&fromNode) != B_OK 205 || message->FindInt64("node", (int64 *)&node) != B_OK 206 || message->FindString("name", &name) != B_OK) 207 break; 208 209 font_directory* directory = _FindDirectory(nodeRef); 210 211 BEntry entry; 212 if (set_entry(nodeRef, name, entry) != B_OK) 213 break; 214 215 if (directory != NULL) { 216 // something has been added to our watched font directories 217 218 // test, if the source directory is one of ours as well 219 nodeRef.node = fromNode; 220 font_directory* fromDirectory = _FindDirectory(nodeRef); 221 222 if (entry.IsDirectory()) { 223 if (fromDirectory == NULL) { 224 // there is a new directory to watch for us 225 _AddPath(entry); 226 FTRACE("new directory moved in"); 227 } else { 228 // A directory from our watched directories has 229 // been renamed or moved within the watched 230 // directories - we only need to update the 231 // path names of the styles in that directory 232 nodeRef.node = node; 233 directory = _FindDirectory(nodeRef); 234 if (directory != NULL) { 235 for (int32 i = 0; i < directory->styles.CountItems(); i++) { 236 FontStyle* style = directory->styles.ItemAt(i); 237 style->UpdatePath(directory->directory); 238 } 239 } 240 FTRACE("directory renamed"); 241 } 242 } else { 243 if (fromDirectory != NULL) { 244 // find style in source and move it to the target 245 nodeRef.node = node; 246 FontStyle* style = fromDirectory->FindStyle(nodeRef); 247 if (style != NULL) { 248 fromDirectory->styles.RemoveItem(style, false); 249 directory->styles.AddItem(style); 250 style->UpdatePath(directory->directory); 251 } 252 FTRACE(("font moved")); 253 } else { 254 FTRACE(("font added: %s\n", name)); 255 _AddFont(*directory, entry); 256 } 257 } 258 } else { 259 // and entry has been removed from our font directories 260 if (entry.IsDirectory()) { 261 if (entry.GetNodeRef(&nodeRef) == B_OK 262 && (directory = _FindDirectory(nodeRef)) != NULL) 263 _RemoveDirectory(directory); 264 } else { 265 // remove font style from directory 266 _RemoveStyle(nodeRef.device, fromNode, node); 267 } 268 } 269 break; 270 } 271 272 case B_ENTRY_REMOVED: 273 { 274 node_ref nodeRef; 275 uint64 directoryNode; 276 if (message->FindInt32("device", &nodeRef.device) != B_OK 277 || message->FindInt64("directory", (int64 *)&directoryNode) != B_OK 278 || message->FindInt64("node", &nodeRef.node) != B_OK) 279 break; 280 281 font_directory* directory = _FindDirectory(nodeRef); 282 if (directory != NULL) { 283 // the directory has been removed, so we remove it as well 284 _RemoveDirectory(directory); 285 } else { 286 // remove font style from directory 287 _RemoveStyle(nodeRef.device, directoryNode, nodeRef.node); 288 } 289 break; 290 } 291 } 292 break; 293 } 294 } 295 } 296 297 298 void 299 FontManager::SaveRecentFontMappings() 300 { 301 } 302 303 304 void 305 FontManager::_AddDefaultMapping(const char* family, const char* style, 306 const char* path) 307 { 308 font_mapping* mapping = new (std::nothrow) font_mapping; 309 if (mapping == NULL) 310 return; 311 312 mapping->family = family; 313 mapping->style = style; 314 BEntry entry(path); 315 316 if (entry.GetRef(&mapping->ref) != B_OK 317 || !entry.Exists() 318 || !fMappings.AddItem(mapping)) 319 delete mapping; 320 } 321 322 323 bool 324 FontManager::_LoadRecentFontMappings() 325 { 326 // default known mappings 327 // TODO: load them for real, and use these as a fallback 328 329 BPath ttfontsPath; 330 if (find_directory(B_BEOS_FONTS_DIRECTORY, &ttfontsPath) == B_OK) { 331 ttfontsPath.Append("ttfonts"); 332 333 BPath veraFontPath = ttfontsPath; 334 veraFontPath.Append("DejaVuSans.ttf"); 335 _AddDefaultMapping("DejaVu Sans", "Book", veraFontPath.Path()); 336 337 veraFontPath.SetTo(ttfontsPath.Path()); 338 veraFontPath.Append("DejaVuSans-Bold.ttf"); 339 _AddDefaultMapping("DejaVu Sans", "Bold", veraFontPath.Path()); 340 341 veraFontPath.SetTo(ttfontsPath.Path()); 342 veraFontPath.Append("DejaVuSansMono.ttf"); 343 _AddDefaultMapping("DejaVu Sans Mono", "Book", veraFontPath.Path()); 344 345 return true; 346 } 347 348 return false; 349 } 350 351 352 status_t 353 FontManager::_AddMappedFont(const char* familyName, const char* styleName) 354 { 355 FTRACE(("_AddMappedFont(family = \"%s\", style = \"%s\")\n", 356 familyName, styleName)); 357 358 for (int32 i = 0; i < fMappings.CountItems(); i++) { 359 font_mapping* mapping = fMappings.ItemAt(i); 360 361 if (mapping->family == familyName) { 362 if (styleName != NULL && mapping->style != styleName) 363 continue; 364 365 BEntry entry(&mapping->ref); 366 if (entry.InitCheck() != B_OK) 367 continue; 368 369 // find parent directory 370 371 node_ref nodeRef; 372 nodeRef.device = mapping->ref.device; 373 nodeRef.node = mapping->ref.directory; 374 font_directory* directory = _FindDirectory(nodeRef); 375 if (directory == NULL) { 376 // unknown directory, maybe this is a user font - try 377 // to create the missing directory 378 BPath path(&entry); 379 if (path.GetParent(&path) != B_OK 380 || _CreateDirectories(path.Path()) != B_OK 381 || (directory = _FindDirectory(nodeRef)) == NULL) 382 continue; 383 } 384 385 return _AddFont(*directory, entry); 386 } 387 } 388 389 return B_ENTRY_NOT_FOUND; 390 } 391 392 393 /*! \brief Removes the style from the font directory. 394 395 It doesn't necessary delete the font style, if it's still 396 in use, though. 397 */ 398 void 399 FontManager::_RemoveStyle(font_directory& directory, FontStyle* style) 400 { 401 FTRACE(("font removed: %s\n", style->Name())); 402 403 directory.styles.RemoveItem(style); 404 directory.revision++; 405 406 fStyleHashTable.RemoveItem(*style); 407 408 style->Release(); 409 } 410 411 412 void 413 FontManager::_RemoveStyle(dev_t device, uint64 directoryNode, uint64 node) 414 { 415 // remove font style from directory 416 node_ref nodeRef; 417 nodeRef.device = device; 418 nodeRef.node = directoryNode; 419 420 font_directory* directory = _FindDirectory(nodeRef); 421 if (directory != NULL) { 422 // find style in directory and remove it 423 nodeRef.node = node; 424 FontStyle* style = directory->FindStyle(nodeRef); 425 if (style != NULL) 426 _RemoveStyle(*directory, style); 427 } 428 } 429 430 431 FontStyle* 432 FontManager::_GetDefaultStyle(const char *familyName, const char *styleName, 433 const char *fallbackFamily, const char *fallbackStyle, 434 uint16 fallbackFace) 435 { 436 // try to find a matching font 437 438 FontStyle* style = GetStyle(familyName, styleName); 439 if (style == NULL) { 440 style = GetStyle(fallbackFamily, fallbackStyle); 441 if (style == NULL) { 442 style = FindStyleMatchingFace(fallbackFace); 443 if (style == NULL && FamilyAt(0) != NULL) 444 style = FamilyAt(0)->StyleAt(0); 445 } 446 } 447 448 return style; 449 } 450 451 452 /*! \brief Sets the fonts that will be used when you create an empty 453 ServerFont without specifying a style, as well as the default 454 Desktop fonts if there are no settings available. 455 */ 456 status_t 457 FontManager::_SetDefaultFonts() 458 { 459 // plain font 460 FontStyle* style = _GetDefaultStyle(DEFAULT_PLAIN_FONT_FAMILY, 461 DEFAULT_PLAIN_FONT_STYLE, FALLBACK_PLAIN_FONT_FAMILY, 462 DEFAULT_PLAIN_FONT_STYLE, 463 B_REGULAR_FACE); 464 if (style == NULL) 465 return B_ERROR; 466 467 fDefaultPlainFont = new (std::nothrow) ServerFont(*style, 468 DEFAULT_PLAIN_FONT_SIZE); 469 if (fDefaultPlainFont == NULL) 470 return B_NO_MEMORY; 471 472 // bold font 473 style = _GetDefaultStyle(DEFAULT_BOLD_FONT_FAMILY, DEFAULT_BOLD_FONT_STYLE, 474 FALLBACK_BOLD_FONT_FAMILY, DEFAULT_BOLD_FONT_STYLE, B_BOLD_FACE); 475 476 fDefaultBoldFont = new (std::nothrow) ServerFont(*style, 477 DEFAULT_BOLD_FONT_SIZE); 478 if (fDefaultBoldFont == NULL) 479 return B_NO_MEMORY; 480 481 // fixed font 482 style = _GetDefaultStyle(DEFAULT_FIXED_FONT_FAMILY, DEFAULT_FIXED_FONT_STYLE, 483 FALLBACK_FIXED_FONT_FAMILY, DEFAULT_FIXED_FONT_STYLE, B_REGULAR_FACE); 484 485 fDefaultFixedFont = new (std::nothrow) ServerFont(*style, 486 DEFAULT_FIXED_FONT_SIZE); 487 if (fDefaultFixedFont == NULL) 488 return B_NO_MEMORY; 489 490 fDefaultFixedFont->SetSpacing(B_FIXED_SPACING); 491 492 return B_OK; 493 } 494 495 496 void 497 FontManager::_PrecacheFontFile(const ServerFont* font) 498 { 499 if (font == NULL) 500 return; 501 502 size_t bufferSize = 32768; 503 uint8* buffer = new (std::nothrow) uint8[bufferSize]; 504 if (buffer == NULL) { 505 // We don't care. Pre-caching doesn't make sense anyways when there 506 // is not enough RAM... 507 return; 508 } 509 510 BFile file(font->Path(), B_READ_ONLY); 511 if (file.InitCheck() != B_OK) { 512 delete[] buffer; 513 return; 514 } 515 516 while (true) { 517 // We just want the file in the kernel file cache... 518 ssize_t read = file.Read(buffer, bufferSize); 519 if (read < (ssize_t)bufferSize) 520 break; 521 } 522 523 delete[] buffer; 524 } 525 526 527 void 528 FontManager::_AddSystemPaths() 529 { 530 BPath path; 531 if (find_directory(B_BEOS_FONTS_DIRECTORY, &path, true) == B_OK) 532 _AddPath(path.Path()); 533 534 // We don't scan these in test mode to help shave off some startup time 535 #if !TEST_MODE 536 if (find_directory(B_COMMON_FONTS_DIRECTORY, &path, true) == B_OK) 537 _AddPath(path.Path()); 538 #endif 539 } 540 541 542 void 543 FontManager::_ScanFontsIfNecessary() 544 { 545 if (!fScanned) 546 _ScanFonts(); 547 } 548 549 550 //! Scans all currently known font directories 551 void 552 FontManager::_ScanFonts() 553 { 554 if (fScanned) 555 return; 556 557 for (int32 i = fDirectories.CountItems(); i-- > 0;) { 558 font_directory* directory = fDirectories.ItemAt(i); 559 560 if (directory->AlreadyScanned()) 561 continue; 562 563 _ScanFontDirectory(*directory); 564 } 565 566 fScanned = true; 567 } 568 569 570 /*! \brief Adds the FontFamily/FontStyle that is represented by this path. 571 */ 572 status_t 573 FontManager::_AddFont(font_directory& directory, BEntry& entry) 574 { 575 node_ref nodeRef; 576 status_t status = entry.GetNodeRef(&nodeRef); 577 if (status < B_OK) 578 return status; 579 580 BPath path; 581 status = entry.GetPath(&path); 582 if (status < B_OK) 583 return status; 584 585 FT_Face face; 586 FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), 0, &face); 587 if (error != 0) 588 return B_ERROR; 589 590 FontFamily *family = _FindFamily(face->family_name); 591 if (family != NULL && family->HasStyle(face->style_name)) { 592 // prevent adding the same style twice 593 // (this indicates a problem with the installed fonts maybe?) 594 FT_Done_Face(face); 595 return B_OK; 596 } 597 598 if (family == NULL) { 599 family = new (std::nothrow) FontFamily(face->family_name, fNextID++); 600 if (family == NULL 601 || !fFamilies.BinaryInsert(family, compare_font_families)) { 602 delete family; 603 FT_Done_Face(face); 604 return B_NO_MEMORY; 605 } 606 } 607 608 FTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name)); 609 610 // the FontStyle takes over ownership of the FT_Face object 611 FontStyle *style = new FontStyle(nodeRef, path.Path(), face); 612 if (!family->AddStyle(style)) { 613 delete style; 614 delete family; 615 return B_NO_MEMORY; 616 } 617 618 directory.styles.AddItem(style); 619 fStyleHashTable.AddItem(style); 620 621 if (directory.AlreadyScanned()) 622 directory.revision++; 623 624 return B_OK; 625 } 626 627 628 FontManager::font_directory* 629 FontManager::_FindDirectory(node_ref& nodeRef) 630 { 631 for (int32 i = fDirectories.CountItems(); i-- > 0;) { 632 font_directory* directory = fDirectories.ItemAt(i); 633 634 if (directory->directory == nodeRef) 635 return directory; 636 } 637 638 return NULL; 639 } 640 641 642 void 643 FontManager::_RemoveDirectory(font_directory* directory) 644 { 645 FTRACE(("FontManager: Remove directory (%Ld)!\n", directory->directory.node)); 646 647 fDirectories.RemoveItem(directory, false); 648 649 // TODO: remove styles from this directory! 650 651 watch_node(&directory->directory, B_STOP_WATCHING, this); 652 delete directory; 653 } 654 655 656 status_t 657 FontManager::_AddPath(const char* path) 658 { 659 BEntry entry; 660 status_t status = entry.SetTo(path); 661 if (status != B_OK) 662 return status; 663 664 return _AddPath(entry); 665 } 666 667 668 status_t 669 FontManager::_AddPath(BEntry& entry, font_directory** _newDirectory) 670 { 671 node_ref nodeRef; 672 status_t status = entry.GetNodeRef(&nodeRef); 673 if (status != B_OK) 674 return status; 675 676 // check if we are already know this directory 677 678 font_directory* directory = _FindDirectory(nodeRef); 679 if (directory != NULL) { 680 if (_newDirectory) 681 *_newDirectory = directory; 682 return B_OK; 683 } 684 685 // it's a new one, so let's add it 686 687 directory = new (std::nothrow) font_directory; 688 if (directory == NULL) 689 return B_NO_MEMORY; 690 691 struct stat stat; 692 status = entry.GetStat(&stat); 693 if (status != B_OK) { 694 delete directory; 695 return status; 696 } 697 698 directory->directory = nodeRef; 699 directory->user = stat.st_uid; 700 directory->group = stat.st_gid; 701 directory->revision = 0; 702 703 status = watch_node(&nodeRef, B_WATCH_DIRECTORY, this); 704 if (status != B_OK) { 705 // we cannot watch this directory - while this is unfortunate, 706 // it's not a critical error 707 printf("could not watch directory %ld:%Ld\n", nodeRef.device, 708 nodeRef.node); 709 // TODO: should go into syslog() 710 } else { 711 BPath path(&entry); 712 FTRACE(("FontManager: now watching: %s\n", path.Path())); 713 } 714 715 fDirectories.AddItem(directory); 716 717 if (_newDirectory) 718 *_newDirectory = directory; 719 720 fScanned = false; 721 return B_OK; 722 } 723 724 725 /*! \brief Creates all unknown font_directories of the specified path - but 726 only if one of its parent directories is already known. 727 728 This method is used to create the font_directories for font_mappings. 729 It recursively walks upwards in the directory hierarchy until it finds 730 a known font_directory (or hits the root directory, in which case it 731 bails out). 732 */ 733 status_t 734 FontManager::_CreateDirectories(const char* path) 735 { 736 FTRACE(("_CreateDirectories(path = %s)\n", path)); 737 738 if (!strcmp(path, "/")) { 739 // we walked our way up to the root 740 return B_ENTRY_NOT_FOUND; 741 } 742 743 BEntry entry; 744 status_t status = entry.SetTo(path); 745 if (status != B_OK) 746 return status; 747 748 node_ref nodeRef; 749 status = entry.GetNodeRef(&nodeRef); 750 if (status != B_OK) 751 return status; 752 753 // check if we are already know this directory 754 755 font_directory* directory = _FindDirectory(nodeRef); 756 if (directory != NULL) 757 return B_OK; 758 759 // We don't know this one yet - keep walking the path upwards 760 // and try to find a match. 761 762 BPath parent(path); 763 status = parent.GetParent(&parent); 764 if (status != B_OK) 765 return status; 766 767 status = _CreateDirectories(parent.Path()); 768 if (status != B_OK) 769 return status; 770 771 // We have our match, create sub directory 772 773 return _AddPath(path); 774 } 775 776 777 /*! \brief Scan a folder for all valid fonts 778 \param directoryPath Path of the folder to scan. 779 */ 780 status_t 781 FontManager::_ScanFontDirectory(font_directory& fontDirectory) 782 { 783 // This bad boy does all the real work. It loads each entry in the 784 // directory. If a valid font file, it adds both the family and the style. 785 786 BDirectory directory; 787 status_t status = directory.SetTo(&fontDirectory.directory); 788 if (status != B_OK) 789 return status; 790 791 BEntry entry; 792 while (directory.GetNextEntry(&entry) == B_OK) { 793 if (entry.IsDirectory()) { 794 // scan this directory recursively 795 font_directory* newDirectory; 796 if (_AddPath(entry, &newDirectory) == B_OK && newDirectory != NULL) 797 _ScanFontDirectory(*newDirectory); 798 799 continue; 800 } 801 802 // TODO: Commenting this out makes my "Unicode glyph lookup" 803 // work with our default fonts. The real fix is to select the 804 // Unicode char map (if supported), and/or adjust the 805 // utf8 -> glyph-index mapping everywhere to handle other 806 // char maps. We could also ignore fonts that don't support 807 // the Unicode lookup as a temporary "solution". 808 #if 0 809 FT_CharMap charmap = _GetSupportedCharmap(face); 810 if (!charmap) { 811 FT_Done_Face(face); 812 continue; 813 } 814 815 face->charmap = charmap; 816 #endif 817 818 _AddFont(fontDirectory, entry); 819 // takes over ownership of the FT_Face object 820 } 821 822 fontDirectory.revision = 1; 823 return B_OK; 824 } 825 826 827 /*! \brief Finds and returns the first valid charmap in a font 828 829 \param face Font handle obtained from FT_Load_Face() 830 \return An FT_CharMap or NULL if unsuccessful 831 */ 832 FT_CharMap 833 FontManager::_GetSupportedCharmap(const FT_Face& face) 834 { 835 for (int32 i = 0; i < face->num_charmaps; i++) { 836 FT_CharMap charmap = face->charmaps[i]; 837 838 switch (charmap->platform_id) { 839 case 3: 840 // if Windows Symbol or Windows Unicode 841 if (charmap->encoding_id == 0 || charmap->encoding_id == 1) 842 return charmap; 843 break; 844 845 case 1: 846 // if Apple Unicode 847 if (charmap->encoding_id == 0) 848 return charmap; 849 break; 850 851 case 0: 852 // if Apple Roman 853 if (charmap->encoding_id == 0) 854 return charmap; 855 break; 856 857 default: 858 break; 859 } 860 } 861 862 return NULL; 863 } 864 865 866 int32 867 FontManager::CheckRevision(uid_t user) 868 { 869 BAutolock locker(this); 870 int32 revision = 0; 871 872 _ScanFontsIfNecessary(); 873 874 for (int32 i = 0; i < fDirectories.CountItems(); i++) { 875 font_directory* directory = fDirectories.ItemAt(i); 876 877 // TODO: for now, add all directories 878 revision += directory->revision; 879 } 880 881 return revision; 882 } 883 884 885 /*! \brief Counts the number of font families available 886 \return The number of unique font families currently available 887 */ 888 int32 889 FontManager::CountFamilies() 890 { 891 _ScanFontsIfNecessary(); 892 893 return fFamilies.CountItems(); 894 } 895 896 897 /*! \brief Counts the number of styles available in a font family 898 \param family Name of the font family to scan 899 \return The number of font styles currently available for the font family 900 */ 901 int32 902 FontManager::CountStyles(const char *familyName) 903 { 904 _ScanFontsIfNecessary(); 905 906 FontFamily *family = GetFamily(familyName); 907 if (family) 908 return family->CountStyles(); 909 910 return 0; 911 } 912 913 914 /*! \brief Counts the number of styles available in a font family 915 \param family Name of the font family to scan 916 \return The number of font styles currently available for the font family 917 */ 918 int32 919 FontManager::CountStyles(uint16 familyID) 920 { 921 _ScanFontsIfNecessary(); 922 923 FontFamily *family = GetFamily(familyID); 924 if (family) 925 return family->CountStyles(); 926 927 return 0; 928 } 929 930 931 FontFamily* 932 FontManager::FamilyAt(int32 index) const 933 { 934 return fFamilies.ItemAt(index); 935 } 936 937 938 FontFamily* 939 FontManager::_FindFamily(const char* name) const 940 { 941 if (name == NULL) 942 return NULL; 943 944 FontFamily family(name, 0); 945 return const_cast<FontFamily*>(fFamilies.BinarySearch(family, 946 compare_font_families)); 947 } 948 949 950 /*! \brief Locates a FontFamily object by name 951 \param name The family to find 952 \return Pointer to the specified family or NULL if not found. 953 */ 954 FontFamily* 955 FontManager::GetFamily(const char* name) 956 { 957 if (name == NULL) 958 return NULL; 959 960 FontFamily* family = _FindFamily(name); 961 if (family != NULL) 962 return family; 963 964 if (fScanned) 965 return NULL; 966 967 // try font mappings before failing 968 if (_AddMappedFont(name) == B_OK) 969 return _FindFamily(name); 970 971 _ScanFonts(); 972 return _FindFamily(name); 973 } 974 975 976 FontFamily* 977 FontManager::GetFamily(uint16 familyID) const 978 { 979 FontKey key(familyID, 0); 980 FontStyle* style = (FontStyle*)fStyleHashTable.GetValue(key); 981 if (style != NULL) 982 return style->Family(); 983 984 return NULL; 985 } 986 987 988 FontStyle* 989 FontManager::GetStyleByIndex(const char* familyName, int32 index) 990 { 991 FontFamily* family = GetFamily(familyName); 992 if (family != NULL) 993 return family->StyleAt(index); 994 995 return NULL; 996 } 997 998 999 FontStyle* 1000 FontManager::GetStyleByIndex(uint16 familyID, int32 index) 1001 { 1002 FontFamily* family = GetFamily(familyID); 1003 if (family != NULL) 1004 return family->StyleAt(index); 1005 1006 return NULL; 1007 } 1008 1009 1010 /*! \brief Retrieves the FontStyle object that comes closest to the one 1011 specified. 1012 1013 \param family The font's family or NULL in which case \a familyID is used 1014 \param style The font's style or NULL in which case \a styleID is used 1015 \param familyID will only be used if \a family is NULL (or empty) 1016 \param styleID will only be used if \a style is NULL (or empty) 1017 \param face is used to specify the style if both \a style is NULL or empty 1018 and styleID is 0xffff. 1019 1020 \return The FontStyle having those attributes or NULL if not available 1021 */ 1022 FontStyle* 1023 FontManager::GetStyle(const char* familyName, const char* styleName, 1024 uint16 familyID, uint16 styleID, uint16 face) 1025 { 1026 FontFamily* family; 1027 1028 // find family 1029 1030 if (familyName != NULL && familyName[0]) 1031 family = GetFamily(familyName); 1032 else 1033 family = GetFamily(familyID); 1034 1035 if (family == NULL) 1036 return NULL; 1037 1038 // find style 1039 1040 if (styleName != NULL && styleName[0]) { 1041 FontStyle* fontStyle = family->GetStyle(styleName); 1042 if (fontStyle != NULL) 1043 return fontStyle; 1044 1045 // before we fail, we try the mappings for a match 1046 if (_AddMappedFont(family->Name(), styleName) == B_OK) { 1047 fontStyle = family->GetStyle(styleName); 1048 if (fontStyle != NULL) 1049 return fontStyle; 1050 } 1051 1052 _ScanFonts(); 1053 return family->GetStyle(styleName); 1054 } 1055 1056 if (styleID != 0xffff) 1057 return family->GetStyleByID(styleID); 1058 1059 // try to get from face 1060 return family->GetStyleMatchingFace(face); 1061 } 1062 1063 1064 /*! \brief Retrieves the FontStyle object 1065 \param family ID for the font's family 1066 \param style ID of the font's style 1067 \return The FontStyle having those attributes or NULL if not available 1068 */ 1069 FontStyle* 1070 FontManager::GetStyle(uint16 familyID, uint16 styleID) const 1071 { 1072 FontKey key(familyID, styleID); 1073 return (FontStyle*)fStyleHashTable.GetValue(key); 1074 } 1075 1076 1077 /*! \brief If you don't find your preferred font style, but are anxious 1078 to have one fitting your needs, you may want to use this method. 1079 */ 1080 FontStyle* 1081 FontManager::FindStyleMatchingFace(uint16 face) const 1082 { 1083 int32 count = fFamilies.CountItems(); 1084 1085 for (int32 i = 0; i < count; i++) { 1086 FontFamily* family = fFamilies.ItemAt(i); 1087 FontStyle* style = family->GetStyleMatchingFace(face); 1088 if (style != NULL) 1089 return style; 1090 } 1091 1092 return NULL; 1093 } 1094 1095 1096 /*! \brief This call is used by the FontStyle class - and the FontStyle class 1097 only - to remove itself from the font manager. 1098 At this point, the style is already no longer available to the user. 1099 */ 1100 void 1101 FontManager::RemoveStyle(FontStyle* style) 1102 { 1103 FontFamily* family = style->Family(); 1104 if (family == NULL) 1105 debugger("family is NULL!"); 1106 1107 FontStyle* check = GetStyle(family->ID(), style->ID()); 1108 if (check != NULL) 1109 debugger("style removed but still available!"); 1110 1111 if (family->RemoveStyle(style) 1112 && family->CountStyles() == 0) 1113 fFamilies.RemoveItem(family); 1114 } 1115 1116 1117 const ServerFont* 1118 FontManager::DefaultPlainFont() const 1119 { 1120 return fDefaultPlainFont; 1121 } 1122 1123 1124 const ServerFont* 1125 FontManager::DefaultBoldFont() const 1126 { 1127 return fDefaultBoldFont; 1128 } 1129 1130 1131 const ServerFont* 1132 FontManager::DefaultFixedFont() const 1133 { 1134 return fDefaultFixedFont; 1135 } 1136 1137 1138 void 1139 FontManager::AttachUser(uid_t userID) 1140 { 1141 BAutolock locker(this); 1142 1143 #if !TEST_MODE 1144 // TODO: actually, find_directory() cannot know which user ID we want here 1145 // TODO: avoids user fonts in safe mode 1146 BPath path; 1147 if (find_directory(B_USER_FONTS_DIRECTORY, &path, true) != B_OK) 1148 return; 1149 1150 _AddPath(path.Path()); 1151 #endif 1152 } 1153 1154 1155 void 1156 FontManager::DetachUser(uid_t userID) 1157 { 1158 BAutolock locker(this); 1159 1160 // TODO! 1161 } 1162 1163