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