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 fHeight.ascent = kUninitializedAscent; 563 fExtraFlags = kUninitializedExtraFlags; 564 565 return B_OK; 566 } 567 568 569 // Sets the font's family and style all at once 570 void 571 BFont::SetFamilyAndStyle(uint32 code) 572 { 573 // R5 has a bug here: the face is not updated even though the IDs are set. 574 // This is a problem because the face flag includes Regular/Bold/Italic 575 // information in addition to stuff like underlining and strikethrough. 576 // As a result, this will need a trip to the server and, thus, be slower 577 // than R5's in order to be correct 578 579 uint16 family, style; 580 style = code & 0xFFFF; 581 family = (code & 0xFFFF0000) >> 16; 582 583 BPrivate::AppServerLink link; 584 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 585 link.AttachString(NULL); // no family and style name 586 link.AttachString(NULL); 587 link.Attach<uint16>(family); 588 link.Attach<uint16>(style); 589 link.Attach<uint16>(fFace); 590 591 int32 fontcode; 592 if (link.FlushWithReply(fontcode) != B_OK || fontcode != B_OK) 593 return; 594 595 link.Read<uint16>(&fFamilyID); 596 link.Read<uint16>(&fStyleID); 597 link.Read<uint16>(&fFace); 598 fHeight.ascent = kUninitializedAscent; 599 fExtraFlags = kUninitializedExtraFlags; 600 } 601 602 603 // Sets the font's family and face all at once 604 status_t 605 BFont::SetFamilyAndFace(const font_family family, uint16 face) 606 { 607 // To comply with the BeBook, this function will only set valid values 608 // i.e. passing a nonexistent family will cause only the face to be set. 609 // Additionally, if a particular face does not exist in a family, the 610 // closest match will be chosen. 611 612 BPrivate::AppServerLink link; 613 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS); 614 link.AttachString(family, sizeof(font_family)); 615 link.AttachString(NULL); // no style given 616 link.Attach<uint16>(fFamilyID); 617 link.Attach<uint16>(0xffff); 618 link.Attach<uint16>(face); 619 620 int32 status = B_ERROR; 621 if (link.FlushWithReply(status) != B_OK || status != B_OK) 622 return status; 623 624 link.Read<uint16>(&fFamilyID); 625 link.Read<uint16>(&fStyleID); 626 link.Read<uint16>(&fFace); 627 fHeight.ascent = kUninitializedAscent; 628 fExtraFlags = kUninitializedExtraFlags; 629 630 return B_OK; 631 } 632 633 634 void 635 BFont::SetSize(float size) 636 { 637 fSize = size; 638 fHeight.ascent = kUninitializedAscent; 639 } 640 641 642 void 643 BFont::SetShear(float shear) 644 { 645 fShear = shear; 646 fHeight.ascent = kUninitializedAscent; 647 } 648 649 650 void 651 BFont::SetRotation(float rotation) 652 { 653 fRotation = rotation; 654 fHeight.ascent = kUninitializedAscent; 655 } 656 657 658 void 659 BFont::SetFalseBoldWidth(float width) 660 { 661 fFalseBoldWidth = width; 662 } 663 664 665 void 666 BFont::SetSpacing(uint8 spacing) 667 { 668 fSpacing = spacing; 669 } 670 671 672 void 673 BFont::SetEncoding(uint8 encoding) 674 { 675 fEncoding = encoding; 676 } 677 678 679 void 680 BFont::SetFace(uint16 face) 681 { 682 if (face == fFace) 683 return; 684 685 SetFamilyAndFace(NULL, face); 686 } 687 688 689 void 690 BFont::SetFlags(uint32 flags) 691 { 692 fFlags = flags; 693 } 694 695 696 void 697 BFont::GetFamilyAndStyle(font_family* family, font_style* style) const 698 { 699 if (family == NULL && style == NULL) 700 return; 701 702 // it's okay to call this function with either family or style set to NULL 703 704 font_family familyBuffer; 705 font_style styleBuffer; 706 707 if (family == NULL) 708 family = &familyBuffer; 709 if (style == NULL) 710 style = &styleBuffer; 711 712 BPrivate::AppServerLink link; 713 link.StartMessage(AS_GET_FAMILY_AND_STYLE); 714 link.Attach<uint16>(fFamilyID); 715 link.Attach<uint16>(fStyleID); 716 717 int32 code; 718 if (link.FlushWithReply(code) != B_OK || code != B_OK) { 719 // the least we can do is to clear the buffers 720 memset(*family, 0, sizeof(font_family)); 721 memset(*style, 0, sizeof(font_style)); 722 return; 723 } 724 725 link.ReadString(*family, sizeof(font_family)); 726 link.ReadString(*style, sizeof(font_style)); 727 } 728 729 730 uint32 731 BFont::FamilyAndStyle() const 732 { 733 return (fFamilyID << 16UL) | fStyleID; 734 } 735 736 737 float 738 BFont::Size() const 739 { 740 return fSize; 741 } 742 743 744 float 745 BFont::Shear() const 746 { 747 return fShear; 748 } 749 750 751 float 752 BFont::Rotation() const 753 { 754 return fRotation; 755 } 756 757 758 float 759 BFont::FalseBoldWidth() const 760 { 761 return fFalseBoldWidth; 762 } 763 764 765 uint8 766 BFont::Spacing() const 767 { 768 return fSpacing; 769 } 770 771 772 uint8 773 BFont::Encoding() const 774 { 775 return fEncoding; 776 } 777 778 779 uint16 780 BFont::Face() const 781 { 782 return fFace; 783 } 784 785 786 uint32 787 BFont::Flags() const 788 { 789 return fFlags; 790 } 791 792 793 font_direction 794 BFont::Direction() const 795 { 796 _GetExtraFlags(); 797 return (font_direction)(fExtraFlags >> B_PRIVATE_FONT_DIRECTION_SHIFT); 798 } 799 800 801 bool 802 BFont::IsFixed() const 803 { 804 _GetExtraFlags(); 805 return (fExtraFlags & B_IS_FIXED) != 0; 806 } 807 808 809 // Returns whether or not the font is fixed-width and contains both 810 // full and half-width characters. 811 bool 812 BFont::IsFullAndHalfFixed() const 813 { 814 // This was left unimplemented as of R5. It is a way to work with both 815 // Kanji and Roman characters in the same fixed-width font. 816 817 _GetExtraFlags(); 818 return (fExtraFlags & B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED) != 0; 819 } 820 821 822 BRect 823 BFont::BoundingBox() const 824 { 825 BPrivate::AppServerLink link; 826 link.StartMessage(AS_GET_FONT_BOUNDING_BOX); 827 link.Attach<uint16>(fFamilyID); 828 link.Attach<uint16>(fStyleID); 829 link.Attach<float>(fSize); 830 831 int32 code; 832 if (link.FlushWithReply(code) != B_OK 833 || code != B_OK) 834 return BRect(0, 0, 0 ,0); 835 836 BRect box; 837 link.Read<BRect>(&box); 838 return box; 839 } 840 841 842 unicode_block 843 BFont::Blocks() const 844 { 845 BPrivate::AppServerLink link; 846 link.StartMessage(AS_GET_UNICODE_BLOCKS); 847 link.Attach<uint16>(fFamilyID); 848 link.Attach<uint16>(fStyleID); 849 850 int32 status; 851 if (link.FlushWithReply(status) != B_OK 852 || status != B_OK) { 853 return unicode_block(~0LL, ~0LL); 854 } 855 856 unicode_block blocksForFont; 857 link.Read<unicode_block>(&blocksForFont); 858 859 return blocksForFont; 860 } 861 862 bool 863 BFont::IncludesBlock(uint32 start, uint32 end) const 864 { 865 BPrivate::AppServerLink link; 866 link.StartMessage(AS_GET_HAS_UNICODE_BLOCK); 867 link.Attach<uint16>(fFamilyID); 868 link.Attach<uint16>(fStyleID); 869 link.Attach<uint32>(start); 870 link.Attach<uint32>(end); 871 872 int32 status; 873 if (link.FlushWithReply(status) != B_OK 874 || status != B_OK) { 875 return false; 876 } 877 878 bool hasBlock; 879 link.Read<bool>(&hasBlock); 880 881 return hasBlock; 882 } 883 884 885 font_file_format 886 BFont::FileFormat() const 887 { 888 BPrivate::AppServerLink link; 889 link.StartMessage(AS_GET_FONT_FILE_FORMAT); 890 link.Attach<uint16>(fFamilyID); 891 link.Attach<uint16>(fStyleID); 892 893 int32 status; 894 if (link.FlushWithReply(status) != B_OK 895 || status != B_OK) { 896 // just take a safe bet... 897 return B_TRUETYPE_WINDOWS; 898 } 899 900 uint16 format; 901 link.Read<uint16>(&format); 902 903 return (font_file_format)format; 904 } 905 906 907 int32 908 BFont::CountTuned() const 909 { 910 BPrivate::AppServerLink link; 911 link.StartMessage(AS_GET_TUNED_COUNT); 912 link.Attach<uint16>(fFamilyID); 913 link.Attach<uint16>(fStyleID); 914 915 int32 code; 916 if (link.FlushWithReply(code) != B_OK 917 || code != B_OK) 918 return -1; 919 920 int32 count; 921 link.Read<int32>(&count); 922 return count; 923 } 924 925 926 void 927 BFont::GetTunedInfo(int32 index, tuned_font_info* info) const 928 { 929 if (info == NULL) 930 return; 931 932 BPrivate::AppServerLink link; 933 link.StartMessage(AS_GET_TUNED_INFO); 934 link.Attach<uint16>(fFamilyID); 935 link.Attach<uint16>(fStyleID); 936 link.Attach<uint32>(index); 937 938 int32 code; 939 if (link.FlushWithReply(code) != B_OK || code != B_OK) 940 return; 941 942 link.Read<tuned_font_info>(info); 943 } 944 945 946 void 947 BFont::TruncateString(BString* inOut, uint32 mode, float width) const 948 { 949 if (mode == B_NO_TRUNCATION) 950 return; 951 952 // NOTE: Careful, we cannot directly use "inOut->String()" as result 953 // array, because the string length increases by 3 bytes in the worst 954 // case scenario. 955 const char* string = inOut->String(); 956 GetTruncatedStrings(&string, 1, mode, width, inOut); 957 } 958 959 960 void 961 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings, 962 uint32 mode, float width, BString resultArray[]) const 963 { 964 if (stringArray != NULL && numStrings > 0) { 965 // the width of the "…" glyph 966 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS); 967 968 for (int32 i = 0; i < numStrings; i++) { 969 resultArray[i] = stringArray[i]; 970 int32 numChars = resultArray[i].CountChars(); 971 972 // get the escapement of each glyph in font units 973 float* escapementArray = new float[numChars]; 974 GetEscapements(stringArray[i], numChars, NULL, escapementArray); 975 976 truncate_string(resultArray[i], mode, width, escapementArray, 977 fSize, ellipsisWidth, numChars); 978 979 delete[] escapementArray; 980 } 981 } 982 } 983 984 985 void 986 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings, 987 uint32 mode, float width, char* resultArray[]) const 988 { 989 if (stringArray != NULL && numStrings > 0) { 990 for (int32 i = 0; i < numStrings; i++) { 991 BString* strings = new BString[numStrings]; 992 GetTruncatedStrings(stringArray, numStrings, mode, width, strings); 993 994 for (int32 i = 0; i < numStrings; i++) 995 strcpy(resultArray[i], strings[i].String()); 996 997 delete[] strings; 998 } 999 } 1000 } 1001 1002 1003 float 1004 BFont::StringWidth(const char* string) const 1005 { 1006 if (string == NULL) 1007 return 0.0; 1008 1009 int32 length = strlen(string); 1010 float width; 1011 GetStringWidths(&string, &length, 1, &width); 1012 1013 return width; 1014 } 1015 1016 1017 float 1018 BFont::StringWidth(const char* string, int32 length) const 1019 { 1020 if (!string || length < 1) 1021 return 0.0f; 1022 1023 float width = 0.0f; 1024 GetStringWidths(&string, &length, 1, &width); 1025 1026 return width; 1027 } 1028 1029 1030 void 1031 BFont::GetStringWidths(const char* stringArray[], const int32 lengthArray[], 1032 int32 numStrings, float widthArray[]) const 1033 { 1034 if (stringArray == NULL || lengthArray == NULL || numStrings < 1 1035 || widthArray == NULL) { 1036 return; 1037 } 1038 1039 BPrivate::AppServerLink link; 1040 link.StartMessage(AS_GET_STRING_WIDTHS); 1041 link.Attach<uint16>(fFamilyID); 1042 link.Attach<uint16>(fStyleID); 1043 link.Attach<float>(fSize); 1044 link.Attach<uint8>(fSpacing); 1045 link.Attach<int32>(numStrings); 1046 1047 // TODO: all strings into a single array??? 1048 // we do have a maximum message length, and it could be easily touched 1049 // here... 1050 for (int32 i = 0; i < numStrings; i++) 1051 link.AttachString(stringArray[i], lengthArray[i]); 1052 1053 status_t status; 1054 if (link.FlushWithReply(status) != B_OK || status != B_OK) 1055 return; 1056 1057 link.Read(widthArray, sizeof(float) * numStrings); 1058 } 1059 1060 1061 void 1062 BFont::GetEscapements(const char charArray[], int32 numChars, 1063 float escapementArray[]) const 1064 { 1065 GetEscapements(charArray, numChars, NULL, escapementArray); 1066 } 1067 1068 1069 void 1070 BFont::GetEscapements(const char charArray[], int32 numChars, 1071 escapement_delta* delta, float escapementArray[]) const 1072 { 1073 if (charArray == NULL || numChars < 1 || escapementArray == NULL) 1074 return; 1075 1076 BPrivate::AppServerLink link; 1077 link.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS); 1078 link.Attach<uint16>(fFamilyID); 1079 link.Attach<uint16>(fStyleID); 1080 link.Attach<float>(fSize); 1081 link.Attach<uint8>(fSpacing); 1082 link.Attach<float>(fRotation); 1083 link.Attach<uint32>(fFlags); 1084 1085 link.Attach<float>(delta ? delta->nonspace : 0.0f); 1086 link.Attach<float>(delta ? delta->space : 0.0f); 1087 link.Attach<int32>(numChars); 1088 1089 // TODO: Should we not worry about the port capacity here?!? 1090 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1091 link.Attach<int32>(bytesInBuffer); 1092 link.Attach(charArray, bytesInBuffer); 1093 1094 int32 code; 1095 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1096 return; 1097 1098 link.Read(escapementArray, numChars * sizeof(float)); 1099 } 1100 1101 1102 void 1103 BFont::GetEscapements(const char charArray[], int32 numChars, 1104 escapement_delta* delta, BPoint escapementArray[]) const 1105 { 1106 GetEscapements(charArray, numChars, delta, escapementArray, NULL); 1107 } 1108 1109 1110 void 1111 BFont::GetEscapements(const char charArray[], int32 numChars, 1112 escapement_delta* delta, BPoint escapementArray[], 1113 BPoint offsetArray[]) const 1114 { 1115 if (charArray == NULL || numChars < 1 || escapementArray == NULL) 1116 return; 1117 1118 BPrivate::AppServerLink link; 1119 link.StartMessage(AS_GET_ESCAPEMENTS); 1120 link.Attach<uint16>(fFamilyID); 1121 link.Attach<uint16>(fStyleID); 1122 link.Attach<float>(fSize); 1123 link.Attach<uint8>(fSpacing); 1124 link.Attach<float>(fRotation); 1125 link.Attach<uint32>(fFlags); 1126 1127 link.Attach<float>(delta ? delta->nonspace : 0.0); 1128 link.Attach<float>(delta ? delta->space : 0.0); 1129 link.Attach<bool>(offsetArray != NULL); 1130 link.Attach<int32>(numChars); 1131 1132 // TODO: Should we not worry about the port capacity here?!? 1133 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1134 link.Attach<int32>(bytesInBuffer); 1135 link.Attach(charArray, bytesInBuffer); 1136 1137 int32 code; 1138 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1139 return; 1140 1141 link.Read(escapementArray, sizeof(BPoint) * numChars); 1142 if (offsetArray) 1143 link.Read(offsetArray, sizeof(BPoint) * numChars); 1144 } 1145 1146 1147 void 1148 BFont::GetEdges(const char charArray[], int32 numChars, 1149 edge_info edgeArray[]) const 1150 { 1151 if (!charArray || numChars < 1 || !edgeArray) 1152 return; 1153 1154 int32 code; 1155 BPrivate::AppServerLink link; 1156 1157 link.StartMessage(AS_GET_EDGES); 1158 link.Attach<uint16>(fFamilyID); 1159 link.Attach<uint16>(fStyleID); 1160 link.Attach<int32>(numChars); 1161 1162 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1163 link.Attach<int32>(bytesInBuffer); 1164 link.Attach(charArray, bytesInBuffer); 1165 1166 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1167 return; 1168 1169 link.Read(edgeArray, sizeof(edge_info) * numChars); 1170 } 1171 1172 1173 void 1174 BFont::GetHeight(font_height* _height) const 1175 { 1176 if (_height == NULL) 1177 return; 1178 1179 if (fHeight.ascent == kUninitializedAscent) { 1180 // we don't have the font height cached yet 1181 BPrivate::AppServerLink link; 1182 1183 link.StartMessage(AS_GET_FONT_HEIGHT); 1184 link.Attach<uint16>(fFamilyID); 1185 link.Attach<uint16>(fStyleID); 1186 link.Attach<float>(fSize); 1187 1188 int32 code; 1189 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1190 return; 1191 1192 // Who put that "const" to this method? :-) 1193 // We made fHeight mutable for this, but we should drop the "const" 1194 // when we can 1195 link.Read<font_height>(&fHeight); 1196 } 1197 1198 *_height = fHeight; 1199 } 1200 1201 1202 void 1203 BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, 1204 font_metric_mode mode, BRect boundingBoxArray[]) const 1205 { 1206 _GetBoundingBoxes(charArray, numChars, mode, false, NULL, 1207 boundingBoxArray, false); 1208 } 1209 1210 1211 void 1212 BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars, 1213 font_metric_mode mode, escapement_delta* delta, 1214 BRect boundingBoxArray[]) const 1215 { 1216 _GetBoundingBoxes(charArray, numChars, mode, true, delta, 1217 boundingBoxArray, true); 1218 } 1219 1220 1221 void 1222 BFont::_GetBoundingBoxes(const char charArray[], int32 numChars, 1223 font_metric_mode mode, bool string_escapement, escapement_delta* delta, 1224 BRect boundingBoxArray[], bool asString) const 1225 { 1226 if (charArray == NULL || numChars < 1 || boundingBoxArray == NULL) 1227 return; 1228 1229 int32 code; 1230 BPrivate::AppServerLink link; 1231 1232 link.StartMessage(asString 1233 ? AS_GET_BOUNDINGBOXES_STRING : AS_GET_BOUNDINGBOXES_CHARS); 1234 link.Attach<uint16>(fFamilyID); 1235 link.Attach<uint16>(fStyleID); 1236 link.Attach<float>(fSize); 1237 link.Attach<float>(fRotation); 1238 link.Attach<float>(fShear); 1239 link.Attach<float>(fFalseBoldWidth); 1240 link.Attach<uint8>(fSpacing); 1241 1242 link.Attach<uint32>(fFlags); 1243 link.Attach<font_metric_mode>(mode); 1244 link.Attach<bool>(string_escapement); 1245 1246 if (delta != NULL) { 1247 link.Attach<escapement_delta>(*delta); 1248 } else { 1249 escapement_delta emptyDelta = {0, 0}; 1250 link.Attach<escapement_delta>(emptyDelta); 1251 } 1252 1253 link.Attach<int32>(numChars); 1254 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1255 link.Attach<int32>(bytesInBuffer); 1256 link.Attach(charArray, bytesInBuffer); 1257 1258 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1259 return; 1260 1261 link.Read(boundingBoxArray, sizeof(BRect) * numChars); 1262 } 1263 1264 1265 void 1266 BFont::GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings, 1267 font_metric_mode mode, escapement_delta deltas[], 1268 BRect boundingBoxArray[]) const 1269 { 1270 if (!stringArray || numStrings < 1 || !boundingBoxArray) 1271 return; 1272 1273 int32 code; 1274 BPrivate::AppServerLink link; 1275 1276 link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS); 1277 link.Attach<uint16>(fFamilyID); 1278 link.Attach<uint16>(fStyleID); 1279 link.Attach<float>(fSize); 1280 link.Attach<float>(fRotation); 1281 link.Attach<float>(fShear); 1282 link.Attach<float>(fFalseBoldWidth); 1283 link.Attach<uint8>(fSpacing); 1284 link.Attach<uint32>(fFlags); 1285 link.Attach<font_metric_mode>(mode); 1286 link.Attach<int32>(numStrings); 1287 1288 if (deltas) { 1289 for (int32 i = 0; i < numStrings; i++) { 1290 link.AttachString(stringArray[i]); 1291 link.Attach<escapement_delta>(deltas[i]); 1292 } 1293 } else { 1294 escapement_delta emptyDelta = {0, 0}; 1295 1296 for (int32 i = 0; i < numStrings; i++) { 1297 link.AttachString(stringArray[i]); 1298 link.Attach<escapement_delta>(emptyDelta); 1299 } 1300 } 1301 1302 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1303 return; 1304 1305 link.Read(boundingBoxArray, sizeof(BRect) * numStrings); 1306 } 1307 1308 1309 void 1310 BFont::GetGlyphShapes(const char charArray[], int32 numChars, 1311 BShape* glyphShapeArray[]) const 1312 { 1313 // TODO: implement code specifically for passing BShapes to and 1314 // from the server 1315 if (!charArray || numChars < 1 || !glyphShapeArray) 1316 return; 1317 1318 int32 code; 1319 BPrivate::AppServerLink link; 1320 1321 link.StartMessage(AS_GET_GLYPH_SHAPES); 1322 link.Attach<uint16>(fFamilyID); 1323 link.Attach<uint16>(fStyleID); 1324 link.Attach<float>(fSize); 1325 link.Attach<float>(fShear); 1326 link.Attach<float>(fRotation); 1327 link.Attach<float>(fFalseBoldWidth); 1328 link.Attach<uint32>(fFlags); 1329 link.Attach<int32>(numChars); 1330 1331 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1332 link.Attach<int32>(bytesInBuffer); 1333 link.Attach(charArray, bytesInBuffer); 1334 1335 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1336 return; 1337 1338 for (int32 i = 0; i < numChars; i++) 1339 link.ReadShape(glyphShapeArray[i]); 1340 } 1341 1342 1343 void 1344 BFont::GetHasGlyphs(const char charArray[], int32 numChars, 1345 bool hasArray[]) const 1346 { 1347 if (!charArray || numChars < 1 || !hasArray) 1348 return; 1349 1350 int32 code; 1351 BPrivate::AppServerLink link; 1352 1353 link.StartMessage(AS_GET_HAS_GLYPHS); 1354 link.Attach<uint16>(fFamilyID); 1355 link.Attach<uint16>(fStyleID); 1356 link.Attach<int32>(numChars); 1357 1358 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars); 1359 link.Attach<int32>(bytesInBuffer); 1360 link.Attach(charArray, bytesInBuffer); 1361 1362 if (link.FlushWithReply(code) != B_OK || code != B_OK) 1363 return; 1364 1365 link.Read(hasArray, sizeof(bool) * numChars); 1366 } 1367 1368 1369 BFont& 1370 BFont::operator=(const BFont& font) 1371 { 1372 fFamilyID = font.fFamilyID; 1373 fStyleID = font.fStyleID; 1374 fSize = font.fSize; 1375 fShear = font.fShear; 1376 fRotation = font.fRotation; 1377 fFalseBoldWidth = font.fFalseBoldWidth; 1378 fSpacing = font.fSpacing; 1379 fEncoding = font.fEncoding; 1380 fFace = font.fFace; 1381 fHeight = font.fHeight; 1382 fFlags = font.fFlags; 1383 fExtraFlags = font.fExtraFlags; 1384 1385 return *this; 1386 } 1387 1388 1389 bool 1390 BFont::operator==(const BFont& font) const 1391 { 1392 return fFamilyID == font.fFamilyID 1393 && fStyleID == font.fStyleID 1394 && fSize == font.fSize 1395 && fShear == font.fShear 1396 && fRotation == font.fRotation 1397 && fFalseBoldWidth == font.fFalseBoldWidth 1398 && fSpacing == font.fSpacing 1399 && fEncoding == font.fEncoding 1400 && fFace == font.fFace; 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 void 1420 BFont::PrintToStream() const 1421 { 1422 font_family family; 1423 font_style style; 1424 GetFamilyAndStyle(&family, &style); 1425 1426 printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n", 1427 family, fFamilyID, style, fStyleID, fFace, fShear, fRotation, fSize, 1428 fHeight.ascent, fHeight.descent, fHeight.leading, fEncoding); 1429 } 1430 1431 1432 void 1433 BFont::_GetExtraFlags() const 1434 { 1435 // TODO: this has to be const in order to allow other font getters to 1436 // stay const as well 1437 if (fExtraFlags != kUninitializedExtraFlags) 1438 return; 1439 1440 BPrivate::AppServerLink link; 1441 link.StartMessage(AS_GET_EXTRA_FONT_FLAGS); 1442 link.Attach<uint16>(fFamilyID); 1443 link.Attach<uint16>(fStyleID); 1444 1445 status_t status = B_ERROR; 1446 if (link.FlushWithReply(status) != B_OK || status != B_OK) { 1447 // use defaut values for the flags 1448 fExtraFlags = (uint32)B_FONT_LEFT_TO_RIGHT 1449 << B_PRIVATE_FONT_DIRECTION_SHIFT; 1450 return; 1451 } 1452 1453 link.Read<uint32>(&fExtraFlags); 1454 } 1455