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