1 /* 2 * Copyright 2007, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Maxim Shemanarev <mcseemagg@yahoo.com> 7 * Stephan Aßmus <superstippi@gmx.de> 8 * Anthony Lee <don.anthony.lee@gmail.com> 9 * Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk> 10 */ 11 12 //---------------------------------------------------------------------------- 13 // Anti-Grain Geometry - Version 2.4 14 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 15 // 16 // Permission to copy, use, modify, sell and distribute this software 17 // is granted provided this copyright notice appears in all copies. 18 // This software is provided "as is" without express or implied 19 // warranty, and with no claim as to its suitability for any purpose. 20 // 21 //---------------------------------------------------------------------------- 22 // Contact: mcseem@antigrain.com 23 // mcseemagg@yahoo.com 24 // http://www.antigrain.com 25 //---------------------------------------------------------------------------- 26 27 28 #include "FontEngine.h" 29 30 #include FT_GLYPH_H 31 #include FT_OUTLINE_H 32 #include FT_LCD_FILTER_H 33 34 #include <stdio.h> 35 36 #include <agg_bitset_iterator.h> 37 #include <agg_renderer_scanline.h> 38 39 #include "GlobalSubpixelSettings.h" 40 41 42 static const bool kFlipY = true; 43 44 45 static inline double 46 int26p6_to_dbl(int p) 47 { 48 return double(p) / 64.0; 49 } 50 51 52 static inline int 53 dbl_to_int26p6(double p) 54 { 55 return int(p * 64.0 + 0.5); 56 } 57 58 59 template<class PathStorage> 60 bool 61 decompose_ft_outline(const FT_Outline& outline, bool flip_y, PathStorage& path) 62 { 63 typedef typename PathStorage::value_type value_type; 64 65 FT_Vector v_last; 66 FT_Vector v_control; 67 FT_Vector v_start; 68 double x1, y1, x2, y2, x3, y3; 69 70 FT_Vector* point; 71 FT_Vector* limit; 72 char* tags; 73 74 int n; // index of contour in outline 75 int first; // index of first point in contour 76 char tag; // current point's state 77 78 first = 0; 79 80 for (n = 0; n < outline.n_contours; n++) { 81 int last; // index of last point in contour 82 83 last = outline.contours[n]; 84 limit = outline.points + last; 85 86 v_start = outline.points[first]; 87 v_last = outline.points[last]; 88 89 v_control = v_start; 90 91 point = outline.points + first; 92 tags = outline.tags + first; 93 tag = FT_CURVE_TAG(tags[0]); 94 95 // A contour cannot start with a cubic control point! 96 if (tag == FT_CURVE_TAG_CUBIC) 97 return false; 98 99 // check first point to determine origin 100 if ( tag == FT_CURVE_TAG_CONIC) { 101 // first point is conic control. Yes, this happens. 102 if (FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { 103 // start at last point if it is on the curve 104 v_start = v_last; 105 limit--; 106 } else { 107 // if both first and last points are conic, 108 // start at their middle and record its position 109 // for closure 110 v_start.x = (v_start.x + v_last.x) / 2; 111 v_start.y = (v_start.y + v_last.y) / 2; 112 113 v_last = v_start; 114 } 115 point--; 116 tags--; 117 } 118 119 x1 = int26p6_to_dbl(v_start.x); 120 y1 = int26p6_to_dbl(v_start.y); 121 if (flip_y) y1 = -y1; 122 path.move_to(value_type(dbl_to_int26p6(x1)), 123 value_type(dbl_to_int26p6(y1))); 124 125 while(point < limit) { 126 point++; 127 tags++; 128 129 tag = FT_CURVE_TAG(tags[0]); 130 switch(tag) { 131 case FT_CURVE_TAG_ON: { // emit a single line_to 132 x1 = int26p6_to_dbl(point->x); 133 y1 = int26p6_to_dbl(point->y); 134 if (flip_y) y1 = -y1; 135 path.line_to(value_type(dbl_to_int26p6(x1)), 136 value_type(dbl_to_int26p6(y1))); 137 //path.line_to(conv(point->x), flip_y ? -conv(point->y) : conv(point->y)); 138 continue; 139 } 140 141 case FT_CURVE_TAG_CONIC: { // consume conic arcs 142 v_control.x = point->x; 143 v_control.y = point->y; 144 145 Do_Conic: 146 if (point < limit) { 147 FT_Vector vec; 148 FT_Vector v_middle; 149 150 point++; 151 tags++; 152 tag = FT_CURVE_TAG(tags[0]); 153 154 vec.x = point->x; 155 vec.y = point->y; 156 157 if (tag == FT_CURVE_TAG_ON) { 158 x1 = int26p6_to_dbl(v_control.x); 159 y1 = int26p6_to_dbl(v_control.y); 160 x2 = int26p6_to_dbl(vec.x); 161 y2 = int26p6_to_dbl(vec.y); 162 if (flip_y) { y1 = -y1; y2 = -y2; } 163 path.curve3(value_type(dbl_to_int26p6(x1)), 164 value_type(dbl_to_int26p6(y1)), 165 value_type(dbl_to_int26p6(x2)), 166 value_type(dbl_to_int26p6(y2))); 167 continue; 168 } 169 170 if (tag != FT_CURVE_TAG_CONIC) 171 return false; 172 173 v_middle.x = (v_control.x + vec.x) / 2; 174 v_middle.y = (v_control.y + vec.y) / 2; 175 176 x1 = int26p6_to_dbl(v_control.x); 177 y1 = int26p6_to_dbl(v_control.y); 178 x2 = int26p6_to_dbl(v_middle.x); 179 y2 = int26p6_to_dbl(v_middle.y); 180 if (flip_y) { y1 = -y1; y2 = -y2; } 181 path.curve3(value_type(dbl_to_int26p6(x1)), 182 value_type(dbl_to_int26p6(y1)), 183 value_type(dbl_to_int26p6(x2)), 184 value_type(dbl_to_int26p6(y2))); 185 186 //path.curve3(conv(v_control.x), 187 // flip_y ? -conv(v_control.y) : conv(v_control.y), 188 // conv(v_middle.x), 189 // flip_y ? -conv(v_middle.y) : conv(v_middle.y)); 190 191 v_control = vec; 192 goto Do_Conic; 193 } 194 195 x1 = int26p6_to_dbl(v_control.x); 196 y1 = int26p6_to_dbl(v_control.y); 197 x2 = int26p6_to_dbl(v_start.x); 198 y2 = int26p6_to_dbl(v_start.y); 199 if (flip_y) { y1 = -y1; y2 = -y2; } 200 path.curve3(value_type(dbl_to_int26p6(x1)), 201 value_type(dbl_to_int26p6(y1)), 202 value_type(dbl_to_int26p6(x2)), 203 value_type(dbl_to_int26p6(y2))); 204 205 //path.curve3(conv(v_control.x), 206 // flip_y ? -conv(v_control.y) : conv(v_control.y), 207 // conv(v_start.x), 208 // flip_y ? -conv(v_start.y) : conv(v_start.y)); 209 goto Close; 210 } 211 212 default: { // FT_CURVE_TAG_CUBIC 213 FT_Vector vec1, vec2; 214 215 if (point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) 216 return false; 217 218 vec1.x = point[0].x; 219 vec1.y = point[0].y; 220 vec2.x = point[1].x; 221 vec2.y = point[1].y; 222 223 point += 2; 224 tags += 2; 225 226 if (point <= limit) { 227 FT_Vector vec; 228 229 vec.x = point->x; 230 vec.y = point->y; 231 232 x1 = int26p6_to_dbl(vec1.x); 233 y1 = int26p6_to_dbl(vec1.y); 234 x2 = int26p6_to_dbl(vec2.x); 235 y2 = int26p6_to_dbl(vec2.y); 236 x3 = int26p6_to_dbl(vec.x); 237 y3 = int26p6_to_dbl(vec.y); 238 if (flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; } 239 path.curve4(value_type(dbl_to_int26p6(x1)), 240 value_type(dbl_to_int26p6(y1)), 241 value_type(dbl_to_int26p6(x2)), 242 value_type(dbl_to_int26p6(y2)), 243 value_type(dbl_to_int26p6(x3)), 244 value_type(dbl_to_int26p6(y3))); 245 246 //path.curve4(conv(vec1.x), 247 // flip_y ? -conv(vec1.y) : conv(vec1.y), 248 // conv(vec2.x), 249 // flip_y ? -conv(vec2.y) : conv(vec2.y), 250 // conv(vec.x), 251 // flip_y ? -conv(vec.y) : conv(vec.y)); 252 continue; 253 } 254 255 x1 = int26p6_to_dbl(vec1.x); 256 y1 = int26p6_to_dbl(vec1.y); 257 x2 = int26p6_to_dbl(vec2.x); 258 y2 = int26p6_to_dbl(vec2.y); 259 x3 = int26p6_to_dbl(v_start.x); 260 y3 = int26p6_to_dbl(v_start.y); 261 if (flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; } 262 path.curve4(value_type(dbl_to_int26p6(x1)), 263 value_type(dbl_to_int26p6(y1)), 264 value_type(dbl_to_int26p6(x2)), 265 value_type(dbl_to_int26p6(y2)), 266 value_type(dbl_to_int26p6(x3)), 267 value_type(dbl_to_int26p6(y3))); 268 269 //path.curve4(conv(vec1.x), 270 // flip_y ? -conv(vec1.y) : conv(vec1.y), 271 // conv(vec2.x), 272 // flip_y ? -conv(vec2.y) : conv(vec2.y), 273 // conv(v_start.x), 274 // flip_y ? -conv(v_start.y) : conv(v_start.y)); 275 goto Close; 276 } 277 } 278 } 279 280 path.close_polygon(); 281 282 Close: 283 first = last + 1; 284 } 285 286 return true; 287 } 288 289 290 template<class Scanline, class ScanlineStorage> 291 void 292 decompose_ft_bitmap_mono(const FT_Bitmap& bitmap, int x, int y, 293 bool flip_y, Scanline& sl, ScanlineStorage& storage) 294 { 295 const uint8* buf = (const uint8*)bitmap.buffer; 296 int pitch = bitmap.pitch; 297 sl.reset(x, x + bitmap.width); 298 storage.prepare(); 299 if (flip_y) { 300 buf += bitmap.pitch * (bitmap.rows - 1); 301 y += bitmap.rows; 302 pitch = -pitch; 303 } 304 for (int i = 0; i < bitmap.rows; i++) { 305 sl.reset_spans(); 306 agg::bitset_iterator bits(buf, 0); 307 for (int j = 0; j < bitmap.width; j++) { 308 if (bits.bit()) 309 sl.add_cell(x + j, agg::cover_full); 310 ++bits; 311 } 312 buf += pitch; 313 if (sl.num_spans()) { 314 sl.finalize(y - i - 1); 315 storage.render(sl); 316 } 317 } 318 } 319 320 321 template<class Scanline, class ScanlineStorage> 322 void 323 decompose_ft_bitmap_gray8(const FT_Bitmap& bitmap, int x, int y, 324 bool flip_y, Scanline& sl, ScanlineStorage& storage) 325 { 326 const uint8* buf = (const uint8*)bitmap.buffer; 327 int pitch = bitmap.pitch; 328 sl.reset(x, x + bitmap.width); 329 storage.prepare(); 330 if (flip_y) { 331 buf += bitmap.pitch * (bitmap.rows - 1); 332 y += bitmap.rows; 333 pitch = -pitch; 334 } 335 for (int i = 0; i < bitmap.rows; i++) { 336 sl.reset_spans(); 337 338 if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { 339 // font has built-in mono bitmap 340 agg::bitset_iterator bits(buf, 0); 341 for (int j = 0; j < bitmap.width; j++) { 342 if (bits.bit()) 343 sl.add_cell(x + j, agg::cover_full); 344 ++bits; 345 } 346 } else { 347 const uint8* p = buf; 348 for (int j = 0; j < bitmap.width; j++) { 349 if (*p) 350 sl.add_cell(x + j, *p); 351 ++p; 352 } 353 } 354 355 buf += pitch; 356 if (sl.num_spans()) { 357 sl.finalize(y - i - 1); 358 storage.render(sl); 359 } 360 } 361 } 362 363 364 template<class Scanline, class ScanlineStorage> 365 void 366 decompose_ft_bitmap_subpix(const FT_Bitmap& bitmap, int x, int y, 367 bool flip_y, Scanline& sl, ScanlineStorage& storage) 368 { 369 #ifdef AVERAGE_BASED_SUBPIXEL_FILTERING 370 const uint8* buf = (const uint8*)bitmap.buffer; 371 int pitch = bitmap.pitch; 372 sl.reset(x, x + bitmap.width / 3); 373 storage.prepare(); 374 375 if (flip_y) { 376 buf += bitmap.pitch * (bitmap.rows - 1); 377 y += bitmap.rows; 378 pitch = -pitch; 379 } 380 381 for (int i = 0; i < bitmap.rows; i++) { 382 sl.reset_spans(); 383 384 if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { 385 // font has built-in mono bitmap 386 agg::bitset_iterator bits(buf, 0); 387 for (int j = 0; j < bitmap.width; j++) { 388 if (bits.bit()) { 389 sl.add_cell(x + j, 390 agg::cover_full, agg::cover_full, agg::cover_full); 391 } 392 ++bits; 393 } 394 } else { 395 const uint8* p = buf; 396 int w = bitmap.width / 3; 397 398 for (int j = 0; j < w; j++) { 399 if (p[0] || p[1] || p[2]) 400 sl.add_cell(x + j, p[0], p[1], p[2]); 401 p += 3; 402 } 403 } 404 405 buf += pitch; 406 if (sl.num_spans()) { 407 sl.finalize(y - i - 1); 408 storage.render(sl); 409 } 410 } 411 #else 412 // filter based anti-colored edges method 413 // Filtering weights 414 const uint8 filter[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 }; 415 416 const uint8* buf = (const uint8*)bitmap.buffer; 417 int pitch = bitmap.pitch; 418 sl.reset(x - 1, x + bitmap.width / 3 + 1); 419 // -1 and +1 to account for additional edge pixels needed by filtering 420 storage.prepare(); 421 if (flip_y) { 422 buf += bitmap.pitch * (bitmap.rows - 1); 423 y += bitmap.rows; 424 pitch = -pitch; 425 } 426 for (int i = 0; i < bitmap.rows; i++) { 427 sl.reset_spans(); 428 429 if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { 430 // font has built-in mono bitmap 431 agg::bitset_iterator bits(buf, 0); 432 for (int j = 0; j < bitmap.width; j++) { 433 if (bits.bit()) { 434 sl.add_cell(x + j, 435 agg::cover_full, agg::cover_full, agg::cover_full); 436 } 437 ++bits; 438 } 439 } else { 440 const uint8* p = buf; 441 uint32 coverR; 442 uint32 coverG; 443 uint32 coverB; 444 int w = bitmap.width / 3; 445 // handle the left extra edge pixel 446 if (w && !(p[0] == p[1] && p[1] == p[2] 447 && (w == 1 || (p[3] == p[4] && p[4] == p[5])))) { 448 449 coverR = 0; 450 coverG = (p[0] * filter[0]) >> 8; 451 coverB = (p[0] * filter[1] + p[1] * filter[0]) >> 8; 452 coverG = coverG | ( -(coverG >> 8)); 453 coverB = coverB | ( -(coverB >> 8)); 454 455 if (coverR || coverG || coverB) 456 sl.add_cell(x - 1, coverR, coverG, coverB); 457 } 458 for (int j = 0; j < w; j++) { 459 if (p[0] == p[1] && p[1] == p[2] 460 && (j == 0 || (p[-3] == p[-2] && p[-2] == p[-1])) 461 && (j == w-1 || (p[3] == p[4] && p[4] == p[5]))) { 462 463 coverR = p[0]; 464 coverG = p[0]; 465 coverB = p[0]; 466 467 } else if (p[0] == p[1] && p[1] == p[2] 468 && (j < w-1 && p[3] == p[4] && p[4] == p[5]) 469 && (j == w-2 || (p[6] == p[7] && p[7] == p[8]))) { 470 471 coverR = ((j > 0 ? p[-2] * filter[4] 472 + p[-1] * filter[3] : 0) 473 + p[0] * filter[2] + p[1] * filter[1] 474 + p[2] * filter[0]) 475 >> 8; 476 coverG = ((j > 0 ? p[-1] * filter[4] : 0) 477 + p[0] * filter[3] + p[1] * filter[2] 478 + p[2] * filter[1]) 479 >> 8; 480 coverB = (p[0] * filter[4] 481 + p[1] * filter[3] + p[2] * filter[2]) >> 8; 482 coverR = coverR | ( -(coverR >> 8)); 483 coverG = coverG | ( -(coverG >> 8)); 484 coverB = coverB | ( -(coverB >> 8)); 485 486 } else if (p[0] == p[1] && p[1] == p[2] 487 && (j > 0 && p[-3] == p[-2] && p[-2] == p[-1]) 488 && (j == 1 || (p[-6] == p[-5] && p[-5] == p[-4]))) { 489 490 coverR = (p[0] * filter[2] + p[1] * filter[1] 491 + p[2] * filter[0]) >> 8; 492 coverG = (p[0] * filter[3] + p[1] * filter[2] 493 + p[2] * filter[1] 494 + (j < w-1 ? p[3] * filter[0] : 0)) 495 >> 8; 496 coverB = (p[0] * filter[4] + p[1] * filter[3] 497 + p[2] * filter[2] 498 + (j < w-1 ? p[3] * filter[1] 499 + p[4] * filter[0] : 0)) 500 >> 8; 501 coverR = coverR | ( -(coverR >> 8)); 502 coverG = coverG | ( -(coverG >> 8)); 503 coverB = coverB | ( -(coverB >> 8)); 504 505 } else { 506 507 coverR = ((j > 0 ? p[-2] * filter[4] 508 + p[-1] * filter[3] : 0) 509 + p[0] * filter[2] + p[1] * filter[1] 510 + p[2] * filter[0]) 511 >> 8; 512 coverG = ((j > 0 ? p[-1] * filter[4] : 0) 513 + p[0] * filter[3] + p[1] * filter[2] 514 + p[2] * filter[1] 515 + (j < w-1 ? p[3] * filter[0] : 0)) 516 >> 8; 517 coverB = (p[0] * filter[4] + p[1] * filter[3] 518 + p[2] * filter[2] 519 + (j < w-1 ? p[3] * filter[1] 520 + p[4] * filter[0] : 0)) 521 >> 8; 522 coverR = coverR | ( -(coverR >> 8)); 523 coverG = coverG | ( -(coverG >> 8)); 524 coverB = coverB | ( -(coverB >> 8)); 525 } 526 527 if (coverR || coverG || coverB) 528 sl.add_cell(x + j, coverR, coverG, coverB); 529 p += 3; 530 } 531 // handle the right extra edge pixel 532 if (w && !(p[-3] == p[-2] && p[-2] == p[-1] 533 && (w == 1 || (p[-6] == p[-5] && p[-5] == p[-4])))) { 534 535 coverR = (p[-2] * filter[4] + p[-1] * filter[3]) >> 8; 536 coverG = (p[-1] * filter[4]) >> 8; 537 coverB = 0; 538 coverR = coverR | ( -(coverR >> 8)); 539 coverG = coverG | ( -(coverG >> 8)); 540 541 if (coverR || coverG || coverB) 542 sl.add_cell(x + w, coverR, coverG, coverB); 543 } 544 } 545 546 buf += pitch; 547 if (sl.num_spans()) { 548 sl.finalize(y - i - 1); 549 storage.render(sl); 550 } 551 } 552 #endif 553 } 554 555 556 // #pragma mark - 557 558 559 FontEngine::FontEngine() 560 : 561 fLastError(0), 562 fLibraryInitialized(false), 563 fLibrary(0), 564 fFace(NULL), 565 566 fGlyphRendering(glyph_ren_native_gray8), 567 fHinting(true), 568 569 fDataSize(0), 570 fDataType(glyph_data_invalid), 571 fBounds(1, 1, 0, 0), 572 fAdvanceX(0.0), 573 fAdvanceY(0.0), 574 fInsetLeft(0.0), 575 fInsetRight(0.0), 576 577 fPath(), 578 fCurves(fPath), 579 fScanlineAA(), 580 fScanlineBin(), 581 fScanlineSubpix(), 582 fScanlineStorageAA(), 583 fScanlineStorageBin(), 584 fScanlineStorageSubpix() 585 { 586 fCurves.approximation_scale(4.0); 587 588 fLastError = FT_Init_FreeType(&fLibrary); 589 if (fLastError == 0) 590 fLibraryInitialized = true; 591 } 592 593 594 FontEngine::~FontEngine() 595 { 596 FT_Done_Face(fFace); 597 598 if (fLibraryInitialized) 599 FT_Done_FreeType(fLibrary); 600 } 601 602 603 unsigned 604 FontEngine::CountFaces() const 605 { 606 if (fFace) 607 return fFace->num_faces; 608 609 return 0; 610 } 611 612 613 uint32 614 FontEngine::GlyphIndexForGlyphCode(uint32 glyphCode) const 615 { 616 return FT_Get_Char_Index(fFace, glyphCode); 617 } 618 619 620 bool 621 FontEngine::PrepareGlyph(uint32 glyphIndex) 622 { 623 FT_Int32 loadFlags = fHinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING; 624 loadFlags |= fGlyphRendering == glyph_ren_subpix ? 625 FT_LOAD_TARGET_LCD : FT_LOAD_TARGET_NORMAL; 626 627 fLastError = FT_Load_Glyph(fFace, glyphIndex, loadFlags); 628 629 if (fLastError != 0) 630 return false; 631 632 fAdvanceX = int26p6_to_dbl(fFace->glyph->advance.x); 633 fAdvanceY = int26p6_to_dbl(fFace->glyph->advance.y); 634 fInsetLeft = int26p6_to_dbl(fFace->glyph->metrics.horiBearingX); 635 fInsetRight = int26p6_to_dbl(fFace->glyph->metrics.horiBearingX 636 + fFace->glyph->metrics.width - fFace->glyph->metrics.horiAdvance); 637 638 switch(fGlyphRendering) { 639 case glyph_ren_native_mono: 640 fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_MONO); 641 if (fLastError == 0) { 642 decompose_ft_bitmap_mono(fFace->glyph->bitmap, 643 fFace->glyph->bitmap_left, kFlipY ? 644 -fFace->glyph->bitmap_top : fFace->glyph->bitmap_top, 645 kFlipY, fScanlineBin, fScanlineStorageBin); 646 fBounds.x1 = fScanlineStorageBin.min_x(); 647 fBounds.y1 = fScanlineStorageBin.min_y(); 648 fBounds.x2 = fScanlineStorageBin.max_x(); 649 fBounds.y2 = fScanlineStorageBin.max_y(); 650 fDataSize = fScanlineStorageBin.byte_size(); 651 fDataType = glyph_data_mono; 652 return true; 653 } 654 break; 655 656 657 case glyph_ren_native_gray8: 658 fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_NORMAL); 659 if (fLastError == 0) { 660 decompose_ft_bitmap_gray8(fFace->glyph->bitmap, 661 fFace->glyph->bitmap_left, kFlipY ? 662 -fFace->glyph->bitmap_top : fFace->glyph->bitmap_top, 663 kFlipY, fScanlineAA, fScanlineStorageAA); 664 fBounds.x1 = fScanlineStorageAA.min_x(); 665 fBounds.y1 = fScanlineStorageAA.min_y(); 666 fBounds.x2 = fScanlineStorageAA.max_x(); 667 fBounds.y2 = fScanlineStorageAA.max_y(); 668 fDataSize = fScanlineStorageAA.byte_size(); 669 fDataType = glyph_data_gray8; 670 return true; 671 } 672 break; 673 674 675 case glyph_ren_subpix: 676 fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_LCD); 677 if (fLastError == 0) { 678 decompose_ft_bitmap_subpix(fFace->glyph->bitmap, 679 fFace->glyph->bitmap_left, kFlipY ? 680 -fFace->glyph->bitmap_top : fFace->glyph->bitmap_top, 681 kFlipY, fScanlineSubpix, fScanlineStorageSubpix); 682 fBounds.x1 = fScanlineStorageSubpix.min_x(); 683 fBounds.y1 = fScanlineStorageSubpix.min_y(); 684 fBounds.x2 = fScanlineStorageSubpix.max_x(); 685 fBounds.y2 = fScanlineStorageSubpix.max_y(); 686 fDataSize = fScanlineStorageSubpix.byte_size(); 687 fDataType = glyph_data_subpix; 688 return true; 689 } 690 break; 691 692 693 case glyph_ren_outline: 694 fPath.remove_all(); 695 if (decompose_ft_outline(fFace->glyph->outline, kFlipY, fPath)) { 696 agg::rect_d bounds = fPath.bounding_rect(); 697 fBounds.x1 = int(floor(bounds.x1)); 698 fBounds.y1 = int(floor(bounds.y1)); 699 fBounds.x2 = int(ceil(bounds.x2)); 700 fBounds.y2 = int(ceil(bounds.y2)); 701 fDataSize = fPath.byte_size(); 702 fDataType = glyph_data_outline; 703 return true; 704 } 705 break; 706 } 707 return false; 708 } 709 710 // #pragma mark - 711 712 // WriteGlyphTo 713 void 714 FontEngine::WriteGlyphTo(uint8* data) const 715 { 716 if (data && fDataSize) { 717 switch(fDataType) { 718 case glyph_data_mono: 719 fScanlineStorageBin.serialize(data); 720 break; 721 722 case glyph_data_gray8: 723 fScanlineStorageAA.serialize(data); 724 break; 725 726 case glyph_data_subpix: 727 fScanlineStorageSubpix.serialize(data); 728 break; 729 730 case glyph_data_outline: 731 fPath.serialize(data); 732 break; 733 734 case glyph_data_invalid: 735 default: 736 break; 737 } 738 } 739 } 740 741 742 // GetKerning 743 bool 744 FontEngine::GetKerning(uint32 first, uint32 second, double* x, double* y) 745 { 746 if (fFace && first && second && FT_HAS_KERNING(fFace)) { 747 FT_Vector delta; 748 FT_Get_Kerning(fFace, first, second, FT_KERNING_DEFAULT, &delta); 749 750 double dx = int26p6_to_dbl(delta.x); 751 double dy = int26p6_to_dbl(delta.y); 752 753 *x += dx; 754 *y += dy; 755 756 return true; 757 } 758 return false; 759 } 760 761 762 // #pragma mark - 763 764 765 bool 766 FontEngine::Init(const char* fontFilePath, unsigned faceIndex, double size, 767 FT_Encoding charMap, glyph_rendering ren_type, bool hinting, 768 const char* fontFileBuffer, const long fontFileBufferSize) 769 { 770 if (!fLibraryInitialized) 771 return false; 772 773 fHinting = hinting; 774 775 fLastError = 0; 776 777 FT_Done_Face(fFace); 778 if (fontFileBuffer && fontFileBufferSize) { 779 fLastError = FT_New_Memory_Face(fLibrary, 780 (const FT_Byte*)fontFileBuffer, fontFileBufferSize, 781 faceIndex, &fFace); 782 } else { 783 fLastError = FT_New_Face(fLibrary, fontFilePath, faceIndex, &fFace); 784 } 785 786 if (fLastError != 0) 787 return false; 788 789 switch(ren_type) { 790 case glyph_ren_native_mono: 791 fGlyphRendering = glyph_ren_native_mono; 792 break; 793 794 case glyph_ren_native_gray8: 795 fGlyphRendering = glyph_ren_native_gray8; 796 break; 797 798 case glyph_ren_subpix: 799 fGlyphRendering = glyph_ren_subpix; 800 break; 801 802 case glyph_ren_outline: 803 if (FT_IS_SCALABLE(fFace)) 804 fGlyphRendering = glyph_ren_outline; 805 else 806 fGlyphRendering = glyph_ren_native_gray8; 807 break; 808 } 809 810 FT_Set_Pixel_Sizes(fFace, 811 unsigned(size * 64.0) >> 6, // pixel_width 812 unsigned(size * 64.0) >> 6); // pixel_height 813 814 if (charMap != FT_ENCODING_NONE) { 815 fLastError = FT_Select_Charmap(fFace, charMap); 816 } else { 817 if (FT_Select_Charmap(fFace, FT_ENCODING_UNICODE) != 0) 818 fLastError = FT_Select_Charmap(fFace, FT_ENCODING_NONE); 819 } 820 821 return fLastError == 0; 822 } 823 824