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