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
42static const bool kFlipY = true;
43
44
45static inline double
46int26p6_to_dbl(int p)
47{
48	return double(p) / 64.0;
49}
50
51
52static inline int
53dbl_to_int26p6(double p)
54{
55	return int(p * 64.0 + 0.5);
56}
57
58
59template<class PathStorage>
60bool
61decompose_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
290template<class Scanline, class ScanlineStorage>
291void
292decompose_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
321template<class Scanline, class ScanlineStorage>
322void
323decompose_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
364template<class Scanline, class ScanlineStorage>
365void
366decompose_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
559FontEngine::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
594FontEngine::~FontEngine()
595{
596	FT_Done_Face(fFace);
597
598	if (fLibraryInitialized)
599		FT_Done_FreeType(fLibrary);
600}
601
602
603unsigned
604FontEngine::CountFaces() const
605{
606	if (fFace)
607		return fFace->num_faces;
608
609	return 0;
610}
611
612
613uint32
614FontEngine::GlyphIndexForGlyphCode(uint32 glyphCode) const
615{
616	return FT_Get_Char_Index(fFace, glyphCode);
617}
618
619
620bool
621FontEngine::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
713void
714FontEngine::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
743bool
744FontEngine::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
765bool
766FontEngine::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