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