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