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