1 /* 2 * Copyright 2001-2005, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 */ 8 9 10 #include <ByteOrder.h> 11 #include <Shape.h> 12 #include <String.h> 13 #include <UTF8.h> 14 15 #include "Angle.h" 16 #include "FontServer.h" 17 #include "moreUTF8.h" 18 #include "truncate_string.h" 19 20 #include FT_FREETYPE_H 21 #include FT_OUTLINE_H 22 23 #include "ServerFont.h" 24 25 26 // functions needed to convert a freetype vector graphics to a BShape 27 inline BPoint 28 VectorToPoint(FT_Vector *vector) 29 { 30 BPoint result; 31 result.x = float(int32(vector->x)) / 2097152; 32 result.y = -float(int32(vector->y)) / 2097152; 33 return result; 34 } 35 36 int 37 MoveToFunc(FT_Vector *to, void *user) 38 { 39 ((BShape *)user)->MoveTo(VectorToPoint(to)); 40 return 0; 41 } 42 43 int 44 LineToFunc(FT_Vector *to, void *user) 45 { 46 ((BShape *)user)->LineTo(VectorToPoint(to)); 47 return 0; 48 } 49 50 int 51 ConicToFunc(FT_Vector *control, FT_Vector *to, void *user) 52 { 53 BPoint controls[3]; 54 55 controls[0] = VectorToPoint(control); 56 controls[1] = VectorToPoint(to); 57 controls[2] = controls[1]; 58 59 ((BShape *)user)->BezierTo(controls); 60 return 0; 61 } 62 63 int 64 CubicToFunc(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *user) 65 { 66 BPoint controls[3]; 67 68 controls[0] = VectorToPoint(control1); 69 controls[1] = VectorToPoint(control2); 70 controls[2] = VectorToPoint(to); 71 72 ((BShape *)user)->BezierTo(controls); 73 return 0; 74 } 75 76 77 // is_white_space 78 inline bool 79 is_white_space(uint16 glyph) 80 { 81 // TODO: handle them all! 82 if (glyph == ' ' || glyph == B_TAB) 83 return true; 84 return false; 85 } 86 87 88 // #pragma mark - 89 90 91 /*! 92 \brief Constructor 93 \param style Style object to which the ServerFont belongs 94 \param size Character size in points 95 \param rotation Rotation in degrees 96 \param shear Shear (slant) in degrees. 45 <= shear <= 135 97 \param flags Style flags as defined in <Font.h> 98 \param spacing String spacing flag as defined in <Font.h> 99 */ 100 ServerFont::ServerFont(FontStyle *style, float size, 101 float rotation, float shear, 102 uint16 flags, uint8 spacing) 103 : fStyle(style), 104 fSize(size), 105 fRotation(rotation), 106 fShear(shear), 107 fBounds(0, 0, 0, 0), 108 fFlags(flags), 109 fSpacing(spacing), 110 fDirection(B_FONT_LEFT_TO_RIGHT), 111 fFace(B_REGULAR_FACE), 112 fEncoding(B_UNICODE_UTF8) 113 114 { 115 if (fStyle) 116 fStyle->AddDependent(); 117 } 118 119 // TODO: fStyle should not be NULL. There should be another FontStyle 120 // constructor, that initializes without actually interfacing with 121 // freetype, so that a ServerFont can be guaranteed to be "valid". 122 123 ServerFont::ServerFont() 124 : fStyle(NULL), 125 fSize(0.0), 126 fRotation(0.0), 127 fShear(90.0), 128 fBounds(0, 0, 0, 0), 129 fFlags(0), 130 fSpacing(B_STRING_SPACING), 131 fDirection(B_FONT_LEFT_TO_RIGHT), 132 fFace(B_REGULAR_FACE), 133 fEncoding(B_UNICODE_UTF8) 134 { 135 } 136 137 /*! 138 \brief Copy Constructor 139 \param font ServerFont to copy 140 */ 141 ServerFont::ServerFont(const ServerFont &font) 142 : fStyle(font.fStyle), 143 fSize(font.fSize), 144 fRotation(font.fRotation), 145 fShear(font.fShear), 146 fBounds(0, 0, 0, 0), 147 fFlags(font.fFlags), 148 fSpacing(font.fSpacing), 149 fDirection(font.fDirection), 150 fFace(font.fFace), 151 fEncoding(font.fEncoding) 152 { 153 if (fStyle) 154 fStyle->AddDependent(); 155 } 156 157 /*! 158 \brief Removes itself as a dependency of its owning style. 159 */ 160 ServerFont::~ServerFont() 161 { 162 if (fStyle) 163 fStyle->RemoveDependent(); 164 } 165 166 /*! 167 \brief Returns a copy of the specified font 168 \param The font to copy from. 169 \return A copy of the specified font 170 */ 171 ServerFont& 172 ServerFont::operator=(const ServerFont& font) 173 { 174 fSize = font.fSize; 175 fRotation = font.fRotation; 176 fShear = font.fShear; 177 fFlags = font.fFlags; 178 fSpacing = font.fSpacing; 179 fDirection = font.fDirection; 180 fFace = font.fFace; 181 fEncoding = font.fEncoding; 182 fBounds = font.fBounds; 183 184 _SetStyle(font.fStyle); 185 186 return *this; 187 } 188 189 /*! 190 \brief Returns the number of strikes in the font 191 \return The number of strikes in the font 192 */ 193 int32 194 ServerFont::CountTuned() 195 { 196 if (fStyle) 197 return fStyle->TunedCount(); 198 199 return 0; 200 } 201 202 /*! 203 \brief Returns the file format of the font. Currently unimplemented. 204 \return B_TRUETYPE_WINDOWS 205 */ 206 font_file_format 207 ServerFont::FileFormat() 208 { 209 // TODO: implement ServerFont::FileFormat 210 return B_TRUETYPE_WINDOWS; 211 } 212 213 const char* 214 ServerFont::GetStyle() const 215 { 216 if (fStyle) 217 return fStyle->Name(); 218 219 return NULL; 220 } 221 222 const char* 223 ServerFont::GetFamily() const 224 { 225 if (fStyle) 226 return fStyle->Family()->Name(); 227 228 return NULL; 229 } 230 231 /*! 232 \brief Sets the ServerFont instance to whatever font is specified 233 \param familyID ID number of the family to set 234 \param styleID ID number of the style to set 235 \return B_OK if successful, B_ERROR if not 236 */ 237 status_t 238 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID) 239 { 240 FontStyle* style = NULL; 241 242 if (gFontServer->Lock()) { 243 style = gFontServer->GetStyle(familyID, styleID); 244 gFontServer->Unlock(); 245 } 246 247 if (!style) 248 return B_ERROR; 249 250 _SetStyle(style); 251 252 return B_OK; 253 } 254 255 /*! 256 \brief Sets the ServerFont instance to whatever font is specified 257 \param fontID the combination of family and style ID numbers 258 \return B_OK if successful, B_ERROR if not 259 */ 260 status_t 261 ServerFont::SetFamilyAndStyle(uint32 fontID) 262 { 263 uint16 style = fontID & 0xFFFF; 264 uint16 family = (fontID & 0xFFFF0000) >> 16; 265 266 return SetFamilyAndStyle(family, style); 267 } 268 269 /*! 270 \brief Gets the ID values for the ServerFont instance in one shot 271 \return the combination of family and style ID numbers 272 */ 273 uint32 274 ServerFont::GetFamilyAndStyle(void) const 275 { 276 return (FamilyID() << 16) | StyleID(); 277 } 278 279 280 BShape ** 281 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars) const 282 { 283 if (!charArray || numChars <= 0) 284 return NULL; 285 286 FT_Outline_Funcs funcs; 287 funcs.move_to = MoveToFunc; 288 funcs.line_to = LineToFunc; 289 funcs.conic_to = ConicToFunc; 290 funcs.cubic_to = CubicToFunc; 291 292 FT_Face face = fStyle->GetFTFace(); 293 if (!face) 294 return NULL; 295 296 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72); 297 298 Angle rotation(fRotation); 299 Angle shear(fShear); 300 301 // First, rotate 302 FT_Matrix rmatrix; 303 rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000); 304 rmatrix.xy = (FT_Fixed)(-rotation.Sine()*0x10000); 305 rmatrix.yx = (FT_Fixed)( rotation.Sine()*0x10000); 306 rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000); 307 308 // Next, shear 309 FT_Matrix smatrix; 310 smatrix.xx = (FT_Fixed)(0x10000); 311 smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000); 312 smatrix.yx = (FT_Fixed)(0); 313 smatrix.yy = (FT_Fixed)(0x10000); 314 315 // Multiply togheter 316 FT_Matrix_Multiply(&rmatrix, &smatrix); 317 318 //FT_Vector pen; 319 //FT_Set_Transform(face, &smatrix, &pen); 320 321 BShape **shapes = (BShape **)malloc(sizeof(BShape *) * numChars); 322 for (int i = 0; i < numChars; i++) { 323 shapes[i] = new BShape(); 324 shapes[i]->Clear(); 325 FT_Load_Char(face, charArray[i], FT_LOAD_NO_BITMAP); 326 FT_Outline outline = face->glyph->outline; 327 FT_Outline_Decompose(&outline, &funcs, shapes[i]); 328 shapes[i]->Close(); 329 } 330 331 return shapes; 332 } 333 334 // GetEscapements 335 BPoint* 336 ServerFont::GetEscapements(const char charArray[], int32 numChars, 337 BPoint offsetArray[]) const 338 { 339 if (!fStyle || !charArray || numChars <= 0 || !offsetArray) 340 return NULL; 341 342 FT_Face face = fStyle->GetFTFace(); 343 if (!face) 344 return NULL; 345 346 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72); 347 348 Angle rotation(fRotation); 349 Angle shear(fShear); 350 351 // First, rotate 352 FT_Matrix rmatrix; 353 rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000); 354 rmatrix.xy = (FT_Fixed)(-rotation.Sine()*0x10000); 355 rmatrix.yx = (FT_Fixed)( rotation.Sine()*0x10000); 356 rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000); 357 358 // Next, shear 359 FT_Matrix smatrix; 360 smatrix.xx = (FT_Fixed)(0x10000); 361 smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000); 362 smatrix.yx = (FT_Fixed)(0); 363 smatrix.yy = (FT_Fixed)(0x10000); 364 365 // Multiply togheter 366 FT_Matrix_Multiply(&rmatrix, &smatrix); 367 368 //FT_Vector pen; 369 //FT_Set_Transform(face, &smatrix, &pen); 370 371 // TODO: I'm not sure if this the correct interpretation 372 // of the BeBook. Have actual tests been done here? 373 374 // TODO: handle UTF8... see below!! 375 BPoint *escapements = (BPoint *)malloc(sizeof(BPoint) * numChars); 376 for (int i = 0; i < numChars; i++) { 377 FT_Load_Char(face, charArray[i], FT_LOAD_NO_BITMAP); 378 // escapements[i].x = float(face->glyph->metrics.width / 64) / fSize; 379 // escapements[i].y = 0; 380 escapements[i].x = float(face->glyph->metrics.horiAdvance / 64) / fSize; 381 escapements[i].y = float(face->glyph->metrics.vertAdvance / 64) / fSize; 382 escapements[i] += offsetArray[i]; 383 } 384 385 return escapements; 386 } 387 388 389 // GetEscapements 390 bool 391 ServerFont::GetEscapements(const char charArray[], int32 numChars, 392 float widthArray[], escapement_delta delta) const 393 { 394 if (!fStyle || !charArray || numChars <= 0) 395 return false; 396 397 FT_Face face = fStyle->GetFTFace(); 398 if (!face) 399 return false; 400 401 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72); 402 403 // UTF8 handling...this can probably be smarter 404 // Here is what I do in the AGGTextRenderer to handle UTF8... 405 // It is probably highly inefficient, so it should be reviewed. 406 int32 numBytes = UTF8CountBytes(charArray, numChars); 407 int32 convertedLength = numBytes * 2; 408 char* convertedBuffer = new char[convertedLength]; 409 410 int32 state = 0; 411 status_t ret; 412 if ((ret = convert_from_utf8(B_UNICODE_CONVERSION, 413 charArray, &numBytes, 414 convertedBuffer, &convertedLength, 415 &state, B_SUBSTITUTE)) >= B_OK 416 && (ret = swap_data(B_INT16_TYPE, convertedBuffer, convertedLength, 417 B_SWAP_BENDIAN_TO_HOST)) >= B_OK) { 418 419 uint16* glyphIndex = (uint16*)convertedBuffer; 420 // just to be sure 421 numChars = min_c((uint32)numChars, convertedLength / sizeof(uint16)); 422 423 for (int i = 0; i < numChars; i++) { 424 FT_Load_Char(face, glyphIndex[i], FT_LOAD_NO_BITMAP); 425 if (face->glyph) { 426 widthArray[i] = ((float)face->glyph->metrics.horiAdvance / 64.0) / fSize; 427 widthArray[i] += is_white_space(glyphIndex[i]) ? delta.space : delta.nonspace; 428 } 429 } 430 } 431 delete[] convertedBuffer; 432 433 return ret >= B_OK; 434 } 435 436 // StringWidth 437 float 438 ServerFont::StringWidth(const char* string, int32 numBytes) const 439 { 440 if (!fStyle || !string || numBytes <= 0) 441 return 0.0; 442 443 FT_Face face = fStyle->GetFTFace(); 444 if (!face) 445 return 0.0; 446 447 float width = 0.0; 448 449 int32 convertedLength = numBytes * 2; 450 char* convertedBuffer = new char[convertedLength]; 451 452 int32 state = 0; 453 status_t ret; 454 if ((ret = convert_from_utf8(B_UNICODE_CONVERSION, 455 string, &numBytes, 456 convertedBuffer, &convertedLength, 457 &state, B_SUBSTITUTE)) >= B_OK 458 && (ret = swap_data(B_INT16_TYPE, convertedBuffer, convertedLength, 459 B_SWAP_BENDIAN_TO_HOST)) >= B_OK) { 460 461 uint16* glyphIndex = (uint16*)convertedBuffer; 462 // just to be sure 463 int numChars = convertedLength / sizeof(uint16); 464 465 for (int i = 0; i < numChars; i++) { 466 FT_Load_Char(face, glyphIndex[i], FT_LOAD_NO_BITMAP); 467 width += (float)face->glyph->metrics.horiAdvance / 64.0; 468 } 469 } 470 delete[] convertedBuffer; 471 472 return width; 473 } 474 475 /*! 476 \brief Returns a BRect which encloses the entire font 477 \return A BRect which encloses the entire font 478 */ 479 BRect 480 ServerFont::BoundingBox() 481 { 482 // TODO: fBounds is nowhere calculated! 483 return fBounds; 484 } 485 486 /*! 487 \brief Obtains the height values for characters in the font in its current state 488 \param fh pointer to a font_height object to receive the values for the font 489 */ 490 void 491 ServerFont::Height(font_height *fh) const 492 { 493 if (fh && fStyle) 494 *fh = fStyle->GetHeight(fSize); 495 } 496 497 // TruncateString 498 void 499 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const 500 { 501 if (inOut) { 502 // the width of the "…" glyph 503 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, 3); 504 const char* string = inOut->String(); 505 int32 length = strlen(string); 506 // temporary array to hold result 507 char* result = new char[length + 3]; 508 // count the individual glyphs 509 int32 numChars = UTF8CountChars(string, length); 510 // get the escapement of each glyph in font units 511 float* escapementArray = new float[numChars]; 512 static escapement_delta delta = (escapement_delta){ 0.0, 0.0 }; 513 GetEscapements(string, numChars, escapementArray, delta); 514 515 truncate_string(string, mode, width, result, 516 escapementArray, fSize, ellipsisWidth, length, numChars); 517 518 inOut->SetTo(result); 519 520 delete[] escapementArray; 521 delete[] result; 522 } 523 } 524 525 // _SetStyle 526 void 527 ServerFont::_SetStyle(FontStyle* style) 528 { 529 if (style != fStyle) { 530 // detach from old style 531 if (fStyle) 532 fStyle->RemoveDependent(); 533 534 fStyle = style; 535 536 // attach to new style 537 if (fStyle) 538 fStyle->AddDependent(); 539 } 540 } 541