1 /* 2 * Copyright 2001-2016, 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 * Michael Lotz <mmlr@mlotz.ch> 9 * Stephan Aßmus <superstippi@gmx.de> 10 */ 11 12 13 #include "ServerFont.h" 14 15 #include "Angle.h" 16 #include "GlyphLayoutEngine.h" 17 #include "FontManager.h" 18 #include "truncate_string.h" 19 #include "utf8_functions.h" 20 21 #include FT_FREETYPE_H 22 #include FT_GLYPH_H 23 #include FT_OUTLINE_H 24 25 #ifdef FONTCONFIG_ENABLED 26 27 #include <fontconfig.h> 28 #include <fcfreetype.h> 29 30 #endif // FONTCONFIG_ENABLED 31 32 #include <Shape.h> 33 #include <String.h> 34 #include <UnicodeBlockObjects.h> 35 #include <UTF8.h> 36 37 #include <agg_bounding_rect.h> 38 39 #include <stdio.h> 40 #include <string.h> 41 42 43 // functions needed to convert a freetype vector graphics to a BShape 44 inline BPoint 45 VectorToPoint(const FT_Vector *vector) 46 { 47 BPoint result; 48 result.x = float(vector->x) / 64; 49 result.y = -float(vector->y) / 64; 50 return result; 51 } 52 53 54 int 55 MoveToFunc(const FT_Vector *to, void *user) 56 { 57 ((BShape *)user)->MoveTo(VectorToPoint(to)); 58 return 0; 59 } 60 61 62 int 63 LineToFunc(const FT_Vector *to, void *user) 64 { 65 ((BShape *)user)->LineTo(VectorToPoint(to)); 66 return 0; 67 } 68 69 70 int 71 ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user) 72 { 73 BPoint controls[3]; 74 75 controls[0] = VectorToPoint(control); 76 controls[1] = VectorToPoint(to); 77 controls[2] = controls[1]; 78 79 ((BShape *)user)->BezierTo(controls); 80 return 0; 81 } 82 83 84 int 85 CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) 86 { 87 BPoint controls[3]; 88 89 controls[0] = VectorToPoint(control1); 90 controls[1] = VectorToPoint(control2); 91 controls[2] = VectorToPoint(to); 92 93 ((BShape *)user)->BezierTo(controls); 94 return 0; 95 } 96 97 98 inline bool 99 is_white_space(uint32 charCode) 100 { 101 switch (charCode) { 102 case 0x0009: /* tab */ 103 case 0x000b: /* vertical tab */ 104 case 0x000c: /* form feed */ 105 case 0x0020: /* space */ 106 case 0x00a0: /* non breaking space */ 107 case 0x000a: /* line feed */ 108 case 0x000d: /* carriage return */ 109 case 0x2028: /* line separator */ 110 case 0x2029: /* paragraph separator */ 111 return true; 112 } 113 114 return false; 115 } 116 117 118 // #pragma mark - 119 120 121 /*! 122 \brief Constructor 123 \param style Style object to which the ServerFont belongs 124 \param size Character size in points 125 \param rotation Rotation in degrees 126 \param shear Shear (slant) in degrees. 45 <= shear <= 135 127 \param flags Style flags as defined in <Font.h> 128 \param spacing String spacing flag as defined in <Font.h> 129 */ 130 ServerFont::ServerFont(FontStyle& style, float size, float rotation, 131 float shear, float falseBoldWidth, uint16 flags, uint8 spacing) 132 : 133 fStyle(&style), 134 fSize(size), 135 fRotation(rotation), 136 fShear(shear), 137 fFalseBoldWidth(falseBoldWidth), 138 fBounds(0, 0, 0, 0), 139 fFlags(flags), 140 fSpacing(spacing), 141 fDirection(style.Direction()), 142 fFace(style.Face()), 143 fEncoding(B_UNICODE_UTF8) 144 { 145 fStyle->Acquire(); 146 } 147 148 149 ServerFont::ServerFont() 150 : 151 fStyle(NULL) 152 { 153 *this = *gFontManager->DefaultPlainFont(); 154 } 155 156 157 /*! 158 \brief Copy Constructor 159 \param font ServerFont to copy 160 */ 161 ServerFont::ServerFont(const ServerFont &font) 162 : 163 fStyle(NULL) 164 { 165 *this = font; 166 } 167 168 169 /*! 170 \brief Removes itself as a dependency of its owning style. 171 */ 172 ServerFont::~ServerFont() 173 { 174 fStyle->Release(); 175 } 176 177 178 /*! 179 \brief Returns a copy of the specified font 180 \param The font to copy from. 181 \return A copy of the specified font 182 */ 183 ServerFont& 184 ServerFont::operator=(const ServerFont& font) 185 { 186 fSize = font.fSize; 187 fRotation = font.fRotation; 188 fShear = font.fShear; 189 fFalseBoldWidth = font.fFalseBoldWidth; 190 fFlags = font.fFlags; 191 fSpacing = font.fSpacing; 192 fEncoding = font.fEncoding; 193 fBounds = font.fBounds; 194 195 SetStyle(font.fStyle); 196 197 return *this; 198 } 199 200 201 bool 202 ServerFont::operator==(const ServerFont& other) const 203 { 204 if (GetFamilyAndStyle() != other.GetFamilyAndStyle()) 205 return false; 206 207 return fSize == other.fSize && fRotation == other.fRotation 208 && fShear == other.fShear && fFalseBoldWidth == other.fFalseBoldWidth 209 && fFlags == other.fFlags && fSpacing == other.fSpacing 210 && fEncoding == other.fEncoding && fBounds == other.fBounds 211 && fDirection == other.fDirection && fFace == other.fFace; 212 } 213 214 215 /*! 216 \brief Returns the number of strikes in the font 217 \return The number of strikes in the font 218 */ 219 int32 220 ServerFont::CountTuned() 221 { 222 return fStyle->TunedCount(); 223 } 224 225 226 /*! 227 \brief Returns the file format of the font. 228 \return Mostly B_TRUETYPE_WINDOWS :) 229 */ 230 font_file_format 231 ServerFont::FileFormat() 232 { 233 return fStyle->FileFormat(); 234 } 235 236 237 const char* 238 ServerFont::Style() const 239 { 240 return fStyle->Name(); 241 } 242 243 244 const char* 245 ServerFont::Family() const 246 { 247 return fStyle->Family()->Name(); 248 } 249 250 251 void 252 ServerFont::SetStyle(FontStyle* style) 253 { 254 if (style && style != fStyle) { 255 // detach from old style 256 if (fStyle != NULL) 257 fStyle->Release(); 258 259 // attach to new style 260 fStyle = style; 261 262 fStyle->Acquire(); 263 264 fFace = fStyle->Face(); 265 fDirection = fStyle->Direction(); 266 } 267 } 268 269 270 /*! 271 \brief Sets the ServerFont instance to whatever font is specified 272 This method will lock the font manager. 273 274 \param familyID ID number of the family to set 275 \param styleID ID number of the style to set 276 \return B_OK if successful, B_ERROR if not 277 */ 278 status_t 279 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID) 280 { 281 FontStyle* style = NULL; 282 283 if (gFontManager->Lock()) { 284 style = gFontManager->GetStyle(familyID, styleID); 285 if (style != NULL) 286 style->Acquire(); 287 288 gFontManager->Unlock(); 289 } 290 291 if (style == NULL) 292 return B_ERROR; 293 294 SetStyle(style); 295 style->Release(); 296 297 return B_OK; 298 } 299 300 301 /*! 302 \brief Sets the ServerFont instance to whatever font is specified 303 \param fontID the combination of family and style ID numbers 304 \return B_OK if successful, B_ERROR if not 305 */ 306 status_t 307 ServerFont::SetFamilyAndStyle(uint32 fontID) 308 { 309 uint16 style = fontID & 0xFFFF; 310 uint16 family = (fontID & 0xFFFF0000) >> 16; 311 312 return SetFamilyAndStyle(family, style); 313 } 314 315 316 status_t 317 ServerFont::SetFace(uint16 face) 318 { 319 // TODO: This needs further investigation. The face variable is actually 320 // flags, but some of them are not enforcable at the same time. Also don't 321 // confuse the Be API "face" with the Freetype face, which is just an 322 // index in case a single font file exports multiple font faces. The 323 // FontStyle class takes care of mapping the font style name to the Be 324 // API face flags in FontStyle::_TranslateStyleToFace(). 325 326 FontStyle* style = NULL; 327 uint16 familyID = FamilyID(); 328 if (gFontManager->Lock()) { 329 int32 count = gFontManager->CountStyles(familyID); 330 for (int32 i = 0; i < count; i++) { 331 style = gFontManager->GetStyleByIndex(familyID, i); 332 if (style == NULL) 333 break; 334 if (style->Face() == face) { 335 style->Acquire(); 336 break; 337 } else 338 style = NULL; 339 } 340 341 gFontManager->Unlock(); 342 } 343 344 if (!style) 345 return B_ERROR; 346 347 SetStyle(style); 348 style->Release(); 349 350 return B_OK; 351 } 352 353 354 /*! 355 \brief Gets the ID values for the ServerFont instance in one shot 356 \return the combination of family and style ID numbers 357 */ 358 uint32 359 ServerFont::GetFamilyAndStyle() const 360 { 361 return (FamilyID() << 16) | StyleID(); 362 } 363 364 365 FT_Face 366 ServerFont::GetTransformedFace(bool rotate, bool shear) const 367 { 368 fStyle->Lock(); 369 FT_Face face = fStyle->FreeTypeFace(); 370 if (!face) { 371 fStyle->Unlock(); 372 return NULL; 373 } 374 375 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72); 376 377 if ((rotate && fRotation != 0) || (shear && fShear != 90)) { 378 FT_Matrix rmatrix, smatrix; 379 380 Angle rotationAngle(fRotation); 381 rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000); 382 rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000); 383 rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000); 384 rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000); 385 386 Angle shearAngle(fShear); 387 smatrix.xx = (FT_Fixed)(0x10000); 388 smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000); 389 smatrix.yx = (FT_Fixed)(0); 390 smatrix.yy = (FT_Fixed)(0x10000); 391 392 // Multiply togheter and apply transform 393 FT_Matrix_Multiply(&rmatrix, &smatrix); 394 FT_Set_Transform(face, &smatrix, NULL); 395 } 396 397 // fStyle will be unlocked in PutTransformedFace() 398 return face; 399 } 400 401 402 void 403 ServerFont::PutTransformedFace(FT_Face face) const 404 { 405 // Reset transformation 406 FT_Set_Transform(face, NULL, NULL); 407 fStyle->Unlock(); 408 } 409 410 411 status_t 412 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars, 413 BShape* shapeArray[]) const 414 { 415 if (!charArray || numChars <= 0 || !shapeArray) 416 return B_BAD_DATA; 417 418 FT_Face face = GetTransformedFace(true, true); 419 if (!face) 420 return B_ERROR; 421 422 FT_Outline_Funcs funcs; 423 funcs.move_to = MoveToFunc; 424 funcs.line_to = LineToFunc; 425 funcs.conic_to = ConicToFunc; 426 funcs.cubic_to = CubicToFunc; 427 funcs.shift = 0; 428 funcs.delta = 0; 429 430 const char* string = charArray; 431 for (int i = 0; i < numChars; i++) { 432 shapeArray[i] = new (std::nothrow) BShape(); 433 if (shapeArray[i] == NULL) { 434 PutTransformedFace(face); 435 return B_NO_MEMORY; 436 } 437 FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 438 FT_Outline outline = face->glyph->outline; 439 FT_Outline_Decompose(&outline, &funcs, shapeArray[i]); 440 shapeArray[i]->Close(); 441 } 442 443 PutTransformedFace(face); 444 return B_OK; 445 } 446 447 448 #ifdef FONTCONFIG_ENABLED 449 450 /*! 451 \brief For a given codepoint, do a binary search of the defined unicode 452 blocks to figure out which one contains the codepoint. 453 \param codePoint is the point to find 454 \param startGuess is the starting point for the binary search (default 0) 455 */ 456 static 457 int32 458 FindBlockForCodepoint(uint32 codePoint, uint32 startGuess) 459 { 460 uint32 min = 0; 461 uint32 max = kNumUnicodeBlockRanges; 462 uint32 guess = (max + min) / 2; 463 464 if (startGuess > 0) 465 guess = startGuess; 466 467 if (codePoint > kUnicodeBlockMap[max-1].end) 468 return -1; 469 470 while ((max >= min) && (guess < kNumUnicodeBlockRanges)) { 471 uint32 start = kUnicodeBlockMap[guess].start; 472 uint32 end = kUnicodeBlockMap[guess].end; 473 474 if (start <= codePoint && end >= codePoint) 475 return guess; 476 477 if (end < codePoint) { 478 min = guess + 1; 479 } else { 480 max = guess - 1; 481 } 482 483 guess = (max + min) / 2; 484 } 485 486 return -1; 487 } 488 489 /*! 490 \brief parses charmap from fontconfig. See fontconfig docs for FcCharSetFirstPage 491 and FcCharSetNextPage for details on format. 492 \param charMap is a fontconfig character map 493 \param baseCodePoint is the base codepoint returned by fontconfig 494 \param blocksForMap is a unicode_block to store the bitmap of contained blocks 495 */ 496 static 497 void 498 ParseFcMap(FcChar32 charMap[], FcChar32 baseCodePoint, unicode_block& blocksForMap) 499 { 500 uint32 block = 0; 501 const uint8 BITS_PER_BLOCK = 32; 502 uint32 currentCodePoint = 0; 503 504 if (baseCodePoint > kUnicodeBlockMap[kNumUnicodeBlockRanges-1].end) 505 return; 506 507 for (int i = 0; i < FC_CHARSET_MAP_SIZE; ++i) { 508 FcChar32 curMapBlock = charMap[i]; 509 int32 rangeStart = -1; 510 int32 startBlock = -1; 511 int32 endBlock = -1; 512 uint32 startPoint = 0; 513 514 currentCodePoint = baseCodePoint + block; 515 516 for (int bit = 0; bit < BITS_PER_BLOCK; ++bit) { 517 if (curMapBlock == 0 && startBlock < 0) 518 // if no more bits are set then short-circuit the loop 519 break; 520 521 if ((curMapBlock & 0x1) != 0 && rangeStart < 0) { 522 rangeStart = bit; 523 startPoint = currentCodePoint + rangeStart; 524 startBlock = FindBlockForCodepoint(startPoint, 0); 525 if (startBlock >= 0) { 526 blocksForMap = blocksForMap 527 | kUnicodeBlockMap[startBlock].block; 528 } 529 } else if (rangeStart >= 0 && startBlock >= 0) { 530 // when we find an empty bit, that's the end of the range 531 uint32 endPoint = currentCodePoint + (bit - 1); 532 533 endBlock = FindBlockForCodepoint(endPoint, 534 startBlock); 535 // start the binary search at the block where we found the 536 // start codepoint to ideally find the end in the same 537 // block. 538 ++startBlock; 539 540 while (startBlock <= endBlock) { 541 // if the starting codepoint is found in a different block 542 // than the ending codepoint, we should add all the blocks 543 // inbetween. 544 blocksForMap = blocksForMap 545 | kUnicodeBlockMap[startBlock].block; 546 ++startBlock; 547 } 548 549 startBlock = -1; 550 endBlock = -1; 551 rangeStart = -1; 552 } 553 554 curMapBlock >>= 1; 555 } 556 557 if (rangeStart >= 0 && startBlock >= 0) { 558 // if we hit the end of the block and had 559 // found a start of the range then we 560 // should end the range at the end of the block 561 uint32 endPoint = currentCodePoint + BITS_PER_BLOCK - 1; 562 563 endBlock = FindBlockForCodepoint(endPoint, 564 startBlock); 565 // start the binary search at the block where we found the 566 // start codepoint to ideally find the end in the same 567 // block. 568 ++startBlock; 569 570 while (startBlock <= endBlock) { 571 // if the starting codepoint is found in a different block 572 // than the ending codepoint, we should add all the blocks 573 // inbetween. 574 blocksForMap = blocksForMap 575 | kUnicodeBlockMap[startBlock].block; 576 ++startBlock; 577 } 578 } 579 580 block += BITS_PER_BLOCK; 581 } 582 } 583 584 #endif // FONTCONFIG_ENABLED 585 586 587 /*! 588 \brief Gets a bitmap that indicates which Unicode blocks are in the font. 589 \param unicode_block to store bitmap in 590 \return B_OK; bitmap will be empty if something went wrong 591 */ 592 status_t 593 ServerFont::GetUnicodeBlocks(unicode_block& blocksForFont) 594 { 595 blocksForFont = unicode_block(); 596 597 #ifdef FONTCONFIG_ENABLED 598 FT_Face face = GetTransformedFace(true, true); 599 if (face == NULL) 600 return B_ERROR; 601 602 FcCharSet *charSet = FcFreeTypeCharSet(face, NULL); 603 if (charSet == NULL) { 604 PutTransformedFace(face); 605 return B_ERROR; 606 } 607 608 FcChar32 charMap[FC_CHARSET_MAP_SIZE]; 609 FcChar32 next = 0; 610 FcChar32 baseCodePoint = FcCharSetFirstPage(charSet, charMap, &next); 611 612 while ((baseCodePoint != FC_CHARSET_DONE) && (next != FC_CHARSET_DONE)) { 613 ParseFcMap(charMap, baseCodePoint, blocksForFont); 614 baseCodePoint = FcCharSetNextPage(charSet, charMap, &next); 615 } 616 617 FcCharSetDestroy(charSet); 618 PutTransformedFace(face); 619 #endif // FONTCONFIG_ENABLED 620 621 return B_OK; 622 } 623 624 /*! 625 \brief Checks if a unicode block specified by a start and end point is defined 626 in the current font 627 \param start of unicode block 628 \param end of unicode block 629 \param hasBlock boolean to store whether the font contains the specified block 630 \return B_OK; hasBlock will be false if something goes wrong 631 */ 632 status_t 633 ServerFont::IncludesUnicodeBlock(uint32 start, uint32 end, bool& hasBlock) 634 { 635 hasBlock = false; 636 637 #ifdef FONTCONFIG_ENABLED 638 FT_Face face = GetTransformedFace(true, true); 639 if (face == NULL) 640 return B_ERROR; 641 642 FcCharSet *charSet = FcFreeTypeCharSet(face, NULL); 643 if (charSet == NULL) { 644 PutTransformedFace(face); 645 return B_ERROR; 646 } 647 648 uint32 curCodePoint = start; 649 650 while (curCodePoint <= end && hasBlock == false) { 651 // loop through range; if any character in the range is in the charset 652 // then the block is represented. 653 if (FcCharSetHasChar(charSet, (FcChar32)curCodePoint) == FcTrue) { 654 hasBlock = true; 655 break; 656 } 657 658 ++curCodePoint; 659 } 660 661 FcCharSetDestroy(charSet); 662 PutTransformedFace(face); 663 #endif // FONTCONFIG_ENABLED 664 665 return B_OK; 666 } 667 668 669 class HasGlyphsConsumer { 670 public: 671 HasGlyphsConsumer(bool* hasArray) 672 : 673 fHasArray(hasArray) 674 { 675 } 676 677 bool NeedsVector() { return false; } 678 void Start() {} 679 void Finish(double x, double y) {} 680 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 681 { 682 fHasArray[index] = false; 683 } 684 685 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 686 FontCacheEntry* entry, double x, double y, double advanceX, 687 double advanceY) 688 { 689 fHasArray[index] = glyph->glyph_index != 0; 690 return true; 691 } 692 693 private: 694 bool* fHasArray; 695 }; 696 697 698 status_t 699 ServerFont::GetHasGlyphs(const char* string, int32 numBytes, int32 numChars, 700 bool* hasArray) const 701 { 702 if (string == NULL || numBytes <= 0 || numChars <= 0 || hasArray == NULL) 703 return B_BAD_DATA; 704 705 HasGlyphsConsumer consumer(hasArray); 706 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 707 numChars, NULL, fSpacing)) { 708 return B_OK; 709 } 710 711 return B_ERROR; 712 } 713 714 715 class EdgesConsumer { 716 public: 717 EdgesConsumer(edge_info* edges, float size) 718 : 719 fEdges(edges), 720 fSize(size) 721 { 722 } 723 724 bool NeedsVector() { return false; } 725 void Start() {} 726 void Finish(double x, double y) {} 727 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 728 { 729 fEdges[index].left = 0.0; 730 fEdges[index].right = 0.0; 731 } 732 733 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 734 FontCacheEntry* entry, double x, double y, double advanceX, 735 double advanceY) 736 { 737 fEdges[index].left = glyph->inset_left / fSize; 738 fEdges[index].right = glyph->inset_right / fSize; 739 return true; 740 } 741 742 private: 743 edge_info* fEdges; 744 float fSize; 745 }; 746 747 748 status_t 749 ServerFont::GetEdges(const char* string, int32 numBytes, int32 numChars, 750 edge_info* edges) const 751 { 752 if (string == NULL || numBytes <= 0 || numChars <= 0 || edges == NULL) 753 return B_BAD_DATA; 754 755 EdgesConsumer consumer(edges, fSize); 756 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 757 numChars, NULL, fSpacing)) { 758 return B_OK; 759 } 760 761 return B_ERROR; 762 763 // FT_Face face = GetTransformedFace(false, false); 764 // if (!face) 765 // return B_ERROR; 766 // 767 // const char *string = charArray; 768 // for (int i = 0; i < numChars; i++) { 769 // FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 770 // edgeArray[i].left = float(face->glyph->metrics.horiBearingX) 771 // / 64 / fSize; 772 // edgeArray[i].right = float(face->glyph->metrics.horiBearingX 773 // + face->glyph->metrics.width - face->glyph->metrics.horiAdvance) 774 // / 64 / fSize; 775 // } 776 // 777 // PutTransformedFace(face); 778 // return B_OK; 779 } 780 781 782 class BPointEscapementConsumer { 783 public: 784 BPointEscapementConsumer(BPoint* escapements, BPoint* offsets, float size) 785 : 786 fEscapements(escapements), 787 fOffsets(offsets), 788 fSize(size) 789 { 790 } 791 792 bool NeedsVector() { return false; } 793 void Start() {} 794 void Finish(double x, double y) {} 795 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 796 { 797 _Set(index, 0, 0); 798 } 799 800 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 801 FontCacheEntry* entry, double x, double y, double advanceX, 802 double advanceY) 803 { 804 return _Set(index, advanceX, advanceY); 805 } 806 807 private: 808 inline bool _Set(int32 index, double x, double y) 809 { 810 fEscapements[index].x = x / fSize; 811 fEscapements[index].y = y / fSize; 812 if (fOffsets) { 813 // ToDo: According to the BeBook: "The offsetArray is applied by 814 // the dynamic spacing in order to improve the relative position 815 // of the character's width with relation to another character, 816 // without altering the width." So this will probably depend on 817 // the spacing mode. 818 fOffsets[index].x = 0; 819 fOffsets[index].y = 0; 820 } 821 return true; 822 } 823 824 BPoint* fEscapements; 825 BPoint* fOffsets; 826 float fSize; 827 }; 828 829 830 status_t 831 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars, 832 escapement_delta delta, BPoint escapementArray[], 833 BPoint offsetArray[]) const 834 { 835 if (string == NULL || numBytes <= 0 || numChars <= 0 836 || escapementArray == NULL) { 837 return B_BAD_DATA; 838 } 839 840 BPointEscapementConsumer consumer(escapementArray, offsetArray, fSize); 841 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 842 numChars, &delta, fSpacing)) { 843 return B_OK; 844 } 845 846 return B_ERROR; 847 } 848 849 850 class WidthEscapementConsumer { 851 public: 852 WidthEscapementConsumer(float* widths, float size) 853 : 854 fWidths(widths), 855 fSize(size) 856 { 857 } 858 859 bool NeedsVector() { return false; } 860 void Start() {} 861 void Finish(double x, double y) {} 862 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 863 { 864 fWidths[index] = 0.0; 865 } 866 867 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 868 FontCacheEntry* entry, double x, double y, double advanceX, 869 double advanceY) 870 { 871 fWidths[index] = advanceX / fSize; 872 return true; 873 } 874 875 private: 876 float* fWidths; 877 float fSize; 878 }; 879 880 881 882 status_t 883 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars, 884 escapement_delta delta, float widthArray[]) const 885 { 886 if (string == NULL || numBytes <= 0 || numChars <= 0 || widthArray == NULL) 887 return B_BAD_DATA; 888 889 WidthEscapementConsumer consumer(widthArray, fSize); 890 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 891 numChars, &delta, fSpacing)) { 892 return B_OK; 893 } 894 895 return B_ERROR; 896 } 897 898 899 class BoundingBoxConsumer { 900 public: 901 BoundingBoxConsumer(Transformable& transform, BRect* rectArray, 902 bool asString) 903 : 904 rectArray(rectArray), 905 stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN), 906 fAsString(asString), 907 fCurves(fPathAdaptor), 908 fContour(fCurves), 909 fTransformedOutline(fCurves, transform), 910 fTransformedContourOutline(fContour, transform), 911 fTransform(transform) 912 { 913 } 914 915 bool NeedsVector() { return false; } 916 void Start() {} 917 void Finish(double x, double y) {} 918 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {} 919 920 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 921 FontCacheEntry* entry, double x, double y, double advanceX, 922 double advanceY) 923 { 924 if (glyph->data_type != glyph_data_outline) { 925 const agg::rect_i& r = glyph->bounds; 926 if (fAsString) { 927 if (rectArray) { 928 rectArray[index].left = r.x1 + x; 929 rectArray[index].top = r.y1 + y; 930 rectArray[index].right = r.x2 + x + 1; 931 rectArray[index].bottom = r.y2 + y + 1; 932 } else { 933 stringBoundingBox = stringBoundingBox 934 | BRect(r.x1 + x, r.y1 + y, 935 r.x2 + x + 1, r.y2 + y + 1); 936 } 937 } else { 938 rectArray[index].left = r.x1; 939 rectArray[index].top = r.y1; 940 rectArray[index].right = r.x2 + 1; 941 rectArray[index].bottom = r.y2 + 1; 942 } 943 } else { 944 if (fAsString) { 945 entry->InitAdaptors(glyph, x, y, 946 fMonoAdaptor, fGray8Adaptor, fPathAdaptor); 947 } else { 948 entry->InitAdaptors(glyph, 0, 0, 949 fMonoAdaptor, fGray8Adaptor, fPathAdaptor); 950 } 951 double left = 0.0; 952 double top = 0.0; 953 double right = -1.0; 954 double bottom = -1.0; 955 uint32 pathID[1]; 956 pathID[0] = 0; 957 // TODO: use fContour if falseboldwidth is > 0 958 agg::bounding_rect(fTransformedOutline, pathID, 0, 1, 959 &left, &top, &right, &bottom); 960 961 if (rectArray) { 962 rectArray[index] = BRect(left, top, right, bottom); 963 } else { 964 stringBoundingBox = stringBoundingBox 965 | BRect(left, top, right, bottom); 966 } 967 } 968 return true; 969 } 970 971 BRect* rectArray; 972 BRect stringBoundingBox; 973 974 private: 975 bool fAsString; 976 FontCacheEntry::GlyphPathAdapter fPathAdaptor; 977 FontCacheEntry::GlyphGray8Adapter fGray8Adaptor; 978 FontCacheEntry::GlyphMonoAdapter fMonoAdaptor; 979 980 FontCacheEntry::CurveConverter fCurves; 981 FontCacheEntry::ContourConverter fContour; 982 983 FontCacheEntry::TransformedOutline fTransformedOutline; 984 FontCacheEntry::TransformedContourOutline fTransformedContourOutline; 985 986 Transformable& fTransform; 987 }; 988 989 990 status_t 991 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes, int32 numChars, 992 BRect rectArray[], bool stringEscapement, font_metric_mode mode, 993 escapement_delta delta, bool asString) 994 { 995 // TODO: The font_metric_mode is not used 996 if (string == NULL || numBytes <= 0 || numChars <= 0 || rectArray == NULL) 997 return B_BAD_DATA; 998 999 Transformable transform(EmbeddedTransformation()); 1000 1001 BoundingBoxConsumer consumer(transform, rectArray, asString); 1002 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 1003 numChars, stringEscapement ? &delta : NULL, fSpacing)) { 1004 return B_OK; 1005 } 1006 return B_ERROR; 1007 } 1008 1009 1010 status_t 1011 ServerFont::GetBoundingBoxesForStrings(char *charArray[], size_t lengthArray[], 1012 int32 numStrings, BRect rectArray[], font_metric_mode mode, 1013 escapement_delta deltaArray[]) 1014 { 1015 // TODO: The font_metric_mode is never used 1016 if (charArray == NULL || lengthArray == NULL || numStrings <= 0 1017 || rectArray == NULL || deltaArray == NULL) { 1018 return B_BAD_DATA; 1019 } 1020 1021 Transformable transform(EmbeddedTransformation()); 1022 1023 for (int32 i = 0; i < numStrings; i++) { 1024 size_t numBytes = lengthArray[i]; 1025 const char* string = charArray[i]; 1026 escapement_delta delta = deltaArray[i]; 1027 1028 BoundingBoxConsumer consumer(transform, NULL, true); 1029 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 1030 INT32_MAX, &delta, fSpacing)) { 1031 return B_ERROR; 1032 } 1033 1034 rectArray[i] = consumer.stringBoundingBox; 1035 } 1036 1037 return B_OK; 1038 } 1039 1040 1041 class StringWidthConsumer { 1042 public: 1043 StringWidthConsumer() 1044 : 1045 width(0.0) 1046 { 1047 } 1048 1049 bool NeedsVector() { return false; } 1050 void Start() {} 1051 void Finish(double x, double y) { width = x; } 1052 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {} 1053 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 1054 FontCacheEntry* entry, double x, double y, double advanceX, 1055 double advanceY) 1056 { 1057 return true; 1058 } 1059 1060 float width; 1061 }; 1062 1063 1064 float 1065 ServerFont::StringWidth(const char *string, int32 numBytes, 1066 const escapement_delta* deltaArray) const 1067 { 1068 if (!string || numBytes <= 0) 1069 return 0.0; 1070 1071 StringWidthConsumer consumer; 1072 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 1073 INT32_MAX, deltaArray, fSpacing)) { 1074 return 0.0; 1075 } 1076 1077 return consumer.width; 1078 } 1079 1080 1081 /*! 1082 \brief Returns a BRect which encloses the entire font 1083 \return A BRect which encloses the entire font 1084 */ 1085 BRect 1086 ServerFont::BoundingBox() 1087 { 1088 // TODO: fBounds is nowhere calculated! 1089 return fBounds; 1090 } 1091 1092 1093 /*! 1094 \brief Obtains the height values for characters in the font in its current state 1095 \param fh pointer to a font_height object to receive the values for the font 1096 */ 1097 void 1098 ServerFont::GetHeight(font_height& height) const 1099 { 1100 fStyle->GetHeight(fSize, height); 1101 } 1102 1103 1104 void 1105 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const 1106 { 1107 if (!inOut) 1108 return; 1109 1110 // the width of the "…" glyph 1111 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS)); 1112 1113 // count the individual glyphs 1114 int32 numChars = inOut->CountChars(); 1115 1116 // get the escapement of each glyph in font units 1117 float* escapementArray = new (std::nothrow) float[numChars]; 1118 if (escapementArray == NULL) 1119 return; 1120 1121 static escapement_delta delta = (escapement_delta){ 0.0, 0.0 }; 1122 if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta, 1123 escapementArray) == B_OK) { 1124 truncate_string(*inOut, mode, width, escapementArray, fSize, 1125 ellipsisWidth, numChars); 1126 } 1127 1128 delete[] escapementArray; 1129 } 1130 1131 1132 Transformable 1133 ServerFont::EmbeddedTransformation() const 1134 { 1135 // TODO: cache this? 1136 Transformable transform; 1137 1138 transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0); 1139 transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0); 1140 1141 return transform; 1142 } 1143 1144