1 /*************************************************************************
2 ** FontEngine.cpp                                                       **
3 **                                                                      **
4 ** This file is part of dvisvgm -- the DVI to SVG converter             **
5 ** Copyright (C) 2005-2015 Martin Gieseking <martin.gieseking@uos.de>   **
6 **                                                                      **
7 ** This program is free software; you can redistribute it and/or        **
8 ** modify it under the terms of the GNU General Public License as       **
9 ** published by the Free Software Foundation; either version 3 of       **
10 ** the License, or (at your option) any later version.                  **
11 **                                                                      **
12 ** This program is distributed in the hope that it will be useful, but  **
13 ** WITHOUT ANY WARRANTY; without even the implied warranty of           **
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         **
15 ** GNU General Public License for more details.                         **
16 **                                                                      **
17 ** You should have received a copy of the GNU General Public License    **
18 ** along with this program; if not, see <http://www.gnu.org/licenses/>. **
19 *************************************************************************/
20 
21 #include <config.h>
22 #include <iostream>
23 #include <sstream>
24 #include <ft2build.h>
25 #include FT_ADVANCES_H
26 #include FT_GLYPH_H
27 #include FT_OUTLINE_H
28 #include FT_TRUETYPE_TABLES_H
29 #include FT_TYPES_H
30 #include "Font.h"
31 #include "FontEngine.h"
32 #include "FontStyle.h"
33 #include "Message.h"
34 
35 using namespace std;
36 
37 
38 /** Converts a floating point value to a 16.16 fixed point value. */
to_16dot16(double val)39 static inline FT_Fixed to_16dot16 (double val) {
40 	return static_cast<FT_Fixed>(val*65536.0 + 0.5);
41 }
42 
43 
44 /** Converts an integer to a 16.16 fixed point value. */
to_16dot16(int val)45 static inline FT_Fixed to_16dot16 (int val) {
46 	return static_cast<FT_Fixed>(val) << 16;
47 }
48 
49 
50 ///////////////////////////////////////////////////////////////////////////
51 
52 
FontEngine()53 FontEngine::FontEngine () : _currentFace(0), _currentFont(0)
54 {
55 	_currentChar = _currentGlyphIndex = 0;
56 	_horDeviceRes = _vertDeviceRes = 300;
57 	if (FT_Init_FreeType(&_library))
58 		Message::estream(true) << "FontEngine: error initializing FreeType library\n";
59 }
60 
61 
~FontEngine()62 FontEngine::~FontEngine () {
63 	if (_currentFace && FT_Done_Face(_currentFace))
64 		Message::estream(true) << "FontEngine: error removing glyph\n";
65 	if (FT_Done_FreeType(_library))
66 		Message::estream(true) << "FontEngine: error removing FreeType library\n";
67 }
68 
69 
70 /** Returns the singleton instance of this class. */
instance()71 FontEngine& FontEngine::instance () {
72 	static FontEngine engine;
73 	return engine;
74 }
75 
76 
version()77 string FontEngine::version () {
78 	FT_Int major, minor, patch;
79 	FT_Library &lib = instance()._library;
80 	FT_Library_Version(lib, &major, &minor, &patch);
81 	ostringstream oss;
82 	oss << major << '.' << minor << '.' << patch;
83 	return oss.str();
84 }
85 
86 
setDeviceResolution(int x,int y)87 void FontEngine::setDeviceResolution (int x, int y) {
88 	_horDeviceRes = x;
89 	_vertDeviceRes = y;
90 }
91 
92 
93 /** Sets the font to be used.
94  * @param[in] fname path to font file
95  * @param[in] fontindex index of font in font collection (multi-font files, like TTC)
96  * @return true on success */
setFont(const string & fname,int fontindex,const CharMapID & charMapID)97 bool FontEngine::setFont (const string &fname, int fontindex, const CharMapID &charMapID) {
98 	if (_currentFace && FT_Done_Face(_currentFace))
99 		Message::estream(true) << "FontEngine: error removing font\n";
100 	if (FT_New_Face(_library, fname.c_str(), fontindex, &_currentFace)) {
101 		Message::estream(true) << "FontEngine: error reading file " << fname << '\n';
102 		return false;
103 	}
104 	if (charMapID.valid())
105 		setCharMap(charMapID);
106 	return true;
107 }
108 
109 
setFont(const Font & font)110 bool FontEngine::setFont (const Font &font) {
111 	if (!_currentFont || _currentFont->name() != font.name()) {
112 		const PhysicalFont *pf = dynamic_cast<const PhysicalFont*>(&font);
113 		_currentFont = &font;
114 		return setFont(font.path(), font.fontIndex(), pf ? pf->getCharMapID() : CharMapID());
115 	}
116 	return true;
117 }
118 
119 
isCIDFont() const120 bool FontEngine::isCIDFont() const {
121 	FT_Bool cid_keyed;
122 	return FT_Get_CID_Is_Internally_CID_Keyed(_currentFace, &cid_keyed) == 0 && cid_keyed;
123 }
124 
125 
setCharMap(const CharMapID & charMapID)126 bool FontEngine::setCharMap (const CharMapID &charMapID) {
127 	for (int i=0; i < _currentFace->num_charmaps; i++) {
128 		FT_CharMap ft_cmap = _currentFace->charmaps[i];
129 		if (ft_cmap->platform_id == charMapID.platform_id && ft_cmap->encoding_id == charMapID.encoding_id) {
130 			FT_Set_Charmap(_currentFace, ft_cmap);
131 			return true;
132 		}
133 	}
134 	return false;
135 }
136 
137 
138 /** Returns a character map that maps from character indexes to character codes
139  *  of the current encoding.
140  *  @param[out] charmap the resulting charmap */
buildCharMap(RangeMap & charmap)141 void FontEngine::buildCharMap (RangeMap &charmap) {
142 	charmap.clear();
143 	FT_UInt glyph_index;
144 	UInt32 charcode = FT_Get_First_Char(_currentFace, &glyph_index);
145 	while (glyph_index) {
146 		charmap.addRange(glyph_index, glyph_index, charcode);
147 		charcode = FT_Get_Next_Char(_currentFace, charcode, &glyph_index);
148 	}
149 }
150 
151 
152 /** Creates a charmap that maps from the custom character encoding to unicode.
153  *  @return pointer to charmap if it could be created, 0 otherwise */
createCustomToUnicodeMap()154 const RangeMap* FontEngine::createCustomToUnicodeMap () {
155 	FT_CharMap ftcharmap = _currentFace->charmap;
156 	if (FT_Select_Charmap(_currentFace, FT_ENCODING_ADOBE_CUSTOM) != 0)
157 		return 0;
158 	RangeMap index_to_source_chrcode;
159 	buildCharMap(index_to_source_chrcode);
160 	if (FT_Select_Charmap(_currentFace, FT_ENCODING_UNICODE) != 0)
161 		return 0;
162 	RangeMap *charmap = new RangeMap;
163 	FT_UInt glyph_index;
164 	UInt32 unicode_point = FT_Get_First_Char(_currentFace, &glyph_index);
165 	while (glyph_index) {
166 		UInt32 custom_charcode = index_to_source_chrcode.valueAt(glyph_index);
167 		charmap->addRange(custom_charcode, custom_charcode, unicode_point);
168 		unicode_point = FT_Get_Next_Char(_currentFace, unicode_point, &glyph_index);
169 	}
170 	FT_Set_Charmap(_currentFace, ftcharmap);
171 	return charmap;
172 }
173 
174 
getFamilyName() const175 const char* FontEngine::getFamilyName () const {
176 	return _currentFace ? _currentFace->family_name : 0;
177 }
178 
179 
getStyleName() const180 const char* FontEngine::getStyleName () const {
181 	return _currentFace ? _currentFace->style_name : 0;
182 }
183 
184 
getUnitsPerEM() const185 int FontEngine::getUnitsPerEM () const {
186 	return _currentFace ? _currentFace->units_per_EM : 0;
187 }
188 
189 
190 /** Returns the ascender of the current font in font units. */
getAscender() const191 int FontEngine::getAscender () const {
192 	return _currentFace ? _currentFace->ascender : 0;
193 }
194 
195 
196 /** Returns the descender of the current font in font units. */
getDescender() const197 int FontEngine::getDescender () const {
198 	return _currentFace ? _currentFace->descender : 0;
199 }
200 
201 
getAdvance(int c) const202 int FontEngine::getAdvance (int c) const {
203 	if (_currentFace) {
204 		FT_Fixed adv=0;
205 		FT_Get_Advance(_currentFace, c, FT_LOAD_NO_SCALE, &adv);
206 		return adv;
207 	}
208 	return 0;
209 }
210 
211 
getHAdvance() const212 int FontEngine::getHAdvance () const {
213 	if (_currentFace) {
214 		TT_OS2 *table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2));
215 		return table ? table->xAvgCharWidth : 0;
216 	}
217 	return 0;
218 }
219 
220 
getHAdvance(const Character & c) const221 int FontEngine::getHAdvance (const Character &c) const {
222 	if (_currentFace) {
223 		FT_Load_Glyph(_currentFace, charIndex(c), FT_LOAD_NO_SCALE);
224 		return _currentFace->glyph->metrics.horiAdvance;
225 	}
226 	return 0;
227 }
228 
229 
getVAdvance(const Character & c) const230 int FontEngine::getVAdvance (const Character &c) const {
231 	if (_currentFace) {
232 		FT_Load_Glyph(_currentFace, charIndex(c), FT_LOAD_NO_SCALE);
233 		if (FT_HAS_VERTICAL(_currentFace))
234 			return _currentFace->glyph->metrics.vertAdvance;
235 		return _currentFace->glyph->metrics.horiAdvance;
236 	}
237 	return 0;
238 }
239 
240 
charIndex(const Character & c) const241 int FontEngine::charIndex (const Character &c) const {
242 	switch (c.type()) {
243 		case Character::CHRCODE:
244 			return FT_Get_Char_Index(_currentFace, (FT_ULong)c.number());
245 		case Character::NAME:
246 			return FT_Get_Name_Index(_currentFace, (FT_String*)c.name());
247 		default:
248 			return c.number();
249 	}
250 }
251 
252 
253 /** Get first available character of the current font face. */
getFirstChar() const254 int FontEngine::getFirstChar () const {
255 	if (_currentFace)
256 		return _currentChar = FT_Get_First_Char(_currentFace, &_currentGlyphIndex);
257 	return 0;
258 }
259 
260 
261 /** Get the next available character of the current font face. */
getNextChar() const262 int FontEngine::getNextChar () const {
263 	if (_currentFace && _currentGlyphIndex)
264 		return _currentChar = FT_Get_Next_Char(_currentFace, _currentChar, &_currentGlyphIndex);
265 	return getFirstChar();
266 }
267 
268 
269 /** Returns the number of glyphs present in the current font face. */
getNumGlyphs() const270 int FontEngine::getNumGlyphs () const {
271 	return _currentFace ? _currentFace->num_glyphs : 0;
272 }
273 
274 
275 /** Returns the glyph name for a given charater code.
276  * @param[in] c char code
277  * @return glyph name */
getGlyphName(const Character & c) const278 string FontEngine::getGlyphName (const Character &c) const {
279 	if (c.type() == Character::NAME)
280 		return c.name();
281 
282 	if (_currentFace && FT_HAS_GLYPH_NAMES(_currentFace)) {
283 		char buf[256];
284 		FT_Get_Glyph_Name(_currentFace, charIndex(c), buf, 256);
285 		return string(buf);
286 	}
287 	return "";
288 }
289 
290 
getPanose() const291 vector<int> FontEngine::getPanose () const {
292 	vector<int> panose(10);
293 	if (_currentFace) {
294 		TT_OS2 *table = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(_currentFace, ft_sfnt_os2));
295 		if (table)
296 			for (int i=0; i < 10; i++)
297 				panose[i] = table->panose[i];
298 	}
299 	return panose;
300 }
301 
302 
getCharMapIDs(vector<CharMapID> & charmapIDs) const303 int FontEngine::getCharMapIDs (vector<CharMapID> &charmapIDs) const {
304 	charmapIDs.clear();
305 	if (_currentFace) {
306 		for (int i=0; i < _currentFace->num_charmaps; i++) {
307 			FT_CharMap charmap = _currentFace->charmaps[i];
308 			charmapIDs.push_back(CharMapID(charmap->platform_id, charmap->encoding_id));
309 		}
310 	}
311 	return charmapIDs.size();
312 }
313 
314 
setUnicodeCharMap()315 CharMapID FontEngine::setUnicodeCharMap () {
316 	if (_currentFace && FT_Select_Charmap(_currentFace, FT_ENCODING_UNICODE) == 0)
317 		return CharMapID(_currentFace->charmap->platform_id, _currentFace->charmap->encoding_id);
318 	return CharMapID();
319 }
320 
321 
setCustomCharMap()322 CharMapID FontEngine::setCustomCharMap () {
323 	if (_currentFace && FT_Select_Charmap(_currentFace, FT_ENCODING_ADOBE_CUSTOM) == 0)
324 		return CharMapID(_currentFace->charmap->platform_id, _currentFace->charmap->encoding_id);
325 	return CharMapID();
326 }
327 
328 
329 // handle API change in freetype version 2.2.1
330 #if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && (FREETYPE_MINOR > 2 || (FREETYPE_MINOR == 2 && FREETYPE_PATCH >= 1)))
331 	typedef const FT_Vector *FTVectorPtr;
332 #else
333 	typedef FT_Vector *FTVectorPtr;
334 #endif
335 
336 
337 // Callback functions used by trace_outline/FT_Outline_Decompose
moveto(FTVectorPtr to,void * user)338 static int moveto (FTVectorPtr to, void *user) {
339 	Glyph *glyph = static_cast<Glyph*>(user);
340 	glyph->moveto(to->x, to->y);
341 	return 0;
342 }
343 
344 
lineto(FTVectorPtr to,void * user)345 static int lineto (FTVectorPtr to, void *user) {
346 	Glyph *glyph = static_cast<Glyph*>(user);
347 	glyph->lineto(to->x, to->y);
348 	return 0;
349 }
350 
351 
conicto(FTVectorPtr control,FTVectorPtr to,void * user)352 static int conicto (FTVectorPtr control, FTVectorPtr to, void *user) {
353 	Glyph *glyph = static_cast<Glyph*>(user);
354 	glyph->conicto(control->x, control->y, to->x, to->y);
355 	return 0;
356 }
357 
358 
cubicto(FTVectorPtr control1,FTVectorPtr control2,FTVectorPtr to,void * user)359 static int cubicto (FTVectorPtr control1, FTVectorPtr control2, FTVectorPtr to, void *user) {
360 	Glyph *glyph = static_cast<Glyph*>(user);
361 	glyph->cubicto(control1->x, control1->y, control2->x, control2->y, to->x, to->y);
362 	return 0;
363 }
364 
365 
366 /** Traces the outline of a glyph by calling the corresponding "drawing" functions.
367  *  Each glyph is composed of straight lines, quadratic (conic) or cubic B�zier curves.
368  *  This function creates a Glyph object representing these graphics segments.
369  *  @param[in] face FreeType object representing the font to scan
370  *  @param[in] font corresponding Font object providing additional data
371  *  @param[in] index index of the glyph to be traced
372  *  @param[out] glyph resulting Glyph object containing the graphics segments
373  *  @param[in] scale if true the current pt size will be considered otherwise the plain TrueType units are used.
374  *  @return false on errors */
trace_outline(FT_Face face,const Font * font,int index,Glyph & glyph,bool scale)375 static bool trace_outline (FT_Face face, const Font *font, int index, Glyph &glyph, bool scale) {
376 	if (face) {
377 		if (FT_Load_Glyph(face, index, scale ? FT_LOAD_DEFAULT : FT_LOAD_NO_SCALE)) {
378 			Message::estream(true) << "can't load glyph " << int(index) << '\n';
379 			return false;
380 		}
381 		if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
382 			Message::estream(true) << "no outlines found in glyph " << int(index) << '\n';
383 			return false;
384 		}
385 		FT_Outline outline = face->glyph->outline;
386 		// apply style parameters if set
387 		if (const FontStyle *style = font->style()) {
388 			FT_Matrix matrix = {to_16dot16(style->extend), to_16dot16(style->slant), 0, to_16dot16(1)};
389 			FT_Outline_Transform(&outline, &matrix);
390 			if (style->bold != 0)
391 				FT_Outline_Embolden(&outline, style->bold/font->scaledSize()*face->units_per_EM);
392 		}
393 		const FT_Outline_Funcs funcs = {moveto, lineto, conicto, cubicto, 0, 0};
394 		FT_Outline_Decompose(&outline, &funcs, &glyph);
395 		return true;
396 	}
397 	Message::wstream(true) << "FontEngine: can't trace outline, no font face selected\n";
398 	return false;
399 }
400 
401 
402 /** Traces the outline of a glyph by calling the corresponding "drawing" functions.
403  *  Each glyph is composed of straight lines, quadratic (conic) or cubic B�zier curves.
404  *  This function creates a Glyph object representing these graphics segments.
405  *  @param[in] c the glyph of this character will be traced
406  *  @param[out] glyph resulting Glyph object containing the graphics segments
407  *  @param[in] scale if true the current pt size will be considered otherwise the plain TrueType units are used.
408  *  @return false on errors */
traceOutline(const Character & c,Glyph & glyph,bool scale) const409 bool FontEngine::traceOutline (const Character &c, Glyph &glyph, bool scale) const {
410 	if (_currentFace)
411 		return trace_outline(_currentFace, _currentFont, charIndex(c), glyph, scale);
412 	Message::wstream(true) << "FontEngine: can't trace outline, no font face selected\n";
413 	return false;
414 }
415