1 /* 2 * Copyright 2001-2015, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Jérôme Duval, jerome.duval@free.fr 8 * Axel Dörfler, axeld@pinc-software.de 9 * Stephan Aßmus <superstippi@gmx.de> 10 * Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk> 11 */ 12 13 14 #include <AppServerLink.h> 15 #include <FontPrivate.h> 16 #include <ObjectList.h> 17 #include <ServerProtocol.h> 18 #include <truncate_string.h> 19 #include <utf8_functions.h> 20 21 #include <Autolock.h> 22 #include <Font.h> 23 #include <Locker.h> 24 #include <Message.h> 25 #include <PortLink.h> 26 #include <Rect.h> 27 #include <Shape.h> 28 #include <String.h> 29 30 #include <new> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <pthread.h> 34 35 36 using namespace std; 37 38 const float kUninitializedAscent = INFINITY; 39 const uint32 kUninitializedExtraFlags = 0xffffffff; 40 41 // The actual objects which the globals point to 42 static BFont sPlainFont; 43 static BFont sBoldFont; 44 static BFont sFixedFont; 45 46 const BFont* be_plain_font = &sPlainFont; 47 const BFont* be_bold_font = &sBoldFont; 48 const BFont* be_fixed_font = &sFixedFont; 49 50 51 struct style { 52 BString name; 53 uint16 face; 54 uint32 flags; 55 }; 56 57 struct family { 58 BString name; 59 uint32 flags; 60 BObjectList<style> styles; 61 }; 62 63 namespace { 64 65 class FontList : public BLocker { 66 public: 67 FontList(); 68 virtual ~FontList(); 69 70 static FontList* Default(); 71 72 bool UpdatedOnServer(); 73 74 status_t FamilyAt(int32 index, font_family* _family, 75 uint32* _flags); 76 status_t StyleAt(font_family family, int32 index, 77 font_style* _style, uint16* _face, 78 uint32* _flags); 79 80 int32 CountFamilies(); 81 int32 CountStyles(font_family family); 82 83 private: 84 status_t _UpdateIfNecessary(); 85 status_t _Update(); 86 int32 _RevisionOnServer(); 87 family* _FindFamily(font_family name); 88 static void _InitSingleton(); 89 90 private: 91 BObjectList<family> fFamilies; 92 family* fLastFamily; 93 bigtime_t fLastUpdate; 94 int32 fRevision; 95 96 static pthread_once_t sDefaultInitOnce; 97 static FontList* sDefaultInstance; 98 }; 99 100 pthread_once_t FontList::sDefaultInitOnce = PTHREAD_ONCE_INIT; 101 FontList* FontList::sDefaultInstance = NULL; 102 103 } // unnamed namespace 104 105 106 // #pragma mark - 107 108 109 static int 110 compare_families(const family* a, const family* b) 111 { 112 // TODO: compare font names according to the user's locale settings 113 return strcmp(a->name.String(), b->name.String()); 114 } 115 116 117 namespace { 118 119 FontList::FontList() 120 : BLocker("font list"), 121 fLastFamily(NULL), 122 fLastUpdate(0), 123 fRevision(0) 124 { 125 } 126 127 128 FontList::~FontList() 129 { 130 } 131 132 133 /*static*/ FontList* 134 FontList::Default() 135 { 136 if (sDefaultInstance == NULL) 137 pthread_once(&sDefaultInitOnce, &_InitSingleton); 138 139 return sDefaultInstance; 140 } 141 142 143 bool 144 FontList::UpdatedOnServer() 145 { 146 return _RevisionOnServer() != fRevision; 147 } 148 149 150 status_t 151 FontList::FamilyAt(int32 index, font_family* _family, uint32* _flags) 152 { 153 BAutolock locker(this); 154 155 status_t status = _UpdateIfNecessary(); 156 if (status < B_OK) 157 return status; 158 159 ::family* family = fFamilies.ItemAt(index); 160 if (family == NULL) 161 return B_BAD_VALUE; 162 163 memcpy(*_family, family->name.String(), family->name.Length() + 1); 164 if (_flags) 165 *_flags = family->flags; 166 return B_OK; 167 } 168 169 170 status_t 171 FontList::StyleAt(font_family familyName, int32 index, font_style* _style, 172 uint16* _face, uint32* _flags) 173 { 174 BAutolock locker(this); 175 176 status_t status = _UpdateIfNecessary(); 177 if (status < B_OK) 178 return status; 179 180 ::family* family = _FindFamily(familyName); 181 if (family == NULL) 182 return B_BAD_VALUE; 183 184 ::style* style = family->styles.ItemAt(index); 185 if (style == NULL) 186 return B_BAD_VALUE; 187 188 memcpy(*_style, style->name.String(), style->name.Length() + 1); 189 if (_face) 190 *_face = style->face; 191 if (_flags) 192 *_flags = style->flags; 193 return B_OK; 194 } 195 196 197 int32 198 FontList::CountFamilies() 199 { 200 BAutolock locker(this); 201 202 _UpdateIfNecessary(); 203 return fFamilies.CountItems(); 204 } 205 206 207 int32 208 FontList::CountStyles(font_family familyName) 209 { 210 BAutolock locker(this); 211 212 _UpdateIfNecessary(); 213 214 ::family* family = _FindFamily(familyName); 215 if (family == NULL) 216 return 0; 217 218 return family->styles.CountItems(); 219 } 220 221 222 status_t 223 FontList::_Update() 224 { 225 // check version 226 227 int32 revision = _RevisionOnServer(); 228 fLastUpdate = system_time(); 229 230 // are we up-to-date already? 231 if (revision == fRevision) 232 return B_OK; 233 234 fFamilies.MakeEmpty(); 235 fLastFamily = NULL; 236 237 BPrivate::AppServerLink link; 238 239 for (int32 index = 0;; index++) { 240 link.StartMessage(AS_GET_FAMILY_AND_STYLES); 241 link.Attach<int32>(index); 242 243 int32 status; 244 if (link.FlushWithReply(status) != B_OK 245 || status != B_OK) 246 break; 247 248 ::family* family = new (nothrow) ::family; 249 if (family == NULL) 250 return B_NO_MEMORY; 251 252 link.ReadString(family->name); 253 link.Read<uint32>(&family->flags); 254 255 int32 styleCount; 256 link.Read<int32>(&styleCount); 257 258 for (int32 i = 0; i < styleCount; i++) { 259 ::style* style = new (nothrow) ::style; 260 if (style == NULL) { 261 delete family; 262 return B_NO_MEMORY; 263 } 264 265 link.ReadString(style->name); 266 link.Read<uint16>(&style->face); 267 link.Read<uint32>(&style->flags); 268 269 family->styles.AddItem(style); 270 } 271 272 fFamilies.BinaryInsert(family, compare_families); 273 } 274 275 fRevision = revision; 276 277 // if the font list has been changed in the mean time, just update again 278 if (UpdatedOnServer()) 279 _Update(); 280 281 return B_OK; 282 } 283 284 285 status_t 286 FontList::_UpdateIfNecessary() 287 { 288 // an updated font list is at least valid for 1 second 289 if (fLastUpdate > system_time() - 1000000) 290 return B_OK; 291 292 return _Update(); 293 } 294 295 296 int32 297 FontList::_RevisionOnServer() 298 { 299 BPrivate::AppServerLink link; 300 link.StartMessage(AS_GET_FONT_LIST_REVISION); 301 302 int32 code; 303 if (link.FlushWithReply(code) != B_OK || code != B_OK) 304 return B_ERROR; 305 306 int32 revision; 307 link.Read<int32>(&revision); 308 309 return revision; 310 } 311 312 313 family* 314 FontList::_FindFamily(font_family name) 315 { 316 if (fLastFamily != NULL && fLastFamily->name == name) 317 return fLastFamily; 318 319 ::family family; 320 family.name = name; 321 fLastFamily = const_cast< ::family*>(fFamilies.BinarySearch(family, 322 compare_families)); 323 return fLastFamily; 324 } 325 326 327 /*static*/ void 328 FontList::_InitSingleton() 329 { 330 sDefaultInstance = new FontList; 331 } 332 333 } // unnamed namespace 334 335 336 // #pragma mark - 337 338 339 void 340 _init_global_fonts_() 341 { 342 BPrivate::AppServerLink link; 343 link.StartMessage(AS_GET_SYSTEM_FONTS); 344 345 int32 code; 346 if (link.FlushWithReply(code) != B_OK 347 || code != B_OK) { 348 printf("DEBUG: Couldn't initialize global fonts!\n"); 349 return; 350 } 351 352 char type[B_OS_NAME_LENGTH]; 353 354 while (link.ReadString(type, sizeof(type)) >= B_OK && type[0]) { 355 BFont dummy; 356 BFont* font = &dummy; 357 358 if (!strcmp(type, "plain")) 359 font = &sPlainFont; 360 else if (!strcmp(type, "bold")) 361 font = &sBoldFont; 362 else if (!strcmp(type, "fixed")) 363 font = &sFixedFont; 364 365 link.Read<uint16>(&font->fFamilyID); 366 link.Read<uint16>(&font->fStyleID); 367 link.Read<float>(&font->fSize); 368 link.Read<uint16>(&font->fFace); 369 link.Read<uint32>(&font->fFlags); 370 371 font->fHeight.ascent = kUninitializedAscent; 372 font->fExtraFlags = kUninitializedExtraFlags; 373 } 374 } 375 376 377 void 378 _font_control_(BFont* font, int32 cmd, void* data) 379 { 380 } 381 382 383 status_t 384 get_font_cache_info(uint32 id, void* set) 385 { 386 return B_ERROR; 387 } 388 389 390 status_t 391 set_font_cache_info(uint32 id, void* set) 392 { 393 return B_ERROR; 394 } 395 396 397 // Private function used to replace the R5 hack which sets a system font 398 void 399 _set_system_font_(const char* which, font_family family, font_style style, 400 float size) 401 { 402 // R5 used a global area offset table to set the system fonts in the Font 403 // preferences panel. Bleah. 404 BPrivate::AppServerLink link; 405 406 link.StartMessage(AS_SET_SYSTEM_FONT); 407 link.AttachString(which, B_OS_NAME_LENGTH); 408 link.AttachString(family, sizeof(font_family)); 409 link.AttachString(style, sizeof(font_style)); 410 link.Attach<float>(size); 411 link.Flush(); 412 } 413 414 415 status_t 416 _get_system_default_font_(const char* which, font_family family, 417 font_style style, float* _size) 418 { 419 BPrivate::AppServerLink link; 420 421 link.StartMessage(AS_GET_SYSTEM_DEFAULT_FONT); 422 link.AttachString(which, B_OS_NAME_LENGTH); 423 424 int32 status = B_ERROR; 425 if (link.FlushWithReply(status) != B_OK 426 || status < B_OK) 427 return status; 428 429 link.ReadString(family, sizeof(font_family)); 430 link.ReadString(style, sizeof(font_style)); 431 link.Read<float>(_size); 432 return B_OK; 433 } 434 435 436 // Returns the number of installed font families 437 int32 438 count_font_families() 439 { 440 return FontList::Default()->CountFamilies(); 441 } 442 443 444 // Returns the number of styles available for a font family 445 int32 446 count_font_styles(font_family family) 447 { 448 return FontList::Default()->CountStyles(family); 449 } 450 451 452 // Retrieves the family name at the specified index 453 status_t 454 get_font_family(int32 index, font_family* _name, uint32* _flags) 455 { 456 if (_name == NULL) 457 return B_BAD_VALUE; 458 459 return FontList::Default()->FamilyAt(index, _name, _flags); 460 } 461 462 463 // Retrieves the family name at the specified index 464 status_t 465 get_font_style(font_family family, int32 index, font_style* _name, 466 uint32* _flags) 467 { 468 return get_font_style(family, index, _name, NULL, _flags); 469 } 470 471 472 // Retrieves the family name at the specified index 473 status_t 474 get_font_style(font_family family, int32 index, font_style* _name, 475 uint16* _face, uint32* _flags) 476 { 477 // The face value returned by this function is not very reliable. At the 478 // same time, the value returned should be fairly reliable, returning the 479 // proper flag for 90%-99% of font names. 480 481 if (_name == NULL) 482 return B_BAD_VALUE; 483 484 return FontList::Default()->StyleAt(family, index, _name, _face, _flags); 485 } 486 487 488 // Updates the font family list 489 bool 490 update_font_families(bool /*checkOnly*/) 491 { 492 return FontList::Default()->UpdatedOnServer(); 493 } 494 495 496 // #pragma mark - 497 498 499 BFont::BFont() 500 : 501 // initialise for be_plain_font (avoid circular definition) 502 fFamilyID(0), 503 fStyleID(0), 504 fSize(10.0), 505 fShear(90.0), 506 fRotation(0.0), 507 fFalseBoldWidth(0.0), 508 fSpacing(B_BITMAP_SPACING), 509 fEncoding(B_UNICODE_UTF8), 510 fFace(0), 511 fFlags(0), 512 fExtraFlags(kUninitializedExtraFlags) 513 { 514 if (be_plain_font != NULL && this != &sPlainFont) 515 *this = *be_plain_font; 516 else { 517 fHeight.ascent = 7.0; 518 fHeight.descent = 2.0; 519 fHeight.leading = 13.0; 520 } 521 } 522 523 524 BFont::BFont(const BFont& font) 525 { 526 *this = font; 527 } 528 529 530 BFont::BFont(const BFont* font) 531 { 532 if (font != NULL) 533 *this = *font; 534 else 535 *this = *be_plain_font; 536 } 537 538 539 // Sets the font's family and style all at once 540 status_t 541 BFont::SetFamilyAndStyle(const font_family family, const font_style style) 542 { 543 if (family == NULL && style == NULL) 544 return B_BAD_VALUE; 545 546 BPrivate::AppServerLink link; 547 548 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 549 link.AttachString(family, sizeof(font_family)); 550 link.AttachString(style, sizeof(font_style)); 551 link.Attach<uint16>(fFamilyID); 552 link.Attach<uint16>(0xffff); 553 link.Attach<uint16>(fFace); 554 555 int32 status = B_ERROR; 556 if (link.FlushWithReply(status) != B_OK || status != B_OK) 557 return status; 558 559 link.Read<uint16>(&fFamilyID); 560 link.Read<uint16>(&fStyleID); 561 link.Read<uint16>(&fFace); 562 563 fHeight.ascent = kUninitializedAscent; 564 fExtraFlags = kUninitializedExtraFlags; 565 566 return B_OK; 567 } 568 569 570 // Sets the font's family and style all at once 571 void 572 BFont::SetFamilyAndStyle(uint32 code) 573 { 574 // R5 has a bug here: the face is not updated even though the IDs are set. 575 // This is a problem because the face flag includes Regular/Bold/Italic 576 // information in addition to stuff like underlining and strikethrough. 577 // As a result, this will need a trip to the server and, thus, be slower 578 // than R5's in order to be correct 579 580 uint16 family, style; 581 style = code & 0xFFFF; 582 family = (code & 0xFFFF0000) >> 16; 583 584 BPrivate::AppServerLink link; 585 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 586 link.AttachString(NULL); // no family and style name 587 link.AttachString(NULL); 588 link.Attach<uint16>(family); 589 link.Attach<uint16>(style); 590 link.Attach<uint16>(fFace); 591 592 int32 fontcode; 593 if (link.FlushWithReply(fontcode) != B_OK || fontcode != B_OK) 594 return; 595 596 link.Read<uint16>(&fFamilyID); 597 link.Read<uint16>(&fStyleID); 598 link.Read<uint16>(&fFace); 599 fHeight.ascent = kUninitializedAscent; 600 fExtraFlags = kUninitializedExtraFlags; 601 } 602 603 604 // Sets the font's family and face all at once 605 status_t 606 BFont::SetFamilyAndFace(const font_family family, uint16 face) 607 { 608 // To comply with the BeBook, this function will only set valid values 609 // i.e. passing a nonexistent family will cause only the face to be set. 610 // Additionally, if a particular face does not exist in a family, the 611 // closest match will be chosen. 612 613 BPrivate::AppServerLink link; 614 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 615 link.AttachString(family, sizeof(font_family)); 616 link.AttachString(NULL); // no style given 617 link.Attach<uint16>(fFamilyID); 618 link.Attach<uint16>(0xffff); 619 link.Attach<uint16>(face); 620 621 int32 status = B_ERROR; 622 if (link.FlushWithReply(status) != B_OK || status != B_OK) 623 return status; 624 625 link.Read<uint16>(&fFamilyID); 626 link.Read<uint16>(&fStyleID); 627 link.Read<uint16>(&fFace); 628 fHeight.ascent = kUninitializedAscent; 629 fExtraFlags = kUninitializedExtraFlags; 630 631 return B_OK; 632 } 633 634 635 void 636 BFont::SetSize(float size) 637 { 638 fSize = size; 639 fHeight.ascent = kUninitializedAscent; 640 } 641 642 643 void 644 BFont::SetShear(float shear) 645 { 646 fShear = shear; 647 fHeight.ascent = kUninitializedAscent; 648 } 649 650 651 void 652 BFont::SetRotation(float rotation) 653 { 654 fRotation = rotation; 655 fHeight.ascent = kUninitializedAscent; 656 } 657 658 659 void 660 BFont::SetFalseBoldWidth(float width) 661 { 662 fFalseBoldWidth = width; 663 } 664 665 666 void 667 BFont::SetSpacing(uint8 spacing) 668 { 669 fSpacing = spacing; 670 } 671 672 673 void 674 BFont::SetEncoding(uint8 encoding) 675 { 676 fEncoding = encoding; 677 } 678 679 680 void 681 BFont::SetFace(uint16 face) 682 { 683 if (face == fFace) 684 return; 685 686 SetFamilyAndFace(NULL, face); 687 } 688 689 690 void 691 BFont::SetFlags(uint32 flags) 692 { 693 fFlags = flags; 694 } 695 696 697 void 698 BFont::GetFamilyAndStyle(font_family* family, font_style* style) const 699 { 700 if (family == NULL && style == NULL) 701 return; 702 703 // it's okay to call this function with either family or style set to NULL 704 705 font_family familyBuffer; 706 font_style styleBuffer; 707 708 if (family == NULL) 709 family = &familyBuffer; 710 if (style == NULL) 711 style = &styleBuffer; 712 713 BPrivate::AppServerLink link; 714 link.StartMessage(AS_GET_FAMILY_AND_STYLE); 715 link.Attach<uint16>(fFamilyID); 716 link.Attach<uint16>(fStyleID); 717 718 int32 code; 719 if (link.FlushWithReply(code) != B_OK || code != B_OK) { 720 // the least we can do is to clear the buffers 721 memset(*family, 0, sizeof(font_family)); 722 memset(*style, 0, sizeof(font_style)); 723 return; 724 } 725 726 link.ReadString(*family, sizeof(font_family)); 727 link.ReadString(*style, sizeof(font_style)); 728 } 729 730 731 uint32 732 BFont::FamilyAndStyle() const 733 { 734 return (fFamilyID << 16UL) | fStyleID; 735 } 736 737 738 float 739 BFont::Size() const 740 { 741 return fSize; 742 } 743 744 745 float 746 BFont::Shear() const 747 { 748 return fShear; 749 } 750 751 752 float 753 BFont::Rotation() const 754 { 755 return fRotation; 756 } 757 758 759 float 760 BFont::FalseBoldWidth() const 761 { 762 return fFalseBoldWidth; 763 } 764 765 766 uint8 767 BFont::Spacing() const 768 { 769 return fSpacing; 770 } 771 772 773 uint8 774 BFont::Encoding() const 775 { 776 return fEncoding; 777 } 778 779 780 uint16 781 BFont::Face() const 782 { 783 return fFace; 784 } 785 786 787 uint32 788 BFont::Flags() const 789 { 790 return fFlags; 791 } 792 793 794 font_direction 795 BFont::Direction() const 796 { 797 _GetExtraFlags(); 798 return (font_direction)(fExtraFlags >> B_PRIVATE_FONT_DIRECTION_SHIFT); 799 } 800 801 802 bool 803 BFont::IsFixed() const 804 { 805 _GetExtraFlags(); 806 return (fExtraFlags & B_IS_FIXED) != 0; 807 } 808 809 810 // Returns whether or not the font is fixed-width and contains both 811 // full and half-width characters. 812 bool 813 BFont::IsFullAndHalfFixed() const 814 { 815 // This was left unimplemented as of R5. It is a way to work with both 816 // Kanji and Roman characters in the same fixed-width font. 817 818 _GetExtraFlags(); 819 return (fExtraFlags & B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED) != 0; 820 } 821 822 823 BRect 824 BFont::BoundingBox() const 825 { 826 BPrivate::AppServerLink link; 827 link.StartMessage(AS_GET_FONT_BOUNDING_BOX); 828 link.Attach<uint16>(fFamilyID); 829 link.Attach<uint16>(fStyleID); 830 link.Attach<float>(fSize); 831 832 int32 code; 833 if (link.FlushWithReply(code) != B_OK 834 || code != B_OK) 835 return BRect(0, 0, 0 ,0); 836 837 BRect box; 838 link.Read<BRect>(&box); 839 return box; 840 } 841 842 843 unicode_block 844 BFont::Blocks() const 845 { 846 BPrivate::AppServerLink link; 847 link.StartMessage(AS_GET_UNICODE_BLOCKS); 848 link.Attach<uint16>(fFamilyID); 849 link.Attach<uint16>(fStyleID); 850 851 int32 status; 852 if (link.FlushWithReply(status) != B_OK 853 || status != B_OK) { 854 return unicode_block(~0LL, ~0LL); 855 } 856 857 unicode_block blocksForFont; 858 link.Read<unicode_block>(&blocksForFont); 859 860 return blocksForFont; 861 } 862 863 bool 864 BFont::IncludesBlock(uint32 start, uint32 end) const 865 { 866 BPrivate::AppServerLink link; 867 link.StartMessage(AS_GET_HAS_UNICODE_BLOCK); 868 link.Attach<uint16>(fFamilyID); 869 link.Attach<uint16>(fStyleID); 870 link.Attach<uint32>(start); 871 link.Attach<uint32>(end); 872 873 int32 status; 874 if (link.FlushWithReply(status) != B_OK 875 || status != B_OK) { 876 return false; 877 } 878 879 bool hasBlock; 880 link.Read<bool>(&hasBlock); 881 882 return hasBlock; 883 } 884 885 886 font_file_format 887 BFont::FileFormat() const 888 { 889 BPrivate::AppServerLink link; 890 link.StartMessage(AS_GET_FONT_FILE_FORMAT); 891 link.Attach<uint16>(fFamilyID); 892 link.Attach<uint16>(fStyleID); 893 894 int32 status; 895 if (link.FlushWithReply(status) != B_OK 896 || status != B_OK) { 897 // just take a safe bet... 898 return B_TRUETYPE_WINDOWS; 899 } 900 901 uint16 format; 902 link.Read<uint16>(&format); 903 904 return (font_file_format)format; 905 } 906 907 908 int32 909 BFont::CountTuned() const 910 { 911 BPrivate::AppServerLink link; 912 link.StartMessage(AS_GET_TUNED_COUNT); 913 link.Attach<uint16>(fFamilyID); 914 link.Attach<uint16>(fStyleID); 915 916 int32 code; 917 if (link.FlushWithReply(code) != B_OK 918 || code != B_OK) 919 return -1; 920 921 int32 count; 922 link.Read<int32>(&count); 923 return count; 924 } 925 926 927 void 928 BFont::GetTunedInfo(int32 index, tuned_font_info* info) const 929 { 930 if (info == NULL) 931 return; 932 933 BPrivate::AppServerLink link; 934 link.StartMessage(AS_GET_TUNED_INFO); 935 link.Attach<uint16>(fFamilyID); 936 link.Attach<uint16>(fStyleID); 937 link.Attach<uint32>(index); 938 939 int32 code; 940 if (link.FlushWithReply(code) != B_OK || code != B_OK) 941 return; 942 943 link.Read<tuned_font_info>(info); 944 } 945 946 947 // Truncates a string to a given _pixel_ width based on the font and size 948 void 949 BFont::TruncateString(BString* inOut, uint32 mode, float width) const 950 { 951 if (mode == B_NO_TRUNCATION) 952 return; 953 954 // NOTE: Careful, we cannot directly use "inOut->String()" as result 955 // array, because the string length increases by 3 bytes in the worst 956 // case scenario. 957 const char* string = inOut->String(); 958 GetTruncatedStrings(&string, 1, mode, width, inOut); 959 } 960 961 962 void 963 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings, 964 uint32 mode, float width, BString resultArray[]) const 965 { 966 if (stringArray != NULL && numStrings > 0) { 967 // the width of the "…" glyph 968 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS); 969 970 for (int32 i = 0; i < numStrings; i++) { 971 resultArray[i] = stringArray[i]; 972 int32 numChars = resultArray[i].CountChars(); 973 974 // get the escapement of each glyph in font units 975 float* escapementArray = new float[numChars]; 976 GetEscapements(stringArray[i], numChars, NULL, escapementArray); 977 978 truncate_string(resultArray[i], mode, width, escapementArray, 979 fSize, ellipsisWidth, numChars); 980 981 delete[] escapementArray; 982 } 983 } 984 } 985 986 987 void 988 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings, 989 uint32 mode, float width, char* resultArray[]) const 990 { 991 if (stringArray != NULL && numStrings > 0) { 992 for (int32 i = 0; i < numStrings; i++) { 993 BString* strings = new BString[numStrings]; 994 GetTruncatedStrings(stringArray, numStrings, mode, width, strings); 995 996 for (int32 i = 0; i < numStrings; i++) 997 strcpy(resultArray[i], strings[i].String()); 998 999 delete[] strings; 1000 } 1001 } 1002 } 1003 1004 1005 float 1006 BFont::StringWidth(const char* string) const 1007 { 1008 if (string == NULL) 1009 return 0.0; 1010 1011 int32 length = strlen(string); 1012 float width; 1013 GetStringWidths(&string, &length, 1, &width); 1014 1015 return width; 1016 } 1017 1018 1019 float 1020 BFont::StringWidth(const char* string, int32 length) const 1021 { 1022 if (!string || length < 1) 1023 return 0.0f; 1024 1025 float width = 0.0f; 1026 GetStringWidths(&string, &length, 1, &width); 1027 1028 return width; 1029 } 1030 1031 1032 void 1033 BFont::GetStringWidths(const char* stringArray[], const int32 lengthArray[], 1034 int32 numStrings, float widthArray[]) const 1035 { 1036 if (stringArray == NULL || lengthArray == NULL || numStrings < 1 1037 || widthArray == NULL) { 1038 return; 1039 } 1040 1041 BPrivate::AppServerLink link; 1042 link.StartMessage(AS_GET_STRING_WIDTHS); 1043 link.Attach<uint16>(fFamilyID); 1044 link.Attach<uint16>(fStyleID); 1045 link.Attach<float>(fSize); 1046 link.Attach<uint8>(fSpacing); 1047 link.Attach<int32>(numStrings); 1048 1049 // TODO: all strings into a single array??? 1050 // we do have a maximum message length, and it could be easily touched 1051 // here... 1052 for (int32 i = 0; i < numStrings; i++) 1053 link.AttachString(stringArray[i], lengthArray[i]); 1054 1055 status_t status; 1056 if (link.FlushWithReply(status) != B_OK || status != B_OK) 1057 return; 1058 1059 link.Read(widthArray, sizeof(float) * numStrings); 1060 } 1061 1062 1063 void 1064 BFont::GetEscapements(const char charArray[], int32 numChars, 1065 float escapementArray[]) const 1066 { 1067 GetEscapements(charArray, numChars, NULL, escapementArray); 1068 } 1069 1070 1071 void 1072 BFont::GetEscapements(const char charArray[], int32 numChars, 1073 escapement_delta* delta, float escapementArray[]) const 1074 { 1075 if (charArray == NULL || numChars < 1 || escapementArray == NULL) 1076 return; 1077 1078 BPrivate::AppServerLink link; 1079 link.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS); 1080 link.Attach<uint16>(fFamilyID); 1081 link.Attach<uint16>(fStyleID); 1082 link.Attach<float>(fSize); 1083 link.Attach<uint8>(fSpacing); 1084 link.Attach<float>(fRotation); 1085 link.Attach<uint32>(fFlags); 1086 1087 link.Attach<float>(delta ? delta->nonspace : 0.0f); 1088 link.Attach<float>(delta ? delta->space : 0.0f); 1089 link.Attach<int32>(numChars); 1090 1091 // TODO: Should we not worry about the port capacity here?!? 1092 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1093 link.Attach<int32>(bytesInBuffer); 1094 link.Attach(charArray, bytesInBuffer); 1095 1096 int32 code; 1097 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1098 return; 1099 1100 link.Read(escapementArray, numChars * sizeof(float)); 1101 } 1102 1103 1104 void 1105 BFont::GetEscapements(const char charArray[], int32 numChars, 1106 escapement_delta* delta, BPoint escapementArray[]) const 1107 { 1108 GetEscapements(charArray, numChars, delta, escapementArray, NULL); 1109 } 1110 1111 1112 void 1113 BFont::GetEscapements(const char charArray[], int32 numChars, 1114 escapement_delta* delta, BPoint escapementArray[], 1115 BPoint offsetArray[]) const 1116 { 1117 if (charArray == NULL || numChars < 1 || escapementArray == NULL) 1118 return; 1119 1120 BPrivate::AppServerLink link; 1121 link.StartMessage(AS_GET_ESCAPEMENTS); 1122 link.Attach<uint16>(fFamilyID); 1123 link.Attach<uint16>(fStyleID); 1124 link.Attach<float>(fSize); 1125 link.Attach<uint8>(fSpacing); 1126 link.Attach<float>(fRotation); 1127 link.Attach<uint32>(fFlags); 1128 1129 link.Attach<float>(delta ? delta->nonspace : 0.0); 1130 link.Attach<float>(delta ? delta->space : 0.0); 1131 link.Attach<bool>(offsetArray != NULL); 1132 link.Attach<int32>(numChars); 1133 1134 // TODO: Should we not worry about the port capacity here?!? 1135 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1136 link.Attach<int32>(bytesInBuffer); 1137 link.Attach(charArray, bytesInBuffer); 1138 1139 int32 code; 1140 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1141 return; 1142 1143 link.Read(escapementArray, sizeof(BPoint) * numChars); 1144 if (offsetArray) 1145 link.Read(offsetArray, sizeof(BPoint) * numChars); 1146 } 1147 1148 1149 void 1150 BFont::GetEdges(const char charArray[], int32 numChars, 1151 edge_info edgeArray[]) const 1152 { 1153 if (!charArray || numChars < 1 || !edgeArray) 1154 return; 1155 1156 int32 code; 1157 BPrivate::AppServerLink link; 1158 1159 link.StartMessage(AS_GET_EDGES); 1160 link.Attach<uint16>(fFamilyID); 1161 link.Attach<uint16>(fStyleID); 1162 link.Attach<int32>(numChars); 1163 1164 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1165 link.Attach<int32>(bytesInBuffer); 1166 link.Attach(charArray, bytesInBuffer); 1167 1168 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1169 return; 1170 1171 link.Read(edgeArray, sizeof(edge_info) * numChars); 1172 } 1173 1174 1175 void 1176 BFont::GetHeight(font_height* _height) const 1177 { 1178 if (_height == NULL) 1179 return; 1180 1181 if (fHeight.ascent == kUninitializedAscent) { 1182 // we don't have the font height cached yet 1183 BPrivate::AppServerLink link; 1184 1185 link.StartMessage(AS_GET_FONT_HEIGHT); 1186 link.Attach<uint16>(fFamilyID); 1187 link.Attach<uint16>(fStyleID); 1188 link.Attach<float>(fSize); 1189 1190 int32 code; 1191 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1192 return; 1193 1194 // Who put that "const" to this method? :-) 1195 // We made fHeight mutable for this, but we should drop the "const" 1196 // when we can 1197 link.Read<font_height>(&fHeight); 1198 } 1199 1200 *_height = fHeight; 1201 } 1202 1203 1204 void 1205 BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, 1206 font_metric_mode mode, BRect boundingBoxArray[]) const 1207 { 1208 _GetBoundingBoxes(charArray, numChars, mode, false, NULL, 1209 boundingBoxArray, false); 1210 } 1211 1212 1213 void 1214 BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars, 1215 font_metric_mode mode, escapement_delta* delta, 1216 BRect boundingBoxArray[]) const 1217 { 1218 _GetBoundingBoxes(charArray, numChars, mode, true, delta, 1219 boundingBoxArray, true); 1220 } 1221 1222 1223 void 1224 BFont::_GetBoundingBoxes(const char charArray[], int32 numChars, 1225 font_metric_mode mode, bool string_escapement, escapement_delta* delta, 1226 BRect boundingBoxArray[], bool asString) const 1227 { 1228 if (charArray == NULL || numChars < 1 || boundingBoxArray == NULL) 1229 return; 1230 1231 int32 code; 1232 BPrivate::AppServerLink link; 1233 1234 link.StartMessage(asString 1235 ? AS_GET_BOUNDINGBOXES_STRING : AS_GET_BOUNDINGBOXES_CHARS); 1236 link.Attach<uint16>(fFamilyID); 1237 link.Attach<uint16>(fStyleID); 1238 link.Attach<float>(fSize); 1239 link.Attach<float>(fRotation); 1240 link.Attach<float>(fShear); 1241 link.Attach<float>(fFalseBoldWidth); 1242 link.Attach<uint8>(fSpacing); 1243 1244 link.Attach<uint32>(fFlags); 1245 link.Attach<font_metric_mode>(mode); 1246 link.Attach<bool>(string_escapement); 1247 1248 if (delta != NULL) { 1249 link.Attach<escapement_delta>(*delta); 1250 } else { 1251 escapement_delta emptyDelta = {0, 0}; 1252 link.Attach<escapement_delta>(emptyDelta); 1253 } 1254 1255 link.Attach<int32>(numChars); 1256 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1257 link.Attach<int32>(bytesInBuffer); 1258 link.Attach(charArray, bytesInBuffer); 1259 1260 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1261 return; 1262 1263 link.Read(boundingBoxArray, sizeof(BRect) * numChars); 1264 } 1265 1266 1267 void 1268 BFont::GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings, 1269 font_metric_mode mode, escapement_delta deltas[], 1270 BRect boundingBoxArray[]) const 1271 { 1272 if (!stringArray || numStrings < 1 || !boundingBoxArray) 1273 return; 1274 1275 int32 code; 1276 BPrivate::AppServerLink link; 1277 1278 link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS); 1279 link.Attach<uint16>(fFamilyID); 1280 link.Attach<uint16>(fStyleID); 1281 link.Attach<float>(fSize); 1282 link.Attach<float>(fRotation); 1283 link.Attach<float>(fShear); 1284 link.Attach<float>(fFalseBoldWidth); 1285 link.Attach<uint8>(fSpacing); 1286 link.Attach<uint32>(fFlags); 1287 link.Attach<font_metric_mode>(mode); 1288 link.Attach<int32>(numStrings); 1289 1290 if (deltas) { 1291 for (int32 i = 0; i < numStrings; i++) { 1292 link.AttachString(stringArray[i]); 1293 link.Attach<escapement_delta>(deltas[i]); 1294 } 1295 } else { 1296 escapement_delta emptyDelta = {0, 0}; 1297 1298 for (int32 i = 0; i < numStrings; i++) { 1299 link.AttachString(stringArray[i]); 1300 link.Attach<escapement_delta>(emptyDelta); 1301 } 1302 } 1303 1304 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1305 return; 1306 1307 link.Read(boundingBoxArray, sizeof(BRect) * numStrings); 1308 } 1309 1310 1311 void 1312 BFont::GetGlyphShapes(const char charArray[], int32 numChars, 1313 BShape* glyphShapeArray[]) const 1314 { 1315 // TODO: implement code specifically for passing BShapes to and 1316 // from the server 1317 if (!charArray || numChars < 1 || !glyphShapeArray) 1318 return; 1319 1320 int32 code; 1321 BPrivate::AppServerLink link; 1322 1323 link.StartMessage(AS_GET_GLYPH_SHAPES); 1324 link.Attach<uint16>(fFamilyID); 1325 link.Attach<uint16>(fStyleID); 1326 link.Attach<float>(fSize); 1327 link.Attach<float>(fShear); 1328 link.Attach<float>(fRotation); 1329 link.Attach<float>(fFalseBoldWidth); 1330 link.Attach<uint32>(fFlags); 1331 link.Attach<int32>(numChars); 1332 1333 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1334 link.Attach<int32>(bytesInBuffer); 1335 link.Attach(charArray, bytesInBuffer); 1336 1337 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1338 return; 1339 1340 for (int32 i = 0; i < numChars; i++) 1341 link.ReadShape(glyphShapeArray[i]); 1342 } 1343 1344 1345 void 1346 BFont::GetHasGlyphs(const char charArray[], int32 numChars, 1347 bool hasArray[]) const 1348 { 1349 if (!charArray || numChars < 1 || !hasArray) 1350 return; 1351 1352 int32 code; 1353 BPrivate::AppServerLink link; 1354 1355 link.StartMessage(AS_GET_HAS_GLYPHS); 1356 link.Attach<uint16>(fFamilyID); 1357 link.Attach<uint16>(fStyleID); 1358 link.Attach<int32>(numChars); 1359 1360 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1361 link.Attach<int32>(bytesInBuffer); 1362 link.Attach(charArray, bytesInBuffer); 1363 1364 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1365 return; 1366 1367 link.Read(hasArray, sizeof(bool) * numChars); 1368 } 1369 1370 1371 BFont& 1372 BFont::operator=(const BFont& font) 1373 { 1374 fFamilyID = font.fFamilyID; 1375 fStyleID = font.fStyleID; 1376 fSize = font.fSize; 1377 fShear = font.fShear; 1378 fRotation = font.fRotation; 1379 fFalseBoldWidth = font.fFalseBoldWidth; 1380 fSpacing = font.fSpacing; 1381 fEncoding = font.fEncoding; 1382 fFace = font.fFace; 1383 fHeight = font.fHeight; 1384 fFlags = font.fFlags; 1385 fExtraFlags = font.fExtraFlags; 1386 1387 return *this; 1388 } 1389 1390 1391 bool 1392 BFont::operator==(const BFont& font) const 1393 { 1394 return fFamilyID == font.fFamilyID 1395 && fStyleID == font.fStyleID 1396 && fSize == font.fSize 1397 && fShear == font.fShear 1398 && fRotation == font.fRotation 1399 && fFalseBoldWidth == font.fFalseBoldWidth 1400 && fSpacing == font.fSpacing 1401 && fEncoding == font.fEncoding 1402 && fFace == font.fFace; 1403 } 1404 1405 1406 bool 1407 BFont::operator!=(const BFont& font) const 1408 { 1409 return fFamilyID != font.fFamilyID 1410 || fStyleID != font.fStyleID 1411 || fSize != font.fSize 1412 || fShear != font.fShear 1413 || fRotation != font.fRotation 1414 || fFalseBoldWidth != font.fFalseBoldWidth 1415 || fSpacing != font.fSpacing 1416 || fEncoding != font.fEncoding 1417 || fFace != font.fFace; 1418 } 1419 1420 1421 void 1422 BFont::PrintToStream() const 1423 { 1424 font_family family; 1425 font_style style; 1426 GetFamilyAndStyle(&family, &style); 1427 1428 printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n", 1429 family, fFamilyID, style, fStyleID, fFace, fShear, fRotation, fSize, 1430 fHeight.ascent, fHeight.descent, fHeight.leading, fEncoding); 1431 } 1432 1433 1434 void 1435 BFont::_GetExtraFlags() const 1436 { 1437 // TODO: this has to be const in order to allow other font getters to 1438 // stay const as well 1439 if (fExtraFlags != kUninitializedExtraFlags) 1440 return; 1441 1442 BPrivate::AppServerLink link; 1443 link.StartMessage(AS_GET_EXTRA_FONT_FLAGS); 1444 link.Attach<uint16>(fFamilyID); 1445 link.Attach<uint16>(fStyleID); 1446 1447 status_t status = B_ERROR; 1448 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1449 // use defaut values for the flags 1450 fExtraFlags = (uint32)B_FONT_LEFT_TO_RIGHT 1451 << B_PRIVATE_FONT_DIRECTION_SHIFT; 1452 return; 1453 } 1454 1455 link.Read<uint32>(&fExtraFlags); 1456 } 1457 1458 1459 status_t 1460 BFont::LoadFont(const char* path) 1461 { 1462 return LoadFont(path, 0, 0); 1463 } 1464 1465 1466 status_t 1467 BFont::LoadFont(const char* path, uint16 index, uint16 instance) 1468 { 1469 BPrivate::AppServerLink link; 1470 link.StartMessage(AS_ADD_FONT_FILE); 1471 link.AttachString(path); 1472 link.Attach<uint16>(index); 1473 link.Attach<uint16>(instance); 1474 status_t status = B_ERROR; 1475 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1476 return status; 1477 } 1478 1479 link.Read<uint16>(&fFamilyID); 1480 link.Read<uint16>(&fStyleID); 1481 link.Read<uint16>(&fFace); 1482 fHeight.ascent = kUninitializedAscent; 1483 fExtraFlags = kUninitializedExtraFlags; 1484 1485 return B_OK; 1486 } 1487 1488 1489 status_t 1490 BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset) 1491 { 1492 return LoadFont(fontAreaID, size, offset, 0, 0); 1493 } 1494 1495 1496 status_t 1497 BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset, uint16 index, uint16 instance) 1498 { 1499 BPrivate::AppServerLink link; 1500 1501 link.StartMessage(AS_ADD_FONT_MEMORY); 1502 1503 link.Attach<int32>(fontAreaID); 1504 link.Attach<size_t>(size); 1505 link.Attach<size_t>(offset); 1506 link.Attach<uint16>(index); 1507 link.Attach<uint16>(instance); 1508 1509 status_t status = B_ERROR; 1510 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1511 return status; 1512 } 1513 1514 link.Read<uint16>(&fFamilyID); 1515 link.Read<uint16>(&fStyleID); 1516 link.Read<uint16>(&fFace); 1517 fHeight.ascent = kUninitializedAscent; 1518 fExtraFlags = kUninitializedExtraFlags; 1519 1520 return B_OK; 1521 } 1522 1523 1524 status_t 1525 BFont::UnloadFont() 1526 { 1527 BPrivate::AppServerLink link; 1528 1529 link.StartMessage(AS_REMOVE_FONT); 1530 1531 link.Attach<uint16>(fFamilyID); 1532 link.Attach<uint16>(fStyleID); 1533 1534 status_t status = B_ERROR; 1535 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1536 return status; 1537 } 1538 1539 // reset to plain font 1540 fFamilyID = 0; 1541 fStyleID = 0; 1542 fFace = 0; 1543 fHeight.ascent = kUninitializedAscent; 1544 fExtraFlags = kUninitializedExtraFlags; 1545 1546 return B_OK; 1547 } 1548