]> www.fi.muni.cz Git - evince.git/blob - pdf/splash/SplashFTFont.cc
Import of xpdf code from gpdf.
[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 "gmem.h"
16 #include "SplashMath.h"
17 #include "SplashGlyphBitmap.h"
18 #include "SplashPath.h"
19 #include "SplashFTFontEngine.h"
20 #include "SplashFTFontFile.h"
21 #include "SplashFTFont.h"
22
23 #include FT_OUTLINE_H
24 #include FT_INTERNAL_OBJECTS_H // needed for FT_New_Size decl
25
26 //------------------------------------------------------------------------
27
28 static int glyphPathMoveTo(FT_Vector *pt, void *path);
29 static int glyphPathLineTo(FT_Vector *pt, void *path);
30 static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path);
31 static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2,
32                             FT_Vector *pt, void *path);
33
34 //------------------------------------------------------------------------
35 // SplashFTFont
36 //------------------------------------------------------------------------
37
38 SplashFTFont::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)(1.2 * size);
116   }
117
118   // compute the transform matrix
119   matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
120   matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
121   matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
122   matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
123 }
124
125 SplashFTFont::~SplashFTFont() {
126 }
127
128 GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
129                              SplashGlyphBitmap *bitmap) {
130   return SplashFont::getGlyph(c, xFrac, 0, bitmap);
131 }
132
133 GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
134                               SplashGlyphBitmap *bitmap) {
135   SplashFTFontFile *ff;
136   FT_Vector offset;
137   FT_GlyphSlot slot;
138   FT_UInt gid;
139   int rowSize;
140   Guchar *p, *q;
141   int i;
142
143   ff = (SplashFTFontFile *)fontFile;
144
145   ff->face->size = sizeObj;
146   offset.x = (FT_Pos)(xFrac * splashFontFractionMul * 64);
147   offset.y = 0;
148   FT_Set_Transform(ff->face, &matrix, &offset);
149   slot = ff->face->glyph;
150
151   if (ff->codeToGID && c < ff->codeToGIDLen) {
152     gid = (FT_UInt)ff->codeToGID[c];
153   } else {
154     gid = (FT_UInt)c;
155   }
156
157   // if we have the FT2 bytecode interpreter, autohinting won't be used
158 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
159   if (FT_Load_Glyph(ff->face, gid,
160                     aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) {
161     return gFalse;
162   }
163 #else
164   // FT2's autohinting doesn't always work very well (especially with
165   // font subsets), so turn it off if anti-aliasing is enabled; if
166   // anti-aliasing is disabled, this seems to be a tossup - some fonts
167   // look better with hinting, some without, so leave hinting on
168   if (FT_Load_Glyph(ff->face, gid,
169                     aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
170                        : FT_LOAD_DEFAULT)) {
171     return gFalse;
172   }
173 #endif
174   if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
175                                : ft_render_mode_mono)) {
176     return gFalse;
177   }
178
179   bitmap->x = -slot->bitmap_left;
180   bitmap->y = slot->bitmap_top;
181   bitmap->w = slot->bitmap.width;
182   bitmap->h = slot->bitmap.rows;
183   bitmap->aa = aa;
184   if (aa) {
185     rowSize = bitmap->w;
186   } else {
187     rowSize = (bitmap->w + 7) >> 3;
188   }
189   bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h);
190   bitmap->freeData = gTrue;
191   for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
192        i < bitmap->h;
193        ++i, p += rowSize, q += slot->bitmap.pitch) {
194     memcpy(p, q, rowSize);
195   }
196
197   return gTrue;
198 }
199
200 SplashPath *SplashFTFont::getGlyphPath(int c) {
201   static FT_Outline_Funcs outlineFuncs = {
202     &glyphPathMoveTo,
203     &glyphPathLineTo,
204     &glyphPathConicTo,
205     &glyphPathCubicTo,
206     0, 0
207   };
208   SplashFTFontFile *ff;
209   SplashPath *path;
210   FT_GlyphSlot slot;
211   FT_UInt gid;
212   FT_Glyph glyph;
213
214   ff = (SplashFTFontFile *)fontFile;
215   ff->face->size = sizeObj;
216   FT_Set_Transform(ff->face, &matrix, NULL);
217   slot = ff->face->glyph;
218   if (ff->codeToGID && c < ff->codeToGIDLen) {
219     gid = ff->codeToGID[c];
220   } else {
221     gid = (FT_UInt)c;
222   }
223   if (FT_Load_Glyph(ff->face, gid, FT_LOAD_DEFAULT)) {
224     return NULL;
225   }
226   if (FT_Get_Glyph(slot, &glyph)) {
227     return NULL;
228   }
229   path = new SplashPath();
230   FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
231                        &outlineFuncs, path);
232   return path;
233 }
234
235 static int glyphPathMoveTo(FT_Vector *pt, void *path) {
236   ((SplashPath *)path)->moveTo(pt->x / 64.0, -pt->y / 64.0);
237   return 0;
238 }
239
240 static int glyphPathLineTo(FT_Vector *pt, void *path) {
241   ((SplashPath *)path)->lineTo(pt->x / 64.0, -pt->y / 64.0);
242   return 0;
243 }
244
245 static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) {
246   SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
247
248   if (!((SplashPath *)path)->getCurPt(&x0, &y0)) {
249     return 0;
250   }
251   xc = ctrl->x / 64.0;
252   yc = -ctrl->y / 64.0;
253   x3 = pt->x / 64.0;
254   y3 = -pt->y / 64.0;
255
256   // A second-order Bezier curve is defined by two endpoints, p0 and
257   // p3, and one control point, pc:
258   //
259   //     p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
260   //
261   // A third-order Bezier curve is defined by the same two endpoints,
262   // p0 and p3, and two control points, p1 and p2:
263   //
264   //     p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
265   //
266   // Applying some algebra, we can convert a second-order curve to a
267   // third-order curve:
268   //
269   //     p1 = (1/3) * (p0 + 2pc)
270   //     p2 = (1/3) * (2pc + p3)
271
272   x1 = (1.0 / 3.0) * (x0 + 2 * xc);
273   y1 = (1.0 / 3.0) * (y0 + 2 * yc);
274   x2 = (1.0 / 3.0) * (2 * xc + x3);
275   y2 = (1.0 / 3.0) * (2 * yc + y3);
276
277   ((SplashPath *)path)->curveTo(x1, y1, x2, y2, x3, y3);
278   return 0;
279 }
280
281 static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2,
282                             FT_Vector *pt, void *path) {
283   ((SplashPath *)path)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0,
284                                 ctrl2->x / 64.0, -ctrl2->y / 64.0,
285                                 pt->x / 64.0, -pt->y / 64.0);
286   return 0;
287 }
288
289 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H