usb_ecm: Use the current configuration instead of a fixed one.
[haiku.git] / src / servers / app / font / FontEngine.cpp
blob0312b0944d5cefc9bc84c6898164a3532d69bef8
1 /*
2 * Copyright 2007, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
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>
12 //----------------------------------------------------------------------------
13 // Anti-Grain Geometry - Version 2.4
14 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
21 //----------------------------------------------------------------------------
22 // Contact: mcseem@antigrain.com
23 // mcseemagg@yahoo.com
24 // http://www.antigrain.com
25 //----------------------------------------------------------------------------
28 #include "FontEngine.h"
30 #include FT_GLYPH_H
31 #include FT_OUTLINE_H
32 #include FT_LCD_FILTER_H
34 #include <stdio.h>
36 #include <agg_bitset_iterator.h>
37 #include <agg_renderer_scanline.h>
39 #include "GlobalSubpixelSettings.h"
42 static const bool kFlipY = true;
45 static inline double
46 int26p6_to_dbl(int p)
48 return double(p) / 64.0;
52 static inline int
53 dbl_to_int26p6(double p)
55 return int(p * 64.0 + 0.5);
59 template<class PathStorage>
60 bool
61 decompose_ft_outline(const FT_Outline& outline, bool flip_y, PathStorage& path)
63 typedef typename PathStorage::value_type value_type;
65 FT_Vector v_last;
66 FT_Vector v_control;
67 FT_Vector v_start;
68 double x1, y1, x2, y2, x3, y3;
70 FT_Vector* point;
71 FT_Vector* limit;
72 char* tags;
74 int n; // index of contour in outline
75 int first; // index of first point in contour
76 char tag; // current point's state
78 first = 0;
80 for (n = 0; n < outline.n_contours; n++) {
81 int last; // index of last point in contour
83 last = outline.contours[n];
84 limit = outline.points + last;
86 v_start = outline.points[first];
87 v_last = outline.points[last];
89 v_control = v_start;
91 point = outline.points + first;
92 tags = outline.tags + first;
93 tag = FT_CURVE_TAG(tags[0]);
95 // A contour cannot start with a cubic control point!
96 if (tag == FT_CURVE_TAG_CUBIC)
97 return false;
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;
113 v_last = v_start;
115 point--;
116 tags--;
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)));
125 while(point < limit) {
126 point++;
127 tags++;
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;
141 case FT_CURVE_TAG_CONIC: { // consume conic arcs
142 v_control.x = point->x;
143 v_control.y = point->y;
145 Do_Conic:
146 if (point < limit) {
147 FT_Vector vec;
148 FT_Vector v_middle;
150 point++;
151 tags++;
152 tag = FT_CURVE_TAG(tags[0]);
154 vec.x = point->x;
155 vec.y = point->y;
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;
170 if (tag != FT_CURVE_TAG_CONIC)
171 return false;
173 v_middle.x = (v_control.x + vec.x) / 2;
174 v_middle.y = (v_control.y + vec.y) / 2;
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)));
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));
191 v_control = vec;
192 goto Do_Conic;
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)));
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;
212 default: { // FT_CURVE_TAG_CUBIC
213 FT_Vector vec1, vec2;
215 if (point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
216 return false;
218 vec1.x = point[0].x;
219 vec1.y = point[0].y;
220 vec2.x = point[1].x;
221 vec2.y = point[1].y;
223 point += 2;
224 tags += 2;
226 if (point <= limit) {
227 FT_Vector vec;
229 vec.x = point->x;
230 vec.y = point->y;
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)));
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;
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)));
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;
280 path.close_polygon();
282 Close:
283 first = last + 1;
286 return true;
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)
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;
304 for (unsigned int i = 0; i < bitmap.rows; i++) {
305 sl.reset_spans();
306 agg::bitset_iterator bits(buf, 0);
307 for (unsigned int j = 0; j < bitmap.width; j++) {
308 if (bits.bit())
309 sl.add_cell(x + j, agg::cover_full);
310 ++bits;
312 buf += pitch;
313 if (sl.num_spans()) {
314 sl.finalize(y - i - 1);
315 storage.render(sl);
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)
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;
335 for (unsigned int i = 0; i < bitmap.rows; i++) {
336 sl.reset_spans();
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 (unsigned int j = 0; j < bitmap.width; j++) {
342 if (bits.bit())
343 sl.add_cell(x + j, agg::cover_full);
344 ++bits;
346 } else {
347 const uint8* p = buf;
348 for (unsigned int j = 0; j < bitmap.width; j++) {
349 if (*p)
350 sl.add_cell(x + j, *p);
351 ++p;
355 buf += pitch;
356 if (sl.num_spans()) {
357 sl.finalize(y - i - 1);
358 storage.render(sl);
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)
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();
375 if (flip_y) {
376 buf += bitmap.pitch * (bitmap.rows - 1);
377 y += bitmap.rows;
378 pitch = -pitch;
381 for (unsigned int i = 0; i < bitmap.rows; i++) {
382 sl.reset_spans();
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 (unsigned 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);
392 ++bits;
394 } else {
395 const uint8* p = buf;
396 int w = bitmap.width / 3;
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;
405 buf += pitch;
406 if (sl.num_spans()) {
407 sl.finalize(y - i - 1);
408 storage.render(sl);
411 #else
412 // filter based anti-colored edges method
413 // Filtering weights
414 const uint8 filter[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 };
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;
426 for (int i = 0; i < bitmap.rows; i++) {
427 sl.reset_spans();
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);
437 ++bits;
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])))) {
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));
455 if (coverR || coverG || coverB)
456 sl.add_cell(x - 1, coverR, coverG, coverB);
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]))) {
463 coverR = p[0];
464 coverG = p[0];
465 coverB = p[0];
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]))) {
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));
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]))) {
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));
505 } else {
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));
527 if (coverR || coverG || coverB)
528 sl.add_cell(x + j, coverR, coverG, coverB);
529 p += 3;
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])))) {
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));
541 if (coverR || coverG || coverB)
542 sl.add_cell(x + w, coverR, coverG, coverB);
546 buf += pitch;
547 if (sl.num_spans()) {
548 sl.finalize(y - i - 1);
549 storage.render(sl);
552 #endif
556 // #pragma mark -
559 FontEngine::FontEngine()
561 fLastError(0),
562 fLibraryInitialized(false),
563 fLibrary(0),
564 fFace(NULL),
566 fGlyphRendering(glyph_ren_native_gray8),
567 fHinting(true),
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),
577 fPath(),
578 fCurves(fPath),
579 fScanlineAA(),
580 fScanlineBin(),
581 fScanlineSubpix(),
582 fScanlineStorageAA(),
583 fScanlineStorageBin(),
584 fScanlineStorageSubpix()
586 fCurves.approximation_scale(4.0);
588 fLastError = FT_Init_FreeType(&fLibrary);
589 if (fLastError == 0)
590 fLibraryInitialized = true;
594 FontEngine::~FontEngine()
596 FT_Done_Face(fFace);
598 if (fLibraryInitialized)
599 FT_Done_FreeType(fLibrary);
603 unsigned
604 FontEngine::CountFaces() const
606 if (fFace)
607 return fFace->num_faces;
609 return 0;
613 uint32
614 FontEngine::GlyphIndexForGlyphCode(uint32 glyphCode) const
616 return FT_Get_Char_Index(fFace, glyphCode);
620 bool
621 FontEngine::PrepareGlyph(uint32 glyphIndex)
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;
627 // Load unscaled and without hinting to get precise advance values
628 // for B_CHAR_SPACING
629 fLastError = FT_Load_Glyph(fFace, glyphIndex, loadFlags
630 | FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
632 fPreciseAdvanceX = (double)fFace->glyph->advance.x / fFace->units_per_EM;
633 fPreciseAdvanceY = (double)fFace->glyph->advance.y / fFace->units_per_EM;
635 // Need to load again with hinting.
636 fLastError = FT_Load_Glyph(fFace, glyphIndex, loadFlags);
638 if (fLastError != 0)
639 return false;
641 fAdvanceX = int26p6_to_dbl(fFace->glyph->advance.x);
642 fAdvanceY = int26p6_to_dbl(fFace->glyph->advance.y);
644 fInsetLeft = int26p6_to_dbl(fFace->glyph->metrics.horiBearingX);
645 fInsetRight = int26p6_to_dbl(fFace->glyph->metrics.horiBearingX
646 + fFace->glyph->metrics.width - fFace->glyph->metrics.horiAdvance);
648 switch(fGlyphRendering) {
649 case glyph_ren_native_mono:
650 fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_MONO);
651 if (fLastError == 0) {
652 decompose_ft_bitmap_mono(fFace->glyph->bitmap,
653 fFace->glyph->bitmap_left, kFlipY ?
654 -fFace->glyph->bitmap_top : fFace->glyph->bitmap_top,
655 kFlipY, fScanlineBin, fScanlineStorageBin);
656 fBounds.x1 = fScanlineStorageBin.min_x();
657 fBounds.y1 = fScanlineStorageBin.min_y();
658 fBounds.x2 = fScanlineStorageBin.max_x();
659 fBounds.y2 = fScanlineStorageBin.max_y();
660 fDataSize = fScanlineStorageBin.byte_size();
661 fDataType = glyph_data_mono;
662 return true;
664 break;
667 case glyph_ren_native_gray8:
668 fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_NORMAL);
669 if (fLastError == 0) {
670 decompose_ft_bitmap_gray8(fFace->glyph->bitmap,
671 fFace->glyph->bitmap_left, kFlipY ?
672 -fFace->glyph->bitmap_top : fFace->glyph->bitmap_top,
673 kFlipY, fScanlineAA, fScanlineStorageAA);
674 fBounds.x1 = fScanlineStorageAA.min_x();
675 fBounds.y1 = fScanlineStorageAA.min_y();
676 fBounds.x2 = fScanlineStorageAA.max_x();
677 fBounds.y2 = fScanlineStorageAA.max_y();
678 fDataSize = fScanlineStorageAA.byte_size();
679 fDataType = glyph_data_gray8;
680 return true;
682 break;
685 case glyph_ren_subpix:
686 fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_LCD);
687 if (fLastError == 0) {
688 decompose_ft_bitmap_subpix(fFace->glyph->bitmap,
689 fFace->glyph->bitmap_left, kFlipY ?
690 -fFace->glyph->bitmap_top : fFace->glyph->bitmap_top,
691 kFlipY, fScanlineSubpix, fScanlineStorageSubpix);
692 fBounds.x1 = fScanlineStorageSubpix.min_x();
693 fBounds.y1 = fScanlineStorageSubpix.min_y();
694 fBounds.x2 = fScanlineStorageSubpix.max_x();
695 fBounds.y2 = fScanlineStorageSubpix.max_y();
696 fDataSize = fScanlineStorageSubpix.byte_size();
697 fDataType = glyph_data_subpix;
698 return true;
700 break;
703 case glyph_ren_outline:
704 fPath.remove_all();
705 if (decompose_ft_outline(fFace->glyph->outline, kFlipY, fPath)) {
706 agg::rect_d bounds = fPath.bounding_rect();
707 fBounds.x1 = int(floor(bounds.x1));
708 fBounds.y1 = int(floor(bounds.y1));
709 fBounds.x2 = int(ceil(bounds.x2));
710 fBounds.y2 = int(ceil(bounds.y2));
711 fDataSize = fPath.byte_size();
712 fDataType = glyph_data_outline;
713 return true;
715 break;
717 return false;
720 // #pragma mark -
722 // WriteGlyphTo
723 void
724 FontEngine::WriteGlyphTo(uint8* data) const
726 if (data && fDataSize) {
727 switch(fDataType) {
728 case glyph_data_mono:
729 fScanlineStorageBin.serialize(data);
730 break;
732 case glyph_data_gray8:
733 fScanlineStorageAA.serialize(data);
734 break;
736 case glyph_data_subpix:
737 fScanlineStorageSubpix.serialize(data);
738 break;
740 case glyph_data_outline:
741 fPath.serialize(data);
742 break;
744 case glyph_data_invalid:
745 default:
746 break;
752 // GetKerning
753 bool
754 FontEngine::GetKerning(uint32 first, uint32 second, double* x, double* y)
756 if (fFace && first && second && FT_HAS_KERNING(fFace)) {
757 FT_Vector delta;
758 FT_Get_Kerning(fFace, first, second, FT_KERNING_DEFAULT, &delta);
760 double dx = int26p6_to_dbl(delta.x);
761 double dy = int26p6_to_dbl(delta.y);
763 *x += dx;
764 *y += dy;
766 return true;
768 return false;
772 // #pragma mark -
775 bool
776 FontEngine::Init(const char* fontFilePath, unsigned faceIndex, double size,
777 FT_Encoding charMap, glyph_rendering ren_type, bool hinting,
778 const char* fontFileBuffer, const long fontFileBufferSize)
780 if (!fLibraryInitialized)
781 return false;
783 fHinting = hinting;
785 fLastError = 0;
787 FT_Done_Face(fFace);
788 if (fontFileBuffer && fontFileBufferSize) {
789 fLastError = FT_New_Memory_Face(fLibrary,
790 (const FT_Byte*)fontFileBuffer, fontFileBufferSize,
791 faceIndex, &fFace);
792 } else {
793 fLastError = FT_New_Face(fLibrary, fontFilePath, faceIndex, &fFace);
796 if (fLastError != 0)
797 return false;
799 switch(ren_type) {
800 case glyph_ren_native_mono:
801 fGlyphRendering = glyph_ren_native_mono;
802 break;
804 case glyph_ren_native_gray8:
805 fGlyphRendering = glyph_ren_native_gray8;
806 break;
808 case glyph_ren_subpix:
809 fGlyphRendering = glyph_ren_subpix;
810 break;
812 case glyph_ren_outline:
813 if (FT_IS_SCALABLE(fFace))
814 fGlyphRendering = glyph_ren_outline;
815 else
816 fGlyphRendering = glyph_ren_native_gray8;
817 break;
820 FT_Set_Pixel_Sizes(fFace,
821 unsigned(size * 64.0) >> 6, // pixel_width
822 unsigned(size * 64.0) >> 6); // pixel_height
824 if (charMap != FT_ENCODING_NONE) {
825 fLastError = FT_Select_Charmap(fFace, charMap);
826 } else {
827 if (FT_Select_Charmap(fFace, FT_ENCODING_UNICODE) != 0)
828 fLastError = FT_Select_Charmap(fFace, FT_ENCODING_NONE);
831 return fLastError == 0;