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