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