1 //========================================================================
5 //========================================================================
9 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
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
,
33 static int glyphPathCubicTo(const FT_Vector
*ctrl1
, const FT_Vector
*ctrl2
,
34 const FT_Vector
*pt
, void *path
);
36 //------------------------------------------------------------------------
38 //------------------------------------------------------------------------
40 SplashFTFont::SplashFTFont(SplashFTFontFile
*fontFileA
, SplashCoord
*matA
,
41 SplashCoord
*textMatA
):
42 SplashFont(fontFileA
, matA
, textMatA
, fontFileA
->engine
->aa
)
45 SplashCoord size
, div
;
48 face
= fontFileA
->face
;
49 if (FT_New_Size(face
, &sizeObj
)) {
53 size
= splashSqrt(mat
[2]*mat
[2] + mat
[3]*mat
[3]);
54 if (FT_Set_Pixel_Sizes(face
, 0, (int)size
)) {
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
));
68 y
= (int)((mat
[1] * face
->bbox
.xMin
+ mat
[3] * face
->bbox
.yMin
) /
69 (div
* face
->units_per_EM
));
71 x
= (int)((mat
[0] * face
->bbox
.xMin
+ mat
[2] * face
->bbox
.yMax
) /
72 (div
* face
->units_per_EM
));
75 } else if (x
> xMax
) {
78 y
= (int)((mat
[1] * face
->bbox
.xMin
+ mat
[3] * face
->bbox
.yMax
) /
79 (div
* face
->units_per_EM
));
82 } else if (y
> yMax
) {
85 x
= (int)((mat
[0] * face
->bbox
.xMax
+ mat
[2] * face
->bbox
.yMin
) /
86 (div
* face
->units_per_EM
));
89 } else if (x
> xMax
) {
92 y
= (int)((mat
[1] * face
->bbox
.xMax
+ mat
[3] * face
->bbox
.yMin
) /
93 (div
* face
->units_per_EM
));
96 } else if (y
> yMax
) {
99 x
= (int)((mat
[0] * face
->bbox
.xMax
+ mat
[2] * face
->bbox
.yMax
) /
100 (div
* face
->units_per_EM
));
103 } else if (x
> xMax
) {
106 y
= (int)((mat
[1] * face
->bbox
.xMax
+ mat
[3] * face
->bbox
.yMax
) /
107 (div
* face
->units_per_EM
));
110 } else if (y
> yMax
) {
113 // This is a kludge: some buggy PDF generators embed fonts with
114 // zero bounding boxes.
121 yMax
= (int)((SplashCoord
)1.2 * size
);
124 // compute the transform matrix
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());
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);
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
;
164 ff
= (SplashFTFontFile
*)fontFile
;
166 ff
->face
->size
= sizeObj
;
167 offset
.x
= (FT_Pos
)(int)((SplashCoord
)xFrac
* splashFontFractionMul
* 64);
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
];
177 if (ff
->trueType
&& gid
== 0) {
178 // skip the TrueType notdef glyph
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
)) {
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
)) {
199 if (FT_Render_Glyph(slot
, aa
? ft_render_mode_normal
200 : ft_render_mode_mono
)) {
204 bitmap
->x
= -slot
->bitmap_left
;
205 bitmap
->y
= slot
->bitmap_top
;
206 bitmap
->w
= slot
->bitmap
.width
;
207 bitmap
->h
= slot
->bitmap
.rows
;
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
;
218 ++i
, p
+= rowSize
, q
+= slot
->bitmap
.pitch
) {
219 memcpy(p
, q
, rowSize
);
225 struct SplashFTFontPath
{
227 SplashCoord textScale
;
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
,
246 SplashFTFontFile
*ff
;
247 SplashFTFontPath path
;
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
];
261 if (ff
->trueType
&& gid
== 0) {
262 // skip the TrueType notdef glyph
265 if (FT_Load_Glyph(ff
->face
, gid
, FT_LOAD_NO_BITMAP
)) {
268 if (FT_Get_Glyph(slot
, &glyph
)) {
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
) {
279 FT_Done_Glyph(glyph
);
283 static int glyphPathMoveTo(const FT_Vector
*pt
, void *path
) {
284 SplashFTFontPath
*p
= (SplashFTFontPath
*)path
;
288 p
->needClose
= gFalse
;
290 p
->path
->moveTo((SplashCoord
)pt
->x
* p
->textScale
/ 64.0,
291 (SplashCoord
)pt
->y
* p
->textScale
/ 64.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
;
304 static int glyphPathConicTo(const FT_Vector
*ctrl
, const FT_Vector
*pt
,
306 SplashFTFontPath
*p
= (SplashFTFontPath
*)path
;
307 SplashCoord x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, xc
, yc
;
309 if (!p
->path
->getCurPt(&x0
, &y0
)) {
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
;
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
;
357 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H