summaryrefslogtreecommitdiff
path: root/Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2014-08-22 07:04:01 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2014-08-22 07:04:01 +0000
commit1612bfd9e3f1db86e943626640b71cdf3df5b9a0 (patch)
tree55b061c358a44ccfce7f8c584a8a876edf864870 /Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc
parent8ed265a1a7e2e74041cd214aa3acc933484adb01 (diff)
poppler 0.26.4
git-svn-id: svn://tug.org/texlive/trunk@35006 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc')
-rw-r--r--Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc513
1 files changed, 513 insertions, 0 deletions
diff --git a/Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc b/Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc
new file mode 100644
index 00000000000..b785826d66b
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.26.4/splash/SplashFTFont.cc
@@ -0,0 +1,513 @@
+//========================================================================
+//
+// SplashFTFont.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2007-2011, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Kristian Høgsberg <krh@bitplanet.net>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+#include FT_SIZES_H
+#include FT_GLYPH_H
+#include "goo/gmem.h"
+#include "SplashMath.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashPath.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFTFontFile.h"
+#include "SplashFTFont.h"
+
+//------------------------------------------------------------------------
+
+static int glyphPathMoveTo(const FT_Vector *pt, void *path);
+static int glyphPathLineTo(const FT_Vector *pt, void *path);
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+ void *path);
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+ const FT_Vector *pt, void *path);
+
+//------------------------------------------------------------------------
+// SplashFTFont
+//------------------------------------------------------------------------
+
+SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA):
+ SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa),
+ enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting),
+ enableSlightHinting(fontFileA->engine->enableSlightHinting)
+{
+ FT_Face face;
+ int div;
+ int x, y;
+#if USE_FIXEDPOINT
+ SplashCoord scale;
+#endif
+
+ face = fontFileA->face;
+ if (FT_New_Size(face, &sizeObj)) {
+ return;
+ }
+ face->size = sizeObj;
+ size = splashRound(splashDist(0, 0, mat[2], mat[3]));
+ if (size < 1) {
+ size = 1;
+ }
+ if (FT_Set_Pixel_Sizes(face, 0, size)) {
+ return;
+ }
+ // if the textMat values are too small, FreeType's fixed point
+ // arithmetic doesn't work so well
+ textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
+
+ div = face->bbox.xMax > 20000 ? 65536 : 1;
+
+#if USE_FIXEDPOINT
+ scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
+
+ // transform the four corners of the font bounding box -- the min
+ // and max values form the bounding box of the transformed font
+ x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
+ mat[2] * (scale * (face->bbox.yMin / div)));
+ xMin = xMax = x;
+ y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
+ mat[3] * (scale * (face->bbox.yMin / div)));
+ yMin = yMax = y;
+ x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
+ mat[2] * (scale * (face->bbox.yMax / div)));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
+ mat[3] * (scale * (face->bbox.yMax / div)));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
+ mat[2] * (scale * (face->bbox.yMin / div)));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
+ mat[3] * (scale * (face->bbox.yMin / div)));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
+ mat[2] * (scale * (face->bbox.yMax / div)));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
+ mat[3] * (scale * (face->bbox.yMax / div)));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+#else // USE_FIXEDPOINT
+ // transform the four corners of the font bounding box -- the min
+ // and max values form the bounding box of the transformed font
+ x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ xMin = xMax = x;
+ y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ yMin = yMax = y;
+ x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+#endif // USE_FIXEDPOINT
+ // This is a kludge: some buggy PDF generators embed fonts with
+ // zero bounding boxes.
+ if (xMax == xMin) {
+ xMin = 0;
+ xMax = size;
+ }
+ if (yMax == yMin) {
+ yMin = 0;
+ yMax = (int)((SplashCoord)1.2 * size);
+ }
+
+ // compute the transform matrix
+#if USE_FIXEDPOINT
+ matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16());
+ matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16());
+ matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16());
+ matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16());
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16());
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16());
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16());
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16());
+#else
+ matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
+ matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
+ matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
+ matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
+#endif
+}
+
+SplashFTFont::~SplashFTFont() {
+}
+
+GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
+}
+
+static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting)
+{
+ int ret = FT_LOAD_DEFAULT;
+ if (aa)
+ ret |= FT_LOAD_NO_BITMAP;
+
+ if (enableFreeTypeHinting) {
+ if (enableSlightHinting) {
+ ret |= FT_LOAD_TARGET_LIGHT;
+ } else {
+ if (trueType) {
+ // FT2's autohinting doesn't always work very well (especially with
+ // font subsets), so turn it off if anti-aliasing is enabled; if
+ // anti-aliasing is disabled, this seems to be a tossup - some fonts
+ // look better with hinting, some without, so leave hinting on
+ if (aa) {
+ ret |= FT_LOAD_NO_AUTOHINT;
+ }
+ } else if (type1) {
+ // Type 1 fonts seem to look better with 'light' hinting mode
+ ret |= FT_LOAD_TARGET_LIGHT;
+ }
+ }
+ } else {
+ ret |= FT_LOAD_NO_HINTING;
+ }
+ return ret;
+}
+
+GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ SplashFTFontFile *ff;
+ FT_Vector offset;
+ FT_GlyphSlot slot;
+ FT_UInt gid;
+ int rowSize;
+ Guchar *p, *q;
+ int i;
+
+ ff = (SplashFTFontFile *)fontFile;
+
+ ff->face->size = sizeObj;
+ offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
+ offset.y = 0;
+ FT_Set_Transform(ff->face, &matrix, &offset);
+ slot = ff->face->glyph;
+
+ if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
+ gid = (FT_UInt)ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+ return gFalse;
+ }
+
+ // prelimirary values based on FT_Outline_Get_CBox
+ // we add two pixels to each side to be in the safe side
+ FT_BBox cbox;
+ FT_Outline_Get_CBox(&ff->face->glyph->outline, &cbox);
+ bitmap->x = -(cbox.xMin / 64) + 2;
+ bitmap->y = (cbox.yMax / 64) + 2;
+ bitmap->w = ((cbox.xMax - cbox.xMin) / 64) + 4;
+ bitmap->h = ((cbox.yMax - cbox.yMin) / 64) + 4;
+
+ *clipRes = clip->testRect(x0 - bitmap->x,
+ y0 - bitmap->y,
+ x0 - bitmap->x + bitmap->w,
+ y0 - bitmap->y + bitmap->h);
+ if (*clipRes == splashClipAllOutside) {
+ bitmap->freeData = gFalse;
+ return gTrue;
+ }
+
+ if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
+ : ft_render_mode_mono)) {
+ return gFalse;
+ }
+
+ if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
+ // this can happen if (a) the glyph is really tiny or (b) the
+ // metrics in the TrueType file are broken
+ return gFalse;
+ }
+
+ bitmap->x = -slot->bitmap_left;
+ bitmap->y = slot->bitmap_top;
+ bitmap->w = slot->bitmap.width;
+ bitmap->h = slot->bitmap.rows;
+ bitmap->aa = aa;
+ if (aa) {
+ rowSize = bitmap->w;
+ } else {
+ rowSize = (bitmap->w + 7) >> 3;
+ }
+ bitmap->data = (Guchar *)gmallocn_checkoverflow(rowSize, bitmap->h);
+ if (!bitmap->data) {
+ return gFalse;
+ }
+ bitmap->freeData = gTrue;
+ for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
+ i < bitmap->h;
+ ++i, p += rowSize, q += slot->bitmap.pitch) {
+ memcpy(p, q, rowSize);
+ }
+
+ return gTrue;
+}
+
+double SplashFTFont::getGlyphAdvance(int c)
+{
+ SplashFTFontFile *ff;
+ FT_Vector offset;
+ FT_UInt gid;
+ FT_Matrix identityMatrix;
+
+ ff = (SplashFTFontFile *)fontFile;
+
+ // init the matrix
+ identityMatrix.xx = 65536; // 1 in 16.16 format
+ identityMatrix.xy = 0;
+ identityMatrix.yx = 0;
+ identityMatrix.yy = 65536; // 1 in 16.16 format
+
+ // init the offset
+ offset.x = 0;
+ offset.y = 0;
+
+ ff->face->size = sizeObj;
+ FT_Set_Transform(ff->face, &identityMatrix, &offset);
+
+ if (ff->codeToGID && c < ff->codeToGIDLen) {
+ gid = (FT_UInt)ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+ return -1;
+ }
+
+ // 64.0 is 1 in 26.6 format
+ return ff->face->glyph->metrics.horiAdvance / 64.0 / size;
+}
+
+struct SplashFTFontPath {
+ SplashPath *path;
+ SplashCoord textScale;
+ GBool needClose;
+};
+
+SplashPath *SplashFTFont::getGlyphPath(int c) {
+ static FT_Outline_Funcs outlineFuncs = {
+#if FREETYPE_MINOR <= 1
+ (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
+ (int (*)(FT_Vector *, void *))&glyphPathLineTo,
+ (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
+ (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
+#else
+ &glyphPathMoveTo,
+ &glyphPathLineTo,
+ &glyphPathConicTo,
+ &glyphPathCubicTo,
+#endif
+ 0, 0
+ };
+ SplashFTFontFile *ff;
+ SplashFTFontPath path;
+ FT_GlyphSlot slot;
+ FT_UInt gid;
+ FT_Glyph glyph;
+
+ ff = (SplashFTFontFile *)fontFile;
+ ff->face->size = sizeObj;
+ FT_Set_Transform(ff->face, &textMatrix, NULL);
+ slot = ff->face->glyph;
+ if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
+ gid = ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+ if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+ return NULL;
+ }
+ if (FT_Get_Glyph(slot, &glyph)) {
+ return NULL;
+ }
+ if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) {
+ return NULL;
+ }
+ path.path = new SplashPath();
+ path.textScale = textScale;
+ path.needClose = gFalse;
+ FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
+ &outlineFuncs, &path);
+ if (path.needClose) {
+ path.path->close();
+ }
+ FT_Done_Glyph(glyph);
+ return path.path;
+}
+
+static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ if (p->needClose) {
+ p->path->close();
+ p->needClose = gFalse;
+ }
+ p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
+ return 0;
+}
+
+static int glyphPathLineTo(const FT_Vector *pt, void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
+ p->needClose = gTrue;
+ return 0;
+}
+
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+ void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+ SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
+
+ if (!p->path->getCurPt(&x0, &y0)) {
+ return 0;
+ }
+ xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
+ yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
+ x3 = (SplashCoord)pt->x * p->textScale / 64.0;
+ y3 = (SplashCoord)pt->y * p->textScale / 64.0;
+
+ // A second-order Bezier curve is defined by two endpoints, p0 and
+ // p3, and one control point, pc:
+ //
+ // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
+ //
+ // A third-order Bezier curve is defined by the same two endpoints,
+ // p0 and p3, and two control points, p1 and p2:
+ //
+ // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
+ //
+ // Applying some algebra, we can convert a second-order curve to a
+ // third-order curve:
+ //
+ // p1 = (1/3) * (p0 + 2pc)
+ // p2 = (1/3) * (2pc + p3)
+
+ x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
+ y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
+ x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
+ y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
+
+ p->path->curveTo(x1, y1, x2, y2, x3, y3);
+ p->needClose = gTrue;
+ return 0;
+}
+
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+ const FT_Vector *pt, void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
+ (SplashCoord)ctrl1->y * p->textScale / 64.0,
+ (SplashCoord)ctrl2->x * p->textScale / 64.0,
+ (SplashCoord)ctrl2->y * p->textScale / 64.0,
+ (SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
+ p->needClose = gTrue;
+ return 0;
+}
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H