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