1 /****************************************************************************\
2 Part of the XeTeX typesetting system
3 Copyright (c) 1994-2008 by SIL International
4 Copyright (c) 2009 by Jonathan Kew
5
6 SIL Author(s): Jonathan Kew
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
23 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 Except as contained in this notice, the name of the copyright holders
28 shall not be used in advertising or otherwise to promote the sale,
29 use or other dealings in this Software without prior written
30 authorization from the copyright holders.
31 \****************************************************************************/
32
33 /*
34 * file name: XeTeXFontInst.cpp
35 *
36 * created on: 2005-10-22
37 * created by: Jonathan Kew
38 *
39 * originally based on PortableFontInstance.cpp from ICU
40 */
41
42 #include <w2c/config.h>
43
44 #include "XeTeXFontInst.h"
45 #include "XeTeXLayoutInterface.h"
46 #include "XeTeX_ext.h"
47
48 #include <string.h>
49 #include FT_GLYPH_H
50 #include FT_ADVANCES_H
51
52 FT_Library gFreeTypeLibrary = 0;
53
54 static hb_font_funcs_t* hbFontFuncs = NULL;
55
XeTeXFontInst(const char * pathname,int index,float pointSize,int & status)56 XeTeXFontInst::XeTeXFontInst(const char* pathname, int index, float pointSize, int &status)
57 : m_pointSize(pointSize)
58 , m_unitsPerEM(0)
59 , m_ascent(0)
60 , m_descent(0)
61 , m_capHeight(0)
62 , m_xHeight(0)
63 , m_italicAngle(0)
64 , m_vertical(false)
65 , m_filename(NULL)
66 , m_index(0)
67 , m_ftFace(0)
68 , m_hbFont(NULL)
69 , m_math(NULL)
70 {
71 if (pathname != NULL)
72 initialize(pathname, index, status);
73 }
74
~XeTeXFontInst()75 XeTeXFontInst::~XeTeXFontInst()
76 {
77 if (m_ftFace != 0) {
78 FT_Done_Face(m_ftFace);
79 m_ftFace = 0;
80 }
81 hb_font_destroy(m_hbFont);
82 delete[] m_filename;
83 free((void*) m_math);
84 }
85
86 /* HarfBuzz font functions */
87
88 static hb_bool_t
_get_glyph(hb_font_t *,void * font_data,hb_codepoint_t ch,hb_codepoint_t vs,hb_codepoint_t * gid,void *)89 _get_glyph(hb_font_t*, void *font_data, hb_codepoint_t ch, hb_codepoint_t vs, hb_codepoint_t *gid, void*)
90 {
91 FT_Face face = (FT_Face) font_data;
92 *gid = 0;
93
94 if (vs)
95 *gid = FT_Face_GetCharVariantIndex (face, ch, vs);
96
97 if (*gid == 0)
98 *gid = FT_Get_Char_Index (face, ch);
99
100 return *gid != 0;
101 }
102
103 static FT_Fixed
_get_glyph_advance(FT_Face face,FT_UInt gid,bool vertical)104 _get_glyph_advance(FT_Face face, FT_UInt gid, bool vertical)
105 {
106 FT_Error error;
107 FT_Fixed advance;
108 int flags = FT_LOAD_NO_SCALE;
109
110 if (vertical)
111 flags |= FT_LOAD_VERTICAL_LAYOUT;
112
113 error = FT_Get_Advance(face, gid, flags, &advance);
114 if (error)
115 advance = 0;
116 else
117 advance = advance;
118
119 /* FreeType's vertical metrics grows downward */
120 if (vertical)
121 advance = -advance;
122
123 return advance;
124 }
125
126 static hb_position_t
_get_glyph_h_advance(hb_font_t *,void * font_data,hb_codepoint_t gid,void *)127 _get_glyph_h_advance(hb_font_t*, void *font_data, hb_codepoint_t gid, void*)
128 {
129 return _get_glyph_advance((FT_Face) font_data, gid, false);
130 }
131
132 static hb_position_t
_get_glyph_v_advance(hb_font_t *,void * font_data,hb_codepoint_t gid,void *)133 _get_glyph_v_advance(hb_font_t*, void *font_data, hb_codepoint_t gid, void*)
134 {
135 return _get_glyph_advance((FT_Face) font_data, gid, true);
136 }
137
138 static hb_bool_t
_get_glyph_h_origin(hb_font_t *,void * font_data,hb_codepoint_t gid,hb_position_t * x,hb_position_t * y,void *)139 _get_glyph_h_origin(hb_font_t*, void *font_data, hb_codepoint_t gid, hb_position_t *x, hb_position_t *y, void*)
140 {
141 // horizontal origin is (0, 0)
142 return true;
143 }
144
145 static hb_bool_t
_get_glyph_v_origin(hb_font_t *,void * font_data,hb_codepoint_t gid,hb_position_t * x,hb_position_t * y,void *)146 _get_glyph_v_origin(hb_font_t*, void *font_data, hb_codepoint_t gid, hb_position_t *x, hb_position_t *y, void*)
147 {
148 // vertical origin is (0, 0) for now
149 return true;
150
151 // TODO
152 // Keep the code below for reference, for now we want to keep vertical
153 // origin at (0, 0) for compatibility with pre-0.9999.
154 // Reconsider this (e.g. using BASE table) when we get around overhauling
155 // the text directionality model and implementing real vertical typesetting.
156
157 FT_Face face = (FT_Face) font_data;
158 FT_Error error;
159
160 error = FT_Load_Glyph (face, gid, FT_LOAD_NO_SCALE);
161 if (!error) {
162 *x = face->glyph->metrics.horiBearingX - face->glyph->metrics.vertBearingX;
163 *y = face->glyph->metrics.horiBearingY - (-face->glyph->metrics.vertBearingY);
164 }
165
166 return !error;
167 }
168
169 static hb_position_t
_get_glyph_h_kerning(hb_font_t *,void * font_data,hb_codepoint_t gid1,hb_codepoint_t gid2,void *)170 _get_glyph_h_kerning(hb_font_t*, void *font_data, hb_codepoint_t gid1, hb_codepoint_t gid2, void*)
171 {
172 FT_Face face = (FT_Face) font_data;
173 FT_Error error;
174 FT_Vector kerning;
175 hb_position_t ret;
176
177 error = FT_Get_Kerning (face, gid1, gid2, FT_KERNING_UNFITTED, &kerning);
178 if (error)
179 ret = 0;
180 else
181 ret = kerning.x;
182 return ret;
183 }
184
185 static hb_position_t
_get_glyph_v_kerning(hb_font_t *,void * font_data,hb_codepoint_t gid1,hb_codepoint_t gid2,void *)186 _get_glyph_v_kerning(hb_font_t*, void *font_data, hb_codepoint_t gid1, hb_codepoint_t gid2, void*)
187 {
188 /* FreeType does not support vertical kerning */
189 return 0;
190 }
191
192 static hb_bool_t
_get_glyph_extents(hb_font_t *,void * font_data,hb_codepoint_t gid,hb_glyph_extents_t * extents,void *)193 _get_glyph_extents(hb_font_t*, void *font_data, hb_codepoint_t gid, hb_glyph_extents_t *extents, void*)
194 {
195 FT_Face face = (FT_Face) font_data;
196 FT_Error error;
197
198 error = FT_Load_Glyph (face, gid, FT_LOAD_NO_SCALE);
199 if (!error) {
200 extents->x_bearing = face->glyph->metrics.horiBearingX;
201 extents->y_bearing = face->glyph->metrics.horiBearingY;
202 extents->width = face->glyph->metrics.width;
203 extents->height = -face->glyph->metrics.height;
204 }
205
206 return !error;
207 }
208
209 static hb_bool_t
_get_glyph_contour_point(hb_font_t *,void * font_data,hb_codepoint_t gid,unsigned int point_index,hb_position_t * x,hb_position_t * y,void *)210 _get_glyph_contour_point(hb_font_t*, void *font_data, hb_codepoint_t gid, unsigned int point_index, hb_position_t *x, hb_position_t *y, void*)
211 {
212 FT_Face face = (FT_Face) font_data;
213 FT_Error error;
214 bool ret = false;
215
216 error = FT_Load_Glyph (face, gid, FT_LOAD_NO_SCALE);
217 if (!error) {
218 if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
219 if (point_index < (unsigned int) face->glyph->outline.n_points) {
220 *x = face->glyph->outline.points[point_index].x;
221 *y = face->glyph->outline.points[point_index].y;
222 ret = true;
223 }
224 }
225 }
226
227 return ret;
228 }
229
230 static hb_bool_t
_get_glyph_name(hb_font_t *,void * font_data,hb_codepoint_t gid,char * name,unsigned int size,void *)231 _get_glyph_name(hb_font_t *, void *font_data, hb_codepoint_t gid, char *name, unsigned int size, void *)
232 {
233 FT_Face face = (FT_Face) font_data;
234 bool ret = false;
235
236 ret = !FT_Get_Glyph_Name (face, gid, name, size);
237 if (ret && (size && !*name))
238 ret = false;
239
240 return ret;
241 }
242
243 static hb_font_funcs_t *
_get_font_funcs(void)244 _get_font_funcs(void)
245 {
246 static hb_font_funcs_t* funcs = hb_font_funcs_create();
247
248 hb_font_funcs_set_glyph_func (funcs, _get_glyph, NULL, NULL);
249 hb_font_funcs_set_glyph_h_advance_func (funcs, _get_glyph_h_advance, NULL, NULL);
250 hb_font_funcs_set_glyph_v_advance_func (funcs, _get_glyph_v_advance, NULL, NULL);
251 hb_font_funcs_set_glyph_h_origin_func (funcs, _get_glyph_h_origin, NULL, NULL);
252 hb_font_funcs_set_glyph_v_origin_func (funcs, _get_glyph_v_origin, NULL, NULL);
253 hb_font_funcs_set_glyph_h_kerning_func (funcs, _get_glyph_h_kerning, NULL, NULL);
254 hb_font_funcs_set_glyph_v_kerning_func (funcs, _get_glyph_v_kerning, NULL, NULL);
255 hb_font_funcs_set_glyph_extents_func (funcs, _get_glyph_extents, NULL, NULL);
256 hb_font_funcs_set_glyph_contour_point_func (funcs, _get_glyph_contour_point, NULL, NULL);
257 hb_font_funcs_set_glyph_name_func (funcs, _get_glyph_name, NULL, NULL);
258
259 return funcs;
260 }
261
262 static hb_blob_t *
_get_table(hb_face_t *,hb_tag_t tag,void * user_data)263 _get_table(hb_face_t *, hb_tag_t tag, void *user_data)
264 {
265 FT_Face face = (FT_Face) user_data;
266 FT_ULong length = 0;
267 FT_Byte *table;
268 FT_Error error;
269 hb_blob_t* blob = NULL;
270
271 error = FT_Load_Sfnt_Table(face, tag, 0, NULL, &length);
272 if (!error) {
273 table = (FT_Byte *) xmalloc(length * sizeof(char));
274 if (table != NULL) {
275 error = FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte*)table, &length);
276 if (!error) {
277 blob = hb_blob_create((const char*) table, length, HB_MEMORY_MODE_WRITABLE, table, free);
278 } else {
279 free(table);
280 }
281 }
282 }
283
284 return blob;
285 }
286
287 void
initialize(const char * pathname,int index,int & status)288 XeTeXFontInst::initialize(const char* pathname, int index, int &status)
289 {
290 TT_Postscript *postTable;
291 TT_OS2* os2Table;
292 FT_Error error;
293 hb_face_t *hbFace;
294
295 if (!gFreeTypeLibrary) {
296 error = FT_Init_FreeType(&gFreeTypeLibrary);
297 if (error) {
298 fprintf(stderr, "FreeType initialization failed! (%d)\n", error);
299 exit(1);
300 }
301 }
302
303 error = FT_New_Face(gFreeTypeLibrary, (char*)pathname, index, &m_ftFace);
304 if (error) {
305 status = 1;
306 return;
307 }
308
309 if (!FT_IS_SCALABLE(m_ftFace)) {
310 status = 1;
311 return;
312 }
313
314 /* for non-sfnt-packaged fonts (presumably Type 1), see if there is an AFM file we can attach */
315 if (index == 0 && !FT_IS_SFNT(m_ftFace)) {
316 char* afm = new char[strlen((const char*)pathname) + 5]; // room to append ".afm"
317 strcpy(afm, (const char*)pathname);
318 char* p = strrchr(afm, '.');
319 if (p == NULL || strlen(p) != 4 || tolower(*(p+1)) != 'p' || tolower(*(p+2)) != 'f')
320 strcat(afm, ".afm"); // append .afm if the extension didn't seem to be .pf[ab]
321 else
322 strcpy(p, ".afm"); // else replace extension with .afm
323 FT_Attach_File(m_ftFace, afm); // ignore error code; AFM might not exist
324 delete[] afm;
325 }
326
327 m_filename = xstrdup(pathname);
328 m_index = index;
329 m_unitsPerEM = m_ftFace->units_per_EM;
330 m_ascent = unitsToPoints(m_ftFace->ascender);
331 m_descent = unitsToPoints(m_ftFace->descender);
332
333 postTable = (TT_Postscript *) getFontTable(ft_sfnt_post);
334 if (postTable != NULL) {
335 m_italicAngle = Fix2D(postTable->italicAngle);
336 }
337
338 os2Table = (TT_OS2*) getFontTable(ft_sfnt_os2);
339 if (os2Table) {
340 m_capHeight = unitsToPoints(os2Table->sCapHeight);
341 m_xHeight = unitsToPoints(os2Table->sxHeight);
342 }
343
344 // Set up HarfBuzz font
345 hbFace = hb_face_create_for_tables(_get_table, m_ftFace, NULL);
346 hb_face_set_index(hbFace, index);
347 hb_face_set_upem(hbFace, m_unitsPerEM);
348 m_hbFont = hb_font_create(hbFace);
349 hb_face_destroy(hbFace);
350
351 if (hbFontFuncs == NULL)
352 hbFontFuncs = _get_font_funcs();
353
354 hb_font_set_funcs(m_hbFont, hbFontFuncs, m_ftFace, NULL);
355 hb_font_set_scale(m_hbFont, m_unitsPerEM, m_unitsPerEM);
356 // We don’t want device tables adjustments
357 hb_font_set_ppem(m_hbFont, 0, 0);
358
359 return;
360 }
361
362 void
setLayoutDirVertical(bool vertical)363 XeTeXFontInst::setLayoutDirVertical(bool vertical)
364 {
365 m_vertical = vertical;
366 }
367
368 const void *
getFontTable(OTTag tag) const369 XeTeXFontInst::getFontTable(OTTag tag) const
370 {
371 FT_ULong tmpLength = 0;
372 FT_Error error = FT_Load_Sfnt_Table(m_ftFace, tag, 0, NULL, &tmpLength);
373 if (error)
374 return NULL;
375
376 void* table = xmalloc(tmpLength * sizeof(char));
377 if (table != NULL) {
378 error = FT_Load_Sfnt_Table(m_ftFace, tag, 0, (FT_Byte*)table, &tmpLength);
379 if (error) {
380 free((void *) table);
381 return NULL;
382 }
383 }
384
385 return table;
386 }
387
388 const char *
getMathTable()389 XeTeXFontInst::getMathTable()
390 {
391 if (m_math == NULL)
392 m_math = (const char*) getFontTable(MATH_TAG);
393 return m_math;
394 }
395
396 const void *
getFontTable(FT_Sfnt_Tag tag) const397 XeTeXFontInst::getFontTable(FT_Sfnt_Tag tag) const
398 {
399 return FT_Get_Sfnt_Table(m_ftFace, tag);
400 }
401
402 void
getGlyphBounds(GlyphID gid,GlyphBBox * bbox)403 XeTeXFontInst::getGlyphBounds(GlyphID gid, GlyphBBox* bbox)
404 {
405 bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0;
406
407 FT_Error error = FT_Load_Glyph(m_ftFace, gid, FT_LOAD_NO_SCALE);
408 if (error)
409 return;
410
411 FT_Glyph glyph;
412 error = FT_Get_Glyph(m_ftFace->glyph, &glyph);
413 if (error == 0) {
414 FT_BBox ft_bbox;
415 FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox);
416 bbox->xMin = unitsToPoints(ft_bbox.xMin);
417 bbox->yMin = unitsToPoints(ft_bbox.yMin);
418 bbox->xMax = unitsToPoints(ft_bbox.xMax);
419 bbox->yMax = unitsToPoints(ft_bbox.yMax);
420 FT_Done_Glyph(glyph);
421 }
422 }
423
424 GlyphID
mapCharToGlyph(UChar32 ch) const425 XeTeXFontInst::mapCharToGlyph(UChar32 ch) const
426 {
427 return FT_Get_Char_Index(m_ftFace, ch);
428 }
429
430 uint16_t
getNumGlyphs() const431 XeTeXFontInst::getNumGlyphs() const
432 {
433 return m_ftFace->num_glyphs;
434 }
435
436 float
getGlyphWidth(GlyphID gid)437 XeTeXFontInst::getGlyphWidth(GlyphID gid)
438 {
439 return unitsToPoints(_get_glyph_advance(m_ftFace, gid, false));
440 }
441
442 void
getGlyphHeightDepth(GlyphID gid,float * ht,float * dp)443 XeTeXFontInst::getGlyphHeightDepth(GlyphID gid, float* ht, float* dp)
444 {
445 GlyphBBox bbox;
446 getGlyphBounds(gid, &bbox);
447
448 if (ht)
449 *ht = bbox.yMax;
450 if (dp)
451 *dp = -bbox.yMin;
452 }
453
454 void
getGlyphSidebearings(GlyphID gid,float * lsb,float * rsb)455 XeTeXFontInst::getGlyphSidebearings(GlyphID gid, float* lsb, float* rsb)
456 {
457 float width = getGlyphWidth(gid);
458
459 GlyphBBox bbox;
460 getGlyphBounds(gid, &bbox);
461
462 if (lsb)
463 *lsb = bbox.xMin;
464 if (rsb)
465 *rsb = width - bbox.xMax;
466 }
467
468 float
getGlyphItalCorr(GlyphID gid)469 XeTeXFontInst::getGlyphItalCorr(GlyphID gid)
470 {
471 float rval = 0.0;
472
473 float width = getGlyphWidth(gid);
474
475 GlyphBBox bbox;
476 getGlyphBounds(gid, &bbox);
477
478 if (bbox.xMax > width)
479 rval = bbox.xMax - width;
480
481 return rval;
482 }
483
484 GlyphID
mapGlyphToIndex(const char * glyphName) const485 XeTeXFontInst::mapGlyphToIndex(const char* glyphName) const
486 {
487 return FT_Get_Name_Index(m_ftFace, const_cast<char*>(glyphName));
488 }
489
490 const char*
getGlyphName(GlyphID gid,int & nameLen)491 XeTeXFontInst::getGlyphName(GlyphID gid, int& nameLen)
492 {
493 if (FT_HAS_GLYPH_NAMES(m_ftFace)) {
494 static char buffer[256];
495 FT_Get_Glyph_Name(m_ftFace, gid, buffer, 256);
496 nameLen = strlen(buffer);
497 return &buffer[0];
498 }
499 else {
500 nameLen = 0;
501 return NULL;
502 }
503 }
504
505 UChar32
getFirstCharCode()506 XeTeXFontInst::getFirstCharCode()
507 {
508 FT_UInt gindex;
509 return FT_Get_First_Char(m_ftFace, &gindex);
510 }
511
512 UChar32
getLastCharCode()513 XeTeXFontInst::getLastCharCode()
514 {
515 FT_UInt gindex;
516 UChar32 ch = FT_Get_First_Char(m_ftFace, &gindex);
517 UChar32 prev = ch;
518 while (gindex != 0) {
519 prev = ch;
520 ch = FT_Get_Next_Char(m_ftFace, ch, &gindex);
521 }
522 return prev;
523 }
524