xref: /haiku/src/servers/app/font/FontEngine.cpp (revision ca8ed5ea660fb6275799a3b7f138b201c41a667b)
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 (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;
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 (unsigned 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 (unsigned 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 (unsigned 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 (unsigned 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 (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);
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 	// 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);
631 
632 	fPreciseAdvanceX = (double)fFace->glyph->advance.x / fFace->units_per_EM;
633 	fPreciseAdvanceY = (double)fFace->glyph->advance.y / fFace->units_per_EM;
634 
635 	// Need to load again with hinting.
636 	fLastError = FT_Load_Glyph(fFace, glyphIndex, loadFlags);
637 
638 	if (fLastError != 0)
639 		return false;
640 
641 	fAdvanceX = int26p6_to_dbl(fFace->glyph->advance.x);
642 	fAdvanceY = int26p6_to_dbl(fFace->glyph->advance.y);
643 
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);
647 
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;
663 			}
664 			break;
665 
666 
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;
681 			}
682 			break;
683 
684 
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;
699 			}
700 			break;
701 
702 
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;
714 			}
715 			break;
716 	}
717 	return false;
718 }
719 
720 // #pragma mark -
721 
722 // WriteGlyphTo
723 void
724 FontEngine::WriteGlyphTo(uint8* data) const
725 {
726 	if (data && fDataSize) {
727 		switch(fDataType) {
728 			case glyph_data_mono:
729 				fScanlineStorageBin.serialize(data);
730 				break;
731 
732 			case glyph_data_gray8:
733 				fScanlineStorageAA.serialize(data);
734 				break;
735 
736 			case glyph_data_subpix:
737 				fScanlineStorageSubpix.serialize(data);
738 				break;
739 
740 			case glyph_data_outline:
741 				fPath.serialize(data);
742 				break;
743 
744 			case glyph_data_invalid:
745 			default:
746 				break;
747 		}
748 	}
749 }
750 
751 
752 // GetKerning
753 bool
754 FontEngine::GetKerning(uint32 first, uint32 second, double* x, double* y)
755 {
756 	if (fFace && first && second && FT_HAS_KERNING(fFace)) {
757 		FT_Vector delta;
758 		FT_Get_Kerning(fFace, first, second, FT_KERNING_DEFAULT, &delta);
759 
760 		double dx = int26p6_to_dbl(delta.x);
761 		double dy = int26p6_to_dbl(delta.y);
762 
763 		*x += dx;
764 		*y += dy;
765 
766 		return true;
767 	}
768 	return false;
769 }
770 
771 
772 // #pragma mark -
773 
774 
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)
779 {
780 	if (!fLibraryInitialized)
781 		return false;
782 
783 	fHinting = hinting;
784 
785 	fLastError = 0;
786 
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);
794 	}
795 
796 	if (fLastError != 0)
797 		return false;
798 
799 	switch(ren_type) {
800 		case glyph_ren_native_mono:
801 			fGlyphRendering = glyph_ren_native_mono;
802 			break;
803 
804 		case glyph_ren_native_gray8:
805 			fGlyphRendering = glyph_ren_native_gray8;
806 			break;
807 
808 		case glyph_ren_subpix:
809 			fGlyphRendering = glyph_ren_subpix;
810 			break;
811 
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;
818 	}
819 
820 	FT_Set_Pixel_Sizes(fFace,
821 		unsigned(size * 64.0) >> 6,		// pixel_width
822 		unsigned(size * 64.0) >> 6);	// pixel_height
823 
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);
829 	}
830 
831 	return fLastError == 0;
832 }
833 
834