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