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