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