beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / splash / SplashFTFont.cc
blobb785826d66ba1c4bd73b699b053346c8b8032a3a
1 //========================================================================
2 //
3 // SplashFTFont.cc
4 //
5 //========================================================================
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
14 // Copyright (C) 2005, 2007-2011, 2014 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2006 Kristian Høgsberg <krh@bitplanet.net>
16 // Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
17 // Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
18 // Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
19 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // To see a description of the changes please see the Changelog file that
22 // came with your tarball or type make ChangeLog if you are building from git
24 //========================================================================
26 #include <config.h>
28 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
30 #ifdef USE_GCC_PRAGMAS
31 #pragma implementation
32 #endif
34 #include <ft2build.h>
35 #include FT_OUTLINE_H
36 #include FT_SIZES_H
37 #include FT_GLYPH_H
38 #include "goo/gmem.h"
39 #include "SplashMath.h"
40 #include "SplashGlyphBitmap.h"
41 #include "SplashPath.h"
42 #include "SplashFTFontEngine.h"
43 #include "SplashFTFontFile.h"
44 #include "SplashFTFont.h"
46 //------------------------------------------------------------------------
48 static int glyphPathMoveTo(const FT_Vector *pt, void *path);
49 static int glyphPathLineTo(const FT_Vector *pt, void *path);
50 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
51 void *path);
52 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
53 const FT_Vector *pt, void *path);
55 //------------------------------------------------------------------------
56 // SplashFTFont
57 //------------------------------------------------------------------------
59 SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
60 SplashCoord *textMatA):
61 SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa),
62 enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting),
63 enableSlightHinting(fontFileA->engine->enableSlightHinting)
65 FT_Face face;
66 int div;
67 int x, y;
68 #if USE_FIXEDPOINT
69 SplashCoord scale;
70 #endif
72 face = fontFileA->face;
73 if (FT_New_Size(face, &sizeObj)) {
74 return;
76 face->size = sizeObj;
77 size = splashRound(splashDist(0, 0, mat[2], mat[3]));
78 if (size < 1) {
79 size = 1;
81 if (FT_Set_Pixel_Sizes(face, 0, size)) {
82 return;
84 // if the textMat values are too small, FreeType's fixed point
85 // arithmetic doesn't work so well
86 textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
88 div = face->bbox.xMax > 20000 ? 65536 : 1;
90 #if USE_FIXEDPOINT
91 scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
93 // transform the four corners of the font bounding box -- the min
94 // and max values form the bounding box of the transformed font
95 x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
96 mat[2] * (scale * (face->bbox.yMin / div)));
97 xMin = xMax = x;
98 y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
99 mat[3] * (scale * (face->bbox.yMin / div)));
100 yMin = yMax = y;
101 x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
102 mat[2] * (scale * (face->bbox.yMax / div)));
103 if (x < xMin) {
104 xMin = x;
105 } else if (x > xMax) {
106 xMax = x;
108 y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
109 mat[3] * (scale * (face->bbox.yMax / div)));
110 if (y < yMin) {
111 yMin = y;
112 } else if (y > yMax) {
113 yMax = y;
115 x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
116 mat[2] * (scale * (face->bbox.yMin / div)));
117 if (x < xMin) {
118 xMin = x;
119 } else if (x > xMax) {
120 xMax = x;
122 y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
123 mat[3] * (scale * (face->bbox.yMin / div)));
124 if (y < yMin) {
125 yMin = y;
126 } else if (y > yMax) {
127 yMax = y;
129 x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
130 mat[2] * (scale * (face->bbox.yMax / div)));
131 if (x < xMin) {
132 xMin = x;
133 } else if (x > xMax) {
134 xMax = x;
136 y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
137 mat[3] * (scale * (face->bbox.yMax / div)));
138 if (y < yMin) {
139 yMin = y;
140 } else if (y > yMax) {
141 yMax = y;
143 #else // USE_FIXEDPOINT
144 // transform the four corners of the font bounding box -- the min
145 // and max values form the bounding box of the transformed font
146 x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
147 (div * face->units_per_EM));
148 xMin = xMax = x;
149 y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
150 (div * face->units_per_EM));
151 yMin = yMax = y;
152 x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
153 (div * face->units_per_EM));
154 if (x < xMin) {
155 xMin = x;
156 } else if (x > xMax) {
157 xMax = x;
159 y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
160 (div * face->units_per_EM));
161 if (y < yMin) {
162 yMin = y;
163 } else if (y > yMax) {
164 yMax = y;
166 x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
167 (div * face->units_per_EM));
168 if (x < xMin) {
169 xMin = x;
170 } else if (x > xMax) {
171 xMax = x;
173 y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
174 (div * face->units_per_EM));
175 if (y < yMin) {
176 yMin = y;
177 } else if (y > yMax) {
178 yMax = y;
180 x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
181 (div * face->units_per_EM));
182 if (x < xMin) {
183 xMin = x;
184 } else if (x > xMax) {
185 xMax = x;
187 y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
188 (div * face->units_per_EM));
189 if (y < yMin) {
190 yMin = y;
191 } else if (y > yMax) {
192 yMax = y;
194 #endif // USE_FIXEDPOINT
195 // This is a kludge: some buggy PDF generators embed fonts with
196 // zero bounding boxes.
197 if (xMax == xMin) {
198 xMin = 0;
199 xMax = size;
201 if (yMax == yMin) {
202 yMin = 0;
203 yMax = (int)((SplashCoord)1.2 * size);
206 // compute the transform matrix
207 #if USE_FIXEDPOINT
208 matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16());
209 matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16());
210 matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16());
211 matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16());
212 textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16());
213 textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16());
214 textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16());
215 textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16());
216 #else
217 matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
218 matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
219 matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
220 matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
221 textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
222 textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
223 textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
224 textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
225 #endif
228 SplashFTFont::~SplashFTFont() {
231 GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
232 SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
233 return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
236 static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting)
238 int ret = FT_LOAD_DEFAULT;
239 if (aa)
240 ret |= FT_LOAD_NO_BITMAP;
242 if (enableFreeTypeHinting) {
243 if (enableSlightHinting) {
244 ret |= FT_LOAD_TARGET_LIGHT;
245 } else {
246 if (trueType) {
247 // FT2's autohinting doesn't always work very well (especially with
248 // font subsets), so turn it off if anti-aliasing is enabled; if
249 // anti-aliasing is disabled, this seems to be a tossup - some fonts
250 // look better with hinting, some without, so leave hinting on
251 if (aa) {
252 ret |= FT_LOAD_NO_AUTOHINT;
254 } else if (type1) {
255 // Type 1 fonts seem to look better with 'light' hinting mode
256 ret |= FT_LOAD_TARGET_LIGHT;
259 } else {
260 ret |= FT_LOAD_NO_HINTING;
262 return ret;
265 GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
266 SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
267 SplashFTFontFile *ff;
268 FT_Vector offset;
269 FT_GlyphSlot slot;
270 FT_UInt gid;
271 int rowSize;
272 Guchar *p, *q;
273 int i;
275 ff = (SplashFTFontFile *)fontFile;
277 ff->face->size = sizeObj;
278 offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
279 offset.y = 0;
280 FT_Set_Transform(ff->face, &matrix, &offset);
281 slot = ff->face->glyph;
283 if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
284 gid = (FT_UInt)ff->codeToGID[c];
285 } else {
286 gid = (FT_UInt)c;
289 if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
290 return gFalse;
293 // prelimirary values based on FT_Outline_Get_CBox
294 // we add two pixels to each side to be in the safe side
295 FT_BBox cbox;
296 FT_Outline_Get_CBox(&ff->face->glyph->outline, &cbox);
297 bitmap->x = -(cbox.xMin / 64) + 2;
298 bitmap->y = (cbox.yMax / 64) + 2;
299 bitmap->w = ((cbox.xMax - cbox.xMin) / 64) + 4;
300 bitmap->h = ((cbox.yMax - cbox.yMin) / 64) + 4;
302 *clipRes = clip->testRect(x0 - bitmap->x,
303 y0 - bitmap->y,
304 x0 - bitmap->x + bitmap->w,
305 y0 - bitmap->y + bitmap->h);
306 if (*clipRes == splashClipAllOutside) {
307 bitmap->freeData = gFalse;
308 return gTrue;
311 if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
312 : ft_render_mode_mono)) {
313 return gFalse;
316 if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
317 // this can happen if (a) the glyph is really tiny or (b) the
318 // metrics in the TrueType file are broken
319 return gFalse;
322 bitmap->x = -slot->bitmap_left;
323 bitmap->y = slot->bitmap_top;
324 bitmap->w = slot->bitmap.width;
325 bitmap->h = slot->bitmap.rows;
326 bitmap->aa = aa;
327 if (aa) {
328 rowSize = bitmap->w;
329 } else {
330 rowSize = (bitmap->w + 7) >> 3;
332 bitmap->data = (Guchar *)gmallocn_checkoverflow(rowSize, bitmap->h);
333 if (!bitmap->data) {
334 return gFalse;
336 bitmap->freeData = gTrue;
337 for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
338 i < bitmap->h;
339 ++i, p += rowSize, q += slot->bitmap.pitch) {
340 memcpy(p, q, rowSize);
343 return gTrue;
346 double SplashFTFont::getGlyphAdvance(int c)
348 SplashFTFontFile *ff;
349 FT_Vector offset;
350 FT_UInt gid;
351 FT_Matrix identityMatrix;
353 ff = (SplashFTFontFile *)fontFile;
355 // init the matrix
356 identityMatrix.xx = 65536; // 1 in 16.16 format
357 identityMatrix.xy = 0;
358 identityMatrix.yx = 0;
359 identityMatrix.yy = 65536; // 1 in 16.16 format
361 // init the offset
362 offset.x = 0;
363 offset.y = 0;
365 ff->face->size = sizeObj;
366 FT_Set_Transform(ff->face, &identityMatrix, &offset);
368 if (ff->codeToGID && c < ff->codeToGIDLen) {
369 gid = (FT_UInt)ff->codeToGID[c];
370 } else {
371 gid = (FT_UInt)c;
374 if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
375 return -1;
378 // 64.0 is 1 in 26.6 format
379 return ff->face->glyph->metrics.horiAdvance / 64.0 / size;
382 struct SplashFTFontPath {
383 SplashPath *path;
384 SplashCoord textScale;
385 GBool needClose;
388 SplashPath *SplashFTFont::getGlyphPath(int c) {
389 static FT_Outline_Funcs outlineFuncs = {
390 #if FREETYPE_MINOR <= 1
391 (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
392 (int (*)(FT_Vector *, void *))&glyphPathLineTo,
393 (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
394 (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
395 #else
396 &glyphPathMoveTo,
397 &glyphPathLineTo,
398 &glyphPathConicTo,
399 &glyphPathCubicTo,
400 #endif
401 0, 0
403 SplashFTFontFile *ff;
404 SplashFTFontPath path;
405 FT_GlyphSlot slot;
406 FT_UInt gid;
407 FT_Glyph glyph;
409 ff = (SplashFTFontFile *)fontFile;
410 ff->face->size = sizeObj;
411 FT_Set_Transform(ff->face, &textMatrix, NULL);
412 slot = ff->face->glyph;
413 if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
414 gid = ff->codeToGID[c];
415 } else {
416 gid = (FT_UInt)c;
418 if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
419 return NULL;
421 if (FT_Get_Glyph(slot, &glyph)) {
422 return NULL;
424 if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) {
425 return NULL;
427 path.path = new SplashPath();
428 path.textScale = textScale;
429 path.needClose = gFalse;
430 FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
431 &outlineFuncs, &path);
432 if (path.needClose) {
433 path.path->close();
435 FT_Done_Glyph(glyph);
436 return path.path;
439 static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
440 SplashFTFontPath *p = (SplashFTFontPath *)path;
442 if (p->needClose) {
443 p->path->close();
444 p->needClose = gFalse;
446 p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
447 (SplashCoord)pt->y * p->textScale / 64.0);
448 return 0;
451 static int glyphPathLineTo(const FT_Vector *pt, void *path) {
452 SplashFTFontPath *p = (SplashFTFontPath *)path;
454 p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
455 (SplashCoord)pt->y * p->textScale / 64.0);
456 p->needClose = gTrue;
457 return 0;
460 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
461 void *path) {
462 SplashFTFontPath *p = (SplashFTFontPath *)path;
463 SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
465 if (!p->path->getCurPt(&x0, &y0)) {
466 return 0;
468 xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
469 yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
470 x3 = (SplashCoord)pt->x * p->textScale / 64.0;
471 y3 = (SplashCoord)pt->y * p->textScale / 64.0;
473 // A second-order Bezier curve is defined by two endpoints, p0 and
474 // p3, and one control point, pc:
476 // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
478 // A third-order Bezier curve is defined by the same two endpoints,
479 // p0 and p3, and two control points, p1 and p2:
481 // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
483 // Applying some algebra, we can convert a second-order curve to a
484 // third-order curve:
486 // p1 = (1/3) * (p0 + 2pc)
487 // p2 = (1/3) * (2pc + p3)
489 x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
490 y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
491 x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
492 y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
494 p->path->curveTo(x1, y1, x2, y2, x3, y3);
495 p->needClose = gTrue;
496 return 0;
499 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
500 const FT_Vector *pt, void *path) {
501 SplashFTFontPath *p = (SplashFTFontPath *)path;
503 p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
504 (SplashCoord)ctrl1->y * p->textScale / 64.0,
505 (SplashCoord)ctrl2->x * p->textScale / 64.0,
506 (SplashCoord)ctrl2->y * p->textScale / 64.0,
507 (SplashCoord)pt->x * p->textScale / 64.0,
508 (SplashCoord)pt->y * p->textScale / 64.0);
509 p->needClose = gTrue;
510 return 0;
513 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H