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