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 (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
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 (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
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	const uint8* buf = (const uint8*)bitmap.buffer;
370	int pitch = bitmap.pitch;
371	sl.reset(x, x + bitmap.width / 3);
372	storage.prepare();
373
374	if (flip_y) {
375		buf += bitmap.pitch * (bitmap.rows - 1);
376		y += bitmap.rows;
377		pitch = -pitch;
378	}
379
380	for (unsigned int i = 0; i < bitmap.rows; i++) {
381		sl.reset_spans();
382
383		if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
384			// font has built-in mono bitmap
385			agg::bitset_iterator bits(buf, 0);
386			for (unsigned int j = 0; j < bitmap.width; j++) {
387				if (bits.bit()) {
388					sl.add_cell(x + j,
389						agg::cover_full, agg::cover_full, agg::cover_full);
390				}
391				++bits;
392			}
393		} else {
394			const uint8* p = buf;
395			int w = bitmap.width / 3;
396
397			for (int j = 0; j < w; j++) {
398				if (p[0] || p[1] || p[2])
399					sl.add_cell(x + j, p[0], p[1], p[2]);
400				p += 3;
401			}
402		}
403
404		buf += pitch;
405		if (sl.num_spans()) {
406			sl.finalize(y - i - 1);
407			storage.render(sl);
408		}
409	}
410}
411
412
413// #pragma mark -
414
415
416FontEngine::FontEngine()
417	:
418	fLastError(0),
419	fLibraryInitialized(false),
420	fLibrary(0),
421	fFace(NULL),
422
423	fGlyphRendering(glyph_ren_native_gray8),
424	fHinting(true),
425
426	fDataSize(0),
427	fDataType(glyph_data_invalid),
428	fBounds(1, 1, 0, 0),
429	fAdvanceX(0.0),
430	fAdvanceY(0.0),
431	fInsetLeft(0.0),
432	fInsetRight(0.0),
433
434	fPath(),
435	fCurves(fPath),
436	fScanlineAA(),
437	fScanlineBin(),
438	fScanlineSubpix(),
439	fScanlineStorageAA(),
440	fScanlineStorageBin(),
441	fScanlineStorageSubpix()
442{
443	fCurves.approximation_scale(4.0);
444
445	fLastError = FT_Init_FreeType(&fLibrary);
446	if (fLastError == 0)
447		fLibraryInitialized = true;
448}
449
450
451FontEngine::~FontEngine()
452{
453	FT_Done_Face(fFace);
454
455	if (fLibraryInitialized)
456		FT_Done_FreeType(fLibrary);
457}
458
459
460unsigned
461FontEngine::CountFaces() const
462{
463	if (fFace)
464		return fFace->num_faces;
465
466	return 0;
467}
468
469
470uint32
471FontEngine::GlyphIndexForGlyphCode(uint32 glyphCode) const
472{
473	return FT_Get_Char_Index(fFace, glyphCode);
474}
475
476
477bool
478FontEngine::PrepareGlyph(uint32 glyphIndex)
479{
480	FT_Int32 loadFlags = fHinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING;
481	loadFlags |= fGlyphRendering == glyph_ren_subpix ?
482		FT_LOAD_TARGET_LCD : FT_LOAD_TARGET_NORMAL;
483
484	// Load unscaled and without hinting to get precise advance values
485	// for B_CHAR_SPACING
486	fLastError = FT_Load_Glyph(fFace, glyphIndex, loadFlags
487		| FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
488
489	fPreciseAdvanceX = (double)fFace->glyph->advance.x / fFace->units_per_EM;
490	fPreciseAdvanceY = (double)fFace->glyph->advance.y / fFace->units_per_EM;
491
492	// Need to load again with hinting.
493	fLastError = FT_Load_Glyph(fFace, glyphIndex, loadFlags);
494
495	if (fLastError != 0)
496		return false;
497
498	fAdvanceX = int26p6_to_dbl(fFace->glyph->advance.x);
499	fAdvanceY = int26p6_to_dbl(fFace->glyph->advance.y);
500
501	fInsetLeft = int26p6_to_dbl(fFace->glyph->metrics.horiBearingX);
502	fInsetRight = int26p6_to_dbl(fFace->glyph->metrics.horiBearingX
503		+ fFace->glyph->metrics.width - fFace->glyph->metrics.horiAdvance);
504
505	switch(fGlyphRendering) {
506		case glyph_ren_native_mono:
507			fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_MONO);
508			if (fLastError == 0) {
509				decompose_ft_bitmap_mono(fFace->glyph->bitmap,
510					fFace->glyph->bitmap_left, kFlipY ?
511					-fFace->glyph->bitmap_top : fFace->glyph->bitmap_top,
512					kFlipY, fScanlineBin, fScanlineStorageBin);
513				fBounds.x1 = fScanlineStorageBin.min_x();
514				fBounds.y1 = fScanlineStorageBin.min_y();
515				fBounds.x2 = fScanlineStorageBin.max_x();
516				fBounds.y2 = fScanlineStorageBin.max_y();
517				fDataSize = fScanlineStorageBin.byte_size();
518				fDataType = glyph_data_mono;
519				return true;
520			}
521			break;
522
523
524		case glyph_ren_native_gray8:
525			fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_NORMAL);
526			if (fLastError == 0) {
527				decompose_ft_bitmap_gray8(fFace->glyph->bitmap,
528					fFace->glyph->bitmap_left, kFlipY ?
529					-fFace->glyph->bitmap_top : fFace->glyph->bitmap_top,
530					kFlipY, fScanlineAA, fScanlineStorageAA);
531				fBounds.x1 = fScanlineStorageAA.min_x();
532				fBounds.y1 = fScanlineStorageAA.min_y();
533				fBounds.x2 = fScanlineStorageAA.max_x();
534				fBounds.y2 = fScanlineStorageAA.max_y();
535				fDataSize = fScanlineStorageAA.byte_size();
536				fDataType = glyph_data_gray8;
537				return true;
538			}
539			break;
540
541
542		case glyph_ren_subpix:
543			fLastError = FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_LCD);
544			if (fLastError == 0) {
545				decompose_ft_bitmap_subpix(fFace->glyph->bitmap,
546					fFace->glyph->bitmap_left, kFlipY ?
547					-fFace->glyph->bitmap_top : fFace->glyph->bitmap_top,
548					kFlipY, fScanlineSubpix, fScanlineStorageSubpix);
549				fBounds.x1 = fScanlineStorageSubpix.min_x();
550				fBounds.y1 = fScanlineStorageSubpix.min_y();
551				fBounds.x2 = fScanlineStorageSubpix.max_x();
552				fBounds.y2 = fScanlineStorageSubpix.max_y();
553				fDataSize = fScanlineStorageSubpix.byte_size();
554				fDataType = glyph_data_subpix;
555				return true;
556			}
557			break;
558
559
560		case glyph_ren_outline:
561			fPath.remove_all();
562			if (decompose_ft_outline(fFace->glyph->outline, kFlipY, fPath)) {
563				agg::rect_d bounds = fPath.bounding_rect();
564				fBounds.x1 = int(floor(bounds.x1));
565				fBounds.y1 = int(floor(bounds.y1));
566				fBounds.x2 = int(ceil(bounds.x2));
567				fBounds.y2 = int(ceil(bounds.y2));
568				fDataSize = fPath.byte_size();
569				fDataType = glyph_data_outline;
570				return true;
571			}
572			break;
573	}
574	return false;
575}
576
577// #pragma mark -
578
579// WriteGlyphTo
580void
581FontEngine::WriteGlyphTo(uint8* data) const
582{
583	if (data && fDataSize) {
584		switch(fDataType) {
585			case glyph_data_mono:
586				fScanlineStorageBin.serialize(data);
587				break;
588
589			case glyph_data_gray8:
590				fScanlineStorageAA.serialize(data);
591				break;
592
593			case glyph_data_subpix:
594				fScanlineStorageSubpix.serialize(data);
595				break;
596
597			case glyph_data_outline:
598				fPath.serialize(data);
599				break;
600
601			case glyph_data_invalid:
602			default:
603				break;
604		}
605	}
606}
607
608
609// GetKerning
610bool
611FontEngine::GetKerning(uint32 first, uint32 second, double* x, double* y)
612{
613	if (fFace && first && second && FT_HAS_KERNING(fFace)) {
614		FT_Vector delta;
615		FT_Get_Kerning(fFace, first, second, FT_KERNING_DEFAULT, &delta);
616
617		double dx = int26p6_to_dbl(delta.x);
618		double dy = int26p6_to_dbl(delta.y);
619
620		*x += dx;
621		*y += dy;
622
623		return true;
624	}
625	return false;
626}
627
628
629// #pragma mark -
630
631
632bool
633FontEngine::Init(const char* fontFilePath, unsigned faceIndex, double size,
634	FT_Encoding charMap, glyph_rendering ren_type, bool hinting,
635	const char* fontFileBuffer, const long fontFileBufferSize)
636{
637	if (!fLibraryInitialized)
638		return false;
639
640	fHinting = hinting;
641
642	fLastError = 0;
643
644	FT_Done_Face(fFace);
645	if (fontFileBuffer && fontFileBufferSize) {
646		fLastError = FT_New_Memory_Face(fLibrary,
647			(const FT_Byte*)fontFileBuffer, fontFileBufferSize,
648			faceIndex, &fFace);
649	} else {
650		fLastError = FT_New_Face(fLibrary, fontFilePath, faceIndex, &fFace);
651	}
652
653	if (fLastError != 0)
654		return false;
655
656	switch(ren_type) {
657		case glyph_ren_native_mono:
658			fGlyphRendering = glyph_ren_native_mono;
659			break;
660
661		case glyph_ren_native_gray8:
662			fGlyphRendering = glyph_ren_native_gray8;
663			break;
664
665		case glyph_ren_subpix:
666			fGlyphRendering = glyph_ren_subpix;
667			break;
668
669		case glyph_ren_outline:
670			if (FT_IS_SCALABLE(fFace))
671				fGlyphRendering = glyph_ren_outline;
672			else
673				fGlyphRendering = glyph_ren_native_gray8;
674			break;
675	}
676
677	FT_Set_Pixel_Sizes(fFace,
678		unsigned(size * 64.0) >> 6,		// pixel_width
679		unsigned(size * 64.0) >> 6);	// pixel_height
680
681	if (charMap != FT_ENCODING_NONE) {
682		fLastError = FT_Select_Charmap(fFace, charMap);
683	} else {
684		if (FT_Select_Charmap(fFace, FT_ENCODING_UNICODE) != 0)
685			fLastError = FT_Select_Charmap(fFace, FT_ENCODING_NONE);
686	}
687
688	return fLastError == 0;
689}
690
691