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 691 entry = GlyphLayoutEngine::FontCacheEntryFor(*this, false); 692 if (entry == NULL) 693 return B_ERROR; 694 695 cacheReference.SetTo(entry); 696 697 uint32 charCode; 698 int32 charIndex = 0; 699 const char* start = string; 700 while (charIndex < numChars && (charCode = UTF8ToCharCode(&string)) != 0) { 701 hasArray[charIndex] = entry->CanCreateGlyph(charCode); 702 703 if (hasArray[charIndex] == false) { 704 if (fallbacks.IsEmpty()) 705 GlyphLayoutEngine::PopulateFallbacks(fallbacks, *this, false); 706 707 if (GlyphLayoutEngine::GetFallbackReference(fallbacks, charCode) != NULL) 708 hasArray[charIndex] = true; 709 } 710 711 charIndex++; 712 if (string - start + 1 > numBytes) 713 break; 714 } 715 716 return B_OK; 717 } 718 719 720 class EdgesConsumer { 721 public: 722 EdgesConsumer(edge_info* edges, float size) 723 : 724 fEdges(edges), 725 fSize(size) 726 { 727 } 728 729 bool NeedsVector() { return false; } 730 void Start() {} 731 void Finish(double x, double y) {} 732 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 733 { 734 fEdges[index].left = 0.0; 735 fEdges[index].right = 0.0; 736 } 737 738 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 739 FontCacheEntry* entry, double x, double y, double advanceX, 740 double advanceY) 741 { 742 fEdges[index].left = glyph->inset_left / fSize; 743 fEdges[index].right = glyph->inset_right / fSize; 744 return true; 745 } 746 747 private: 748 edge_info* fEdges; 749 float fSize; 750 }; 751 752 753 status_t 754 ServerFont::GetEdges(const char* string, int32 numBytes, int32 numChars, 755 edge_info* edges) const 756 { 757 if (string == NULL || numBytes <= 0 || numChars <= 0 || edges == NULL) 758 return B_BAD_DATA; 759 760 EdgesConsumer consumer(edges, fSize); 761 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 762 numChars, NULL, fSpacing)) { 763 return B_OK; 764 } 765 766 return B_ERROR; 767 768 // FT_Face face = GetTransformedFace(false, false); 769 // if (!face) 770 // return B_ERROR; 771 // 772 // const char *string = charArray; 773 // for (int i = 0; i < numChars; i++) { 774 // FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 775 // edgeArray[i].left = float(face->glyph->metrics.horiBearingX) 776 // / 64 / fSize; 777 // edgeArray[i].right = float(face->glyph->metrics.horiBearingX 778 // + face->glyph->metrics.width - face->glyph->metrics.horiAdvance) 779 // / 64 / fSize; 780 // } 781 // 782 // PutTransformedFace(face); 783 // return B_OK; 784 } 785 786 787 class BPointEscapementConsumer { 788 public: 789 BPointEscapementConsumer(BPoint* escapements, BPoint* offsets, float size) 790 : 791 fEscapements(escapements), 792 fOffsets(offsets), 793 fSize(size) 794 { 795 } 796 797 bool NeedsVector() { return false; } 798 void Start() {} 799 void Finish(double x, double y) {} 800 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 801 { 802 _Set(index, 0, 0); 803 } 804 805 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 806 FontCacheEntry* entry, double x, double y, double advanceX, 807 double advanceY) 808 { 809 return _Set(index, advanceX, advanceY); 810 } 811 812 private: 813 inline bool _Set(int32 index, double x, double y) 814 { 815 fEscapements[index].x = x / fSize; 816 fEscapements[index].y = y / fSize; 817 if (fOffsets) { 818 // ToDo: According to the BeBook: "The offsetArray is applied by 819 // the dynamic spacing in order to improve the relative position 820 // of the character's width with relation to another character, 821 // without altering the width." So this will probably depend on 822 // the spacing mode. 823 fOffsets[index].x = 0; 824 fOffsets[index].y = 0; 825 } 826 return true; 827 } 828 829 BPoint* fEscapements; 830 BPoint* fOffsets; 831 float fSize; 832 }; 833 834 835 status_t 836 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars, 837 escapement_delta delta, BPoint escapementArray[], 838 BPoint offsetArray[]) const 839 { 840 if (string == NULL || numBytes <= 0 || numChars <= 0 841 || escapementArray == NULL) { 842 return B_BAD_DATA; 843 } 844 845 BPointEscapementConsumer consumer(escapementArray, offsetArray, fSize); 846 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 847 numChars, &delta, fSpacing)) { 848 return B_OK; 849 } 850 851 return B_ERROR; 852 } 853 854 855 class WidthEscapementConsumer { 856 public: 857 WidthEscapementConsumer(float* widths, float size) 858 : 859 fWidths(widths), 860 fSize(size) 861 { 862 } 863 864 bool NeedsVector() { return false; } 865 void Start() {} 866 void Finish(double x, double y) {} 867 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 868 { 869 fWidths[index] = 0.0; 870 } 871 872 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 873 FontCacheEntry* entry, double x, double y, double advanceX, 874 double advanceY) 875 { 876 fWidths[index] = advanceX / fSize; 877 return true; 878 } 879 880 private: 881 float* fWidths; 882 float fSize; 883 }; 884 885 886 887 status_t 888 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars, 889 escapement_delta delta, float widthArray[]) const 890 { 891 if (string == NULL || numBytes <= 0 || numChars <= 0 || widthArray == NULL) 892 return B_BAD_DATA; 893 894 WidthEscapementConsumer consumer(widthArray, fSize); 895 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 896 numChars, &delta, fSpacing)) { 897 return B_OK; 898 } 899 900 return B_ERROR; 901 } 902 903 904 class BoundingBoxConsumer { 905 public: 906 BoundingBoxConsumer(Transformable& transform, BRect* rectArray, 907 bool asString) 908 : 909 rectArray(rectArray), 910 stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN), 911 fAsString(asString), 912 fCurves(fPathAdaptor), 913 fContour(fCurves), 914 fTransformedOutline(fCurves, transform), 915 fTransformedContourOutline(fContour, transform), 916 fTransform(transform) 917 { 918 } 919 920 bool NeedsVector() { return false; } 921 void Start() {} 922 void Finish(double x, double y) {} 923 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {} 924 925 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 926 FontCacheEntry* entry, double x, double y, double advanceX, 927 double advanceY) 928 { 929 if (glyph->data_type != glyph_data_outline) { 930 const agg::rect_i& r = glyph->bounds; 931 if (fAsString) { 932 if (rectArray) { 933 rectArray[index].left = r.x1 + x; 934 rectArray[index].top = r.y1 + y; 935 rectArray[index].right = r.x2 + x + 1; 936 rectArray[index].bottom = r.y2 + y + 1; 937 } else { 938 stringBoundingBox = stringBoundingBox 939 | BRect(r.x1 + x, r.y1 + y, 940 r.x2 + x + 1, r.y2 + y + 1); 941 } 942 } else { 943 rectArray[index].left = r.x1; 944 rectArray[index].top = r.y1; 945 rectArray[index].right = r.x2 + 1; 946 rectArray[index].bottom = r.y2 + 1; 947 } 948 } else { 949 if (fAsString) { 950 entry->InitAdaptors(glyph, x, y, 951 fMonoAdaptor, fGray8Adaptor, fPathAdaptor); 952 } else { 953 entry->InitAdaptors(glyph, 0, 0, 954 fMonoAdaptor, fGray8Adaptor, fPathAdaptor); 955 } 956 double left = 0.0; 957 double top = 0.0; 958 double right = -1.0; 959 double bottom = -1.0; 960 uint32 pathID[1]; 961 pathID[0] = 0; 962 // TODO: use fContour if falseboldwidth is > 0 963 agg::bounding_rect(fTransformedOutline, pathID, 0, 1, 964 &left, &top, &right, &bottom); 965 966 if (rectArray) { 967 rectArray[index] = BRect(left, top, right, bottom); 968 } else { 969 stringBoundingBox = stringBoundingBox 970 | BRect(left, top, right, bottom); 971 } 972 } 973 return true; 974 } 975 976 BRect* rectArray; 977 BRect stringBoundingBox; 978 979 private: 980 bool fAsString; 981 FontCacheEntry::GlyphPathAdapter fPathAdaptor; 982 FontCacheEntry::GlyphGray8Adapter fGray8Adaptor; 983 FontCacheEntry::GlyphMonoAdapter fMonoAdaptor; 984 985 FontCacheEntry::CurveConverter fCurves; 986 FontCacheEntry::ContourConverter fContour; 987 988 FontCacheEntry::TransformedOutline fTransformedOutline; 989 FontCacheEntry::TransformedContourOutline fTransformedContourOutline; 990 991 Transformable& fTransform; 992 }; 993 994 995 status_t 996 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes, int32 numChars, 997 BRect rectArray[], bool stringEscapement, font_metric_mode mode, 998 escapement_delta delta, bool asString) 999 { 1000 // TODO: The font_metric_mode is not used 1001 if (string == NULL || numBytes <= 0 || numChars <= 0 || rectArray == NULL) 1002 return B_BAD_DATA; 1003 1004 Transformable transform(EmbeddedTransformation()); 1005 1006 BoundingBoxConsumer consumer(transform, rectArray, asString); 1007 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 1008 numChars, stringEscapement ? &delta : NULL, fSpacing)) { 1009 return B_OK; 1010 } 1011 return B_ERROR; 1012 } 1013 1014 1015 status_t 1016 ServerFont::GetBoundingBoxesForStrings(char *charArray[], size_t lengthArray[], 1017 int32 numStrings, BRect rectArray[], font_metric_mode mode, 1018 escapement_delta deltaArray[]) 1019 { 1020 // TODO: The font_metric_mode is never used 1021 if (charArray == NULL || lengthArray == NULL || numStrings <= 0 1022 || rectArray == NULL || deltaArray == NULL) { 1023 return B_BAD_DATA; 1024 } 1025 1026 Transformable transform(EmbeddedTransformation()); 1027 1028 for (int32 i = 0; i < numStrings; i++) { 1029 size_t numBytes = lengthArray[i]; 1030 const char* string = charArray[i]; 1031 escapement_delta delta = deltaArray[i]; 1032 1033 BoundingBoxConsumer consumer(transform, NULL, true); 1034 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 1035 INT32_MAX, &delta, fSpacing)) { 1036 return B_ERROR; 1037 } 1038 1039 rectArray[i] = consumer.stringBoundingBox; 1040 } 1041 1042 return B_OK; 1043 } 1044 1045 1046 class StringWidthConsumer { 1047 public: 1048 StringWidthConsumer() 1049 : 1050 width(0.0) 1051 { 1052 } 1053 1054 bool NeedsVector() { return false; } 1055 void Start() {} 1056 void Finish(double x, double y) { width = x; } 1057 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {} 1058 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 1059 FontCacheEntry* entry, double x, double y, double advanceX, 1060 double advanceY) 1061 { 1062 return true; 1063 } 1064 1065 float width; 1066 }; 1067 1068 1069 float 1070 ServerFont::StringWidth(const char *string, int32 numBytes, 1071 const escapement_delta* deltaArray) const 1072 { 1073 if (!string || numBytes <= 0) 1074 return 0.0; 1075 1076 StringWidthConsumer consumer; 1077 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 1078 INT32_MAX, deltaArray, fSpacing)) { 1079 return 0.0; 1080 } 1081 1082 return consumer.width; 1083 } 1084 1085 1086 /*! 1087 \brief Returns a BRect which encloses the entire font 1088 \return A BRect which encloses the entire font 1089 */ 1090 BRect 1091 ServerFont::BoundingBox() 1092 { 1093 FT_Face face = fStyle->FreeTypeFace(); 1094 1095 if (fBounds.IsValid() && 1096 fBounds.IntegerWidth() > 0 && 1097 fBounds.IntegerHeight() > 0) 1098 return fBounds; 1099 1100 // if font has vector outlines, get the bounding box 1101 // from freetype and scale it by the font size 1102 if (IsScalable()) { 1103 FT_BBox bounds = face->bbox; 1104 fBounds.left = (float)bounds.xMin / (float)face->units_per_EM; 1105 fBounds.right = (float)bounds.xMax / (float)face->units_per_EM; 1106 fBounds.top = (float)bounds.yMin / (float)face->units_per_EM; 1107 fBounds.bottom = (float)bounds.yMax / (float)face->units_per_EM; 1108 1109 float scaledWidth = fBounds.Width() * fSize; 1110 float scaledHeight = fBounds.Height() * fSize; 1111 1112 fBounds.InsetBy((fBounds.Width() - scaledWidth) / 2.f, 1113 (fBounds.Height() - scaledHeight) / 2.f); 1114 } else { 1115 // otherwise find the bitmap that is closest in size 1116 // to the requested size 1117 float pixelSize = fSize * 64.f; 1118 float minDelta = abs(face->available_sizes[0].size - pixelSize); 1119 float width = face->available_sizes[0].x_ppem; 1120 float height = face->available_sizes[0].y_ppem; 1121 1122 for (int i = 1; i < face->num_fixed_sizes; ++i) { 1123 float delta = abs(face->available_sizes[i].size - pixelSize); 1124 if (delta < minDelta) { 1125 width = face->available_sizes[i].x_ppem; 1126 height = face->available_sizes[i].y_ppem; 1127 } 1128 } 1129 1130 fBounds.top = 0; 1131 fBounds.left = 0; 1132 fBounds.right = width / 64.f; 1133 fBounds.bottom = height / 64.f; 1134 } 1135 1136 return fBounds; 1137 } 1138 1139 1140 /*! 1141 \brief Obtains the height values for characters in the font in its current state 1142 \param fh pointer to a font_height object to receive the values for the font 1143 */ 1144 void 1145 ServerFont::GetHeight(font_height& height) const 1146 { 1147 fStyle->GetHeight(fSize, height); 1148 } 1149 1150 1151 void 1152 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const 1153 { 1154 if (!inOut) 1155 return; 1156 1157 // the width of the "…" glyph 1158 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS)); 1159 1160 // count the individual glyphs 1161 int32 numChars = inOut->CountChars(); 1162 1163 // get the escapement of each glyph in font units 1164 float* escapementArray = new (std::nothrow) float[numChars]; 1165 if (escapementArray == NULL) 1166 return; 1167 1168 static escapement_delta delta = (escapement_delta){ 0.0, 0.0 }; 1169 if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta, 1170 escapementArray) == B_OK) { 1171 truncate_string(*inOut, mode, width, escapementArray, fSize, 1172 ellipsisWidth, numChars); 1173 } 1174 1175 delete[] escapementArray; 1176 } 1177 1178 1179 Transformable 1180 ServerFont::EmbeddedTransformation() const 1181 { 1182 // TODO: cache this? 1183 Transformable transform; 1184 1185 transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0); 1186 transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0); 1187 1188 return transform; 1189 } 1190 1191