1 /* 2 * Copyright 2001-2006, 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 */ 10 11 12 #include "ServerFont.h" 13 14 #include "Angle.h" 15 #include "FontManager.h" 16 #include "truncate_string.h" 17 #include "utf8_functions.h" 18 19 #include FT_FREETYPE_H 20 #include FT_GLYPH_H 21 #include FT_OUTLINE_H 22 23 #include <Shape.h> 24 #include <String.h> 25 #include <UTF8.h> 26 27 28 // functions needed to convert a freetype vector graphics to a BShape 29 inline BPoint 30 VectorToPoint(const FT_Vector *vector) 31 { 32 BPoint result; 33 result.x = float(vector->x) / 64; 34 result.y = -float(vector->y) / 64; 35 return result; 36 } 37 38 39 int 40 MoveToFunc(const FT_Vector *to, void *user) 41 { 42 ((BShape *)user)->MoveTo(VectorToPoint(to)); 43 return 0; 44 } 45 46 47 int 48 LineToFunc(const FT_Vector *to, void *user) 49 { 50 ((BShape *)user)->LineTo(VectorToPoint(to)); 51 return 0; 52 } 53 54 55 int 56 ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user) 57 { 58 BPoint controls[3]; 59 60 controls[0] = VectorToPoint(control); 61 controls[1] = VectorToPoint(to); 62 controls[2] = controls[1]; 63 64 ((BShape *)user)->BezierTo(controls); 65 return 0; 66 } 67 68 69 int 70 CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) 71 { 72 BPoint controls[3]; 73 74 controls[0] = VectorToPoint(control1); 75 controls[1] = VectorToPoint(control2); 76 controls[2] = VectorToPoint(to); 77 78 ((BShape *)user)->BezierTo(controls); 79 return 0; 80 } 81 82 83 inline bool 84 is_white_space(uint32 charCode) 85 { 86 switch (charCode) { 87 case 0x0009: /* tab */ 88 case 0x000b: /* vertical tab */ 89 case 0x000c: /* form feed */ 90 case 0x0020: /* space */ 91 case 0x00a0: /* non breaking space */ 92 case 0x000a: /* line feed */ 93 case 0x000d: /* carriage return */ 94 case 0x2028: /* line separator */ 95 case 0x2029: /* paragraph separator */ 96 return true; 97 } 98 99 return false; 100 } 101 102 103 // #pragma mark - 104 105 106 /*! 107 \brief Constructor 108 \param style Style object to which the ServerFont belongs 109 \param size Character size in points 110 \param rotation Rotation in degrees 111 \param shear Shear (slant) in degrees. 45 <= shear <= 135 112 \param flags Style flags as defined in <Font.h> 113 \param spacing String spacing flag as defined in <Font.h> 114 */ 115 ServerFont::ServerFont(FontStyle& style, float size, 116 float rotation, float shear, float falseBoldWidth, 117 uint16 flags, uint8 spacing) 118 : fStyle(&style), 119 fSize(size), 120 fRotation(rotation), 121 fShear(shear), 122 fFalseBoldWidth(falseBoldWidth), 123 fBounds(0, 0, 0, 0), 124 fFlags(flags), 125 fSpacing(spacing), 126 fDirection(style.Direction()), 127 fFace(style.Face()), 128 fEncoding(B_UNICODE_UTF8) 129 { 130 fStyle->Acquire(); 131 } 132 133 134 ServerFont::ServerFont() 135 : 136 fStyle(NULL) 137 { 138 *this = *gFontManager->DefaultPlainFont(); 139 } 140 141 142 /*! 143 \brief Copy Constructor 144 \param font ServerFont to copy 145 */ 146 ServerFont::ServerFont(const ServerFont &font) 147 : 148 fStyle(NULL) 149 { 150 *this = font; 151 } 152 153 154 /*! 155 \brief Removes itself as a dependency of its owning style. 156 */ 157 ServerFont::~ServerFont() 158 { 159 fStyle->Release(); 160 } 161 162 163 /*! 164 \brief Returns a copy of the specified font 165 \param The font to copy from. 166 \return A copy of the specified font 167 */ 168 ServerFont& 169 ServerFont::operator=(const ServerFont& font) 170 { 171 if (font.fStyle) { 172 fSize = font.fSize; 173 fRotation = font.fRotation; 174 fShear = font.fShear; 175 fFalseBoldWidth = font.fFalseBoldWidth; 176 fFlags = font.fFlags; 177 fSpacing = font.fSpacing; 178 fEncoding = font.fEncoding; 179 fBounds = font.fBounds; 180 181 SetStyle(font.fStyle); 182 } 183 184 return *this; 185 } 186 187 188 /*! 189 \brief Returns the number of strikes in the font 190 \return The number of strikes in the font 191 */ 192 int32 193 ServerFont::CountTuned() 194 { 195 return fStyle->TunedCount(); 196 } 197 198 199 /*! 200 \brief Returns the file format of the font. 201 \return Mostly B_TRUETYPE_WINDOWS :) 202 */ 203 font_file_format 204 ServerFont::FileFormat() 205 { 206 return fStyle->FileFormat(); 207 } 208 209 210 const char* 211 ServerFont::Style() const 212 { 213 return fStyle->Name(); 214 } 215 216 217 const char* 218 ServerFont::Family() const 219 { 220 return fStyle->Family()->Name(); 221 } 222 223 224 void 225 ServerFont::SetStyle(FontStyle* style) 226 { 227 if (style && style != fStyle) { 228 // detach from old style 229 if (fStyle) 230 fStyle->Release(); 231 232 // attach to new style 233 fStyle = style; 234 235 fStyle->Acquire(); 236 237 fFace = fStyle->Face(); 238 fDirection = fStyle->Direction(); 239 } 240 } 241 242 243 /*! 244 \brief Sets the ServerFont instance to whatever font is specified 245 This method will lock the font manager. 246 247 \param familyID ID number of the family to set 248 \param styleID ID number of the style to set 249 \return B_OK if successful, B_ERROR if not 250 */ 251 status_t 252 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID) 253 { 254 FontStyle* style = NULL; 255 256 if (gFontManager->Lock()) { 257 style = gFontManager->GetStyle(familyID, styleID); 258 if (style != NULL) 259 style->Acquire(); 260 261 gFontManager->Unlock(); 262 } 263 264 if (!style) 265 return B_ERROR; 266 267 SetStyle(style); 268 style->Release(); 269 270 return B_OK; 271 } 272 273 274 /*! 275 \brief Sets the ServerFont instance to whatever font is specified 276 \param fontID the combination of family and style ID numbers 277 \return B_OK if successful, B_ERROR if not 278 */ 279 status_t 280 ServerFont::SetFamilyAndStyle(uint32 fontID) 281 { 282 uint16 style = fontID & 0xFFFF; 283 uint16 family = (fontID & 0xFFFF0000) >> 16; 284 285 return SetFamilyAndStyle(family, style); 286 } 287 288 289 void 290 ServerFont::SetFace(uint32 face) 291 { 292 // TODO: change font style as requested! 293 fFace = face; 294 } 295 296 297 /*! 298 \brief Gets the ID values for the ServerFont instance in one shot 299 \return the combination of family and style ID numbers 300 */ 301 uint32 302 ServerFont::GetFamilyAndStyle() const 303 { 304 return (FamilyID() << 16) | StyleID(); 305 } 306 307 308 FT_Face 309 ServerFont::GetTransformedFace(bool rotate, bool shear) const 310 { 311 fStyle->Lock(); 312 FT_Face face = fStyle->FreeTypeFace(); 313 if (!face) { 314 fStyle->Unlock(); 315 return NULL; 316 } 317 318 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72); 319 320 if ((rotate && fRotation != 0) || (shear && fShear != 90)) { 321 FT_Matrix rmatrix, smatrix; 322 323 Angle rotationAngle(fRotation); 324 rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000); 325 rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000); 326 rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000); 327 rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000); 328 329 Angle shearAngle(fShear); 330 smatrix.xx = (FT_Fixed)(0x10000); 331 smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000); 332 smatrix.yx = (FT_Fixed)(0); 333 smatrix.yy = (FT_Fixed)(0x10000); 334 335 // Multiply togheter and apply transform 336 FT_Matrix_Multiply(&rmatrix, &smatrix); 337 FT_Set_Transform(face, &smatrix, NULL); 338 } 339 340 return face; 341 } 342 343 344 void 345 ServerFont::PutTransformedFace(FT_Face face) const 346 { 347 // Reset transformation 348 FT_Set_Transform(face, NULL, NULL); 349 fStyle->Unlock(); 350 } 351 352 353 status_t 354 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars, 355 BShape *shapeArray[]) const 356 { 357 if (!charArray || numChars <= 0 || !shapeArray) 358 return B_BAD_DATA; 359 360 FT_Face face = GetTransformedFace(true, true); 361 if (!face) 362 return B_ERROR; 363 364 FT_Outline_Funcs funcs; 365 funcs.move_to = MoveToFunc; 366 funcs.line_to = LineToFunc; 367 funcs.conic_to = ConicToFunc; 368 funcs.cubic_to = CubicToFunc; 369 funcs.shift = 0; 370 funcs.delta = 0; 371 372 const char *string = charArray; 373 for (int i = 0; i < numChars; i++) { 374 shapeArray[i] = new BShape(); 375 FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 376 FT_Outline outline = face->glyph->outline; 377 FT_Outline_Decompose(&outline, &funcs, shapeArray[i]); 378 shapeArray[i]->Close(); 379 } 380 381 PutTransformedFace(face); 382 return B_OK; 383 } 384 385 386 status_t 387 ServerFont::GetHasGlyphs(const char charArray[], int32 numChars, 388 bool hasArray[]) const 389 { 390 if (!charArray || numChars <= 0 || !hasArray) 391 return B_BAD_DATA; 392 393 FT_Face face = GetTransformedFace(false, false); 394 if (!face) 395 return B_ERROR; 396 397 const char *string = charArray; 398 for (int i = 0; i < numChars; i++) 399 hasArray[i] = FT_Get_Char_Index(face, UTF8ToCharCode(&string)) > 0; 400 401 PutTransformedFace(face); 402 return B_OK; 403 } 404 405 406 status_t 407 ServerFont::GetEdges(const char charArray[], int32 numChars, 408 edge_info edgeArray[]) const 409 { 410 if (!charArray || numChars <= 0 || !edgeArray) 411 return B_BAD_DATA; 412 413 FT_Face face = GetTransformedFace(false, false); 414 if (!face) 415 return B_ERROR; 416 417 const char *string = charArray; 418 for (int i = 0; i < numChars; i++) { 419 FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 420 edgeArray[i].left = float(face->glyph->metrics.horiBearingX) 421 / 64 / fSize; 422 edgeArray[i].right = float(face->glyph->metrics.horiBearingX 423 + face->glyph->metrics.width - face->glyph->metrics.horiAdvance) 424 / 64 / fSize; 425 } 426 427 PutTransformedFace(face); 428 return B_OK; 429 } 430 431 432 status_t 433 ServerFont::GetEscapements(const char charArray[], int32 numChars, 434 escapement_delta delta, BPoint escapementArray[], BPoint offsetArray[]) const 435 { 436 if (!charArray || numChars <= 0 || !escapementArray) 437 return B_BAD_DATA; 438 439 FT_Face face = GetTransformedFace(true, false); 440 if (!face) 441 return B_ERROR; 442 443 const char *string = charArray; 444 for (int i = 0; i < numChars; i++) { 445 uint32 charCode = UTF8ToCharCode(&string); 446 FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP); 447 escapementArray[i].x = is_white_space(charCode) ? delta.space : delta.nonspace; 448 escapementArray[i].x += float(face->glyph->advance.x) / 64; 449 escapementArray[i].y = -float(face->glyph->advance.y) / 64; 450 escapementArray[i].x /= fSize; 451 escapementArray[i].y /= fSize; 452 453 if (offsetArray) { 454 // ToDo: According to the BeBook: "The offsetArray is applied by 455 // the dynamic spacing in order to improve the relative position 456 // of the character's width with relation to another character, 457 // without altering the width." So this will probably depend on 458 // the spacing mode. 459 offsetArray[i].x = 0; 460 offsetArray[i].y = 0; 461 } 462 } 463 464 PutTransformedFace(face); 465 return B_OK; 466 } 467 468 469 status_t 470 ServerFont::GetEscapements(const char charArray[], int32 numChars, 471 escapement_delta delta, float widthArray[]) const 472 { 473 if (!charArray || numChars <= 0 || !widthArray) 474 return B_BAD_DATA; 475 476 FT_Face face = GetTransformedFace(false, false); 477 if (!face) 478 return B_ERROR; 479 480 const char *string = charArray; 481 for (int i = 0; i < numChars; i++) { 482 uint32 charCode = UTF8ToCharCode(&string); 483 FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP); 484 widthArray[i] = is_white_space(charCode) ? delta.space : delta.nonspace; 485 widthArray[i] += float(face->glyph->metrics.horiAdvance) / 64.0; 486 widthArray[i] /= fSize; 487 } 488 489 PutTransformedFace(face); 490 return B_OK; 491 } 492 493 494 status_t 495 ServerFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars, 496 BRect rectArray[], bool stringEscapement, font_metric_mode mode, 497 escapement_delta delta) 498 { 499 if (!charArray || numChars <= 0 || !rectArray) 500 return B_BAD_DATA; 501 502 FT_Face face = GetTransformedFace(true, true); 503 if (!face) 504 return B_ERROR; 505 506 const char *string = charArray; 507 for (int i = 0; i < numChars; i++) { 508 uint32 charCode = UTF8ToCharCode(&string); 509 if (stringEscapement) { 510 if (i > 0) 511 rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0); 512 513 rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0); 514 } 515 516 FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP); 517 if (i < numChars - 1) { 518 rectArray[i + 1].left = rectArray[i + 1].right = rectArray[i].left 519 + face->glyph->metrics.horiAdvance / 64.0; 520 } 521 522 rectArray[i].left += float(face->glyph->metrics.horiBearingX) /64.0; 523 rectArray[i].right += float(face->glyph->metrics.horiBearingX 524 + face->glyph->metrics.width) / 64.0; 525 rectArray[i].top = -float(face->glyph->metrics.horiBearingY) / 64.0; 526 rectArray[i].bottom = float(face->glyph->metrics.height 527 - face->glyph->metrics.horiBearingY) /64.0; 528 } 529 530 PutTransformedFace(face); 531 return B_OK; 532 } 533 534 535 status_t 536 ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[], 537 int32 numStrings, BRect rectArray[], font_metric_mode mode, escapement_delta deltaArray[]) 538 { 539 if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray) 540 return B_BAD_DATA; 541 542 FT_Face face = GetTransformedFace(true, true); 543 if (!face) 544 return B_ERROR; 545 546 for (int32 i = 0; i < numStrings; i++) { 547 // TODO: ... 548 } 549 550 PutTransformedFace(face); 551 return B_OK; 552 } 553 554 555 float 556 ServerFont::StringWidth(const char *_string, int32 numChars) const 557 { 558 if (!_string || numChars <= 0) 559 return 0.0; 560 561 FT_Face face = GetTransformedFace(false, false); 562 if (!face) 563 return 0.0; 564 565 float width = 0.0; 566 const char *string = _string; 567 for (int i = 0; i < numChars; i++) { 568 FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP); 569 width += face->glyph->advance.x / 64.0; 570 } 571 572 PutTransformedFace(face); 573 return width; 574 } 575 576 577 /*! 578 \brief Returns a BRect which encloses the entire font 579 \return A BRect which encloses the entire font 580 */ 581 BRect 582 ServerFont::BoundingBox() 583 { 584 // TODO: fBounds is nowhere calculated! 585 return fBounds; 586 } 587 588 589 /*! 590 \brief Obtains the height values for characters in the font in its current state 591 \param fh pointer to a font_height object to receive the values for the font 592 */ 593 void 594 ServerFont::GetHeight(font_height& height) const 595 { 596 fStyle->GetHeight(fSize, height); 597 } 598 599 600 void 601 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const 602 { 603 if (!inOut) 604 return; 605 606 // the width of the "…" glyph 607 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, 1); 608 const char *string = inOut->String(); 609 int32 length = inOut->Length(); 610 611 // temporary array to hold result 612 char *result = new char[length + 3]; 613 614 // count the individual glyphs 615 int32 numChars = UTF8CountChars(string, -1); 616 617 // get the escapement of each glyph in font units 618 float *escapementArray = new float[numChars]; 619 static escapement_delta delta = (escapement_delta){ 0.0, 0.0 }; 620 if (GetEscapements(string, numChars, delta, escapementArray) == B_OK) { 621 truncate_string(string, mode, width, result, escapementArray, fSize, 622 ellipsisWidth, length, numChars); 623 624 inOut->SetTo(result); 625 } 626 627 delete[] escapementArray; 628 delete[] result; 629 } 630 631