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 #include <Shape.h> 26 #include <String.h> 27 #include <UTF8.h> 28 29 #include <agg_bounding_rect.h> 30 31 #include <stdio.h> 32 #include <string.h> 33 34 35 // functions needed to convert a freetype vector graphics to a BShape 36 inline BPoint 37 VectorToPoint(const FT_Vector *vector) 38 { 39 BPoint result; 40 result.x = float(vector->x) / 64; 41 result.y = -float(vector->y) / 64; 42 return result; 43 } 44 45 46 int 47 MoveToFunc(const FT_Vector *to, void *user) 48 { 49 ((BShape *)user)->MoveTo(VectorToPoint(to)); 50 return 0; 51 } 52 53 54 int 55 LineToFunc(const FT_Vector *to, void *user) 56 { 57 ((BShape *)user)->LineTo(VectorToPoint(to)); 58 return 0; 59 } 60 61 62 int 63 ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user) 64 { 65 BPoint controls[3]; 66 67 controls[0] = VectorToPoint(control); 68 controls[1] = VectorToPoint(to); 69 controls[2] = controls[1]; 70 71 ((BShape *)user)->BezierTo(controls); 72 return 0; 73 } 74 75 76 int 77 CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) 78 { 79 BPoint controls[3]; 80 81 controls[0] = VectorToPoint(control1); 82 controls[1] = VectorToPoint(control2); 83 controls[2] = VectorToPoint(to); 84 85 ((BShape *)user)->BezierTo(controls); 86 return 0; 87 } 88 89 90 inline bool 91 is_white_space(uint32 charCode) 92 { 93 switch (charCode) { 94 case 0x0009: /* tab */ 95 case 0x000b: /* vertical tab */ 96 case 0x000c: /* form feed */ 97 case 0x0020: /* space */ 98 case 0x00a0: /* non breaking space */ 99 case 0x000a: /* line feed */ 100 case 0x000d: /* carriage return */ 101 case 0x2028: /* line separator */ 102 case 0x2029: /* paragraph separator */ 103 return true; 104 } 105 106 return false; 107 } 108 109 110 // #pragma mark - 111 112 113 /*! 114 \brief Constructor 115 \param style Style object to which the ServerFont belongs 116 \param size Character size in points 117 \param rotation Rotation in degrees 118 \param shear Shear (slant) in degrees. 45 <= shear <= 135 119 \param flags Style flags as defined in <Font.h> 120 \param spacing String spacing flag as defined in <Font.h> 121 */ 122 ServerFont::ServerFont(FontStyle& style, float size, float rotation, 123 float shear, float falseBoldWidth, uint16 flags, uint8 spacing) 124 : 125 fStyle(&style), 126 fSize(size), 127 fRotation(rotation), 128 fShear(shear), 129 fFalseBoldWidth(falseBoldWidth), 130 fBounds(0, 0, 0, 0), 131 fFlags(flags), 132 fSpacing(spacing), 133 fDirection(style.Direction()), 134 fFace(style.Face()), 135 fEncoding(B_UNICODE_UTF8) 136 { 137 fStyle->Acquire(); 138 } 139 140 141 ServerFont::ServerFont() 142 : 143 fStyle(NULL) 144 { 145 *this = *gFontManager->DefaultPlainFont(); 146 } 147 148 149 /*! 150 \brief Copy Constructor 151 \param font ServerFont to copy 152 */ 153 ServerFont::ServerFont(const ServerFont &font) 154 : 155 fStyle(NULL) 156 { 157 *this = font; 158 } 159 160 161 /*! 162 \brief Removes itself as a dependency of its owning style. 163 */ 164 ServerFont::~ServerFont() 165 { 166 fStyle->Release(); 167 } 168 169 170 /*! 171 \brief Returns a copy of the specified font 172 \param The font to copy from. 173 \return A copy of the specified font 174 */ 175 ServerFont& 176 ServerFont::operator=(const ServerFont& font) 177 { 178 fSize = font.fSize; 179 fRotation = font.fRotation; 180 fShear = font.fShear; 181 fFalseBoldWidth = font.fFalseBoldWidth; 182 fFlags = font.fFlags; 183 fSpacing = font.fSpacing; 184 fEncoding = font.fEncoding; 185 fBounds = font.fBounds; 186 187 SetStyle(font.fStyle); 188 189 return *this; 190 } 191 192 193 bool 194 ServerFont::operator==(const ServerFont& other) const 195 { 196 if (GetFamilyAndStyle() != other.GetFamilyAndStyle()) 197 return false; 198 199 return fSize == other.fSize && fRotation == other.fRotation 200 && fShear == other.fShear && fFalseBoldWidth == other.fFalseBoldWidth 201 && fFlags == other.fFlags && fSpacing == other.fSpacing 202 && fEncoding == other.fEncoding && fBounds == other.fBounds 203 && fDirection == other.fDirection && fFace == other.fFace; 204 } 205 206 207 /*! 208 \brief Returns the number of strikes in the font 209 \return The number of strikes in the font 210 */ 211 int32 212 ServerFont::CountTuned() 213 { 214 return fStyle->TunedCount(); 215 } 216 217 218 /*! 219 \brief Returns the file format of the font. 220 \return Mostly B_TRUETYPE_WINDOWS :) 221 */ 222 font_file_format 223 ServerFont::FileFormat() 224 { 225 return fStyle->FileFormat(); 226 } 227 228 229 const char* 230 ServerFont::Style() const 231 { 232 return fStyle->Name(); 233 } 234 235 236 const char* 237 ServerFont::Family() const 238 { 239 return fStyle->Family()->Name(); 240 } 241 242 243 void 244 ServerFont::SetStyle(FontStyle* style) 245 { 246 if (style && style != fStyle) { 247 // detach from old style 248 if (fStyle != NULL) 249 fStyle->Release(); 250 251 // attach to new style 252 fStyle = style; 253 254 fStyle->Acquire(); 255 256 fFace = fStyle->Face(); 257 fDirection = fStyle->Direction(); 258 } 259 } 260 261 262 /*! 263 \brief Sets the ServerFont instance to whatever font is specified 264 This method will lock the font manager. 265 266 \param familyID ID number of the family to set 267 \param styleID ID number of the style to set 268 \return B_OK if successful, B_ERROR if not 269 */ 270 status_t 271 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID) 272 { 273 FontStyle* style = NULL; 274 275 if (gFontManager->Lock()) { 276 style = gFontManager->GetStyle(familyID, styleID); 277 if (style != NULL) 278 style->Acquire(); 279 280 gFontManager->Unlock(); 281 } 282 283 if (style == NULL) 284 return B_ERROR; 285 286 SetStyle(style); 287 style->Release(); 288 289 return B_OK; 290 } 291 292 293 /*! 294 \brief Sets the ServerFont instance to whatever font is specified 295 \param fontID the combination of family and style ID numbers 296 \return B_OK if successful, B_ERROR if not 297 */ 298 status_t 299 ServerFont::SetFamilyAndStyle(uint32 fontID) 300 { 301 uint16 style = fontID & 0xFFFF; 302 uint16 family = (fontID & 0xFFFF0000) >> 16; 303 304 return SetFamilyAndStyle(family, style); 305 } 306 307 308 status_t 309 ServerFont::SetFace(uint16 face) 310 { 311 // TODO: This needs further investigation. The face variable is actually 312 // flags, but some of them are not enforcable at the same time. Also don't 313 // confuse the Be API "face" with the Freetype face, which is just an 314 // index in case a single font file exports multiple font faces. The 315 // FontStyle class takes care of mapping the font style name to the Be 316 // API face flags in FontStyle::_TranslateStyleToFace(). 317 318 FontStyle* style = NULL; 319 uint16 familyID = FamilyID(); 320 if (gFontManager->Lock()) { 321 int32 count = gFontManager->CountStyles(familyID); 322 for (int32 i = 0; i < count; i++) { 323 style = gFontManager->GetStyleByIndex(familyID, i); 324 if (style == NULL) 325 break; 326 if (style->Face() == face) { 327 style->Acquire(); 328 break; 329 } else 330 style = NULL; 331 } 332 333 gFontManager->Unlock(); 334 } 335 336 if (!style) 337 return B_ERROR; 338 339 SetStyle(style); 340 style->Release(); 341 342 return B_OK; 343 } 344 345 346 /*! 347 \brief Gets the ID values for the ServerFont instance in one shot 348 \return the combination of family and style ID numbers 349 */ 350 uint32 351 ServerFont::GetFamilyAndStyle() const 352 { 353 return (FamilyID() << 16) | StyleID(); 354 } 355 356 357 FT_Face 358 ServerFont::GetTransformedFace(bool rotate, bool shear) const 359 { 360 fStyle->Lock(); 361 FT_Face face = fStyle->FreeTypeFace(); 362 if (!face) { 363 fStyle->Unlock(); 364 return NULL; 365 } 366 367 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72); 368 369 if ((rotate && fRotation != 0) || (shear && fShear != 90)) { 370 FT_Matrix rmatrix, smatrix; 371 372 Angle rotationAngle(fRotation); 373 rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000); 374 rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000); 375 rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000); 376 rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000); 377 378 Angle shearAngle(fShear); 379 smatrix.xx = (FT_Fixed)(0x10000); 380 smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000); 381 smatrix.yx = (FT_Fixed)(0); 382 smatrix.yy = (FT_Fixed)(0x10000); 383 384 // Multiply togheter and apply transform 385 FT_Matrix_Multiply(&rmatrix, &smatrix); 386 FT_Set_Transform(face, &smatrix, NULL); 387 } 388 389 // fStyle will be unlocked in PutTransformedFace() 390 return face; 391 } 392 393 394 void 395 ServerFont::PutTransformedFace(FT_Face face) const 396 { 397 // Reset transformation 398 FT_Set_Transform(face, NULL, NULL); 399 fStyle->Unlock(); 400 } 401 402 403 status_t 404 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars, 405 BShape* shapeArray[]) const 406 { 407 if (!charArray || numChars <= 0 || !shapeArray) 408 return B_BAD_DATA; 409 410 FT_Face face = GetTransformedFace(true, true); 411 if (!face) 412 return B_ERROR; 413 414 FT_Outline_Funcs funcs; 415 funcs.move_to = MoveToFunc; 416 funcs.line_to = LineToFunc; 417 funcs.conic_to = ConicToFunc; 418 funcs.cubic_to = CubicToFunc; 419 funcs.shift = 0; 420 funcs.delta = 0; 421 422 const char* string = charArray; 423 for (int i = 0; i < numChars; i++) { 424 shapeArray[i] = new (std::nothrow) BShape(); 425 if (shapeArray[i] == NULL) { 426 PutTransformedFace(face); 427 return B_NO_MEMORY; 428 } 429 FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 430 FT_Outline outline = face->glyph->outline; 431 FT_Outline_Decompose(&outline, &funcs, shapeArray[i]); 432 shapeArray[i]->Close(); 433 } 434 435 PutTransformedFace(face); 436 return B_OK; 437 } 438 439 440 class HasGlyphsConsumer { 441 public: 442 HasGlyphsConsumer(bool* hasArray) 443 : fHasArray(hasArray) 444 { 445 } 446 bool NeedsVector() { return false; } 447 void Start() {} 448 void Finish(double x, double y) {} 449 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 450 { 451 fHasArray[index] = false; 452 } 453 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 454 FontCacheEntry* entry, double x, double y, double advanceX, 455 double advanceY) 456 { 457 fHasArray[index] = glyph->glyph_index != 0; 458 return true; 459 } 460 461 private: 462 bool* fHasArray; 463 }; 464 465 466 status_t 467 ServerFont::GetHasGlyphs(const char* string, int32 numBytes, 468 bool* hasArray) const 469 { 470 if (!string || numBytes <= 0 || !hasArray) 471 return B_BAD_DATA; 472 473 HasGlyphsConsumer consumer(hasArray); 474 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 475 NULL, fSpacing)) 476 return B_OK; 477 478 return B_ERROR; 479 } 480 481 482 class EdgesConsumer { 483 public: 484 EdgesConsumer(edge_info* edges, float size) 485 : fEdges(edges) 486 , fSize(size) 487 { 488 } 489 bool NeedsVector() { return false; } 490 void Start() {} 491 void Finish(double x, double y) {} 492 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 493 { 494 fEdges[index].left = 0.0; 495 fEdges[index].right = 0.0; 496 } 497 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 498 FontCacheEntry* entry, double x, double y, double advanceX, 499 double advanceY) 500 { 501 fEdges[index].left = glyph->inset_left / fSize; 502 fEdges[index].right = glyph->inset_right / fSize; 503 return true; 504 } 505 506 private: 507 edge_info* fEdges; 508 float fSize; 509 }; 510 511 512 status_t 513 ServerFont::GetEdges(const char* string, int32 numBytes, 514 edge_info* edges) const 515 { 516 if (!string || numBytes <= 0 || !edges) 517 return B_BAD_DATA; 518 519 EdgesConsumer consumer(edges, fSize); 520 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 521 NULL, fSpacing)) { 522 return B_OK; 523 } 524 525 return B_ERROR; 526 527 // FT_Face face = GetTransformedFace(false, false); 528 // if (!face) 529 // return B_ERROR; 530 // 531 // const char *string = charArray; 532 // for (int i = 0; i < numChars; i++) { 533 // FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 534 // edgeArray[i].left = float(face->glyph->metrics.horiBearingX) 535 // / 64 / fSize; 536 // edgeArray[i].right = float(face->glyph->metrics.horiBearingX 537 // + face->glyph->metrics.width - face->glyph->metrics.horiAdvance) 538 // / 64 / fSize; 539 // } 540 // 541 // PutTransformedFace(face); 542 // return B_OK; 543 } 544 545 546 class BPointEscapementConsumer { 547 public: 548 BPointEscapementConsumer(BPoint* escapements, BPoint* offsets, 549 int32 numChars, float size) 550 : 551 fEscapements(escapements), 552 fOffsets(offsets), 553 fNumChars(numChars), 554 fSize(size) 555 { 556 } 557 558 bool NeedsVector() { return false; } 559 void Start() {} 560 void Finish(double x, double y) {} 561 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 562 { 563 _Set(index, 0, 0); 564 } 565 566 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 567 FontCacheEntry* entry, double x, double y, double advanceX, 568 double advanceY) 569 { 570 return _Set(index, advanceX, advanceY); 571 } 572 573 private: 574 inline bool _Set(int32 index, double x, double y) 575 { 576 if (index >= fNumChars) 577 return false; 578 579 fEscapements[index].x = x / fSize; 580 fEscapements[index].y = y / fSize; 581 if (fOffsets) { 582 // ToDo: According to the BeBook: "The offsetArray is applied by 583 // the dynamic spacing in order to improve the relative position 584 // of the character's width with relation to another character, 585 // without altering the width." So this will probably depend on 586 // the spacing mode. 587 fOffsets[index].x = 0; 588 fOffsets[index].y = 0; 589 } 590 return true; 591 } 592 593 BPoint* fEscapements; 594 BPoint* fOffsets; 595 int32 fNumChars; 596 float fSize; 597 }; 598 599 600 status_t 601 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars, 602 escapement_delta delta, BPoint escapementArray[], 603 BPoint offsetArray[]) const 604 { 605 if (!string || numBytes <= 0 || !escapementArray) 606 return B_BAD_DATA; 607 608 BPointEscapementConsumer consumer(escapementArray, offsetArray, numChars, 609 fSize); 610 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 611 &delta, fSpacing)) { 612 return B_OK; 613 } 614 615 return B_ERROR; 616 } 617 618 619 class WidthEscapementConsumer { 620 public: 621 WidthEscapementConsumer(float* widths, int32 numChars, float size) 622 : 623 fWidths(widths), 624 fNumChars(numChars), 625 fSize(size) 626 { 627 } 628 629 bool NeedsVector() { return false; } 630 void Start() {} 631 void Finish(double x, double y) {} 632 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) 633 { 634 fWidths[index] = 0.0; 635 } 636 637 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 638 FontCacheEntry* entry, double x, double y, double advanceX, 639 double advanceY) 640 { 641 if (index >= fNumChars) 642 return false; 643 644 fWidths[index] = advanceX / fSize; 645 return true; 646 } 647 648 private: 649 float* fWidths; 650 int32 fNumChars; 651 float fSize; 652 }; 653 654 655 656 status_t 657 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars, 658 escapement_delta delta, float widthArray[]) const 659 { 660 if (!string || numBytes <= 0 || !widthArray) 661 return B_BAD_DATA; 662 663 WidthEscapementConsumer consumer(widthArray, numChars, fSize); 664 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 665 &delta, fSpacing)) { 666 return B_OK; 667 } 668 return B_ERROR; 669 } 670 671 672 class BoundingBoxConsumer { 673 public: 674 BoundingBoxConsumer(Transformable& transform, BRect* rectArray, 675 bool asString) 676 : rectArray(rectArray) 677 , stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN) 678 , fAsString(asString) 679 , fCurves(fPathAdaptor) 680 , fContour(fCurves) 681 , fTransformedOutline(fCurves, transform) 682 , fTransformedContourOutline(fContour, transform) 683 , fTransform(transform) 684 { 685 } 686 687 bool NeedsVector() { return false; } 688 void Start() {} 689 void Finish(double x, double y) {} 690 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {} 691 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 692 FontCacheEntry* entry, double x, double y, double advanceX, 693 double advanceY) 694 { 695 if (glyph->data_type != glyph_data_outline) { 696 const agg::rect_i& r = glyph->bounds; 697 if (fAsString) { 698 if (rectArray) { 699 rectArray[index].left = r.x1 + x; 700 rectArray[index].top = r.y1 + y; 701 rectArray[index].right = r.x2 + x + 1; 702 rectArray[index].bottom = r.y2 + y + 1; 703 } else { 704 stringBoundingBox = stringBoundingBox 705 | BRect(r.x1 + x, r.y1 + y, 706 r.x2 + x + 1, r.y2 + y + 1); 707 } 708 } else { 709 rectArray[index].left = r.x1; 710 rectArray[index].top = r.y1; 711 rectArray[index].right = r.x2 + 1; 712 rectArray[index].bottom = r.y2 + 1; 713 } 714 } else { 715 if (fAsString) { 716 entry->InitAdaptors(glyph, x, y, 717 fMonoAdaptor, fGray8Adaptor, fPathAdaptor); 718 } else { 719 entry->InitAdaptors(glyph, 0, 0, 720 fMonoAdaptor, fGray8Adaptor, fPathAdaptor); 721 } 722 double left = 0.0; 723 double top = 0.0; 724 double right = -1.0; 725 double bottom = -1.0; 726 uint32 pathID[1]; 727 pathID[0] = 0; 728 // TODO: use fContour if falseboldwidth is > 0 729 agg::bounding_rect(fTransformedOutline, pathID, 0, 1, 730 &left, &top, &right, &bottom); 731 732 if (rectArray) { 733 rectArray[index] = BRect(left, top, right, bottom); 734 } else { 735 stringBoundingBox = stringBoundingBox 736 | BRect(left, top, right, bottom); 737 } 738 } 739 return true; 740 } 741 742 BRect* rectArray; 743 BRect stringBoundingBox; 744 745 private: 746 bool fAsString; 747 FontCacheEntry::GlyphPathAdapter fPathAdaptor; 748 FontCacheEntry::GlyphGray8Adapter fGray8Adaptor; 749 FontCacheEntry::GlyphMonoAdapter fMonoAdaptor; 750 751 FontCacheEntry::CurveConverter fCurves; 752 FontCacheEntry::ContourConverter fContour; 753 754 FontCacheEntry::TransformedOutline fTransformedOutline; 755 FontCacheEntry::TransformedContourOutline fTransformedContourOutline; 756 757 Transformable& fTransform; 758 }; 759 760 761 status_t 762 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes, 763 BRect rectArray[], bool stringEscapement, font_metric_mode mode, 764 escapement_delta delta, bool asString) 765 { 766 // TODO: The font_metric_mode is not used 767 if (!string || numBytes <= 0 || !rectArray) 768 return B_BAD_DATA; 769 770 Transformable transform(EmbeddedTransformation()); 771 772 BoundingBoxConsumer consumer(transform, rectArray, asString); 773 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 774 stringEscapement ? &delta : NULL, fSpacing)) { 775 return B_OK; 776 } 777 return B_ERROR; 778 } 779 780 781 status_t 782 ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[], 783 int32 numStrings, BRect rectArray[], font_metric_mode mode, 784 escapement_delta deltaArray[]) 785 { 786 // TODO: The font_metric_mode is never used 787 if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray) 788 return B_BAD_DATA; 789 790 Transformable transform(EmbeddedTransformation()); 791 792 for (int32 i = 0; i < numStrings; i++) { 793 int32 numBytes = lengthArray[i]; 794 const char* string = charArray[i]; 795 escapement_delta delta = deltaArray[i]; 796 797 BoundingBoxConsumer consumer(transform, NULL, true); 798 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 799 &delta, fSpacing)) { 800 return B_ERROR; 801 } 802 803 rectArray[i] = consumer.stringBoundingBox; 804 } 805 806 return B_OK; 807 } 808 809 810 class StringWidthConsumer { 811 public: 812 StringWidthConsumer() : width(0.0) {} 813 bool NeedsVector() { return false; } 814 void Start() {} 815 void Finish(double x, double y) { width = x; } 816 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {} 817 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph, 818 FontCacheEntry* entry, double x, double y, double advanceX, 819 double advanceY) 820 { return true; } 821 822 float width; 823 }; 824 825 826 float 827 ServerFont::StringWidth(const char *string, int32 numBytes, 828 const escapement_delta* deltaArray) const 829 { 830 if (!string || numBytes <= 0) 831 return 0.0; 832 833 StringWidthConsumer consumer; 834 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes, 835 deltaArray, fSpacing)) { 836 return 0.0; 837 } 838 839 return consumer.width; 840 } 841 842 843 /*! 844 \brief Returns a BRect which encloses the entire font 845 \return A BRect which encloses the entire font 846 */ 847 BRect 848 ServerFont::BoundingBox() 849 { 850 // TODO: fBounds is nowhere calculated! 851 return fBounds; 852 } 853 854 855 /*! 856 \brief Obtains the height values for characters in the font in its current state 857 \param fh pointer to a font_height object to receive the values for the font 858 */ 859 void 860 ServerFont::GetHeight(font_height& height) const 861 { 862 fStyle->GetHeight(fSize, height); 863 } 864 865 866 void 867 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const 868 { 869 if (!inOut) 870 return; 871 872 // the width of the "…" glyph 873 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS)); 874 875 // count the individual glyphs 876 int32 numChars = inOut->CountChars(); 877 878 // get the escapement of each glyph in font units 879 float* escapementArray = new (std::nothrow) float[numChars]; 880 if (escapementArray == NULL) 881 return; 882 883 static escapement_delta delta = (escapement_delta){ 0.0, 0.0 }; 884 if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta, 885 escapementArray) == B_OK) { 886 truncate_string(*inOut, mode, width, escapementArray, fSize, 887 ellipsisWidth, numChars); 888 } 889 890 delete[] escapementArray; 891 } 892 893 894 Transformable 895 ServerFont::EmbeddedTransformation() const 896 { 897 // TODO: cache this? 898 Transformable transform; 899 900 transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0); 901 transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0); 902 903 return transform; 904 } 905 906