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