1 //========================================================================
2 //
3 // SplashFTFont.cc
4 //
5 //========================================================================
6
7 #include <aconf.h>
8
9 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <ft2build.h>
16 #include FT_OUTLINE_H
17 #include FT_SIZES_H
18 #include FT_GLYPH_H
19 #include "gmem.h"
20 #include "SplashMath.h"
21 #include "SplashGlyphBitmap.h"
22 #include "SplashPath.h"
23 #include "SplashFTFontEngine.h"
24 #include "SplashFTFontFile.h"
25 #include "SplashFTFont.h"
26
27 //------------------------------------------------------------------------
28
29 static int glyphPathMoveTo(const FT_Vector *pt, void *path);
30 static int glyphPathLineTo(const FT_Vector *pt, void *path);
31 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
32 void *path);
33 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
34 const FT_Vector *pt, void *path);
35
36 //------------------------------------------------------------------------
37 // SplashFTFont
38 //------------------------------------------------------------------------
39
SplashFTFont(SplashFTFontFile * fontFileA,SplashCoord * matA,SplashCoord * textMatA)40 SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
41 SplashCoord *textMatA):
42 SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
43 {
44 FT_Face face;
45 SplashCoord size, div;
46 int x, y;
47
48 face = fontFileA->face;
49
50 if (FT_New_Size(face, &sizeObj)) {
51 return;
52 }
53 face->size = sizeObj;
54 size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
55 if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
56 return;
57 }
58
59 this->ascender = face->ascender;
60 this->descender = face->descender;
61
62 // if the textMat values are too small, FreeType's fixed point
63 // arithmetic doesn't work so well
64 textScale = splashSqrt(textMat[2]*textMat[2] + textMat[3]*textMat[3]) / size;
65
66 div = face->bbox.xMax > 20000 ? 65536 : 1;
67
68 // transform the four corners of the font bounding box -- the min
69 // and max values form the bounding box of the transformed font
70 x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
71 (div * face->units_per_EM));
72 xMin = xMax = x;
73 y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
74 (div * face->units_per_EM));
75 yMin = yMax = y;
76 x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
77 (div * face->units_per_EM));
78 if (x < xMin) {
79 xMin = x;
80 } else if (x > xMax) {
81 xMax = x;
82 }
83 y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
84 (div * face->units_per_EM));
85 if (y < yMin) {
86 yMin = y;
87 } else if (y > yMax) {
88 yMax = y;
89 }
90 x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
91 (div * face->units_per_EM));
92 if (x < xMin) {
93 xMin = x;
94 } else if (x > xMax) {
95 xMax = x;
96 }
97 y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
98 (div * face->units_per_EM));
99 if (y < yMin) {
100 yMin = y;
101 } else if (y > yMax) {
102 yMax = y;
103 }
104 x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
105 (div * face->units_per_EM));
106 if (x < xMin) {
107 xMin = x;
108 } else if (x > xMax) {
109 xMax = x;
110 }
111 y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
112 (div * face->units_per_EM));
113 if (y < yMin) {
114 yMin = y;
115 } else if (y > yMax) {
116 yMax = y;
117 }
118 // This is a kludge: some buggy PDF generators embed fonts with
119 // zero bounding boxes.
120 if (xMax == xMin) {
121 xMin = 0;
122 xMax = (int)size;
123 }
124 if (yMax == yMin) {
125 yMin = 0;
126 yMax = (int)((SplashCoord)1.2 * size);
127 }
128
129 // compute the transform matrix
130 #if USE_FIXEDPOINT
131 matrix.xx = (FT_Fixed)((mat[0] / size).getRaw());
132 matrix.yx = (FT_Fixed)((mat[1] / size).getRaw());
133 matrix.xy = (FT_Fixed)((mat[2] / size).getRaw());
134 matrix.yy = (FT_Fixed)((mat[3] / size).getRaw());
135 textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)).getRaw());
136 textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)).getRaw());
137 textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)).getRaw());
138 textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)).getRaw());
139 #else
140 matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
141 matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
142 matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
143 matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
144 textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)) * 65536);
145 textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)) * 65536);
146 textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)) * 65536);
147 textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)) * 65536);
148 #endif
149 }
150
~SplashFTFont()151 SplashFTFont::~SplashFTFont() {
152 }
153
getGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap)154 GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
155 SplashGlyphBitmap *bitmap) {
156 return SplashFont::getGlyph(c, xFrac, 0, bitmap);
157 }
158
makeGlyph(int c,int xFrac,int yFrac,SplashGlyphBitmap * bitmap)159 GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
160 SplashGlyphBitmap *bitmap) {
161 SplashFTFontFile *ff;
162 FT_Vector offset;
163 FT_GlyphSlot slot;
164 FT_UInt gid;
165 int rowSize;
166 Guchar *p, *q;
167 int i;
168
169 ff = (SplashFTFontFile *)fontFile;
170
171 ff->face->size = sizeObj;
172 offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
173 offset.y = 0;
174 FT_Set_Transform(ff->face, &matrix, &offset);
175 slot = ff->face->glyph;
176
177 if (ff->codeToGID && c < ff->codeToGIDLen) {
178 gid = (FT_UInt)ff->codeToGID[c];
179 } else {
180 gid = (FT_UInt)c;
181 }
182 if (ff->trueType && gid == 0) {
183 // skip the TrueType notdef glyph
184 return gFalse;
185 }
186
187 // if we have the FT2 bytecode interpreter, autohinting won't be used
188 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
189 if (FT_Load_Glyph(ff->face, gid,
190 aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) {
191 return gFalse;
192 }
193 #else
194 // FT2's autohinting doesn't always work very well (especially with
195 // font subsets), so turn it off if anti-aliasing is enabled; if
196 // anti-aliasing is disabled, this seems to be a tossup - some fonts
197 // look better with hinting, some without, so leave hinting on
198 if (FT_Load_Glyph(ff->face, gid,
199 aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
200 : FT_LOAD_DEFAULT)) {
201 return gFalse;
202 }
203 #endif
204 if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
205 : ft_render_mode_mono)) {
206 return gFalse;
207 }
208
209 bitmap->x = -slot->bitmap_left;
210 bitmap->y = slot->bitmap_top;
211 bitmap->w = slot->bitmap.width;
212 bitmap->h = slot->bitmap.rows;
213 bitmap->aa = aa;
214 if (aa) {
215 rowSize = bitmap->w;
216 } else {
217 rowSize = (bitmap->w + 7) >> 3;
218 }
219 bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h);
220 bitmap->freeData = gTrue;
221 for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
222 i < bitmap->h;
223 ++i, p += rowSize, q += slot->bitmap.pitch) {
224 memcpy(p, q, rowSize);
225 }
226
227 return gTrue;
228 }
229
230 struct SplashFTFontPath {
231 SplashPath *path;
232 SplashCoord textScale;
233 GBool needClose;
234 };
235
getNumChars()236 int SplashFTFont::getNumChars()
237 {
238 SplashFTFontFile* ff = (SplashFTFontFile *)fontFile;
239 return ff->face->num_glyphs;
240 }
241
getGlyphPath(int c)242 SplashPath *SplashFTFont::getGlyphPath(int c) {
243 static FT_Outline_Funcs outlineFuncs = {
244 #if FREETYPE_MINOR <= 1
245 (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
246 (int (*)(FT_Vector *, void *))&glyphPathLineTo,
247 (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
248 (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
249 #else
250 &glyphPathMoveTo,
251 &glyphPathLineTo,
252 &glyphPathConicTo,
253 &glyphPathCubicTo,
254 #endif
255 0, 0
256 };
257 SplashFTFontFile *ff;
258 SplashFTFontPath path;
259 FT_GlyphSlot slot;
260 FT_UInt gid;
261 FT_Glyph glyph;
262
263 this->last_advance = -1;
264
265 ff = (SplashFTFontFile *)fontFile;
266 ff->face->size = sizeObj;
267 FT_Set_Transform(ff->face, &textMatrix, NULL);
268 slot = ff->face->glyph;
269 if (ff->codeToGID && c < ff->codeToGIDLen) {
270 gid = ff->codeToGID[c];
271 } else {
272 gid = (FT_UInt)c;
273 }
274 if (ff->trueType && gid == 0) {
275 // skip the TrueType notdef glyph
276 return NULL;
277 }
278 int error = 0;
279 if ((error=FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP))) {
280 if ((error=FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING))) {
281 fprintf(stderr, "Truetype wasn't able to load glyph %d, error %d\n", gid, error);
282 return NULL;
283 }
284 }
285 if (FT_Get_Glyph(slot, &glyph)) {
286 return NULL;
287 }
288 this->last_advance = glyph->advance.x/65536.0;
289
290 path.path = new SplashPath();
291 path.textScale = textScale;
292 path.needClose = gFalse;
293 error = FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
294 &outlineFuncs, &path);
295 if(error) {
296 fprintf(stderr, "Truetype wasn't able to read glyph %d, error %d\n", gid, error);
297 }
298 if (path.needClose) {
299 path.path->close();
300 }
301 FT_Done_Glyph(glyph);
302 return path.path;
303 }
304
glyphPathMoveTo(const FT_Vector * pt,void * path)305 static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
306 SplashFTFontPath *p = (SplashFTFontPath *)path;
307
308 if (p->needClose) {
309 p->path->close();
310 p->needClose = gFalse;
311 }
312 p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
313 (SplashCoord)pt->y * p->textScale / 64.0);
314 return 0;
315 }
316
glyphPathLineTo(const FT_Vector * pt,void * path)317 static int glyphPathLineTo(const FT_Vector *pt, void *path) {
318 SplashFTFontPath *p = (SplashFTFontPath *)path;
319
320 p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
321 (SplashCoord)pt->y * p->textScale / 64.0);
322 p->needClose = gTrue;
323 return 0;
324 }
325
glyphPathConicTo(const FT_Vector * ctrl,const FT_Vector * pt,void * path)326 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
327 void *path) {
328 SplashFTFontPath *p = (SplashFTFontPath *)path;
329 SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
330
331 if (!p->path->getCurPt(&x0, &y0)) {
332 return 0;
333 }
334 xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
335 yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
336 x3 = (SplashCoord)pt->x * p->textScale / 64.0;
337 y3 = (SplashCoord)pt->y * p->textScale / 64.0;
338
339 // A second-order Bezier curve is defined by two endpoints, p0 and
340 // p3, and one control point, pc:
341 //
342 // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
343 //
344 // A third-order Bezier curve is defined by the same two endpoints,
345 // p0 and p3, and two control points, p1 and p2:
346 //
347 // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
348 //
349 // Applying some algebra, we can convert a second-order curve to a
350 // third-order curve:
351 //
352 // p1 = (1/3) * (p0 + 2pc)
353 // p2 = (1/3) * (2pc + p3)
354
355 x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
356 y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
357 x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
358 y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
359
360 p->path->curveTo(x1, y1, x2, y2, x3, y3);
361 p->needClose = gTrue;
362 return 0;
363 }
364
glyphPathCubicTo(const FT_Vector * ctrl1,const FT_Vector * ctrl2,const FT_Vector * pt,void * path)365 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
366 const FT_Vector *pt, void *path) {
367 SplashFTFontPath *p = (SplashFTFontPath *)path;
368
369 p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
370 (SplashCoord)ctrl1->y * p->textScale / 64.0,
371 (SplashCoord)ctrl2->x * p->textScale / 64.0,
372 (SplashCoord)ctrl2->y * p->textScale / 64.0,
373 (SplashCoord)pt->x * p->textScale / 64.0,
374 (SplashCoord)pt->y * p->textScale / 64.0);
375 p->needClose = gTrue;
376 return 0;
377 }
378
379 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
380