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 uint32 _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 uint32 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 uint32 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 uint32 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 // Go on as if our list is up to date. If it is a one-time thing 305 // we'll try again soon. If it isn't, we have a bigger problem. 306 return fRevision; 307 } 308 309 uint32 revision; 310 link.Read<uint32>(&revision); 311 312 return revision; 313 } 314 315 316 family* 317 FontList::_FindFamily(font_family name) 318 { 319 if (fLastFamily != NULL && fLastFamily->name == name) 320 return fLastFamily; 321 322 ::family family; 323 family.name = name; 324 fLastFamily = const_cast< ::family*>(fFamilies.BinarySearch(family, 325 compare_families)); 326 return fLastFamily; 327 } 328 329 330 /*static*/ void 331 FontList::_InitSingleton() 332 { 333 sDefaultInstance = new FontList; 334 } 335 336 } // unnamed namespace 337 338 339 // #pragma mark - 340 341 342 void 343 _init_global_fonts_() 344 { 345 BPrivate::AppServerLink link; 346 link.StartMessage(AS_GET_SYSTEM_FONTS); 347 348 int32 code; 349 if (link.FlushWithReply(code) != B_OK 350 || code != B_OK) { 351 printf("DEBUG: Couldn't initialize global fonts!\n"); 352 return; 353 } 354 355 char type[B_OS_NAME_LENGTH]; 356 357 while (link.ReadString(type, sizeof(type)) >= B_OK && type[0]) { 358 BFont dummy; 359 BFont* font = &dummy; 360 361 if (!strcmp(type, "plain")) 362 font = &sPlainFont; 363 else if (!strcmp(type, "bold")) 364 font = &sBoldFont; 365 else if (!strcmp(type, "fixed")) 366 font = &sFixedFont; 367 368 link.Read<uint16>(&font->fFamilyID); 369 link.Read<uint16>(&font->fStyleID); 370 link.Read<float>(&font->fSize); 371 link.Read<uint16>(&font->fFace); 372 link.Read<uint32>(&font->fFlags); 373 374 font->fHeight.ascent = kUninitializedAscent; 375 font->fExtraFlags = kUninitializedExtraFlags; 376 } 377 } 378 379 380 void 381 _font_control_(BFont* font, int32 cmd, void* data) 382 { 383 } 384 385 386 status_t 387 get_font_cache_info(uint32 id, void* set) 388 { 389 return B_ERROR; 390 } 391 392 393 status_t 394 set_font_cache_info(uint32 id, void* set) 395 { 396 return B_ERROR; 397 } 398 399 400 // Private function used to replace the R5 hack which sets a system font 401 void 402 _set_system_font_(const char* which, font_family family, font_style style, 403 float size) 404 { 405 // R5 used a global area offset table to set the system fonts in the Font 406 // preferences panel. Bleah. 407 BPrivate::AppServerLink link; 408 409 link.StartMessage(AS_SET_SYSTEM_FONT); 410 link.AttachString(which, B_OS_NAME_LENGTH); 411 link.AttachString(family, sizeof(font_family)); 412 link.AttachString(style, sizeof(font_style)); 413 link.Attach<float>(size); 414 link.Flush(); 415 } 416 417 418 status_t 419 _get_system_default_font_(const char* which, font_family family, 420 font_style style, float* _size) 421 { 422 BPrivate::AppServerLink link; 423 424 link.StartMessage(AS_GET_SYSTEM_DEFAULT_FONT); 425 link.AttachString(which, B_OS_NAME_LENGTH); 426 427 int32 status = B_ERROR; 428 if (link.FlushWithReply(status) != B_OK 429 || status < B_OK) 430 return status; 431 432 link.ReadString(family, sizeof(font_family)); 433 link.ReadString(style, sizeof(font_style)); 434 link.Read<float>(_size); 435 return B_OK; 436 } 437 438 439 // Returns the number of installed font families 440 int32 441 count_font_families() 442 { 443 return FontList::Default()->CountFamilies(); 444 } 445 446 447 // Returns the number of styles available for a font family 448 int32 449 count_font_styles(font_family family) 450 { 451 return FontList::Default()->CountStyles(family); 452 } 453 454 455 // Retrieves the family name at the specified index 456 status_t 457 get_font_family(int32 index, font_family* _name, uint32* _flags) 458 { 459 if (_name == NULL) 460 return B_BAD_VALUE; 461 462 return FontList::Default()->FamilyAt(index, _name, _flags); 463 } 464 465 466 // Retrieves the family name at the specified index 467 status_t 468 get_font_style(font_family family, int32 index, font_style* _name, 469 uint32* _flags) 470 { 471 return get_font_style(family, index, _name, NULL, _flags); 472 } 473 474 475 // Retrieves the family name at the specified index 476 status_t 477 get_font_style(font_family family, int32 index, font_style* _name, 478 uint16* _face, uint32* _flags) 479 { 480 // The face value returned by this function is not very reliable. At the 481 // same time, the value returned should be fairly reliable, returning the 482 // proper flag for 90%-99% of font names. 483 484 if (_name == NULL) 485 return B_BAD_VALUE; 486 487 return FontList::Default()->StyleAt(family, index, _name, _face, _flags); 488 } 489 490 491 // Updates the font family list 492 bool 493 update_font_families(bool /*checkOnly*/) 494 { 495 return FontList::Default()->UpdatedOnServer(); 496 } 497 498 499 // #pragma mark - 500 501 502 BFont::BFont() 503 : 504 // initialise for be_plain_font (avoid circular definition) 505 fFamilyID(0), 506 fStyleID(0), 507 fSize(10.0), 508 fShear(90.0), 509 fRotation(0.0), 510 fFalseBoldWidth(0.0), 511 fSpacing(B_BITMAP_SPACING), 512 fEncoding(B_UNICODE_UTF8), 513 fFace(0), 514 fFlags(0), 515 fExtraFlags(kUninitializedExtraFlags) 516 { 517 if (be_plain_font != NULL && this != &sPlainFont) 518 *this = *be_plain_font; 519 else { 520 fHeight.ascent = 7.0; 521 fHeight.descent = 2.0; 522 fHeight.leading = 13.0; 523 } 524 } 525 526 527 BFont::BFont(const BFont& font) 528 { 529 *this = font; 530 } 531 532 533 BFont::BFont(const BFont* font) 534 { 535 if (font != NULL) 536 *this = *font; 537 else 538 *this = *be_plain_font; 539 } 540 541 542 // Sets the font's family and style all at once 543 status_t 544 BFont::SetFamilyAndStyle(const font_family family, const font_style style) 545 { 546 if (family == NULL && style == NULL) 547 return B_BAD_VALUE; 548 549 BPrivate::AppServerLink link; 550 551 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 552 link.AttachString(family, sizeof(font_family)); 553 link.AttachString(style, sizeof(font_style)); 554 link.Attach<uint16>(fFamilyID); 555 link.Attach<uint16>(0xffff); 556 link.Attach<uint16>(fFace); 557 558 int32 status = B_ERROR; 559 if (link.FlushWithReply(status) != B_OK || status != B_OK) 560 return status; 561 562 link.Read<uint16>(&fFamilyID); 563 link.Read<uint16>(&fStyleID); 564 link.Read<uint16>(&fFace); 565 566 fHeight.ascent = kUninitializedAscent; 567 fExtraFlags = kUninitializedExtraFlags; 568 569 return B_OK; 570 } 571 572 573 // Sets the font's family and style all at once 574 void 575 BFont::SetFamilyAndStyle(uint32 code) 576 { 577 // R5 has a bug here: the face is not updated even though the IDs are set. 578 // This is a problem because the face flag includes Regular/Bold/Italic 579 // information in addition to stuff like underlining and strikethrough. 580 // As a result, this will need a trip to the server and, thus, be slower 581 // than R5's in order to be correct 582 583 uint16 family, style; 584 style = code & 0xFFFF; 585 family = (code & 0xFFFF0000) >> 16; 586 587 BPrivate::AppServerLink link; 588 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 589 link.AttachString(NULL); // no family and style name 590 link.AttachString(NULL); 591 link.Attach<uint16>(family); 592 link.Attach<uint16>(style); 593 link.Attach<uint16>(fFace); 594 595 int32 fontcode; 596 if (link.FlushWithReply(fontcode) != B_OK || fontcode != B_OK) 597 return; 598 599 link.Read<uint16>(&fFamilyID); 600 link.Read<uint16>(&fStyleID); 601 link.Read<uint16>(&fFace); 602 fHeight.ascent = kUninitializedAscent; 603 fExtraFlags = kUninitializedExtraFlags; 604 } 605 606 607 // Sets the font's family and face all at once 608 status_t 609 BFont::SetFamilyAndFace(const font_family family, uint16 face) 610 { 611 // To comply with the BeBook, this function will only set valid values 612 // i.e. passing a nonexistent family will cause only the face to be set. 613 // Additionally, if a particular face does not exist in a family, the 614 // closest match will be chosen. 615 616 BPrivate::AppServerLink link; 617 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 618 link.AttachString(family, sizeof(font_family)); 619 link.AttachString(NULL); // no style given 620 link.Attach<uint16>(fFamilyID); 621 link.Attach<uint16>(0xffff); 622 link.Attach<uint16>(face); 623 624 int32 status = B_ERROR; 625 if (link.FlushWithReply(status) != B_OK || status != B_OK) 626 return status; 627 628 link.Read<uint16>(&fFamilyID); 629 link.Read<uint16>(&fStyleID); 630 link.Read<uint16>(&fFace); 631 fHeight.ascent = kUninitializedAscent; 632 fExtraFlags = kUninitializedExtraFlags; 633 634 return B_OK; 635 } 636 637 638 void 639 BFont::SetSize(float size) 640 { 641 fSize = size; 642 fHeight.ascent = kUninitializedAscent; 643 } 644 645 646 void 647 BFont::SetShear(float shear) 648 { 649 fShear = shear; 650 fHeight.ascent = kUninitializedAscent; 651 } 652 653 654 void 655 BFont::SetRotation(float rotation) 656 { 657 fRotation = rotation; 658 fHeight.ascent = kUninitializedAscent; 659 } 660 661 662 void 663 BFont::SetFalseBoldWidth(float width) 664 { 665 fFalseBoldWidth = width; 666 } 667 668 669 void 670 BFont::SetSpacing(uint8 spacing) 671 { 672 fSpacing = spacing; 673 } 674 675 676 void 677 BFont::SetEncoding(uint8 encoding) 678 { 679 fEncoding = encoding; 680 } 681 682 683 void 684 BFont::SetFace(uint16 face) 685 { 686 if (face == fFace) 687 return; 688 689 SetFamilyAndFace(NULL, face); 690 } 691 692 693 void 694 BFont::SetFlags(uint32 flags) 695 { 696 fFlags = flags; 697 } 698 699 700 void 701 BFont::GetFamilyAndStyle(font_family* family, font_style* style) const 702 { 703 if (family == NULL && style == NULL) 704 return; 705 706 // it's okay to call this function with either family or style set to NULL 707 708 font_family familyBuffer; 709 font_style styleBuffer; 710 711 if (family == NULL) 712 family = &familyBuffer; 713 if (style == NULL) 714 style = &styleBuffer; 715 716 BPrivate::AppServerLink link; 717 link.StartMessage(AS_GET_FAMILY_AND_STYLE); 718 link.Attach<uint16>(fFamilyID); 719 link.Attach<uint16>(fStyleID); 720 721 int32 code; 722 if (link.FlushWithReply(code) != B_OK || code != B_OK) { 723 // the least we can do is to clear the buffers 724 memset(*family, 0, sizeof(font_family)); 725 memset(*style, 0, sizeof(font_style)); 726 return; 727 } 728 729 link.ReadString(*family, sizeof(font_family)); 730 link.ReadString(*style, sizeof(font_style)); 731 } 732 733 734 uint32 735 BFont::FamilyAndStyle() const 736 { 737 return (fFamilyID << 16UL) | fStyleID; 738 } 739 740 741 float 742 BFont::Size() const 743 { 744 return fSize; 745 } 746 747 748 float 749 BFont::Shear() const 750 { 751 return fShear; 752 } 753 754 755 float 756 BFont::Rotation() const 757 { 758 return fRotation; 759 } 760 761 762 float 763 BFont::FalseBoldWidth() const 764 { 765 return fFalseBoldWidth; 766 } 767 768 769 uint8 770 BFont::Spacing() const 771 { 772 return fSpacing; 773 } 774 775 776 uint8 777 BFont::Encoding() const 778 { 779 return fEncoding; 780 } 781 782 783 uint16 784 BFont::Face() const 785 { 786 return fFace; 787 } 788 789 790 uint32 791 BFont::Flags() const 792 { 793 return fFlags; 794 } 795 796 797 font_direction 798 BFont::Direction() const 799 { 800 _GetExtraFlags(); 801 return (font_direction)(fExtraFlags >> B_PRIVATE_FONT_DIRECTION_SHIFT); 802 } 803 804 805 bool 806 BFont::IsFixed() const 807 { 808 _GetExtraFlags(); 809 return (fExtraFlags & B_IS_FIXED) != 0; 810 } 811 812 813 // Returns whether or not the font is fixed-width and contains both 814 // full and half-width characters. 815 bool 816 BFont::IsFullAndHalfFixed() const 817 { 818 // This was left unimplemented as of R5. It is a way to work with both 819 // Kanji and Roman characters in the same fixed-width font. 820 821 _GetExtraFlags(); 822 return (fExtraFlags & B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED) != 0; 823 } 824 825 826 BRect 827 BFont::BoundingBox() const 828 { 829 BPrivate::AppServerLink link; 830 link.StartMessage(AS_GET_FONT_BOUNDING_BOX); 831 link.Attach<uint16>(fFamilyID); 832 link.Attach<uint16>(fStyleID); 833 link.Attach<float>(fSize); 834 835 int32 code; 836 if (link.FlushWithReply(code) != B_OK 837 || code != B_OK) 838 return BRect(0, 0, 0 ,0); 839 840 BRect box; 841 link.Read<BRect>(&box); 842 return box; 843 } 844 845 846 unicode_block 847 BFont::Blocks() const 848 { 849 BPrivate::AppServerLink link; 850 link.StartMessage(AS_GET_UNICODE_BLOCKS); 851 link.Attach<uint16>(fFamilyID); 852 link.Attach<uint16>(fStyleID); 853 854 int32 status; 855 if (link.FlushWithReply(status) != B_OK 856 || status != B_OK) { 857 return unicode_block(~0LL, ~0LL); 858 } 859 860 unicode_block blocksForFont; 861 link.Read<unicode_block>(&blocksForFont); 862 863 return blocksForFont; 864 } 865 866 bool 867 BFont::IncludesBlock(uint32 start, uint32 end) const 868 { 869 BPrivate::AppServerLink link; 870 link.StartMessage(AS_GET_HAS_UNICODE_BLOCK); 871 link.Attach<uint16>(fFamilyID); 872 link.Attach<uint16>(fStyleID); 873 link.Attach<uint32>(start); 874 link.Attach<uint32>(end); 875 876 int32 status; 877 if (link.FlushWithReply(status) != B_OK 878 || status != B_OK) { 879 return false; 880 } 881 882 bool hasBlock; 883 link.Read<bool>(&hasBlock); 884 885 return hasBlock; 886 } 887 888 889 font_file_format 890 BFont::FileFormat() const 891 { 892 BPrivate::AppServerLink link; 893 link.StartMessage(AS_GET_FONT_FILE_FORMAT); 894 link.Attach<uint16>(fFamilyID); 895 link.Attach<uint16>(fStyleID); 896 897 int32 status; 898 if (link.FlushWithReply(status) != B_OK 899 || status != B_OK) { 900 // just take a safe bet... 901 return B_TRUETYPE_WINDOWS; 902 } 903 904 uint16 format; 905 link.Read<uint16>(&format); 906 907 return (font_file_format)format; 908 } 909 910 911 int32 912 BFont::CountTuned() const 913 { 914 BPrivate::AppServerLink link; 915 link.StartMessage(AS_GET_TUNED_COUNT); 916 link.Attach<uint16>(fFamilyID); 917 link.Attach<uint16>(fStyleID); 918 919 int32 code; 920 if (link.FlushWithReply(code) != B_OK 921 || code != B_OK) 922 return -1; 923 924 int32 count; 925 link.Read<int32>(&count); 926 return count; 927 } 928 929 930 void 931 BFont::GetTunedInfo(int32 index, tuned_font_info* info) const 932 { 933 if (info == NULL) 934 return; 935 936 BPrivate::AppServerLink link; 937 link.StartMessage(AS_GET_TUNED_INFO); 938 link.Attach<uint16>(fFamilyID); 939 link.Attach<uint16>(fStyleID); 940 link.Attach<uint32>(index); 941 942 int32 code; 943 if (link.FlushWithReply(code) != B_OK || code != B_OK) 944 return; 945 946 link.Read<tuned_font_info>(info); 947 } 948 949 950 // Truncates a string to a given _pixel_ width based on the font and size 951 void 952 BFont::TruncateString(BString* inOut, uint32 mode, float width) const 953 { 954 if (mode == B_NO_TRUNCATION) 955 return; 956 957 // NOTE: Careful, we cannot directly use "inOut->String()" as result 958 // array, because the string length increases by 3 bytes in the worst 959 // case scenario. 960 const char* string = inOut->String(); 961 GetTruncatedStrings(&string, 1, mode, width, inOut); 962 } 963 964 965 void 966 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings, 967 uint32 mode, float width, BString resultArray[]) const 968 { 969 if (stringArray != NULL && numStrings > 0) { 970 // the width of the "…" glyph 971 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS); 972 973 for (int32 i = 0; i < numStrings; i++) { 974 resultArray[i] = stringArray[i]; 975 int32 numChars = resultArray[i].CountChars(); 976 977 // get the escapement of each glyph in font units 978 float* escapementArray = new float[numChars]; 979 GetEscapements(stringArray[i], numChars, NULL, escapementArray); 980 981 truncate_string(resultArray[i], mode, width, escapementArray, 982 fSize, ellipsisWidth, numChars); 983 984 delete[] escapementArray; 985 } 986 } 987 } 988 989 990 void 991 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings, 992 uint32 mode, float width, char* resultArray[]) const 993 { 994 if (stringArray != NULL && numStrings > 0) { 995 for (int32 i = 0; i < numStrings; i++) { 996 BString* strings = new BString[numStrings]; 997 GetTruncatedStrings(stringArray, numStrings, mode, width, strings); 998 999 for (int32 i = 0; i < numStrings; i++) 1000 strcpy(resultArray[i], strings[i].String()); 1001 1002 delete[] strings; 1003 } 1004 } 1005 } 1006 1007 1008 float 1009 BFont::StringWidth(const char* string) const 1010 { 1011 if (string == NULL) 1012 return 0.0; 1013 1014 int32 length = strlen(string); 1015 float width; 1016 GetStringWidths(&string, &length, 1, &width); 1017 1018 return width; 1019 } 1020 1021 1022 float 1023 BFont::StringWidth(const char* string, int32 length) const 1024 { 1025 if (!string || length < 1) 1026 return 0.0f; 1027 1028 float width = 0.0f; 1029 GetStringWidths(&string, &length, 1, &width); 1030 1031 return width; 1032 } 1033 1034 1035 void 1036 BFont::GetStringWidths(const char* stringArray[], const int32 lengthArray[], 1037 int32 numStrings, float widthArray[]) const 1038 { 1039 if (stringArray == NULL || lengthArray == NULL || numStrings < 1 1040 || widthArray == NULL) { 1041 return; 1042 } 1043 1044 BPrivate::AppServerLink link; 1045 link.StartMessage(AS_GET_STRING_WIDTHS); 1046 link.Attach<uint16>(fFamilyID); 1047 link.Attach<uint16>(fStyleID); 1048 link.Attach<float>(fSize); 1049 link.Attach<uint8>(fSpacing); 1050 link.Attach<int32>(numStrings); 1051 1052 // TODO: all strings into a single array??? 1053 // we do have a maximum message length, and it could be easily touched 1054 // here... 1055 for (int32 i = 0; i < numStrings; i++) 1056 link.AttachString(stringArray[i], lengthArray[i]); 1057 1058 status_t status; 1059 if (link.FlushWithReply(status) != B_OK || status != B_OK) 1060 return; 1061 1062 link.Read(widthArray, sizeof(float) * numStrings); 1063 } 1064 1065 1066 void 1067 BFont::GetEscapements(const char charArray[], int32 numChars, 1068 float escapementArray[]) const 1069 { 1070 GetEscapements(charArray, numChars, NULL, escapementArray); 1071 } 1072 1073 1074 void 1075 BFont::GetEscapements(const char charArray[], int32 numChars, 1076 escapement_delta* delta, float escapementArray[]) const 1077 { 1078 if (charArray == NULL || numChars < 1 || escapementArray == NULL) 1079 return; 1080 1081 BPrivate::AppServerLink link; 1082 link.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS); 1083 link.Attach<uint16>(fFamilyID); 1084 link.Attach<uint16>(fStyleID); 1085 link.Attach<float>(fSize); 1086 link.Attach<uint8>(fSpacing); 1087 link.Attach<float>(fRotation); 1088 link.Attach<uint32>(fFlags); 1089 1090 link.Attach<float>(delta ? delta->nonspace : 0.0f); 1091 link.Attach<float>(delta ? delta->space : 0.0f); 1092 link.Attach<int32>(numChars); 1093 1094 // TODO: Should we not worry about the port capacity here?!? 1095 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1096 link.Attach<int32>(bytesInBuffer); 1097 link.Attach(charArray, bytesInBuffer); 1098 1099 int32 code; 1100 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1101 return; 1102 1103 link.Read(escapementArray, numChars * sizeof(float)); 1104 } 1105 1106 1107 void 1108 BFont::GetEscapements(const char charArray[], int32 numChars, 1109 escapement_delta* delta, BPoint escapementArray[]) const 1110 { 1111 GetEscapements(charArray, numChars, delta, escapementArray, NULL); 1112 } 1113 1114 1115 void 1116 BFont::GetEscapements(const char charArray[], int32 numChars, 1117 escapement_delta* delta, BPoint escapementArray[], 1118 BPoint offsetArray[]) const 1119 { 1120 if (charArray == NULL || numChars < 1 || escapementArray == NULL) 1121 return; 1122 1123 BPrivate::AppServerLink link; 1124 link.StartMessage(AS_GET_ESCAPEMENTS); 1125 link.Attach<uint16>(fFamilyID); 1126 link.Attach<uint16>(fStyleID); 1127 link.Attach<float>(fSize); 1128 link.Attach<uint8>(fSpacing); 1129 link.Attach<float>(fRotation); 1130 link.Attach<uint32>(fFlags); 1131 1132 link.Attach<float>(delta ? delta->nonspace : 0.0); 1133 link.Attach<float>(delta ? delta->space : 0.0); 1134 link.Attach<bool>(offsetArray != NULL); 1135 link.Attach<int32>(numChars); 1136 1137 // TODO: Should we not worry about the port capacity here?!? 1138 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1139 link.Attach<int32>(bytesInBuffer); 1140 link.Attach(charArray, bytesInBuffer); 1141 1142 int32 code; 1143 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1144 return; 1145 1146 link.Read(escapementArray, sizeof(BPoint) * numChars); 1147 if (offsetArray) 1148 link.Read(offsetArray, sizeof(BPoint) * numChars); 1149 } 1150 1151 1152 void 1153 BFont::GetEdges(const char charArray[], int32 numChars, 1154 edge_info edgeArray[]) const 1155 { 1156 if (!charArray || numChars < 1 || !edgeArray) 1157 return; 1158 1159 int32 code; 1160 BPrivate::AppServerLink link; 1161 1162 link.StartMessage(AS_GET_EDGES); 1163 link.Attach<uint16>(fFamilyID); 1164 link.Attach<uint16>(fStyleID); 1165 link.Attach<int32>(numChars); 1166 1167 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1168 link.Attach<int32>(bytesInBuffer); 1169 link.Attach(charArray, bytesInBuffer); 1170 1171 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1172 return; 1173 1174 link.Read(edgeArray, sizeof(edge_info) * numChars); 1175 } 1176 1177 1178 void 1179 BFont::GetHeight(font_height* _height) const 1180 { 1181 if (_height == NULL) 1182 return; 1183 1184 if (fHeight.ascent == kUninitializedAscent) { 1185 // we don't have the font height cached yet 1186 BPrivate::AppServerLink link; 1187 1188 link.StartMessage(AS_GET_FONT_HEIGHT); 1189 link.Attach<uint16>(fFamilyID); 1190 link.Attach<uint16>(fStyleID); 1191 link.Attach<float>(fSize); 1192 1193 int32 code; 1194 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1195 return; 1196 1197 // Who put that "const" to this method? :-) 1198 // We made fHeight mutable for this, but we should drop the "const" 1199 // when we can 1200 link.Read<font_height>(&fHeight); 1201 } 1202 1203 *_height = fHeight; 1204 } 1205 1206 1207 void 1208 BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, 1209 font_metric_mode mode, BRect boundingBoxArray[]) const 1210 { 1211 _GetBoundingBoxes(charArray, numChars, mode, false, NULL, 1212 boundingBoxArray, false); 1213 } 1214 1215 1216 void 1217 BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars, 1218 font_metric_mode mode, escapement_delta* delta, 1219 BRect boundingBoxArray[]) const 1220 { 1221 _GetBoundingBoxes(charArray, numChars, mode, true, delta, 1222 boundingBoxArray, true); 1223 } 1224 1225 1226 void 1227 BFont::_GetBoundingBoxes(const char charArray[], int32 numChars, 1228 font_metric_mode mode, bool string_escapement, escapement_delta* delta, 1229 BRect boundingBoxArray[], bool asString) const 1230 { 1231 if (charArray == NULL || numChars < 1 || boundingBoxArray == NULL) 1232 return; 1233 1234 int32 code; 1235 BPrivate::AppServerLink link; 1236 1237 link.StartMessage(asString 1238 ? AS_GET_BOUNDINGBOXES_STRING : AS_GET_BOUNDINGBOXES_CHARS); 1239 link.Attach<uint16>(fFamilyID); 1240 link.Attach<uint16>(fStyleID); 1241 link.Attach<float>(fSize); 1242 link.Attach<float>(fRotation); 1243 link.Attach<float>(fShear); 1244 link.Attach<float>(fFalseBoldWidth); 1245 link.Attach<uint8>(fSpacing); 1246 1247 link.Attach<uint32>(fFlags); 1248 link.Attach<font_metric_mode>(mode); 1249 link.Attach<bool>(string_escapement); 1250 1251 if (delta != NULL) { 1252 link.Attach<escapement_delta>(*delta); 1253 } else { 1254 escapement_delta emptyDelta = {0, 0}; 1255 link.Attach<escapement_delta>(emptyDelta); 1256 } 1257 1258 link.Attach<int32>(numChars); 1259 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1260 link.Attach<int32>(bytesInBuffer); 1261 link.Attach(charArray, bytesInBuffer); 1262 1263 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1264 return; 1265 1266 link.Read(boundingBoxArray, sizeof(BRect) * numChars); 1267 } 1268 1269 1270 void 1271 BFont::GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings, 1272 font_metric_mode mode, escapement_delta deltas[], 1273 BRect boundingBoxArray[]) const 1274 { 1275 if (!stringArray || numStrings < 1 || !boundingBoxArray) 1276 return; 1277 1278 int32 code; 1279 BPrivate::AppServerLink link; 1280 1281 link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS); 1282 link.Attach<uint16>(fFamilyID); 1283 link.Attach<uint16>(fStyleID); 1284 link.Attach<float>(fSize); 1285 link.Attach<float>(fRotation); 1286 link.Attach<float>(fShear); 1287 link.Attach<float>(fFalseBoldWidth); 1288 link.Attach<uint8>(fSpacing); 1289 link.Attach<uint32>(fFlags); 1290 link.Attach<font_metric_mode>(mode); 1291 link.Attach<int32>(numStrings); 1292 1293 if (deltas) { 1294 for (int32 i = 0; i < numStrings; i++) { 1295 link.AttachString(stringArray[i]); 1296 link.Attach<escapement_delta>(deltas[i]); 1297 } 1298 } else { 1299 escapement_delta emptyDelta = {0, 0}; 1300 1301 for (int32 i = 0; i < numStrings; i++) { 1302 link.AttachString(stringArray[i]); 1303 link.Attach<escapement_delta>(emptyDelta); 1304 } 1305 } 1306 1307 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1308 return; 1309 1310 link.Read(boundingBoxArray, sizeof(BRect) * numStrings); 1311 } 1312 1313 1314 void 1315 BFont::GetGlyphShapes(const char charArray[], int32 numChars, 1316 BShape* glyphShapeArray[]) const 1317 { 1318 // TODO: implement code specifically for passing BShapes to and 1319 // from the server 1320 if (!charArray || numChars < 1 || !glyphShapeArray) 1321 return; 1322 1323 int32 code; 1324 BPrivate::AppServerLink link; 1325 1326 link.StartMessage(AS_GET_GLYPH_SHAPES); 1327 link.Attach<uint16>(fFamilyID); 1328 link.Attach<uint16>(fStyleID); 1329 link.Attach<float>(fSize); 1330 link.Attach<float>(fShear); 1331 link.Attach<float>(fRotation); 1332 link.Attach<float>(fFalseBoldWidth); 1333 link.Attach<uint32>(fFlags); 1334 link.Attach<int32>(numChars); 1335 1336 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1337 link.Attach<int32>(bytesInBuffer); 1338 link.Attach(charArray, bytesInBuffer); 1339 1340 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1341 return; 1342 1343 for (int32 i = 0; i < numChars; i++) 1344 link.ReadShape(glyphShapeArray[i]); 1345 } 1346 1347 1348 void 1349 BFont::GetHasGlyphs(const char charArray[], int32 numChars, 1350 bool hasArray[]) const 1351 { 1352 GetHasGlyphs(charArray, numChars, hasArray, true); 1353 } 1354 1355 1356 void 1357 BFont::GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[], 1358 bool useFallbacks) const 1359 { 1360 if (!charArray || numChars < 1 || !hasArray) 1361 return; 1362 1363 int32 code; 1364 BPrivate::AppServerLink link; 1365 1366 link.StartMessage(AS_GET_HAS_GLYPHS); 1367 link.Attach<uint16>(fFamilyID); 1368 link.Attach<uint16>(fStyleID); 1369 link.Attach<int32>(numChars); 1370 1371 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1372 link.Attach<int32>(bytesInBuffer); 1373 link.Attach(charArray, bytesInBuffer); 1374 1375 link.Attach<bool>(useFallbacks); 1376 1377 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1378 return; 1379 1380 link.Read(hasArray, sizeof(bool) * numChars); 1381 } 1382 1383 1384 BFont& 1385 BFont::operator=(const BFont& font) 1386 { 1387 fFamilyID = font.fFamilyID; 1388 fStyleID = font.fStyleID; 1389 fSize = font.fSize; 1390 fShear = font.fShear; 1391 fRotation = font.fRotation; 1392 fFalseBoldWidth = font.fFalseBoldWidth; 1393 fSpacing = font.fSpacing; 1394 fEncoding = font.fEncoding; 1395 fFace = font.fFace; 1396 fHeight = font.fHeight; 1397 fFlags = font.fFlags; 1398 fExtraFlags = font.fExtraFlags; 1399 1400 return *this; 1401 } 1402 1403 1404 bool 1405 BFont::operator==(const BFont& font) const 1406 { 1407 return fFamilyID == font.fFamilyID 1408 && fStyleID == font.fStyleID 1409 && fSize == font.fSize 1410 && fShear == font.fShear 1411 && fRotation == font.fRotation 1412 && fFalseBoldWidth == font.fFalseBoldWidth 1413 && fSpacing == font.fSpacing 1414 && fEncoding == font.fEncoding 1415 && fFace == font.fFace; 1416 } 1417 1418 1419 bool 1420 BFont::operator!=(const BFont& font) const 1421 { 1422 return fFamilyID != font.fFamilyID 1423 || fStyleID != font.fStyleID 1424 || fSize != font.fSize 1425 || fShear != font.fShear 1426 || fRotation != font.fRotation 1427 || fFalseBoldWidth != font.fFalseBoldWidth 1428 || fSpacing != font.fSpacing 1429 || fEncoding != font.fEncoding 1430 || fFace != font.fFace; 1431 } 1432 1433 1434 void 1435 BFont::PrintToStream() const 1436 { 1437 font_family family; 1438 font_style style; 1439 GetFamilyAndStyle(&family, &style); 1440 1441 printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n", 1442 family, fFamilyID, style, fStyleID, fFace, fShear, fRotation, fSize, 1443 fHeight.ascent, fHeight.descent, fHeight.leading, fEncoding); 1444 } 1445 1446 1447 void 1448 BFont::_GetExtraFlags() const 1449 { 1450 // TODO: this has to be const in order to allow other font getters to 1451 // stay const as well 1452 if (fExtraFlags != kUninitializedExtraFlags) 1453 return; 1454 1455 BPrivate::AppServerLink link; 1456 link.StartMessage(AS_GET_EXTRA_FONT_FLAGS); 1457 link.Attach<uint16>(fFamilyID); 1458 link.Attach<uint16>(fStyleID); 1459 1460 status_t status = B_ERROR; 1461 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1462 // use defaut values for the flags 1463 fExtraFlags = (uint32)B_FONT_LEFT_TO_RIGHT 1464 << B_PRIVATE_FONT_DIRECTION_SHIFT; 1465 return; 1466 } 1467 1468 link.Read<uint32>(&fExtraFlags); 1469 } 1470 1471 1472 status_t 1473 BFont::LoadFont(const char* path) 1474 { 1475 return LoadFont(path, 0, 0); 1476 } 1477 1478 1479 status_t 1480 BFont::LoadFont(const char* path, uint16 index, uint16 instance) 1481 { 1482 BPrivate::AppServerLink link; 1483 link.StartMessage(AS_ADD_FONT_FILE); 1484 link.AttachString(path); 1485 link.Attach<uint16>(index); 1486 link.Attach<uint16>(instance); 1487 status_t status = B_ERROR; 1488 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1489 return status; 1490 } 1491 1492 link.Read<uint16>(&fFamilyID); 1493 link.Read<uint16>(&fStyleID); 1494 link.Read<uint16>(&fFace); 1495 fHeight.ascent = kUninitializedAscent; 1496 fExtraFlags = kUninitializedExtraFlags; 1497 1498 return B_OK; 1499 } 1500 1501 1502 status_t 1503 BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset) 1504 { 1505 return LoadFont(fontAreaID, size, offset, 0, 0); 1506 } 1507 1508 1509 status_t 1510 BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset, uint16 index, uint16 instance) 1511 { 1512 BPrivate::AppServerLink link; 1513 1514 link.StartMessage(AS_ADD_FONT_MEMORY); 1515 1516 link.Attach<int32>(fontAreaID); 1517 link.Attach<size_t>(size); 1518 link.Attach<size_t>(offset); 1519 link.Attach<uint16>(index); 1520 link.Attach<uint16>(instance); 1521 1522 status_t status = B_ERROR; 1523 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1524 return status; 1525 } 1526 1527 link.Read<uint16>(&fFamilyID); 1528 link.Read<uint16>(&fStyleID); 1529 link.Read<uint16>(&fFace); 1530 fHeight.ascent = kUninitializedAscent; 1531 fExtraFlags = kUninitializedExtraFlags; 1532 1533 return B_OK; 1534 } 1535 1536 1537 status_t 1538 BFont::UnloadFont() 1539 { 1540 BPrivate::AppServerLink link; 1541 1542 link.StartMessage(AS_REMOVE_FONT); 1543 1544 link.Attach<uint16>(fFamilyID); 1545 link.Attach<uint16>(fStyleID); 1546 1547 status_t status = B_ERROR; 1548 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1549 return status; 1550 } 1551 1552 // reset to plain font 1553 fFamilyID = sPlainFont.fFamilyID; 1554 fStyleID = sPlainFont.fStyleID; 1555 fFace = sPlainFont.fFace; 1556 fExtraFlags = sPlainFont.fExtraFlags; 1557 1558 fHeight.ascent = kUninitializedAscent; 1559 1560 return B_OK; 1561 } 1562