# use AROS_LIB/INCLUDES
[AROS-Contrib.git] / arospdf / splash / SplashFTFont.cc
blob21b76c6860a9f132c0e715444c294e2e9ed32b2c
1 //========================================================================
2 //
3 // SplashFTFont.cc
4 //
5 //========================================================================
7 #include <aconf.h>
9 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
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"
27 //------------------------------------------------------------------------
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);
36 //------------------------------------------------------------------------
37 // SplashFTFont
38 //------------------------------------------------------------------------
40 SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
41 SplashCoord *textMatA):
42 SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
44 FT_Face face;
45 SplashCoord size, div;
46 int x, y;
48 face = fontFileA->face;
49 if (FT_New_Size(face, &sizeObj)) {
50 return;
52 face->size = sizeObj;
53 size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
54 if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
55 return;
57 // if the textMat values are too small, FreeType's fixed point
58 // arithmetic doesn't work so well
59 textScale = splashSqrt(textMat[2]*textMat[2] + textMat[3]*textMat[3]) / size;
61 div = face->bbox.xMax > 20000 ? 65536 : 1;
63 // transform the four corners of the font bounding box -- the min
64 // and max values form the bounding box of the transformed font
65 x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
66 (div * face->units_per_EM));
67 xMin = xMax = x;
68 y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
69 (div * face->units_per_EM));
70 yMin = yMax = y;
71 x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
72 (div * face->units_per_EM));
73 if (x < xMin) {
74 xMin = x;
75 } else if (x > xMax) {
76 xMax = x;
78 y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
79 (div * face->units_per_EM));
80 if (y < yMin) {
81 yMin = y;
82 } else if (y > yMax) {
83 yMax = y;
85 x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
86 (div * face->units_per_EM));
87 if (x < xMin) {
88 xMin = x;
89 } else if (x > xMax) {
90 xMax = x;
92 y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
93 (div * face->units_per_EM));
94 if (y < yMin) {
95 yMin = y;
96 } else if (y > yMax) {
97 yMax = y;
99 x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
100 (div * face->units_per_EM));
101 if (x < xMin) {
102 xMin = x;
103 } else if (x > xMax) {
104 xMax = x;
106 y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
107 (div * face->units_per_EM));
108 if (y < yMin) {
109 yMin = y;
110 } else if (y > yMax) {
111 yMax = y;
113 // This is a kludge: some buggy PDF generators embed fonts with
114 // zero bounding boxes.
115 if (xMax == xMin) {
116 xMin = 0;
117 xMax = (int)size;
119 if (yMax == yMin) {
120 yMin = 0;
121 yMax = (int)((SplashCoord)1.2 * size);
124 // compute the transform matrix
125 #if USE_FIXEDPOINT
126 matrix.xx = (FT_Fixed)((mat[0] / size).getRaw());
127 matrix.yx = (FT_Fixed)((mat[1] / size).getRaw());
128 matrix.xy = (FT_Fixed)((mat[2] / size).getRaw());
129 matrix.yy = (FT_Fixed)((mat[3] / size).getRaw());
130 textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)).getRaw());
131 textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)).getRaw());
132 textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)).getRaw());
133 textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)).getRaw());
134 #else
135 matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
136 matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
137 matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
138 matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
139 textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)) * 65536);
140 textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)) * 65536);
141 textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)) * 65536);
142 textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)) * 65536);
143 #endif
146 SplashFTFont::~SplashFTFont() {
149 GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
150 SplashGlyphBitmap *bitmap) {
151 return SplashFont::getGlyph(c, xFrac, 0, bitmap);
154 GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
155 SplashGlyphBitmap *bitmap) {
156 SplashFTFontFile *ff;
157 FT_Vector offset;
158 FT_GlyphSlot slot;
159 FT_UInt gid;
160 int rowSize;
161 Guchar *p, *q;
162 int i;
164 ff = (SplashFTFontFile *)fontFile;
166 ff->face->size = sizeObj;
167 offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
168 offset.y = 0;
169 FT_Set_Transform(ff->face, &matrix, &offset);
170 slot = ff->face->glyph;
172 if (ff->codeToGID && c < ff->codeToGIDLen) {
173 gid = (FT_UInt)ff->codeToGID[c];
174 } else {
175 gid = (FT_UInt)c;
177 if (ff->trueType && gid == 0) {
178 // skip the TrueType notdef glyph
179 return gFalse;
182 // if we have the FT2 bytecode interpreter, autohinting won't be used
183 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
184 if (FT_Load_Glyph(ff->face, gid,
185 aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) {
186 return gFalse;
188 #else
189 // FT2's autohinting doesn't always work very well (especially with
190 // font subsets), so turn it off if anti-aliasing is enabled; if
191 // anti-aliasing is disabled, this seems to be a tossup - some fonts
192 // look better with hinting, some without, so leave hinting on
193 if (FT_Load_Glyph(ff->face, gid,
194 aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
195 : FT_LOAD_DEFAULT)) {
196 return gFalse;
198 #endif
199 if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
200 : ft_render_mode_mono)) {
201 return gFalse;
204 bitmap->x = -slot->bitmap_left;
205 bitmap->y = slot->bitmap_top;
206 bitmap->w = slot->bitmap.width;
207 bitmap->h = slot->bitmap.rows;
208 bitmap->aa = aa;
209 if (aa) {
210 rowSize = bitmap->w;
211 } else {
212 rowSize = (bitmap->w + 7) >> 3;
214 bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h);
215 bitmap->freeData = gTrue;
216 for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
217 i < bitmap->h;
218 ++i, p += rowSize, q += slot->bitmap.pitch) {
219 memcpy(p, q, rowSize);
222 return gTrue;
225 struct SplashFTFontPath {
226 SplashPath *path;
227 SplashCoord textScale;
228 GBool needClose;
231 SplashPath *SplashFTFont::getGlyphPath(int c) {
232 static FT_Outline_Funcs outlineFuncs = {
233 #if FREETYPE_MINOR <= 1
234 (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
235 (int (*)(FT_Vector *, void *))&glyphPathLineTo,
236 (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
237 (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
238 #else
239 &glyphPathMoveTo,
240 &glyphPathLineTo,
241 &glyphPathConicTo,
242 &glyphPathCubicTo,
243 #endif
244 0, 0
246 SplashFTFontFile *ff;
247 SplashFTFontPath path;
248 FT_GlyphSlot slot;
249 FT_UInt gid;
250 FT_Glyph glyph;
252 ff = (SplashFTFontFile *)fontFile;
253 ff->face->size = sizeObj;
254 FT_Set_Transform(ff->face, &textMatrix, NULL);
255 slot = ff->face->glyph;
256 if (ff->codeToGID && c < ff->codeToGIDLen) {
257 gid = ff->codeToGID[c];
258 } else {
259 gid = (FT_UInt)c;
261 if (ff->trueType && gid == 0) {
262 // skip the TrueType notdef glyph
263 return NULL;
265 if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) {
266 return NULL;
268 if (FT_Get_Glyph(slot, &glyph)) {
269 return NULL;
271 path.path = new SplashPath();
272 path.textScale = textScale;
273 path.needClose = gFalse;
274 FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
275 &outlineFuncs, &path);
276 if (path.needClose) {
277 path.path->close();
279 FT_Done_Glyph(glyph);
280 return path.path;
283 static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
284 SplashFTFontPath *p = (SplashFTFontPath *)path;
286 if (p->needClose) {
287 p->path->close();
288 p->needClose = gFalse;
290 p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
291 (SplashCoord)pt->y * p->textScale / 64.0);
292 return 0;
295 static int glyphPathLineTo(const FT_Vector *pt, void *path) {
296 SplashFTFontPath *p = (SplashFTFontPath *)path;
298 p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
299 (SplashCoord)pt->y * p->textScale / 64.0);
300 p->needClose = gTrue;
301 return 0;
304 static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
305 void *path) {
306 SplashFTFontPath *p = (SplashFTFontPath *)path;
307 SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
309 if (!p->path->getCurPt(&x0, &y0)) {
310 return 0;
312 xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
313 yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
314 x3 = (SplashCoord)pt->x * p->textScale / 64.0;
315 y3 = (SplashCoord)pt->y * p->textScale / 64.0;
317 // A second-order Bezier curve is defined by two endpoints, p0 and
318 // p3, and one control point, pc:
320 // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
322 // A third-order Bezier curve is defined by the same two endpoints,
323 // p0 and p3, and two control points, p1 and p2:
325 // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
327 // Applying some algebra, we can convert a second-order curve to a
328 // third-order curve:
330 // p1 = (1/3) * (p0 + 2pc)
331 // p2 = (1/3) * (2pc + p3)
333 x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
334 y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
335 x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
336 y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
338 p->path->curveTo(x1, y1, x2, y2, x3, y3);
339 p->needClose = gTrue;
340 return 0;
343 static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
344 const FT_Vector *pt, void *path) {
345 SplashFTFontPath *p = (SplashFTFontPath *)path;
347 p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
348 (SplashCoord)ctrl1->y * p->textScale / 64.0,
349 (SplashCoord)ctrl2->x * p->textScale / 64.0,
350 (SplashCoord)ctrl2->y * p->textScale / 64.0,
351 (SplashCoord)pt->x * p->textScale / 64.0,
352 (SplashCoord)pt->y * p->textScale / 64.0);
353 p->needClose = gTrue;
354 return 0;
357 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H