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