Coverage Report

Created: 2023-09-25 06:41

/src/xpdf-4.04/splash/SplashFTFont.cc
Line
Count
Source (jump to first uncovered line)
1
//========================================================================
2
//
3
// SplashFTFont.cc
4
//
5
// Copyright 2003-2013 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#if HAVE_FREETYPE_H
12
13
#ifdef USE_GCC_PRAGMAS
14
#pragma implementation
15
#endif
16
17
#include <ft2build.h>
18
#include FT_OUTLINE_H
19
#include FT_SIZES_H
20
#include FT_GLYPH_H
21
#include "gmem.h"
22
#include "gmempp.h"
23
#include "SplashMath.h"
24
#include "SplashGlyphBitmap.h"
25
#include "SplashPath.h"
26
#include "SplashFontEngine.h"
27
#include "SplashFTFontEngine.h"
28
#include "SplashFTFontFile.h"
29
#include "SplashFTFont.h"
30
31
//------------------------------------------------------------------------
32
33
static int glyphPathMoveTo(const FT_Vector *pt, void *path);
34
static int glyphPathLineTo(const FT_Vector *pt, void *path);
35
static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
36
          void *path);
37
static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
38
          const FT_Vector *pt, void *path);
39
40
//------------------------------------------------------------------------
41
// SplashFTFont
42
//------------------------------------------------------------------------
43
44
SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
45
         SplashCoord *textMatA):
46
  SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
47
0
{
48
0
  FT_Face face;
49
0
  int size, div;
50
0
  int x, y;
51
#if USE_FIXEDPOINT
52
  SplashCoord scale;
53
#endif
54
55
0
  face = fontFileA->face;
56
0
  if (FT_New_Size(face, &sizeObj)) {
57
0
    return;
58
0
  }
59
0
  face->size = sizeObj;
60
0
  size = splashRound(splashDist(0, 0, mat[2], mat[3]));
61
0
  if (size < 1) {
62
0
    size = 1;
63
0
  }
64
0
  if (FT_Set_Pixel_Sizes(face, 0, size)) {
65
0
    return;
66
0
  }
67
  // if the textMat values are too small, FreeType's fixed point
68
  // arithmetic doesn't work so well
69
0
  textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
70
  // avoid problems with singular (or close-to-singular) matrices
71
0
  if (textScale < 0.00001) {
72
0
    textScale = 0.00001;
73
0
  }
74
75
0
  div = face->bbox.xMax > 20000 ? 65536 : 1;
76
77
#if USE_FIXEDPOINT
78
  scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
79
80
  // transform the four corners of the font bounding box -- the min
81
  // and max values form the bounding box of the transformed font
82
  x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
83
      mat[2] * (scale * (face->bbox.yMin / div)));
84
  xMin = xMax = x;
85
  y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
86
      mat[3] * (scale * (face->bbox.yMin / div)));
87
  yMin = yMax = y;
88
  x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
89
      mat[2] * (scale * (face->bbox.yMax / div)));
90
  if (x < xMin) {
91
    xMin = x;
92
  } else if (x > xMax) {
93
    xMax = x;
94
  }
95
  y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
96
      mat[3] * (scale * (face->bbox.yMax / div)));
97
  if (y < yMin) {
98
    yMin = y;
99
  } else if (y > yMax) {
100
    yMax = y;
101
  }
102
  x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
103
      mat[2] * (scale * (face->bbox.yMin / div)));
104
  if (x < xMin) {
105
    xMin = x;
106
  } else if (x > xMax) {
107
    xMax = x;
108
  }
109
  y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
110
      mat[3] * (scale * (face->bbox.yMin / div)));
111
  if (y < yMin) {
112
    yMin = y;
113
  } else if (y > yMax) {
114
    yMax = y;
115
  }
116
  x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
117
      mat[2] * (scale * (face->bbox.yMax / div)));
118
  if (x < xMin) {
119
    xMin = x;
120
  } else if (x > xMax) {
121
    xMax = x;
122
  }
123
  y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
124
      mat[3] * (scale * (face->bbox.yMax / div)));
125
  if (y < yMin) {
126
    yMin = y;
127
  } else if (y > yMax) {
128
    yMax = y;
129
  }
130
#else // USE_FIXEDPOINT
131
  // transform the four corners of the font bounding box -- the min
132
  // and max values form the bounding box of the transformed font
133
0
  x = (int)((mat[0] * (SplashCoord)face->bbox.xMin
134
0
       + mat[2] * (SplashCoord)face->bbox.yMin) /
135
0
      (div * face->units_per_EM));
136
0
  xMin = xMax = x;
137
0
  y = (int)((mat[1] * (SplashCoord)face->bbox.xMin
138
0
       + mat[3] * (SplashCoord)face->bbox.yMin) /
139
0
      (div * face->units_per_EM));
140
0
  yMin = yMax = y;
141
0
  x = (int)((mat[0] * (SplashCoord)face->bbox.xMin
142
0
       + mat[2] * (SplashCoord)face->bbox.yMax) /
143
0
      (div * face->units_per_EM));
144
0
  if (x < xMin) {
145
0
    xMin = x;
146
0
  } else if (x > xMax) {
147
0
    xMax = x;
148
0
  }
149
0
  y = (int)((mat[1] * (SplashCoord)face->bbox.xMin
150
0
       + mat[3] * (SplashCoord)face->bbox.yMax) /
151
0
      (div * face->units_per_EM));
152
0
  if (y < yMin) {
153
0
    yMin = y;
154
0
  } else if (y > yMax) {
155
0
    yMax = y;
156
0
  }
157
0
  x = (int)((mat[0] * (SplashCoord)face->bbox.xMax
158
0
       + mat[2] * (SplashCoord)face->bbox.yMin) /
159
0
      (div * face->units_per_EM));
160
0
  if (x < xMin) {
161
0
    xMin = x;
162
0
  } else if (x > xMax) {
163
0
    xMax = x;
164
0
  }
165
0
  y = (int)((mat[1] * (SplashCoord)face->bbox.xMax
166
0
       + mat[3] * (SplashCoord)face->bbox.yMin) /
167
0
      (div * face->units_per_EM));
168
0
  if (y < yMin) {
169
0
    yMin = y;
170
0
  } else if (y > yMax) {
171
0
    yMax = y;
172
0
  }
173
0
  x = (int)((mat[0] * (SplashCoord)face->bbox.xMax
174
0
       + mat[2] * (SplashCoord)face->bbox.yMax) /
175
0
      (div * face->units_per_EM));
176
0
  if (x < xMin) {
177
0
    xMin = x;
178
0
  } else if (x > xMax) {
179
0
    xMax = x;
180
0
  }
181
0
  y = (int)((mat[1] * (SplashCoord)face->bbox.xMax
182
0
       + mat[3] * (SplashCoord)face->bbox.yMax) /
183
0
      (div * face->units_per_EM));
184
0
  if (y < yMin) {
185
0
    yMin = y;
186
0
  } else if (y > yMax) {
187
0
    yMax = y;
188
0
  }
189
0
#endif // USE_FIXEDPOINT
190
  // This is a kludge: some buggy PDF generators embed fonts with
191
  // zero bounding boxes.
192
0
  if (xMax == xMin) {
193
0
    xMin = 0;
194
0
    xMax = size;
195
0
  }
196
0
  if (yMax == yMin) {
197
0
    yMin = 0;
198
0
    yMax = (int)((SplashCoord)1.2 * size);
199
0
  }
200
201
  // compute the transform matrix
202
#if USE_FIXEDPOINT
203
  matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16());
204
  matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16());
205
  matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16());
206
  matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16());
207
  textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16());
208
  textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16());
209
  textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16());
210
  textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16());
211
#else
212
0
  matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
213
0
  matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
214
0
  matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
215
0
  matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
216
0
  textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
217
0
  textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
218
0
  textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
219
0
  textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
220
0
#endif
221
0
}
222
223
0
SplashFTFont::~SplashFTFont() {
224
0
}
225
226
GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
227
0
           SplashGlyphBitmap *bitmap) {
228
0
  return SplashFont::getGlyph(c, xFrac, 0, bitmap);
229
0
}
230
231
GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
232
0
            SplashGlyphBitmap *bitmap) {
233
0
  SplashFTFontFile *ff;
234
0
  FT_Vector offset;
235
0
  FT_GlyphSlot slot;
236
0
  int gid;
237
0
  FT_Int32 flags;
238
0
  int rowSize;
239
0
  Guchar *p, *q;
240
0
  int i;
241
242
0
  ff = (SplashFTFontFile *)fontFile;
243
244
0
  ff->face->size = sizeObj;
245
0
  offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
246
0
  offset.y = 0;
247
0
  FT_Set_Transform(ff->face, &matrix, &offset);
248
0
  slot = ff->face->glyph;
249
250
0
  if (ff->codeToGID && c < ff->codeToGIDLen) {
251
0
    gid = ff->codeToGID[c];
252
0
  } else {
253
0
    gid = c;
254
0
  }
255
0
  if (ff->fontType == splashFontTrueType && gid < 0) {
256
    // skip the TrueType notdef glyph
257
0
    return gFalse;
258
0
  }
259
260
  // Set up the load flags:
261
  // * disable bitmaps because they look ugly when scaled, rotated,
262
  //   etc.
263
  // * disable autohinting because it can fail badly with font subsets
264
  //   that use invalid glyph names (the FreeType autohinter depends
265
  //   on the glyph name to figure out how to autohint the glyph)
266
  // * but enable light autohinting for Type 1 fonts because regular
267
  //   hinting looks pretty bad, and the invalid glyph name issue
268
  //   seems to be very rare (Type 1 fonts are mostly used for
269
  //   substitution, in which case the full font is being used, which
270
  //   means we have the glyph names)
271
  // This also sets the "pedantic" flag, running the FreeType hinter
272
  // in paranoid mode.  If that triggers any errors, we disable
273
  // hinting below.
274
0
  flags = FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC;
275
0
  if (ff->engine->flags & splashFTNoHinting) {
276
0
    flags |= FT_LOAD_NO_HINTING;
277
0
  } else if (ff->fontType == splashFontType1) {
278
0
    flags |= FT_LOAD_TARGET_LIGHT;
279
0
  } else {
280
0
    flags |= FT_LOAD_NO_AUTOHINT;
281
0
  }
282
0
  if (FT_Load_Glyph(ff->face, (FT_UInt)gid, flags)) {
283
    // fonts with broken hinting instructions can cause errors here;
284
    // try again with no hinting (this is probably only relevant for
285
    // TrueType fonts)
286
0
    flags = FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
287
0
    if (FT_Load_Glyph(ff->face, (FT_UInt)gid, flags)) {
288
0
      return gFalse;
289
0
    }
290
0
  }
291
0
  if (FT_Render_Glyph(slot, aa ? FT_RENDER_MODE_NORMAL
292
0
                   : FT_RENDER_MODE_MONO)) {
293
0
    return gFalse;
294
0
  }
295
0
  if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
296
    // this can happen if (a) the glyph is really tiny or (b) the
297
    // metrics in the TrueType file are broken
298
0
    return gFalse;
299
0
  }
300
301
0
  bitmap->x = -slot->bitmap_left;
302
0
  bitmap->y = slot->bitmap_top;
303
0
  bitmap->w = slot->bitmap.width;
304
0
  bitmap->h = slot->bitmap.rows;
305
0
  bitmap->aa = aa;
306
0
  if (aa) {
307
0
    rowSize = bitmap->w;
308
0
  } else {
309
0
    rowSize = (bitmap->w + 7) >> 3;
310
0
  }
311
0
  bitmap->data = (Guchar *)gmallocn(bitmap->h, rowSize);
312
0
  bitmap->freeData = gTrue;
313
0
  for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
314
0
       i < bitmap->h;
315
0
       ++i, p += rowSize, q += slot->bitmap.pitch) {
316
0
    memcpy(p, q, rowSize);
317
0
  }
318
319
0
  return gTrue;
320
0
}
321
322
struct SplashFTFontPath {
323
  SplashPath *path;
324
  SplashCoord textScale;
325
  GBool needClose;
326
};
327
328
0
SplashPath *SplashFTFont::getGlyphPath(int c) {
329
0
  static FT_Outline_Funcs outlineFuncs = {
330
#if FREETYPE_MINOR <= 1
331
    (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
332
    (int (*)(FT_Vector *, void *))&glyphPathLineTo,
333
    (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
334
    (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
335
#else
336
0
    &glyphPathMoveTo,
337
0
    &glyphPathLineTo,
338
0
    &glyphPathConicTo,
339
0
    &glyphPathCubicTo,
340
0
#endif
341
0
    0, 0
342
0
  };
343
0
  SplashFTFontFile *ff;
344
0
  SplashFTFontPath path;
345
0
  FT_GlyphSlot slot;
346
0
  int gid;
347
0
  FT_Glyph glyph;
348
349
0
  ff = (SplashFTFontFile *)fontFile;
350
0
  ff->face->size = sizeObj;
351
0
  FT_Set_Transform(ff->face, &textMatrix, NULL);
352
0
  slot = ff->face->glyph;
353
0
  if (ff->codeToGID && c < ff->codeToGIDLen) {
354
0
    gid = ff->codeToGID[c];
355
0
  } else {
356
0
    gid = c;
357
0
  }
358
0
  if (ff->fontType == splashFontTrueType && gid < 0) {
359
    // skip the TrueType notdef glyph
360
0
    return NULL;
361
0
  }
362
0
  if (FT_Load_Glyph(ff->face, (FT_UInt)gid, FT_LOAD_NO_BITMAP)) {
363
    // fonts with broken hinting instructions can cause errors here;
364
    // try again with no hinting (this is probably only relevant for
365
    // TrueType fonts)
366
0
    if (FT_Load_Glyph(ff->face, (FT_UInt)gid,
367
0
          FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) {
368
0
      return NULL;
369
0
    }
370
0
  }
371
0
  if (FT_Get_Glyph(slot, &glyph)) {
372
0
    return NULL;
373
0
  }
374
0
  path.path = new SplashPath();
375
0
  path.textScale = textScale;
376
0
  path.needClose = gFalse;
377
0
  FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
378
0
           &outlineFuncs, &path);
379
0
  if (path.needClose) {
380
0
    path.path->close();
381
0
  }
382
0
  FT_Done_Glyph(glyph);
383
0
  return path.path;
384
0
}
385
386
0
static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
387
0
  SplashFTFontPath *p = (SplashFTFontPath *)path;
388
389
0
  if (p->needClose) {
390
0
    p->path->close();
391
0
    p->needClose = gFalse;
392
0
  }
393
0
  p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
394
0
      (SplashCoord)pt->y * p->textScale / 64.0);
395
0
  return 0;
396
0
}
397
398
0
static int glyphPathLineTo(const FT_Vector *pt, void *path) {
399
0
  SplashFTFontPath *p = (SplashFTFontPath *)path;
400
401
0
  p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
402
0
      (SplashCoord)pt->y * p->textScale / 64.0);
403
0
  p->needClose = gTrue;
404
0
  return 0;
405
0
}
406
407
static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
408
0
          void *path) {
409
0
  SplashFTFontPath *p = (SplashFTFontPath *)path;
410
0
  SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
411
412
0
  if (!p->path->getCurPt(&x0, &y0)) {
413
0
    return 0;
414
0
  }
415
0
  xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
416
0
  yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
417
0
  x3 = (SplashCoord)pt->x * p->textScale / 64.0;
418
0
  y3 = (SplashCoord)pt->y * p->textScale / 64.0;
419
420
  // A second-order Bezier curve is defined by two endpoints, p0 and
421
  // p3, and one control point, pc:
422
  //
423
  //     p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
424
  //
425
  // A third-order Bezier curve is defined by the same two endpoints,
426
  // p0 and p3, and two control points, p1 and p2:
427
  //
428
  //     p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
429
  //
430
  // Applying some algebra, we can convert a second-order curve to a
431
  // third-order curve:
432
  //
433
  //     p1 = (1/3) * (p0 + 2pc)
434
  //     p2 = (1/3) * (2pc + p3)
435
436
0
  x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
437
0
  y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
438
0
  x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
439
0
  y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
440
441
0
  p->path->curveTo(x1, y1, x2, y2, x3, y3);
442
0
  p->needClose = gTrue;
443
0
  return 0;
444
0
}
445
446
static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
447
0
          const FT_Vector *pt, void *path) {
448
0
  SplashFTFontPath *p = (SplashFTFontPath *)path;
449
450
0
  p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
451
0
       (SplashCoord)ctrl1->y * p->textScale / 64.0,
452
0
       (SplashCoord)ctrl2->x * p->textScale / 64.0,
453
0
       (SplashCoord)ctrl2->y * p->textScale / 64.0,
454
0
       (SplashCoord)pt->x * p->textScale / 64.0,
455
0
       (SplashCoord)pt->y * p->textScale / 64.0);
456
0
  p->needClose = gTrue;
457
0
  return 0;
458
0
}
459
460
#endif // HAVE_FREETYPE_H