xref: /haiku/src/servers/app/font/FontEngine.cpp (revision 6c4a44e36ba846c54467103f884d65dfa13e7fcb)
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