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