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