1 //========================================================================
5 //========================================================================
7 //========================================================================
9 // Modified under the Poppler project - http://poppler.freedesktop.org
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
14 // Copyright (C) 2005, 2007-2011, 2014 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2006 Kristian Høgsberg <krh@bitplanet.net>
16 // Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
17 // Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
18 // Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
19 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // To see a description of the changes please see the Changelog file that
22 // came with your tarball or type make ChangeLog if you are building from git
24 //========================================================================
28 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
30 #ifdef USE_GCC_PRAGMAS
31 #pragma implementation
39 #include "SplashMath.h"
40 #include "SplashGlyphBitmap.h"
41 #include "SplashPath.h"
42 #include "SplashFTFontEngine.h"
43 #include "SplashFTFontFile.h"
44 #include "SplashFTFont.h"
46 //------------------------------------------------------------------------
48 static int glyphPathMoveTo(const FT_Vector
*pt
, void *path
);
49 static int glyphPathLineTo(const FT_Vector
*pt
, void *path
);
50 static int glyphPathConicTo(const FT_Vector
*ctrl
, const FT_Vector
*pt
,
52 static int glyphPathCubicTo(const FT_Vector
*ctrl1
, const FT_Vector
*ctrl2
,
53 const FT_Vector
*pt
, void *path
);
55 //------------------------------------------------------------------------
57 //------------------------------------------------------------------------
59 SplashFTFont::SplashFTFont(SplashFTFontFile
*fontFileA
, SplashCoord
*matA
,
60 SplashCoord
*textMatA
):
61 SplashFont(fontFileA
, matA
, textMatA
, fontFileA
->engine
->aa
),
62 enableFreeTypeHinting(fontFileA
->engine
->enableFreeTypeHinting
),
63 enableSlightHinting(fontFileA
->engine
->enableSlightHinting
)
72 face
= fontFileA
->face
;
73 if (FT_New_Size(face
, &sizeObj
)) {
77 size
= splashRound(splashDist(0, 0, mat
[2], mat
[3]));
81 if (FT_Set_Pixel_Sizes(face
, 0, size
)) {
84 // if the textMat values are too small, FreeType's fixed point
85 // arithmetic doesn't work so well
86 textScale
= splashDist(0, 0, textMat
[2], textMat
[3]) / size
;
88 div
= face
->bbox
.xMax
> 20000 ? 65536 : 1;
91 scale
= (SplashCoord
)1 / (SplashCoord
)face
->units_per_EM
;
93 // transform the four corners of the font bounding box -- the min
94 // and max values form the bounding box of the transformed font
95 x
= (int)(mat
[0] * (scale
* (face
->bbox
.xMin
/ div
)) +
96 mat
[2] * (scale
* (face
->bbox
.yMin
/ div
)));
98 y
= (int)(mat
[1] * (scale
* (face
->bbox
.xMin
/ div
)) +
99 mat
[3] * (scale
* (face
->bbox
.yMin
/ div
)));
101 x
= (int)(mat
[0] * (scale
* (face
->bbox
.xMin
/ div
)) +
102 mat
[2] * (scale
* (face
->bbox
.yMax
/ div
)));
105 } else if (x
> xMax
) {
108 y
= (int)(mat
[1] * (scale
* (face
->bbox
.xMin
/ div
)) +
109 mat
[3] * (scale
* (face
->bbox
.yMax
/ div
)));
112 } else if (y
> yMax
) {
115 x
= (int)(mat
[0] * (scale
* (face
->bbox
.xMax
/ div
)) +
116 mat
[2] * (scale
* (face
->bbox
.yMin
/ div
)));
119 } else if (x
> xMax
) {
122 y
= (int)(mat
[1] * (scale
* (face
->bbox
.xMax
/ div
)) +
123 mat
[3] * (scale
* (face
->bbox
.yMin
/ div
)));
126 } else if (y
> yMax
) {
129 x
= (int)(mat
[0] * (scale
* (face
->bbox
.xMax
/ div
)) +
130 mat
[2] * (scale
* (face
->bbox
.yMax
/ div
)));
133 } else if (x
> xMax
) {
136 y
= (int)(mat
[1] * (scale
* (face
->bbox
.xMax
/ div
)) +
137 mat
[3] * (scale
* (face
->bbox
.yMax
/ div
)));
140 } else if (y
> yMax
) {
143 #else // USE_FIXEDPOINT
144 // transform the four corners of the font bounding box -- the min
145 // and max values form the bounding box of the transformed font
146 x
= (int)((mat
[0] * face
->bbox
.xMin
+ mat
[2] * face
->bbox
.yMin
) /
147 (div
* face
->units_per_EM
));
149 y
= (int)((mat
[1] * face
->bbox
.xMin
+ mat
[3] * face
->bbox
.yMin
) /
150 (div
* face
->units_per_EM
));
152 x
= (int)((mat
[0] * face
->bbox
.xMin
+ mat
[2] * face
->bbox
.yMax
) /
153 (div
* face
->units_per_EM
));
156 } else if (x
> xMax
) {
159 y
= (int)((mat
[1] * face
->bbox
.xMin
+ mat
[3] * face
->bbox
.yMax
) /
160 (div
* face
->units_per_EM
));
163 } else if (y
> yMax
) {
166 x
= (int)((mat
[0] * face
->bbox
.xMax
+ mat
[2] * face
->bbox
.yMin
) /
167 (div
* face
->units_per_EM
));
170 } else if (x
> xMax
) {
173 y
= (int)((mat
[1] * face
->bbox
.xMax
+ mat
[3] * face
->bbox
.yMin
) /
174 (div
* face
->units_per_EM
));
177 } else if (y
> yMax
) {
180 x
= (int)((mat
[0] * face
->bbox
.xMax
+ mat
[2] * face
->bbox
.yMax
) /
181 (div
* face
->units_per_EM
));
184 } else if (x
> xMax
) {
187 y
= (int)((mat
[1] * face
->bbox
.xMax
+ mat
[3] * face
->bbox
.yMax
) /
188 (div
* face
->units_per_EM
));
191 } else if (y
> yMax
) {
194 #endif // USE_FIXEDPOINT
195 // This is a kludge: some buggy PDF generators embed fonts with
196 // zero bounding boxes.
203 yMax
= (int)((SplashCoord
)1.2 * size
);
206 // compute the transform matrix
208 matrix
.xx
= (FT_Fixed
)((mat
[0] / size
).get16Dot16());
209 matrix
.yx
= (FT_Fixed
)((mat
[1] / size
).get16Dot16());
210 matrix
.xy
= (FT_Fixed
)((mat
[2] / size
).get16Dot16());
211 matrix
.yy
= (FT_Fixed
)((mat
[3] / size
).get16Dot16());
212 textMatrix
.xx
= (FT_Fixed
)((textMat
[0] / (textScale
* size
)).get16Dot16());
213 textMatrix
.yx
= (FT_Fixed
)((textMat
[1] / (textScale
* size
)).get16Dot16());
214 textMatrix
.xy
= (FT_Fixed
)((textMat
[2] / (textScale
* size
)).get16Dot16());
215 textMatrix
.yy
= (FT_Fixed
)((textMat
[3] / (textScale
* size
)).get16Dot16());
217 matrix
.xx
= (FT_Fixed
)((mat
[0] / size
) * 65536);
218 matrix
.yx
= (FT_Fixed
)((mat
[1] / size
) * 65536);
219 matrix
.xy
= (FT_Fixed
)((mat
[2] / size
) * 65536);
220 matrix
.yy
= (FT_Fixed
)((mat
[3] / size
) * 65536);
221 textMatrix
.xx
= (FT_Fixed
)((textMat
[0] / (textScale
* size
)) * 65536);
222 textMatrix
.yx
= (FT_Fixed
)((textMat
[1] / (textScale
* size
)) * 65536);
223 textMatrix
.xy
= (FT_Fixed
)((textMat
[2] / (textScale
* size
)) * 65536);
224 textMatrix
.yy
= (FT_Fixed
)((textMat
[3] / (textScale
* size
)) * 65536);
228 SplashFTFont::~SplashFTFont() {
231 GBool
SplashFTFont::getGlyph(int c
, int xFrac
, int yFrac
,
232 SplashGlyphBitmap
*bitmap
, int x0
, int y0
, SplashClip
*clip
, SplashClipResult
*clipRes
) {
233 return SplashFont::getGlyph(c
, xFrac
, 0, bitmap
, x0
, y0
, clip
, clipRes
);
236 static FT_Int32
getFTLoadFlags(GBool type1
, GBool trueType
, GBool aa
, GBool enableFreeTypeHinting
, GBool enableSlightHinting
)
238 int ret
= FT_LOAD_DEFAULT
;
240 ret
|= FT_LOAD_NO_BITMAP
;
242 if (enableFreeTypeHinting
) {
243 if (enableSlightHinting
) {
244 ret
|= FT_LOAD_TARGET_LIGHT
;
247 // FT2's autohinting doesn't always work very well (especially with
248 // font subsets), so turn it off if anti-aliasing is enabled; if
249 // anti-aliasing is disabled, this seems to be a tossup - some fonts
250 // look better with hinting, some without, so leave hinting on
252 ret
|= FT_LOAD_NO_AUTOHINT
;
255 // Type 1 fonts seem to look better with 'light' hinting mode
256 ret
|= FT_LOAD_TARGET_LIGHT
;
260 ret
|= FT_LOAD_NO_HINTING
;
265 GBool
SplashFTFont::makeGlyph(int c
, int xFrac
, int yFrac
,
266 SplashGlyphBitmap
*bitmap
, int x0
, int y0
, SplashClip
*clip
, SplashClipResult
*clipRes
) {
267 SplashFTFontFile
*ff
;
275 ff
= (SplashFTFontFile
*)fontFile
;
277 ff
->face
->size
= sizeObj
;
278 offset
.x
= (FT_Pos
)(int)((SplashCoord
)xFrac
* splashFontFractionMul
* 64);
280 FT_Set_Transform(ff
->face
, &matrix
, &offset
);
281 slot
= ff
->face
->glyph
;
283 if (ff
->codeToGID
&& c
< ff
->codeToGIDLen
&& c
>= 0) {
284 gid
= (FT_UInt
)ff
->codeToGID
[c
];
289 if (FT_Load_Glyph(ff
->face
, gid
, getFTLoadFlags(ff
->type1
, ff
->trueType
, aa
, enableFreeTypeHinting
, enableSlightHinting
))) {
293 // prelimirary values based on FT_Outline_Get_CBox
294 // we add two pixels to each side to be in the safe side
296 FT_Outline_Get_CBox(&ff
->face
->glyph
->outline
, &cbox
);
297 bitmap
->x
= -(cbox
.xMin
/ 64) + 2;
298 bitmap
->y
= (cbox
.yMax
/ 64) + 2;
299 bitmap
->w
= ((cbox
.xMax
- cbox
.xMin
) / 64) + 4;
300 bitmap
->h
= ((cbox
.yMax
- cbox
.yMin
) / 64) + 4;
302 *clipRes
= clip
->testRect(x0
- bitmap
->x
,
304 x0
- bitmap
->x
+ bitmap
->w
,
305 y0
- bitmap
->y
+ bitmap
->h
);
306 if (*clipRes
== splashClipAllOutside
) {
307 bitmap
->freeData
= gFalse
;
311 if (FT_Render_Glyph(slot
, aa
? ft_render_mode_normal
312 : ft_render_mode_mono
)) {
316 if (slot
->bitmap
.width
== 0 || slot
->bitmap
.rows
== 0) {
317 // this can happen if (a) the glyph is really tiny or (b) the
318 // metrics in the TrueType file are broken
322 bitmap
->x
= -slot
->bitmap_left
;
323 bitmap
->y
= slot
->bitmap_top
;
324 bitmap
->w
= slot
->bitmap
.width
;
325 bitmap
->h
= slot
->bitmap
.rows
;
330 rowSize
= (bitmap
->w
+ 7) >> 3;
332 bitmap
->data
= (Guchar
*)gmallocn_checkoverflow(rowSize
, bitmap
->h
);
336 bitmap
->freeData
= gTrue
;
337 for (i
= 0, p
= bitmap
->data
, q
= slot
->bitmap
.buffer
;
339 ++i
, p
+= rowSize
, q
+= slot
->bitmap
.pitch
) {
340 memcpy(p
, q
, rowSize
);
346 double SplashFTFont::getGlyphAdvance(int c
)
348 SplashFTFontFile
*ff
;
351 FT_Matrix identityMatrix
;
353 ff
= (SplashFTFontFile
*)fontFile
;
356 identityMatrix
.xx
= 65536; // 1 in 16.16 format
357 identityMatrix
.xy
= 0;
358 identityMatrix
.yx
= 0;
359 identityMatrix
.yy
= 65536; // 1 in 16.16 format
365 ff
->face
->size
= sizeObj
;
366 FT_Set_Transform(ff
->face
, &identityMatrix
, &offset
);
368 if (ff
->codeToGID
&& c
< ff
->codeToGIDLen
) {
369 gid
= (FT_UInt
)ff
->codeToGID
[c
];
374 if (FT_Load_Glyph(ff
->face
, gid
, getFTLoadFlags(ff
->type1
, ff
->trueType
, aa
, enableFreeTypeHinting
, enableSlightHinting
))) {
378 // 64.0 is 1 in 26.6 format
379 return ff
->face
->glyph
->metrics
.horiAdvance
/ 64.0 / size
;
382 struct SplashFTFontPath
{
384 SplashCoord textScale
;
388 SplashPath
*SplashFTFont::getGlyphPath(int c
) {
389 static FT_Outline_Funcs outlineFuncs
= {
390 #if FREETYPE_MINOR <= 1
391 (int (*)(FT_Vector
*, void *))&glyphPathMoveTo
,
392 (int (*)(FT_Vector
*, void *))&glyphPathLineTo
,
393 (int (*)(FT_Vector
*, FT_Vector
*, void *))&glyphPathConicTo
,
394 (int (*)(FT_Vector
*, FT_Vector
*, FT_Vector
*, void *))&glyphPathCubicTo
,
403 SplashFTFontFile
*ff
;
404 SplashFTFontPath path
;
409 ff
= (SplashFTFontFile
*)fontFile
;
410 ff
->face
->size
= sizeObj
;
411 FT_Set_Transform(ff
->face
, &textMatrix
, NULL
);
412 slot
= ff
->face
->glyph
;
413 if (ff
->codeToGID
&& c
< ff
->codeToGIDLen
&& c
>= 0) {
414 gid
= ff
->codeToGID
[c
];
418 if (FT_Load_Glyph(ff
->face
, gid
, getFTLoadFlags(ff
->type1
, ff
->trueType
, aa
, enableFreeTypeHinting
, enableSlightHinting
))) {
421 if (FT_Get_Glyph(slot
, &glyph
)) {
424 if (FT_Outline_Check(&((FT_OutlineGlyph
)glyph
)->outline
)) {
427 path
.path
= new SplashPath();
428 path
.textScale
= textScale
;
429 path
.needClose
= gFalse
;
430 FT_Outline_Decompose(&((FT_OutlineGlyph
)glyph
)->outline
,
431 &outlineFuncs
, &path
);
432 if (path
.needClose
) {
435 FT_Done_Glyph(glyph
);
439 static int glyphPathMoveTo(const FT_Vector
*pt
, void *path
) {
440 SplashFTFontPath
*p
= (SplashFTFontPath
*)path
;
444 p
->needClose
= gFalse
;
446 p
->path
->moveTo((SplashCoord
)pt
->x
* p
->textScale
/ 64.0,
447 (SplashCoord
)pt
->y
* p
->textScale
/ 64.0);
451 static int glyphPathLineTo(const FT_Vector
*pt
, void *path
) {
452 SplashFTFontPath
*p
= (SplashFTFontPath
*)path
;
454 p
->path
->lineTo((SplashCoord
)pt
->x
* p
->textScale
/ 64.0,
455 (SplashCoord
)pt
->y
* p
->textScale
/ 64.0);
456 p
->needClose
= gTrue
;
460 static int glyphPathConicTo(const FT_Vector
*ctrl
, const FT_Vector
*pt
,
462 SplashFTFontPath
*p
= (SplashFTFontPath
*)path
;
463 SplashCoord x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, xc
, yc
;
465 if (!p
->path
->getCurPt(&x0
, &y0
)) {
468 xc
= (SplashCoord
)ctrl
->x
* p
->textScale
/ 64.0;
469 yc
= (SplashCoord
)ctrl
->y
* p
->textScale
/ 64.0;
470 x3
= (SplashCoord
)pt
->x
* p
->textScale
/ 64.0;
471 y3
= (SplashCoord
)pt
->y
* p
->textScale
/ 64.0;
473 // A second-order Bezier curve is defined by two endpoints, p0 and
474 // p3, and one control point, pc:
476 // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
478 // A third-order Bezier curve is defined by the same two endpoints,
479 // p0 and p3, and two control points, p1 and p2:
481 // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
483 // Applying some algebra, we can convert a second-order curve to a
484 // third-order curve:
486 // p1 = (1/3) * (p0 + 2pc)
487 // p2 = (1/3) * (2pc + p3)
489 x1
= (SplashCoord
)(1.0 / 3.0) * (x0
+ (SplashCoord
)2 * xc
);
490 y1
= (SplashCoord
)(1.0 / 3.0) * (y0
+ (SplashCoord
)2 * yc
);
491 x2
= (SplashCoord
)(1.0 / 3.0) * ((SplashCoord
)2 * xc
+ x3
);
492 y2
= (SplashCoord
)(1.0 / 3.0) * ((SplashCoord
)2 * yc
+ y3
);
494 p
->path
->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
495 p
->needClose
= gTrue
;
499 static int glyphPathCubicTo(const FT_Vector
*ctrl1
, const FT_Vector
*ctrl2
,
500 const FT_Vector
*pt
, void *path
) {
501 SplashFTFontPath
*p
= (SplashFTFontPath
*)path
;
503 p
->path
->curveTo((SplashCoord
)ctrl1
->x
* p
->textScale
/ 64.0,
504 (SplashCoord
)ctrl1
->y
* p
->textScale
/ 64.0,
505 (SplashCoord
)ctrl2
->x
* p
->textScale
/ 64.0,
506 (SplashCoord
)ctrl2
->y
* p
->textScale
/ 64.0,
507 (SplashCoord
)pt
->x
* p
->textScale
/ 64.0,
508 (SplashCoord
)pt
->y
* p
->textScale
/ 64.0);
509 p
->needClose
= gTrue
;
513 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H