1 //========================================================================
2 //
3 // SplashFTFont.cc
4 //
5 // Copyright 2003-2013 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 #include <aconf.h>
10 
11 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
12 
13 #ifdef USE_GCC_PRAGMAS
14 #pragma implementation
15 #endif
16 
17 #include <ft2build.h>
18 #include FT_OUTLINE_H
19 #include FT_SIZES_H
20 #include FT_GLYPH_H
21 #include "gmem.h"
22 #include "SplashMath.h"
23 #include "SplashGlyphBitmap.h"
24 #include "SplashPath.h"
25 #include "SplashFontEngine.h"
26 #include "SplashFTFontEngine.h"
27 #include "SplashFTFontFile.h"
28 #include "SplashFTFont.h"
29 
30 //------------------------------------------------------------------------
31 
32 static int glyphPathMoveTo(const FT_Vector *pt, void *path);
33 static int glyphPathLineTo(const FT_Vector *pt, void *path);
34 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
35 			    void *path);
36 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
37 			    const FT_Vector *pt, void *path);
38 
39 //------------------------------------------------------------------------
40 // SplashFTFont
41 //------------------------------------------------------------------------
42 
SplashFTFont(SplashFTFontFile * fontFileA,SplashCoord * matA,SplashCoord * textMatA)43 SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
44 			   SplashCoord *textMatA):
45   SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
46 {
47   FT_Face face;
48   int size, div;
49   int x, y;
50 #if USE_FIXEDPOINT
51   SplashCoord scale;
52 #endif
53 
54   face = fontFileA->face;
55   if (FT_New_Size(face, &sizeObj)) {
56     return;
57   }
58   face->size = sizeObj;
59   size = splashRound(splashDist(0, 0, mat[2], mat[3]));
60   if (size < 1) {
61     size = 1;
62   }
63   if (FT_Set_Pixel_Sizes(face, 0, size)) {
64     return;
65   }
66   // if the textMat values are too small, FreeType's fixed point
67   // arithmetic doesn't work so well
68   textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
69 
70   div = face->bbox.xMax > 20000 ? 65536 : 1;
71 
72 #if USE_FIXEDPOINT
73   scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
74 
75   // transform the four corners of the font bounding box -- the min
76   // and max values form the bounding box of the transformed font
77   x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
78 	    mat[2] * (scale * (face->bbox.yMin / div)));
79   xMin = xMax = x;
80   y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
81 	    mat[3] * (scale * (face->bbox.yMin / div)));
82   yMin = yMax = y;
83   x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
84 	    mat[2] * (scale * (face->bbox.yMax / div)));
85   if (x < xMin) {
86     xMin = x;
87   } else if (x > xMax) {
88     xMax = x;
89   }
90   y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
91 	    mat[3] * (scale * (face->bbox.yMax / div)));
92   if (y < yMin) {
93     yMin = y;
94   } else if (y > yMax) {
95     yMax = y;
96   }
97   x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
98 	    mat[2] * (scale * (face->bbox.yMin / div)));
99   if (x < xMin) {
100     xMin = x;
101   } else if (x > xMax) {
102     xMax = x;
103   }
104   y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
105 	    mat[3] * (scale * (face->bbox.yMin / div)));
106   if (y < yMin) {
107     yMin = y;
108   } else if (y > yMax) {
109     yMax = y;
110   }
111   x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
112 	    mat[2] * (scale * (face->bbox.yMax / div)));
113   if (x < xMin) {
114     xMin = x;
115   } else if (x > xMax) {
116     xMax = x;
117   }
118   y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
119 	    mat[3] * (scale * (face->bbox.yMax / div)));
120   if (y < yMin) {
121     yMin = y;
122   } else if (y > yMax) {
123     yMax = y;
124   }
125 #else // USE_FIXEDPOINT
126   // transform the four corners of the font bounding box -- the min
127   // and max values form the bounding box of the transformed font
128   x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
129 	    (div * face->units_per_EM));
130   xMin = xMax = x;
131   y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
132 	    (div * face->units_per_EM));
133   yMin = yMax = y;
134   x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
135 	    (div * face->units_per_EM));
136   if (x < xMin) {
137     xMin = x;
138   } else if (x > xMax) {
139     xMax = x;
140   }
141   y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
142 	    (div * face->units_per_EM));
143   if (y < yMin) {
144     yMin = y;
145   } else if (y > yMax) {
146     yMax = y;
147   }
148   x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
149 	    (div * face->units_per_EM));
150   if (x < xMin) {
151     xMin = x;
152   } else if (x > xMax) {
153     xMax = x;
154   }
155   y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
156 	    (div * face->units_per_EM));
157   if (y < yMin) {
158     yMin = y;
159   } else if (y > yMax) {
160     yMax = y;
161   }
162   x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
163 	    (div * face->units_per_EM));
164   if (x < xMin) {
165     xMin = x;
166   } else if (x > xMax) {
167     xMax = x;
168   }
169   y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
170 	    (div * face->units_per_EM));
171   if (y < yMin) {
172     yMin = y;
173   } else if (y > yMax) {
174     yMax = y;
175   }
176 #endif // USE_FIXEDPOINT
177   // This is a kludge: some buggy PDF generators embed fonts with
178   // zero bounding boxes.
179   if (xMax == xMin) {
180     xMin = 0;
181     xMax = size;
182   }
183   if (yMax == yMin) {
184     yMin = 0;
185     yMax = (int)((SplashCoord)1.2 * size);
186   }
187 
188   // compute the transform matrix
189 #if USE_FIXEDPOINT
190   matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16());
191   matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16());
192   matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16());
193   matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16());
194   textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16());
195   textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16());
196   textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16());
197   textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16());
198 #else
199   matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
200   matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
201   matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
202   matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
203   textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
204   textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
205   textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
206   textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
207 #endif
208 }
209 
~SplashFTFont()210 SplashFTFont::~SplashFTFont() {
211 }
212 
getGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap)213 GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
214 			     SplashGlyphBitmap *bitmap) {
215   return SplashFont::getGlyph(c, xFrac, 0, bitmap);
216 }
217 
makeGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap)218 GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
219 			      SplashGlyphBitmap *bitmap) {
220   SplashFTFontFile *ff;
221   FT_Vector offset;
222   FT_GlyphSlot slot;
223   FT_UInt gid;
224   FT_Int32 flags;
225   int rowSize;
226   Guchar *p, *q;
227   int i;
228 
229   ff = (SplashFTFontFile *)fontFile;
230 
231   ff->face->size = sizeObj;
232   offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
233   offset.y = 0;
234   FT_Set_Transform(ff->face, &matrix, &offset);
235   slot = ff->face->glyph;
236 
237   if (ff->codeToGID && c < ff->codeToGIDLen) {
238     gid = (FT_UInt)ff->codeToGID[c];
239   } else {
240     gid = (FT_UInt)c;
241   }
242   if (ff->trueType && gid < 0) {
243     // skip the TrueType notdef glyph
244     return gFalse;
245   }
246 
247   // Set up the load flags:
248   // * disable bitmaps because they look ugly when scaled, rotated,
249   //   etc.
250   // * disable autohinting because it can fail badly with font subsets
251   //   that use invalid glyph names (the FreeType autohinter depends
252   //   on the glyph name to figure out how to autohint the glyph)
253   // * but enable light autohinting for Type 1 fonts because regular
254   //   hinting looks pretty bad, and the invalid glyph name issue
255   //   seems to be very rare (Type 1 fonts are mostly used for
256   //   substitution, in which case the full font is being used, which
257   //   means we have the glyph names)
258   flags = FT_LOAD_NO_BITMAP;
259   if (ff->engine->flags & splashFTNoHinting) {
260     flags |= FT_LOAD_NO_HINTING;
261   } else if (ff->useLightHinting) {
262     flags |= FT_LOAD_TARGET_LIGHT;
263   } else {
264     flags |= FT_LOAD_NO_AUTOHINT;
265   }
266   if (FT_Load_Glyph(ff->face, gid, flags)) {
267     return gFalse;
268   }
269   if (FT_Render_Glyph(slot, aa ? FT_RENDER_MODE_NORMAL
270 		               : FT_RENDER_MODE_MONO)) {
271     return gFalse;
272   }
273   if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
274     // this can happen if (a) the glyph is really tiny or (b) the
275     // metrics in the TrueType file are broken
276     return gFalse;
277   }
278 
279   bitmap->x = -slot->bitmap_left;
280   bitmap->y = slot->bitmap_top;
281   bitmap->w = slot->bitmap.width;
282   bitmap->h = slot->bitmap.rows;
283   bitmap->aa = aa;
284   if (aa) {
285     rowSize = bitmap->w;
286   } else {
287     rowSize = (bitmap->w + 7) >> 3;
288   }
289   bitmap->data = (Guchar *)gmallocn(bitmap->h, rowSize);
290   bitmap->freeData = gTrue;
291   for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
292        i < bitmap->h;
293        ++i, p += rowSize, q += slot->bitmap.pitch) {
294     memcpy(p, q, rowSize);
295   }
296 
297   return gTrue;
298 }
299 
300 struct SplashFTFontPath {
301   SplashPath *path;
302   SplashCoord textScale;
303   GBool needClose;
304 };
305 
getGlyphPath(int c)306 SplashPath *SplashFTFont::getGlyphPath(int c) {
307   static FT_Outline_Funcs outlineFuncs = {
308 #if FREETYPE_MINOR <= 1
309     (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
310     (int (*)(FT_Vector *, void *))&glyphPathLineTo,
311     (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
312     (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
313 #else
314     &glyphPathMoveTo,
315     &glyphPathLineTo,
316     &glyphPathConicTo,
317     &glyphPathCubicTo,
318 #endif
319     0, 0
320   };
321   SplashFTFontFile *ff;
322   SplashFTFontPath path;
323   FT_GlyphSlot slot;
324   FT_UInt gid;
325   FT_Glyph glyph;
326 
327   ff = (SplashFTFontFile *)fontFile;
328   ff->face->size = sizeObj;
329   FT_Set_Transform(ff->face, &textMatrix, NULL);
330   slot = ff->face->glyph;
331   if (ff->codeToGID && c < ff->codeToGIDLen) {
332     gid = ff->codeToGID[c];
333   } else {
334     gid = (FT_UInt)c;
335   }
336   if (ff->trueType && gid < 0) {
337     // skip the TrueType notdef glyph
338     return NULL;
339   }
340   if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) {
341     return NULL;
342   }
343   if (FT_Get_Glyph(slot, &glyph)) {
344     return NULL;
345   }
346   path.path = new SplashPath();
347   path.textScale = textScale;
348   path.needClose = gFalse;
349   FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
350 		       &outlineFuncs, &path);
351   if (path.needClose) {
352     path.path->close();
353   }
354   FT_Done_Glyph(glyph);
355   return path.path;
356 }
357 
glyphPathMoveTo(const FT_Vector * pt,void * path)358 static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
359   SplashFTFontPath *p = (SplashFTFontPath *)path;
360 
361   if (p->needClose) {
362     p->path->close();
363     p->needClose = gFalse;
364   }
365   p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
366 		  (SplashCoord)pt->y * p->textScale / 64.0);
367   return 0;
368 }
369 
glyphPathLineTo(const FT_Vector * pt,void * path)370 static int glyphPathLineTo(const FT_Vector *pt, void *path) {
371   SplashFTFontPath *p = (SplashFTFontPath *)path;
372 
373   p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
374 		  (SplashCoord)pt->y * p->textScale / 64.0);
375   p->needClose = gTrue;
376   return 0;
377 }
378 
glyphPathConicTo(const FT_Vector * ctrl,const FT_Vector * pt,void * path)379 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
380 			    void *path) {
381   SplashFTFontPath *p = (SplashFTFontPath *)path;
382   SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
383 
384   if (!p->path->getCurPt(&x0, &y0)) {
385     return 0;
386   }
387   xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
388   yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
389   x3 = (SplashCoord)pt->x * p->textScale / 64.0;
390   y3 = (SplashCoord)pt->y * p->textScale / 64.0;
391 
392   // A second-order Bezier curve is defined by two endpoints, p0 and
393   // p3, and one control point, pc:
394   //
395   //     p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
396   //
397   // A third-order Bezier curve is defined by the same two endpoints,
398   // p0 and p3, and two control points, p1 and p2:
399   //
400   //     p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
401   //
402   // Applying some algebra, we can convert a second-order curve to a
403   // third-order curve:
404   //
405   //     p1 = (1/3) * (p0 + 2pc)
406   //     p2 = (1/3) * (2pc + p3)
407 
408   x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
409   y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
410   x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
411   y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
412 
413   p->path->curveTo(x1, y1, x2, y2, x3, y3);
414   p->needClose = gTrue;
415   return 0;
416 }
417 
glyphPathCubicTo(const FT_Vector * ctrl1,const FT_Vector * ctrl2,const FT_Vector * pt,void * path)418 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
419 			    const FT_Vector *pt, void *path) {
420   SplashFTFontPath *p = (SplashFTFontPath *)path;
421 
422   p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
423 		   (SplashCoord)ctrl1->y * p->textScale / 64.0,
424 		   (SplashCoord)ctrl2->x * p->textScale / 64.0,
425 		   (SplashCoord)ctrl2->y * p->textScale / 64.0,
426 		   (SplashCoord)pt->x * p->textScale / 64.0,
427 		   (SplashCoord)pt->y * p->textScale / 64.0);
428   p->needClose = gTrue;
429   return 0;
430 }
431 
432 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
433