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