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