1 //========================================================================
2 //
3 // SplashFTFont.cc
4 //
5 //========================================================================
6 
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
10 //
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
13 //
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>
20 //
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
23 //
24 //========================================================================
25 
26 #include <config.h>
27 
28 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
29 
30 #ifdef USE_GCC_PRAGMAS
31 #pragma implementation
32 #endif
33 
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"
45 
46 //------------------------------------------------------------------------
47 
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);
54 
55 //------------------------------------------------------------------------
56 // SplashFTFont
57 //------------------------------------------------------------------------
58 
SplashFTFont(SplashFTFontFile * fontFileA,SplashCoord * matA,SplashCoord * textMatA)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)
64 {
65   FT_Face face;
66   int div;
67   int x, y;
68 #if USE_FIXEDPOINT
69   SplashCoord scale;
70 #endif
71 
72   face = fontFileA->face;
73   if (FT_New_Size(face, &sizeObj)) {
74     return;
75   }
76   face->size = sizeObj;
77   size = splashRound(splashDist(0, 0, mat[2], mat[3]));
78   if (size < 1) {
79     size = 1;
80   }
81   if (FT_Set_Pixel_Sizes(face, 0, size)) {
82     return;
83   }
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;
87 
88   div = face->bbox.xMax > 20000 ? 65536 : 1;
89 
90 #if USE_FIXEDPOINT
91   scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
92 
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;
107   }
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;
114   }
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;
121   }
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;
128   }
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;
135   }
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;
142   }
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;
158   }
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;
165   }
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;
172   }
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;
179   }
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;
186   }
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;
193   }
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;
200   }
201   if (yMax == yMin) {
202     yMin = 0;
203     yMax = (int)((SplashCoord)1.2 * size);
204   }
205 
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
226 }
227 
~SplashFTFont()228 SplashFTFont::~SplashFTFont() {
229 }
230 
getGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap,int x0,int y0,SplashClip * clip,SplashClipResult * clipRes)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);
234 }
235 
getFTLoadFlags(GBool type1,GBool trueType,GBool aa,GBool enableFreeTypeHinting,GBool enableSlightHinting)236 static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting)
237 {
238   int ret = FT_LOAD_DEFAULT;
239   if (aa)
240     ret |= FT_LOAD_NO_BITMAP;
241 
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;
253 	}
254       } else if (type1) {
255 	// Type 1 fonts seem to look better with 'light' hinting mode
256 	ret |= FT_LOAD_TARGET_LIGHT;
257       }
258     }
259   } else {
260     ret |= FT_LOAD_NO_HINTING;
261   }
262   return ret;
263 }
264 
makeGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap,int x0,int y0,SplashClip * clip,SplashClipResult * clipRes)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;
274 
275   ff = (SplashFTFontFile *)fontFile;
276 
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;
282 
283   if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
284     gid = (FT_UInt)ff->codeToGID[c];
285   } else {
286     gid = (FT_UInt)c;
287   }
288 
289   if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
290     return gFalse;
291   }
292 
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;
301 
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;
309   }
310 
311   if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
312 		               : ft_render_mode_mono)) {
313     return gFalse;
314   }
315 
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;
320   }
321 
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;
331   }
332   bitmap->data = (Guchar *)gmallocn_checkoverflow(rowSize, bitmap->h);
333   if (!bitmap->data) {
334     return gFalse;
335   }
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);
341   }
342 
343   return gTrue;
344 }
345 
getGlyphAdvance(int c)346 double SplashFTFont::getGlyphAdvance(int c)
347 {
348   SplashFTFontFile *ff;
349   FT_Vector offset;
350   FT_UInt gid;
351   FT_Matrix identityMatrix;
352 
353   ff = (SplashFTFontFile *)fontFile;
354 
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
360 
361   // init the offset
362   offset.x = 0;
363   offset.y = 0;
364 
365   ff->face->size = sizeObj;
366   FT_Set_Transform(ff->face, &identityMatrix, &offset);
367 
368   if (ff->codeToGID && c < ff->codeToGIDLen) {
369     gid = (FT_UInt)ff->codeToGID[c];
370   } else {
371     gid = (FT_UInt)c;
372   }
373 
374   if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
375     return -1;
376   }
377 
378   // 64.0 is 1 in 26.6 format
379   return ff->face->glyph->metrics.horiAdvance / 64.0 / size;
380 }
381 
382 struct SplashFTFontPath {
383   SplashPath *path;
384   SplashCoord textScale;
385   GBool needClose;
386 };
387 
getGlyphPath(int c)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
402   };
403   SplashFTFontFile *ff;
404   SplashFTFontPath path;
405   FT_GlyphSlot slot;
406   FT_UInt gid;
407   FT_Glyph glyph;
408 
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;
417   }
418   if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
419     return NULL;
420   }
421   if (FT_Get_Glyph(slot, &glyph)) {
422     return NULL;
423   }
424   if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) {
425     return NULL;
426   }
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();
434   }
435   FT_Done_Glyph(glyph);
436   return path.path;
437 }
438 
glyphPathMoveTo(const FT_Vector * pt,void * path)439 static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
440   SplashFTFontPath *p = (SplashFTFontPath *)path;
441 
442   if (p->needClose) {
443     p->path->close();
444     p->needClose = gFalse;
445   }
446   p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
447 		  (SplashCoord)pt->y * p->textScale / 64.0);
448   return 0;
449 }
450 
glyphPathLineTo(const FT_Vector * pt,void * path)451 static int glyphPathLineTo(const FT_Vector *pt, void *path) {
452   SplashFTFontPath *p = (SplashFTFontPath *)path;
453 
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;
458 }
459 
glyphPathConicTo(const FT_Vector * ctrl,const FT_Vector * pt,void * path)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;
464 
465   if (!p->path->getCurPt(&x0, &y0)) {
466     return 0;
467   }
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;
472 
473   // A second-order Bezier curve is defined by two endpoints, p0 and
474   // p3, and one control point, pc:
475   //
476   //     p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
477   //
478   // A third-order Bezier curve is defined by the same two endpoints,
479   // p0 and p3, and two control points, p1 and p2:
480   //
481   //     p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
482   //
483   // Applying some algebra, we can convert a second-order curve to a
484   // third-order curve:
485   //
486   //     p1 = (1/3) * (p0 + 2pc)
487   //     p2 = (1/3) * (2pc + p3)
488 
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);
493 
494   p->path->curveTo(x1, y1, x2, y2, x3, y3);
495   p->needClose = gTrue;
496   return 0;
497 }
498 
glyphPathCubicTo(const FT_Vector * ctrl1,const FT_Vector * ctrl2,const FT_Vector * pt,void * path)499 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
500 			    const FT_Vector *pt, void *path) {
501   SplashFTFontPath *p = (SplashFTFontPath *)path;
502 
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;
511 }
512 
513 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
514