Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/base/gxhintn.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Type 1 hinter, a new algorithm */
18
19
#include "memory_.h"
20
#include "math_.h"
21
#include "assert_.h"
22
#include "gx.h"
23
#include "gxfixed.h"
24
#include "gxarith.h"
25
#include "gstypes.h"
26
#include "gxmatrix.h"
27
#include "gxpath.h"
28
#include "gxfont.h"
29
#include "gxfont1.h"
30
#include "gxtype1.h"
31
#include "gxhintn.h"
32
#include "gzpath.h"
33
#include "gserrors.h"
34
35
/*  todo :
36
    - Diagonal stems are not hinted;
37
    - Some fonts have no StdHW, StdWW. Adobe appears to autohint them.
38
    - Measure Adobe's flattness parameter.
39
    - Test Adobe compatibility for rotated/skewed glyphs.
40
 */
41
42
/*  Stem processing basics :
43
    (See the glyph AE in Times-Roman by Adobe.)
44
45
    0. This supposes that glyph is transformed to device space
46
       with a random matrix.
47
48
       All outline poles and all hint commands are stored in arrays
49
       before staring the exact processing.
50
51
       HR pole is pole before which stem replacement happens.
52
53
    1. Stem hints may be primary ones (defined in the beginning of charstring),
54
       and secondary ones (defined at HR poles). Consider that
55
       secondary stem hints may be redundant (see AE in Times-Roman).
56
       Secondary stems are HIGHER priority than basic ones.
57
58
    2. The range of secondary stem command is from its HR pole to next HR pole.
59
       The range of primary stem command is entire glyph.
60
61
    3. The TT interpreter aligned stem3 with centering the middle stem.
62
63
    4. If a stem boundary corresponds to a pole aligned with an alignment zone,
64
       pass aligned coordinate to the stem command.
65
       Use the stem boundary longitude middle point for alignment with
66
       skewed or rotated matrix. Use standard stem width for computing
67
       opposite coordinates.
68
69
    4a. If a stem width rounds to several StemSnap* element,
70
       choose the element, to which more stems can round.
71
       See Adobe Technical Note #5049.
72
73
    5. If several stems have a same boundary coordinate,
74
       this boundary gets more priority when aligned.
75
76
    6. Considering each set of repeating stem commands as a stem complex, pass
77
       aligned coordinates to opposite boundaries of stem commands.
78
79
    7. Pass aligned boundary coordinate to poles within stem command range.
80
       Note that this will pass aligned coordinates back to poles,
81
       from which stem alignment was taken.
82
83
    8. Interpolate unaligned poles.
84
85
    9. After the alignment is done, it is desirable to check for
86
       anomalous negative contours and fix them, but we have no
87
       good algorithm for this. The rasterizer must be tolerant
88
       to such contours (which may have self-crosses, self-contacts,
89
       or may change to opposite direction).
90
91
*/
92
93
/*  Dotsection processing basics :
94
95
    If stem replacement occures, dotsection to be ignored.
96
    To check this properly, we test whether extremal poles of contour
97
    were actually aligned with stem hints.
98
99
    If a contour was aligned with stem hints by both X and Y,
100
    no special processing required.
101
102
    Otherwise if dotsection center falls near vstem axis,
103
    we align it by X with the axis. Otherwise we align
104
    it by X to half-pixel. Then we align the center by Y to
105
    half-pixel, and shift entire contour to satisfy
106
    the alignment of the center.
107
*/
108
109
/*  vstem3/hstem3 processing basics :
110
    They are handled by the type 1,2 interpreters (gstype1.c, gstype2.c).
111
 */
112
113
/*  flex processing basics :
114
    With type 1 it is handled with t1_hinter__flex_* functions.
115
    With type 2 it is handled by gstype2.c .
116
 */
117
118
#define ADOBE_OVERSHOOT_COMPATIBILIY 0
119
#define ADOBE_SHIFT_CHARPATH 0
120
121
/*  The CONTRAST_STEMS option aligns one of two stem boundaries
122
    to integral pixel boundary when AlignToPixels = 0.
123
    It gives more contrast stems, because a bigger part
124
    of boldness is concentrated in smaller number of pixels.
125
*/
126
0
#define CONTRAST_STEMS 1
127
128
static const char *s_pole_array = "t1_hinter pole array";
129
static const char *s_zone_array = "t1_hinter zone array";
130
static const char *s_hint_array = "t1_hinter hint array";
131
static const char *s_contour_array = "t1_hinter contour array";
132
static const char *s_subglyph_array = "t1_hinter subglyph array";
133
static const char *s_hint_range_array = "t1_hinter hint_range array";
134
static const char *s_hint_applying_array = "t1_hinter hint_applying array";
135
static const char *s_stem_snap_array = "t1_hinter stem_snap array";
136
static const char *s_stem_snap_vote_array = "t1_hinter stem_snap_vote array";
137
138
0
#define member_prt(type, ptr, offset) (type *)((char *)(ptr) + (offset))
139
140
typedef int32_t int24;
141
#define HAVE_INT64_T
142
143
static const unsigned int split_bits = 12;
144
static const unsigned int max_coord_bits = 24; /* = split_bits * 2 */
145
static const unsigned int matrix_bits = 19; /* <= sizeof(int) * 8 - 1 - split_bits */
146
static const unsigned int g2o_bitshift = 12; /* <= matrix_bits + max_coord_bits - (sizeof(int) * 8 + 1) */
147
#ifndef HAVE_INT64_T
148
static const int32_t FFFFF000 = ~(int32_t)0xFFF; /* = ~(((int32_t)1 << split_bits) - 1) */
149
#endif
150
/* Constants above must satisfy expressions given in comments. */
151
152
/* Computes (a*b)>>s, s <= 12 */
153
static inline int32_t mul_shift(int24 a, int19 b, unsigned int s)
154
9.47M
{
155
9.47M
#ifdef HAVE_INT64_T
156
9.47M
    return ( (int64_t)a * (int64_t)b ) >> s; /* unrounded result */
157
#else
158
    { /* 32 bit fallback */
159
        int32_t aa = a & FFFFF000, a0 = a - aa, a1 = aa >> s;
160
        return ((a0 * b) >> s) + a1 * b; /* unrounded result */
161
    }
162
#endif
163
9.47M
}
164
165
/* Computes (a*b)>>s, s <= 12, with rounding */
166
static inline int32_t mul_shift_round(int24 a, int19 b, unsigned int s)
167
274M
{
168
274M
#ifdef HAVE_INT64_T
169
274M
    return (( ( (int64_t)a * (int64_t)b ) >> (s - 1)) + 1) >> 1;
170
#else
171
    { /* 32 bit version */
172
        int32_t aa = a & FFFFF000, a0 = a - aa, a1 = aa >> s;
173
        return ((((a0 * b) >> (s - 1)) + 1) >> 1) + a1 * b; /* rounded result */
174
    }
175
#endif
176
274M
}
177
178
static inline int32_t shift_rounded(int32_t v, unsigned int s)
179
9.47M
{   return ((v >> (s - 1)) + 1) >> 1;
180
9.47M
}
181
182
static inline int32_t Max(int32_t a, int32_t b)
183
14.2M
{   return a > b ? a : b;
184
14.2M
}
185
186
static inline long rshift(long a, int b)
187
9.47M
{   return b > 0 ? a << b : a >> -b;
188
9.47M
}
189
/*---------------------- members of matrix classes -------------------------*/
190
191
static inline void double_matrix__set(double_matrix * self, const gs_matrix_fixed * m)
192
2.36M
{   self->xx = m->xx;
193
2.36M
    self->xy = m->xy;
194
2.36M
    self->yx = m->yx;
195
2.36M
    self->yy = m->yy;
196
2.36M
}
197
198
static inline int double_matrix__invert_to(const double_matrix * self, double_matrix * m)
199
2.36M
{   double det = self->xx * self->yy - self->xy * self->yx;
200
201
2.36M
    if (fabs(det) * 1000000 <= fabs(self->xx) + fabs(self->xy) + fabs(self->yx) + fabs(self->yy))
202
0
        return_error(gs_error_rangecheck);
203
2.36M
    m->xx =  self->yy / det;
204
2.36M
    m->xy = -self->xy / det;
205
2.36M
    m->yx = -self->yx / det;
206
2.36M
    m->yy =  self->xx / det;
207
2.36M
    return 0;
208
2.36M
}
209
210
static void fraction_matrix__drop_bits(fraction_matrix * self, unsigned int bits)
211
0
{   self->xx = shift_rounded(self->xx, bits);
212
0
    self->xy = shift_rounded(self->xy, bits);
213
0
    self->yx = shift_rounded(self->yx, bits);
214
0
    self->yy = shift_rounded(self->yy, bits);
215
0
    self->denominator >>= bits;
216
0
    self->bitshift -= bits;
217
0
}
218
219
static void fraction_matrix__set(fraction_matrix * self, const double_matrix * pmat)
220
4.73M
{   double axx = fabs(pmat->xx), axy = fabs(pmat->xy);
221
4.73M
    double ayx = fabs(pmat->yx), ayy = fabs(pmat->yy);
222
4.73M
    double scale = max(axx + axy, ayx + ayy);
223
4.73M
    int matrix_exp, m;
224
225
4.73M
    (void)frexp(scale, &matrix_exp);
226
4.73M
    self->bitshift = matrix_bits - matrix_exp;
227
4.73M
    if (self->bitshift >= sizeof( self->denominator) * 8) {
228
0
        self->denominator = 0;
229
0
        self->xx = self->xy = self->yx = self->yy = 0;
230
4.73M
    } else {
231
4.73M
        self->denominator = 1 << self->bitshift;
232
        /* Round towards zero for a better view of mirrored characters : */
233
4.73M
        self->xx = (int32_t)(pmat->xx * self->denominator + 0.5);
234
4.73M
        self->xy = (int32_t)(pmat->xy * self->denominator + 0.5);
235
4.73M
        self->yx = (int32_t)(pmat->yx * self->denominator + 0.5);
236
4.73M
        self->yy = (int32_t)(pmat->yy * self->denominator + 0.5);
237
4.73M
        m = Max(Max(any_abs(self->xx), any_abs(self->xy)), Max(any_abs(self->yx), any_abs(self->yy)));
238
4.73M
        (void)frexp(m, &matrix_exp);
239
4.73M
        if (matrix_exp > matrix_bits)
240
0
            fraction_matrix__drop_bits(self, matrix_exp - matrix_bits);
241
4.73M
    }
242
4.73M
}
243
244
static inline int fraction_matrix__to_double(const fraction_matrix * self, double_matrix * pmat)
245
4.73M
{
246
4.73M
    if (self->denominator == 0)
247
0
        return_error(gs_error_rangecheck);
248
4.73M
    pmat->xx = (double)self->xx / self->denominator;
249
4.73M
    pmat->xy = (double)self->xy / self->denominator;
250
4.73M
    pmat->yx = (double)self->yx / self->denominator;
251
4.73M
    pmat->yy = (double)self->yy / self->denominator;
252
4.73M
    return 0;
253
4.73M
}
254
255
static int fraction_matrix__invert_to(const fraction_matrix * self, fraction_matrix * pmat)
256
2.36M
{   double_matrix m, M;
257
2.36M
    int code;
258
259
2.36M
    code = fraction_matrix__to_double(self, &M);
260
2.36M
    if (code < 0)
261
0
        return code;
262
2.36M
    code = double_matrix__invert_to(&M, &m);
263
2.36M
    if (code < 0)
264
0
        return code;
265
2.36M
    fraction_matrix__set(pmat, &m);
266
2.36M
    return 0;
267
2.36M
}
268
269
static inline int32_t fraction_matrix__transform_x(fraction_matrix *self, int24 x, int24 y, unsigned int s)
270
68.6M
{   return mul_shift_round(x, self->xx, s) + mul_shift_round(y, self->yx, s);
271
68.6M
}
272
static inline int32_t fraction_matrix__transform_y(fraction_matrix *self, int24 x, int24 y, unsigned int s)
273
68.6M
{   return mul_shift_round(x, self->xy, s) + mul_shift_round(y, self->yy, s);
274
68.6M
}
275
276
/*--------------------------- friends ------------------------------*/
277
278
static inline int ranger_step_f(int i, int beg, int end)
279
0
{   return (i == end ? beg : i + 1);
280
0
}
281
282
static inline int ranger_step_b(int i, int beg, int end)
283
0
{   return (i == beg ? end : i - 1);
284
0
}
285
286
static inline fixed o2d(const t1_hinter *h, t1_hinter_space_coord v)
287
137M
{
288
137M
    int s = h->g2o_fraction_bits - _fixed_shift;
289
290
137M
    if (s >= 1)
291
136M
        return ((v >> (h->g2o_fraction_bits - _fixed_shift - 1)) + 1) >> 1;
292
678k
    else if (s == 0)
293
0
        return v;
294
678k
    else
295
678k
        return v << -s;
296
137M
}
297
298
static inline fixed d2o(const t1_hinter *h, t1_hinter_space_coord v)
299
4.73M
{   int s = h->g2o_fraction_bits - _fixed_shift;
300
301
4.73M
    if (s >= 0)
302
4.73M
        return v << s;
303
0
    else
304
0
        return v >> -s;
305
4.73M
}
306
307
static inline void g2o(t1_hinter * h, t1_glyph_space_coord gx, t1_glyph_space_coord gy, t1_hinter_space_coord *ox, t1_hinter_space_coord *oy)
308
723
{   *ox = fraction_matrix__transform_x(&h->ctmf, gx, gy, g2o_bitshift);
309
723
    *oy = fraction_matrix__transform_y(&h->ctmf, gx, gy, g2o_bitshift);
310
723
}
311
312
static inline t1_hinter_space_coord g2o_dist(t1_glyph_space_coord gd, int19 coef)
313
0
{   return mul_shift(gd, coef, g2o_bitshift);
314
0
}
315
316
static inline void g2d(t1_hinter * h, t1_glyph_space_coord gx, t1_glyph_space_coord gy, fixed *dx, fixed *dy)
317
68.6M
{
318
68.6M
    *dx = fraction_matrix__transform_x(&h->ctmf, gx, gy, g2o_bitshift);
319
68.6M
    *dy = fraction_matrix__transform_y(&h->ctmf, gx, gy, g2o_bitshift);
320
68.6M
    *dx = o2d(h, *dx);
321
68.6M
    *dy = o2d(h, *dy);
322
68.6M
    *dx += h->orig_dx;
323
68.6M
    *dy += h->orig_dy;
324
68.6M
}
325
326
static inline void o2g(t1_hinter * h, t1_hinter_space_coord ox, t1_hinter_space_coord oy, t1_glyph_space_coord *gx, t1_glyph_space_coord *gy)
327
0
{   *gx = fraction_matrix__transform_x(&h->ctmi, ox, oy, split_bits);
328
0
    *gy = fraction_matrix__transform_y(&h->ctmi, ox, oy, split_bits);
329
0
    *gx = shift_rounded(*gx, h->g2o_fraction_bits + h->ctmi.bitshift - _fixed_shift - split_bits);
330
0
    *gy = shift_rounded(*gy, h->g2o_fraction_bits + h->ctmi.bitshift - _fixed_shift - split_bits);
331
0
}
332
333
static inline t1_glyph_space_coord o2g_dist(t1_hinter * h, t1_hinter_space_coord od, int19 coef)
334
9.47M
{   return shift_rounded(mul_shift(od, coef, split_bits), h->g2o_fraction_bits + h->ctmi.bitshift - _fixed_shift - split_bits);
335
9.47M
}
336
337
/* --------------------- t1_hint class members ---------------------*/
338
339
static void t1_hint__set_aligned_coord(t1_hint * self, t1_glyph_space_coord gc, t1_pole * pole, enum t1_align_type align, int quality)
340
0
{   t1_glyph_space_coord g = (self->type == hstem ? pole->gy : pole->gx);
341
342
0
    if (any_abs(self->g0 - g) < any_abs(self->g1 - g)) {
343
0
        if (self->aligned0 <= align && self->q0 > quality)
344
0
            self->ag0 = gc, self->aligned0 = align, self->q0 = quality;
345
0
    } else {
346
0
        if (self->aligned1 <= align && self->q1 > quality)
347
0
            self->ag1 = gc, self->aligned1 = align, self->q1 = quality;
348
0
    }
349
0
}
350
351
/* --------------------- t1_hinter class members - import --------------------*/
352
353
void t1_hinter__init(t1_hinter * self, gx_path *output_path)
354
29.5M
{
355
29.5M
    self->max_import_coord = (1 << max_coord_bits);
356
29.5M
    self->stem_snap_count[0] = self->stem_snap_count[1] = 0;
357
29.5M
    self->stem_snap_vote_count = 0;
358
29.5M
    self->zone_count = 0;
359
29.5M
    self->pole_count = 0;
360
29.5M
    self->hint_count = 0;
361
29.5M
    self->contour_count = 0;
362
29.5M
    self->subglyph_count = 0;
363
29.5M
    self->hint_range_count = 0;
364
29.5M
    self->flex_count = 0;
365
29.5M
    self->have_flex = false;
366
367
29.5M
    self->max_subglyph_count = count_of(self->subglyph0);
368
29.5M
    self->max_contour_count = count_of(self->contour0);
369
29.5M
    self->max_zone_count = count_of(self->zone0);
370
29.5M
    self->max_pole_count = count_of(self->pole0);
371
29.5M
    self->max_hint_count = count_of(self->hint0);
372
29.5M
    self->max_hint_range_count = count_of(self->hint_range0);
373
29.5M
    self->max_hint_applying_count = count_of(self->hint_applying0);
374
29.5M
    self->max_stem_snap_count[0] = count_of(self->stem_snap0[0]);
375
29.5M
    self->max_stem_snap_count[1] = count_of(self->stem_snap0[1]);
376
29.5M
    self->max_stem_snap_vote_count = count_of(self->stem_snap_vote0);
377
378
29.5M
    self->pole = self->pole0;
379
29.5M
    self->hint = self->hint0;
380
29.5M
    self->zone = self->zone0;
381
29.5M
    self->contour = self->contour0;
382
29.5M
    self->subglyph = self->subglyph0;
383
29.5M
    self->hint_range = self->hint_range0;
384
29.5M
    self->hint_applying = self->hint_applying0;
385
29.5M
    self->stem_snap[0] = self->stem_snap0[0];
386
29.5M
    self->stem_snap[1] = self->stem_snap0[1];
387
29.5M
    self->stem_snap_vote = self->stem_snap_vote0;
388
389
29.5M
    self->FontType = 1;
390
29.5M
    self->ForceBold = false;
391
29.5M
    self->base_font_scale = 0;
392
29.5M
    self->resolution = 0;
393
29.5M
    self->heigt_transform_coef = self->width_transform_coef = 0;
394
29.5M
    self->heigt_transform_coef_rat = self->width_transform_coef_rat = 0;
395
29.5M
    self->heigt_transform_coef_inv = self->width_transform_coef_inv = 0;
396
29.5M
    self->cx = self->cy = 0;
397
29.5M
    self->contour[0] = 0;
398
29.5M
    self->subglyph[0] = 0;
399
29.5M
    self->keep_stem_width = false;
400
29.5M
    self->charpath_flag = false;
401
29.5M
    self->grid_fit_x = self->grid_fit_y = true;
402
29.5M
    self->output_path = output_path;
403
29.5M
    self->memory = (output_path == 0 ? 0 : output_path->memory);
404
29.5M
    self->disable_hinting = (self->memory == NULL);
405
29.5M
    self->pass_through = self->disable_hinting;
406
29.5M
    self->autohinting = false;
407
29.5M
    self->fix_contour_sign = false;
408
29.5M
    self->path_opened = false;
409
29.5M
    self->orig_dx = 0;
410
29.5M
    self->orig_dy = 0;
411
29.5M
    self->g2o_fraction_bits = 0;
412
413
29.5M
    self->stem_snap[0][0] = self->stem_snap[1][0] = 100; /* default */
414
415
29.5M
    memset(&self->ctmf, 0x00, sizeof(self->ctmf));
416
29.5M
    memset(&self->ctmi, 0x00, sizeof(self->ctmi));
417
29.5M
}
418
419
static inline void t1_hinter__free_arrays(t1_hinter * self)
420
2.36M
{   if (self->pole != self->pole0)
421
0
        gs_free_object(self->memory, self->pole, s_pole_array);
422
2.36M
    if (self->hint != self->hint0)
423
0
        gs_free_object(self->memory, self->hint, s_hint_array);
424
2.36M
    if (self->zone != self->zone0)
425
0
        gs_free_object(self->memory, self->zone, s_zone_array);
426
2.36M
    if (self->contour != self->contour0)
427
0
        gs_free_object(self->memory, self->contour, s_contour_array);
428
2.36M
    if (self->subglyph != self->subglyph0)
429
0
        gs_free_object(self->memory, self->subglyph, s_subglyph_array);
430
2.36M
    if (self->hint_range != self->hint_range0)
431
0
        gs_free_object(self->memory, self->hint_range, s_hint_range_array);
432
2.36M
    if (self->hint_applying != self->hint_applying0)
433
0
        gs_free_object(self->memory, self->hint_applying, s_hint_applying_array);
434
2.36M
    if (self->stem_snap[0] != self->stem_snap0[0])
435
0
        gs_free_object(self->memory, self->stem_snap[0], s_stem_snap_array);
436
2.36M
    if (self->stem_snap[1] != self->stem_snap0[1])
437
0
        gs_free_object(self->memory, self->stem_snap[1], s_stem_snap_array);
438
2.36M
    if (self->stem_snap_vote != self->stem_snap_vote0)
439
0
        gs_free_object(self->memory, self->stem_snap_vote, s_stem_snap_vote_array);
440
2.36M
    self->pole = 0;
441
2.36M
    self->hint = 0;
442
2.36M
    self->zone = 0;
443
2.36M
    self->contour = 0;
444
2.36M
    self->hint_range = 0;
445
2.36M
    self->hint_applying = 0;
446
2.36M
    self->stem_snap[0] = self->stem_snap[1] = 0;
447
2.36M
    self->stem_snap_vote = 0;
448
2.36M
}
449
450
static inline void t1_hinter__init_outline(t1_hinter * self)
451
2.36M
{
452
2.36M
    self->contour_count = 0;
453
2.36M
    self->pole_count = 0;
454
2.36M
    self->contour[0] = 0;
455
2.36M
    self->hint_count = 0;
456
2.36M
    self->primary_hint_count = -1;
457
2.36M
    self->suppress_overshoots = false;
458
2.36M
    self->path_opened = false;
459
2.36M
}
460
461
static void t1_hinter__compute_rat_transform_coef(t1_hinter * self)
462
2.36M
{
463
2.36M
    double heigt_transform_coef = self->heigt_transform_coef == 0 ? 1.0 : self->heigt_transform_coef;
464
465
2.36M
    assert(self->heigt_transform_coef != 0.0);
466
467
    /* Round towards zero for a better view of mirrored characters : */
468
2.36M
    self->heigt_transform_coef_rat = (int19)(heigt_transform_coef * self->ctmf.denominator + 0.5);
469
2.36M
    self->width_transform_coef_rat = (int19)(heigt_transform_coef * self->ctmf.denominator + 0.5);
470
2.36M
    self->heigt_transform_coef_inv = (int19)(self->ctmi.denominator / heigt_transform_coef + 0.5);
471
2.36M
    self->width_transform_coef_inv = (int19)(self->ctmi.denominator / heigt_transform_coef + 0.5);
472
2.36M
}
473
474
static inline void t1_hinter__adjust_matrix_precision(t1_hinter * self, fixed xx, fixed yy)
475
73.3M
{
476
73.3M
    ufixed x = any_abs(xx), y = any_abs(yy);
477
73.3M
    ufixed c = (x > y ? x : y);
478
479
73.3M
    while (c >= self->max_import_coord) {
480
        /* Reduce the precision of ctmf to allow products to fit into 32 bits : */
481
0
        self->max_import_coord <<= 1;
482
0
        fraction_matrix__drop_bits(&self->ctmf, 1);
483
0
        fraction_matrix__drop_bits(&self->ctmi, 1);
484
0
        self->g2o_fraction_bits -= 1;
485
0
        self->g2o_fraction >>= 1;
486
0
        t1_hinter__compute_rat_transform_coef(self);
487
0
    }
488
73.3M
    if (self->ctmf.denominator == 0) {
489
        /* ctmf should be degenerate. */
490
36.0k
        self->ctmf.denominator = 1;
491
36.0k
    }
492
73.3M
}
493
494
static inline void t1_hinter__set_origin(t1_hinter * self, fixed dx, fixed dy)
495
2.36M
{
496
2.36M
    fixed align_x = rshift(fixed_1, (self->align_to_pixels ? (int)self->log2_pixels_x : self->log2_subpixels_x));
497
2.36M
    fixed align_y = rshift(fixed_1, (self->align_to_pixels ? (int)self->log2_pixels_y : self->log2_subpixels_y));
498
499
2.36M
    self->orig_dx = (dx + align_x / 2) & ~(align_x - 1);
500
2.36M
    self->orig_dy = (dy + align_y / 2) & ~(align_y - 1);
501
2.36M
    t1_hinter__adjust_matrix_precision(self, self->orig_dx, self->orig_dy);
502
2.36M
    self->orig_ox = d2o(self, self->orig_dx);
503
2.36M
    self->orig_oy = d2o(self, self->orig_dy);
504
#   if ADOBE_SHIFT_CHARPATH
505
        /*  Adobe CPSI rounds coordinates for 'charpath' :
506
            X to trunc(x+0.5)
507
            Y to trunc(y)+0.5
508
        */
509
        if (self->charpath_flag) {
510
            self->orig_dx += fixed_half;
511
            self->orig_dx &= ~(fixed_1 - 1);
512
            self->orig_dy &= ~(fixed_1 - 1);
513
            self->orig_dy += fixed_half;
514
        } else {
515
            self->orig_dy += fixed_1;
516
            /* Adobe CPSI does this, not sure why. */
517
            /* fixme : check bbox of cached bitmap. */
518
        }
519
#   endif
520
2.36M
}
521
522
int t1_hinter__set_mapping(t1_hinter * self, gs_matrix_fixed * ctm,
523
                    gs_matrix * FontMatrix, gs_matrix * baseFontMatrix,
524
                    int log2_pixels_x, int log2_pixels_y,
525
                    int log2_subpixels_x, int log2_subpixels_y,
526
                    fixed origin_x, fixed origin_y, bool align_to_pixels)
527
2.36M
{   float axx = fabs(ctm->xx), axy = fabs(ctm->xy);
528
2.36M
    float ayx = fabs(ctm->xx), ayy = fabs(ctm->xy);
529
2.36M
    float scale = max(axx + axy, ayx + ayy);
530
2.36M
    double_matrix CTM;
531
2.36M
    int code;
532
533
2.36M
    self->disable_hinting |= (scale < 1/1024. || scale > 4);
534
2.36M
    self->pass_through |= self->disable_hinting;
535
2.36M
    self->log2_pixels_x = log2_pixels_x;
536
2.36M
    self->log2_pixels_y = log2_pixels_y;
537
2.36M
    self->log2_subpixels_x = log2_subpixels_x;
538
2.36M
    self->log2_subpixels_y = log2_subpixels_y;
539
2.36M
    double_matrix__set(&CTM, ctm);
540
2.36M
    fraction_matrix__set(&self->ctmf, &CTM);
541
2.36M
    self->g2o_fraction_bits = self->ctmf.bitshift - g2o_bitshift + _fixed_shift;
542
2.36M
    if (self->g2o_fraction_bits > max_coord_bits) {
543
0
        fraction_matrix__drop_bits(&self->ctmf, self->g2o_fraction_bits - max_coord_bits);
544
0
        self->g2o_fraction_bits = max_coord_bits;
545
0
    }
546
2.36M
    if (self->ctmf.denominator != 0) {
547
2.36M
        code = fraction_matrix__invert_to(&self->ctmf, &self->ctmi); /* Note: ctmi is inversion of ctmf, not ctm. */
548
2.36M
        if (code == gs_error_rangecheck)
549
0
            self->ctmf.denominator = 0;
550
2.36M
        else if (code < 0)
551
0
            return code;
552
2.36M
    }
553
2.36M
    if (self->ctmf.denominator != 0) {
554
2.36M
        self->g2o_fraction = 1 << self->g2o_fraction_bits;
555
        /* Note : possibly we'll adjust the matrix precision dynamically
556
           with adjust_matrix_precision while importing the glyph. */
557
2.36M
        if (self->g2o_fraction == 0)
558
0
            return_error(gs_error_limitcheck);
559
2.36M
    }
560
2.36M
    if (self->ctmf.denominator == 0 || self->ctmi.denominator == 0) {
561
        /* ctmf should be degenerate. */
562
0
        self->disable_hinting = true;
563
0
        self->pass_through = true;
564
0
        self->ctmf.denominator = 1;
565
0
    }
566
2.36M
    self->transposed = (any_abs(self->ctmf.xy) * 10 > any_abs(self->ctmf.xx));
567
2.36M
    {   /* height_transform_coef is scaling factor for the
568
           distance between horizontal lines while transformation.
569
           width_transform_coef defines similarly.
570
        */
571
2.36M
        double_matrix m;
572
2.36M
        double vp, sp, div_x, div_y;
573
574
2.36M
        code = fraction_matrix__to_double(&self->ctmf, &m);
575
2.36M
        if (code < 0)
576
0
            return code;
577
2.36M
        vp = any_abs(m.xx * m.yy - m.yx * m.xy);
578
2.36M
        sp = any_abs(m.xx * m.yx + m.xy * m.yy);
579
2.36M
        div_x = hypot(m.xx, m.yx);
580
2.36M
        div_y = hypot(m.xy, m.yy);
581
2.36M
        if (vp != 0 && div_x != 0 && div_y != 0) {
582
2.36M
            if (!self->transposed) {
583
2.36M
                self->heigt_transform_coef = vp / div_x;
584
2.36M
                self->width_transform_coef = vp / div_y;
585
2.36M
            } else {
586
2
                self->heigt_transform_coef = vp / div_y;
587
2
                self->width_transform_coef = vp / div_x;
588
2
            }
589
2.36M
            t1_hinter__compute_rat_transform_coef(self);
590
2.36M
            self->keep_stem_width = (sp <= vp / 3); /* small skew */
591
2.36M
        }
592
2.36M
    }
593
0
    {   /* Compute font size and resolution : */
594
2.36M
        gs_point p0, p1, p2;
595
2.36M
        double d0, d1, d2;
596
597
2.36M
        gs_distance_transform(0, 1, baseFontMatrix, &p0);
598
2.36M
        gs_distance_transform(0, 1, FontMatrix, &p1);
599
2.36M
        gs_distance_transform(0, 1, (gs_matrix *)ctm, &p2);
600
2.36M
        d0 = hypot(p0.x, p0.y);
601
2.36M
        d1 = hypot(p1.x, p1.y);
602
2.36M
        d2 = hypot(p2.x, p2.y);
603
2.36M
        self->base_font_scale = d0;
604
2.36M
        self->font_size =  floor(d1 / d0 * 10000 + 0.5) / 10000;
605
2.36M
        self->resolution = floor(d2 / d1 * 10000000 + 0.5) / 10000000;
606
        /*
607
         * fixme: base_font_scale, font_size and resolution are computed wrongly
608
         * for any of the following cases :
609
         *
610
         * 1. CIDFontType0C with FontMatrix=[0.001 0 0 0.001 0 0] gives 1/1000 size.
611
         * A known example : CIDembedded.pdf . We could obtain the Type 9 FontMatrix
612
         * in type1_exec_init from penum->fstack.
613
         *
614
         * 2. See comment in pdf_font_orig_matrix.
615
         *
616
         * Currently we don't use these values with a regular build.
617
         * The ADOBE_OVERSHOOT_COMPATIBILIY build needs to fix them.
618
         */
619
2.36M
    }
620
2.36M
    if (1 || /* Doesn't work - see comment above. */
621
2.36M
            self->resolution * self->font_size >= 2) {
622
        /* Enable the grid fitting separately for axes : */
623
2.36M
        self->grid_fit_y = (any_abs(self->ctmf.xy) * 10 < any_abs(self->ctmf.xx) ||
624
2.36M
                            any_abs(self->ctmf.xx) * 10 < any_abs(self->ctmf.xy));
625
2.36M
        self->grid_fit_x = (any_abs(self->ctmf.yx) * 10 < any_abs(self->ctmf.yy) ||
626
2.36M
                            any_abs(self->ctmf.yy) * 10 < any_abs(self->ctmf.yx));
627
2.36M
    } else {
628
        /* Disable the grid fitting for very small fonts. */
629
0
        self->grid_fit_x = self->grid_fit_y = false;
630
0
    }
631
2.36M
    self->align_to_pixels = align_to_pixels;
632
2.36M
    t1_hinter__set_origin(self, origin_x, origin_y);
633
2.36M
    self->pixel_o_x = rshift(self->g2o_fraction, (self->align_to_pixels ? (int)self->log2_pixels_x : self->log2_subpixels_x));
634
2.36M
    self->pixel_o_y = rshift(self->g2o_fraction, (self->align_to_pixels ? (int)self->log2_pixels_y : self->log2_subpixels_y));
635
2.36M
    self->pixel_gh = any_abs(o2g_dist(self, self->pixel_o_x, self->heigt_transform_coef_inv));
636
2.36M
    self->pixel_gw = any_abs(o2g_dist(self, self->pixel_o_y, self->width_transform_coef_inv));
637
2.36M
    return 0;
638
2.36M
}
639
640
static void t1_hinter__make_zone(t1_hinter * self, t1_zone *zone, float * blues, enum t1_zone_type type, t1_glyph_space_coord blue_fuzz)
641
0
{   t1_glyph_space_coord d = 0;
642
643
0
    zone->type = type;
644
0
    zone->y           = float2fixed(blues[0] + d);
645
0
    zone->overshoot_y = float2fixed(blues[1] + d);
646
0
    zone->y_min = min(zone->y, zone->overshoot_y) - blue_fuzz;
647
0
    zone->y_max = max(zone->y, zone->overshoot_y) + blue_fuzz;
648
0
    if (type == botzone ? zone->overshoot_y > zone->y : zone->overshoot_y < zone->y) {
649
0
        int v = zone->overshoot_y; zone->overshoot_y = zone->y; zone->y = v;
650
0
    }
651
0
    t1_hinter__adjust_matrix_precision(self, zone->y_min, zone->y_max);
652
0
}
653
654
static bool t1_hinter__realloc_array(gs_memory_t *mem, void **a, void *a0, int *max_count, int elem_size, int enhancement, const char *cname)
655
0
{
656
0
    void *aa = gs_alloc_bytes(mem, (size_t)(*max_count + enhancement * 2) * elem_size, cname);
657
658
0
    if (aa == NULL)
659
0
        return true;
660
0
    memcpy(aa, *a, (size_t)*max_count * elem_size);
661
0
    if (*a != a0)
662
0
        gs_free_object(mem, *a, cname);
663
0
    *a = aa;
664
0
    *max_count += enhancement * 2;
665
0
    return false;
666
0
}
667
668
static int t1_hinter__set_alignment_zones(gs_memory_t *mem, t1_hinter * self, float * blues, int count, enum t1_zone_type type, bool family)
669
0
{   int count2 = count / 2, i, j;
670
671
0
    if (!family) {
672
        /* Store zones : */
673
0
        if (count2 + self->zone_count >= self->max_zone_count)
674
0
            if(t1_hinter__realloc_array(mem, (void **)&self->zone, self->zone0, &self->max_zone_count,
675
0
                                        sizeof(self->zone0) / count_of(self->zone0),
676
0
                                        max(T1_MAX_ALIGNMENT_ZONES, count), s_zone_array))
677
0
                return_error(gs_error_VMerror);
678
0
        for (i = 0; i < count2; i++)
679
0
            t1_hinter__make_zone(self, &self->zone[self->zone_count + i], blues + i + i, type, self->blue_fuzz);
680
0
        self->zone_count += count2;
681
0
    } else {
682
        /* Replace with family zones if allowed : */
683
0
        t1_zone zone;
684
0
        for (i = 0; i < count2; i++) {
685
0
            t1_hinter__make_zone(self, &zone, blues + i, type, self->blue_fuzz);
686
0
            for (j = 0; j<self->zone_count; j++) {
687
0
                t1_zone *zone1 = &self->zone[j];
688
0
                if (any_abs(zone.y -           zone1->y          ) * self->heigt_transform_coef <= 1 &&
689
0
                    any_abs(zone.overshoot_y - zone1->overshoot_y) * self->heigt_transform_coef <= 1)
690
0
                    *zone1 = zone;
691
0
            }
692
0
        }
693
0
    }
694
0
    return 0;
695
0
}
696
697
static int t1_hinter__set_stem_snap(gs_memory_t *mem, t1_hinter * self, float * value, int count, unsigned short hv)
698
0
{   int count0 = self->stem_snap_count[hv], i, j;
699
0
    t1_glyph_space_coord pixel_g = (!hv ? self->pixel_gh : self->pixel_gw);
700
701
0
    if (pixel_g == 0)
702
0
        return 0;
703
0
    if (count + count0 >= self->max_stem_snap_count[hv])
704
0
        if(t1_hinter__realloc_array(mem, (void **)&self->stem_snap[hv], self->stem_snap0[hv], &self->max_stem_snap_count[hv],
705
0
                                        sizeof(self->stem_snap0[0]) / count_of(self->stem_snap0[0]),
706
0
                                        max(T1_MAX_STEM_SNAPS, count), s_stem_snap_array))
707
0
            return_error(gs_error_VMerror);
708
0
    if (count + count0 >= self->max_stem_snap_vote_count)
709
0
        if(t1_hinter__realloc_array(mem, (void **)&self->stem_snap_vote, self->stem_snap_vote0, &self->max_stem_snap_vote_count,
710
0
                                        sizeof(self->stem_snap_vote0) / count_of(self->stem_snap_vote0),
711
0
                                        max(T1_MAX_STEM_SNAPS, count), s_stem_snap_vote_array))
712
0
            return_error(gs_error_VMerror);
713
0
    if (count == 1 || (count > 0 && float2fixed(value[count - 1] - value[0]) > pixel_g)) {
714
0
        for (i = 0; i < count; i++)
715
0
            self->stem_snap[hv][i] = float2fixed(value[i]);
716
0
        self->stem_snap_count[hv] = count;
717
0
        for (i = 0; i < count; i++) {
718
0
            for (j = i + 1; j < count; j++)
719
0
                if (self->stem_snap[hv][i] > self->stem_snap[hv][j]) {
720
0
                    t1_glyph_space_coord v = self->stem_snap[hv][i];
721
722
0
                    self->stem_snap[hv][i] = self->stem_snap[hv][j];
723
0
                    self->stem_snap[hv][j] = v;
724
0
                }
725
0
        }
726
0
        for (i = 1, j = 0; i < count; i++) {
727
0
            if (self->stem_snap[hv][j] != self->stem_snap[hv][i]) {
728
0
                j++;
729
0
                self->stem_snap[hv][j] = self->stem_snap[hv][i];
730
0
            }
731
0
        }
732
0
        self->stem_snap_count[hv] = j + 1;
733
0
    }
734
0
    return 0;
735
    /* We store unrounded stem snap elements, align stem width
736
       to an unrounded element, and then round the width to pixels.
737
       As an alternative we tried to round stem snap elements when storing them,
738
       and aligh stem width to the closest rounded value. The fist alternative gives
739
       results closer to Adobe, and therefore we believe that Adobe does the same.
740
       With the second alternative many glyphs render some wider,
741
       for example in aaon97_p7.pdf, adesso1.pdf at 300 dpi.
742
743
       Another arbitrary solution is ignoring stem snap when
744
       its variation is lesser than 1 pixel. We believe that a threshold
745
       must exist because Adobe says that stem snaps work for high resolutions only.
746
       However we took the 1 pixel value for the threshold from scratch,
747
       and experiments give good results.
748
749
       At last, we ignore Std*V when stem snap is used.
750
       Doing so because we don't know cases when Std*V
751
       isn't equal to any stem snap element.
752
       */
753
0
}
754
755
int t1_hinter__set_font_data(gs_memory_t *mem, t1_hinter * self, int FontType, gs_type1_data *pdata, bool no_grid_fitting, bool is_resource)
756
2.36M
{   int code;
757
758
2.36M
    t1_hinter__init_outline(self);
759
2.36M
    self->FontType = FontType;
760
2.36M
    self->BlueScale = pdata->BlueScale;
761
2.36M
    self->blue_shift = float2fixed(pdata->BlueShift);
762
2.36M
    self->blue_fuzz  = float2fixed(pdata->BlueFuzz);
763
2.36M
    self->suppress_overshoots = (self->BlueScale > self->heigt_transform_coef / (1 << self->log2_pixels_y) - 0.00020417);
764
2.36M
    self->overshoot_threshold = (self->heigt_transform_coef != 0 ? (t1_glyph_space_coord)(fixed_half * (1 << self->log2_pixels_y) / self->heigt_transform_coef) : 0);
765
2.36M
    self->ForceBold = pdata->ForceBold;
766
2.36M
    self->disable_hinting |= no_grid_fitting;
767
2.36M
    self->pass_through |= no_grid_fitting;
768
2.36M
    self->charpath_flag = no_grid_fitting;
769
2.36M
    self->fix_contour_sign = (!is_resource && self->memory != NULL);
770
2.36M
    if (self->fix_contour_sign)
771
0
        self->pass_through = false;
772
2.36M
    if (self->pass_through)
773
2.36M
        return 0;
774
0
    code = t1_hinter__set_alignment_zones(mem, self, pdata->OtherBlues.values, pdata->OtherBlues.count, botzone, false);
775
0
    if (code >= 0)
776
0
        code = t1_hinter__set_alignment_zones(mem, self, pdata->BlueValues.values, min(2, pdata->BlueValues.count), botzone, false);
777
0
    if (code >= 0)
778
0
        code = t1_hinter__set_alignment_zones(mem, self, pdata->BlueValues.values + 2, pdata->BlueValues.count - 2, topzone, false);
779
0
    if (code >= 0)
780
0
        code = t1_hinter__set_alignment_zones(mem, self, pdata->FamilyOtherBlues.values, pdata->FamilyOtherBlues.count, botzone, true);
781
0
    if (code >= 0)
782
0
        code = t1_hinter__set_alignment_zones(mem, self, pdata->FamilyBlues.values, min(2, pdata->FamilyBlues.count), botzone, true);
783
0
    if (code >= 0)
784
0
        code = t1_hinter__set_alignment_zones(mem, self, pdata->FamilyBlues.values + 2, pdata->FamilyBlues.count - 2, topzone, true);
785
0
    if (code >= 0)
786
0
        code = t1_hinter__set_stem_snap(mem, self, pdata->StdHW.values, pdata->StdHW.count, 0);
787
0
    if (code >= 0)
788
0
        code = t1_hinter__set_stem_snap(mem, self, pdata->StdVW.values, pdata->StdVW.count, 1);
789
0
    if (code >= 0)
790
0
        code = t1_hinter__set_stem_snap(mem, self, pdata->StemSnapH.values, pdata->StemSnapH.count, 0);
791
0
    if (code >= 0)
792
0
        code = t1_hinter__set_stem_snap(mem, self, pdata->StemSnapV.values, pdata->StemSnapV.count, 1);
793
0
    return code;
794
2.36M
}
795
796
int t1_hinter__set_font42_data(t1_hinter * self, int FontType, gs_type42_data *pdata, bool no_grid_fitting)
797
0
{
798
0
    t1_hinter__init_outline(self);
799
0
    self->FontType = FontType;
800
0
    self->BlueScale = 0.039625; /* A Type 1 spec default. */
801
0
    self->blue_shift = 7; /* A Type 1 spec default. */
802
0
    self->blue_fuzz  = 1; /* A Type 1 spec default. */
803
0
    self->suppress_overshoots = (self->BlueScale > self->heigt_transform_coef / (1 << self->log2_pixels_y) - 0.00020417);
804
0
    self->overshoot_threshold = (self->heigt_transform_coef != 0 ? (t1_glyph_space_coord)(fixed_half * (1 << self->log2_pixels_y) / self->heigt_transform_coef) : 0);
805
0
    self->ForceBold = false;
806
0
    self->pass_through |= no_grid_fitting;
807
0
    self->charpath_flag = no_grid_fitting;
808
0
    self->autohinting = true;
809
0
    if (self->pass_through)
810
0
        return 0;
811
    /* Currently we don't provice alignments zones or stem snap. */
812
0
    return 0;
813
0
}
814
815
static inline int t1_hinter__can_add_pole(t1_hinter * self, t1_pole **pole)
816
5.78k
{   if (self->pole_count >= self->max_pole_count)
817
0
        if(t1_hinter__realloc_array(self->memory, (void **)&self->pole, self->pole0, &self->max_pole_count,
818
0
                                    sizeof(self->pole0) / count_of(self->pole0), T1_MAX_POLES, s_pole_array))
819
0
            return_error(gs_error_VMerror);
820
5.78k
    *pole = &self->pole[self->pole_count];
821
5.78k
    return 0;
822
5.78k
}
823
824
static inline int t1_hinter__add_pole(t1_hinter * self, t1_glyph_space_coord xx, t1_glyph_space_coord yy, enum t1_pole_type type)
825
5.78k
{   t1_pole *pole;
826
5.78k
    int code = t1_hinter__can_add_pole(self, &pole);
827
828
5.78k
    if (code < 0)
829
0
        return code;
830
5.78k
    pole->gx = pole->ax = self->cx += xx;
831
5.78k
    pole->gy = pole->ay = self->cy += yy;
832
5.78k
    pole->ox = pole->oy = 0;
833
5.78k
    pole->type = type;
834
5.78k
    pole->contour_index = self->contour_count;
835
5.78k
    pole->aligned_x = pole->aligned_y = unaligned;
836
5.78k
    pole->boundary_length_x = pole->boundary_length_y = 0;
837
5.78k
    self->pole_count++;
838
5.78k
    return 0;
839
5.78k
}
840
841
int t1_hinter__sbw(t1_hinter * self, fixed sbx, fixed sby, fixed wx,  fixed wy)
842
29.5M
{   self->cx = self->orig_gx = self->subglyph_orig_gx = sbx;
843
29.5M
    self->cy = self->orig_gy = self->subglyph_orig_gy = sby;
844
29.5M
    self->width_gx = wx;
845
29.5M
    self->width_gy = wy;
846
29.5M
    return 0;
847
29.5M
}
848
849
int t1_hinter__sbw_seac(t1_hinter * self, fixed sbx, fixed sby)
850
0
{   t1_hinter__adjust_matrix_precision(self, sbx, sby);
851
0
    self->cx = self->subglyph_orig_gx = self->orig_gx + sbx;
852
0
    self->cy = self->subglyph_orig_gy = self->orig_gy + sby;
853
0
    return 0;
854
0
}
855
856
static bool t1_hinter__find_flex(t1_hinter * self, int k, int contour_beg, int contour_end,
857
                       t1_glyph_space_coord pixel_g, t1_glyph_space_coord threshold,
858
                       int i0, int i1, int N, int *j0, int *j1,
859
                       t1_glyph_space_coord *gm)
860
0
{
861
0
    int i, j, n = N - 5, m, l;
862
0
    t1_glyph_space_coord *p_gc = (!k ? &self->pole[0].gx : &self->pole[0].gy);
863
0
    t1_glyph_space_coord *p_gd = (!k ? &self->pole[0].gy : &self->pole[0].gx);
864
0
    int offset_gc = (char *)p_gc - (char *)&self->pole[0];
865
0
    int offset_gd = (char *)p_gd - (char *)&self->pole[0];
866
0
    t1_glyph_space_coord gc0, gc1, gd0, gd1, gcl, gdl, gcp = 0, gdp = 0, gcd, gcm = 0;
867
868
0
    for (i = i0; n; n--, i = i + 1) {
869
0
        if (i == contour_end)
870
0
            i = contour_beg;
871
0
        if (self->pole[i].type == offcurve)
872
0
            continue;
873
0
        gc0 = *member_prt(t1_glyph_space_coord, &self->pole[i], offset_gc);
874
0
        gd0 = *member_prt(t1_glyph_space_coord, &self->pole[i], offset_gd);
875
0
        for (j = i1, m = n; m; m--, j--) {
876
0
            if (j < contour_beg)
877
0
                j = contour_end - 1;
878
0
            if (self->pole[j].type == offcurve)
879
0
                continue;
880
0
            gc1 = *member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc);
881
0
            gd1 = *member_prt(t1_glyph_space_coord, &self->pole[j], offset_gd);
882
0
            if (any_abs(gd1 - gd0) < pixel_g * 4) /* Arbitrary check for 4 pixels length. */
883
0
                continue;
884
0
            if (gc0 == gc1) { /* Arbitrary check for strong equality. */
885
                /* Compute the curvity direction relative to the middle coord. */
886
0
                bool gt = false, lt = false;
887
0
                double area = 0, area0;
888
0
                int dir = 0, prev_dir = 0, dir_change = 0;
889
890
0
                *gm = gc0; /* Safety. */
891
                /* fixme: optimize: the computaion of gt, lt may be replaced with
892
                   a longer loop, so that dir_change accounts outer segments.
893
                   optimize : move the 1st iteratiot outside the loop. */
894
0
                for (l = i; ; gcp = gcl, gdp = gdl, prev_dir = dir, l++) {
895
0
                    if (l == contour_end)
896
0
                        l = contour_beg;
897
0
                    gcl = *member_prt(t1_glyph_space_coord, &self->pole[l], offset_gc);
898
0
                    gdl = *member_prt(t1_glyph_space_coord, &self->pole[l], offset_gd);
899
0
                    if (l != i) {
900
0
                        area += (double)(gcp - gc0) * (gdl - gdp) - (double)(gdp - gd0) * (gcl - gcp);
901
0
                        gcd = gcl - gc0;
902
0
                        gcd = any_abs(gcd);
903
0
                        if (gcm < gcd) {
904
0
                            *gm = gcl;
905
0
                            gcm = gcd;
906
0
                        }
907
0
                        dir = (gcp < gcl ? 1 : gcp > gcl ? -1 : prev_dir);
908
0
                        if (dir * prev_dir < 0)
909
0
                            dir_change++;
910
0
                    }
911
0
                    if (l == j)
912
0
                        break;
913
0
                    if (gcl < gc0)
914
0
                        lt = true;
915
0
                    if (gcl > gc0)
916
0
                        gt = true;
917
0
                }
918
0
                if (dir_change > 1)
919
0
                    continue;
920
0
                if (gcm > threshold)
921
0
                    continue;
922
0
                area = any_abs(area) / 2; /* Flex area. */
923
0
                area0 = (double)(gd1 - gd0) * gcm; /* Surrounding rectangle. */
924
0
                area0 = any_abs(area0);
925
0
                if (area > area0 * 0.75)
926
0
                    continue; /* looks as a rounded rectangle. */
927
0
                if (!lt || !gt) {
928
0
                    int ii = i - 1, jj = j + 1;
929
0
                    t1_glyph_space_coord gii, gjj;
930
931
0
                    if (ii < contour_beg)
932
0
                        ii = contour_end - 1;
933
0
                    if (jj == contour_end)
934
0
                        jj = contour_beg;
935
0
                    gii = *member_prt(t1_glyph_space_coord, &self->pole[ii], offset_gc);
936
0
                    gjj = *member_prt(t1_glyph_space_coord, &self->pole[jj], offset_gc);
937
0
                    if ((lt && gii <= gc0 && gjj <= gc0) ||
938
0
                        (gt && gii >= gc0 && gjj >= gc0)) {
939
0
                        *j0 = i;
940
0
                        *j1 = j;
941
0
                        return true;
942
0
                    }
943
0
                }
944
0
            }
945
0
        }
946
        /* Leave the loop here because t1_hinter__fix_missed_flex
947
           will try the interval starting with the next pole.
948
           We reserve the 'i' cycle for fonding a "best" flex
949
           within the interval. */
950
0
        break;
951
0
    }
952
0
    return false;
953
0
}
954
955
static void t1_hinter__compact_flex(t1_hinter * self, int contour_beg, int contour_end, int i0, int i1, int *pi)
956
0
{
957
0
    if (i0 > i1) {
958
0
        t1_hinter__compact_flex(self, contour_beg, contour_end, i0, contour_end, pi);
959
0
        t1_hinter__compact_flex(self, contour_beg, contour_end, contour_beg, i1, pi);
960
0
    } else if (i0 < i1) {
961
0
        int j;
962
0
        int s = i1 - i0 - 1;
963
964
0
        for (j = 0; j < self->hint_range_count; j++) {
965
0
            if (self->hint_range[j].beg_pole >= i1)
966
0
                self->hint_range[j].beg_pole -= s;
967
0
            else if (self->hint_range[j].beg_pole > i0)
968
0
                self->hint_range[j].beg_pole = i0;
969
0
            if (self->hint_range[j].end_pole >= i1)
970
0
                self->hint_range[j].end_pole -= s;
971
0
            else if (self->hint_range[j].end_pole > i0)
972
0
                self->hint_range[j].end_pole = i0;
973
0
        }
974
0
        memmove(&self->pole[i0 + 1], &self->pole[i1], sizeof(*self->pole) * (self->pole_count - i1));
975
0
        self->contour[self->contour_count] -= s;
976
0
        self->pole_count -= s;
977
0
        if (*pi >= i1)
978
0
            *pi -= s;
979
0
        else if (i0 <= *pi)
980
0
            *pi = i0;
981
0
    }
982
0
}
983
984
static void t1_hinter__adjust_stem_hints_by_missed_flex(t1_hinter * self, t1_glyph_space_coord g0,
985
                                                         t1_glyph_space_coord gm, int k)
986
0
{
987
    /* While fixing a missed flex, a part of outline is shifted.
988
       If there are stem hints pointing to that outline part, we need to move
989
       their coordinates as well. Here we do so in some hackish way :
990
       shift any stem that falls into the related coordinate gap.
991
       It would be nice to have a thinner choice,
992
       but it appears some complicated, because it could
993
       multiply stem hints when a hint points to several stems,
994
       and only some of them are shifted.
995
       For a simplification we assume that a well designed hint
996
       must shift all such stems when unbending a flex.
997
    */
998
0
    t1_glyph_space_coord gg = g0;
999
0
    int i;
1000
1001
0
    k = !k;
1002
0
    if (gm < g0) {
1003
0
        g0 ^= gm; gm ^= g0; g0 ^= gm;
1004
0
    }
1005
0
    for (i = 0; i < self->hint_count; i++)
1006
0
        if (k == (self->hint[i].type != hstem)) {
1007
0
            t1_hint *hint = &self->hint[i];
1008
1009
0
            if (g0 <= hint->g0 && hint->g0 <= gm)
1010
0
                hint->g0 = hint->ag0 = gg;
1011
0
            if (g0 <= hint->g1 && hint->g1 <= gm)
1012
0
                hint->g1 = hint->ag1 = gg;
1013
0
        }
1014
0
}
1015
1016
static void t1_hinter__fix_missed_flex(t1_hinter * self)
1017
0
{
1018
0
    int contour_beg, contour_end;
1019
0
    int i, j, k, pj, n, j0, j1;
1020
1021
0
    if (self->contour_count == 0)
1022
0
        return;
1023
0
    contour_beg = self->contour[self->contour_count -1];
1024
0
    contour_end = self->pole_count - 1; /* the last contour's 'closepath'. */
1025
0
    if (contour_beg + 8 >= contour_end)
1026
0
        return;
1027
0
    for (k = 0; k < 2; k++) {
1028
0
        t1_glyph_space_coord *p_gc = (!k ? &self->pole[0].gx : &self->pole[0].gy);
1029
0
        t1_glyph_space_coord *p_gd = (!k ? &self->pole[0].gy : &self->pole[0].gx);
1030
0
        int offset_gc = (char *)p_gc - (char *)&self->pole[0];
1031
0
        int offset_gd = (char *)p_gd - (char *)&self->pole[0];
1032
0
        t1_glyph_space_coord pixel_g = (!k ? self->pixel_gw : self->pixel_gh);
1033
0
        t1_glyph_space_coord threshold = pixel_g * 5 / 10;
1034
0
        t1_glyph_space_coord gc0, gc1, gc, gcj, gd = 0, ge, gm;
1035
0
        int dir = 0, prev_dir;
1036
0
        bool wrapped = false;
1037
1038
0
        gc = *member_prt(t1_glyph_space_coord, &self->pole[contour_beg], offset_gc);
1039
0
        gc0 = gc - threshold;
1040
0
        gc1 = gc + threshold;
1041
        /* Backward search for a plattue start. */
1042
0
        for (i = contour_end; i > contour_beg; i--) {
1043
0
            gcj = *member_prt(t1_glyph_space_coord, &self->pole[i], offset_gc);
1044
0
            if (self->pole[i].type == offcurve)
1045
0
                continue;
1046
0
            if (gcj < gc0 || gcj > gc1)
1047
0
                break;
1048
0
        }
1049
0
        if (i == contour_end) {
1050
0
            i = contour_beg;
1051
0
            wrapped = true;
1052
0
        } else
1053
0
            i++;
1054
        /* Forward search for all platues. */
1055
0
        for (;;i++) {
1056
0
            prev_dir = 0;
1057
0
            if (i == contour_end) {
1058
0
                if (wrapped)
1059
0
                    break;
1060
0
                wrapped = true;
1061
0
                i = contour_beg;
1062
0
            }
1063
0
            gc = *member_prt(t1_glyph_space_coord, &self->pole[i], offset_gc);
1064
0
            ge = *member_prt(t1_glyph_space_coord, &self->pole[i], offset_gd);
1065
0
            gc0 = gc - threshold;
1066
0
            gc1 = gc + threshold;
1067
0
            for (pj = i, j = i + 1, n = 0; ; pj = j, j++, n++) {
1068
0
                if (j == contour_end)
1069
0
                    j = contour_beg;
1070
0
                if (j == i)
1071
0
                    break; /* against bad glyphs. */
1072
0
                if (self->pole[j].type == offcurve)
1073
0
                    continue;
1074
0
                gcj = *member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc);
1075
0
                if (gcj < gc0 || gcj > gc1)
1076
0
                    break;
1077
0
                gd = *member_prt(t1_glyph_space_coord, &self->pole[i], offset_gd);
1078
0
                dir = (gd > ge ? 1 : -1);
1079
0
                if (dir * prev_dir < 0)
1080
0
                    break;
1081
0
                ge = gd;
1082
0
                prev_dir = dir;
1083
0
            }
1084
0
            if (n < 6)
1085
0
                continue;
1086
0
            if (t1_hinter__find_flex(self, k, contour_beg, contour_end, pixel_g, threshold, i, pj, n, &j0, &j1, &gm)) {
1087
0
                t1_hinter__compact_flex(self, contour_beg, contour_end, j0, j1, &i);
1088
0
                t1_hinter__adjust_stem_hints_by_missed_flex(self, gc, gm, k);
1089
0
                contour_end = self->pole_count - 1;
1090
0
            }
1091
0
        }
1092
0
    }
1093
0
}
1094
1095
int t1_hinter__rmoveto(t1_hinter * self, fixed xx, fixed yy)
1096
5.22M
{   int code;
1097
1098
5.22M
    t1_hinter__adjust_matrix_precision(self, xx, yy);
1099
5.22M
    if (self->flex_count == 0) {
1100
5.22M
        if (self->pass_through) {
1101
5.22M
            t1_glyph_space_coord gx = self->cx += xx;
1102
5.22M
            t1_glyph_space_coord gy = self->cy += yy;
1103
5.22M
            fixed fx, fy;
1104
1105
5.22M
            if (self->path_opened) {
1106
366k
                code = gx_path_close_subpath(self->output_path);
1107
366k
                if (code < 0)
1108
0
                    return code;
1109
366k
                self->path_opened = false;
1110
366k
            }
1111
5.22M
            g2d(self, gx, gy, &fx, &fy);
1112
5.22M
            code = gx_path_add_point(self->output_path, fx, fy);
1113
5.22M
            if (self->flex_count == 0) {
1114
5.22M
                self->bx = self->cx;
1115
5.22M
                self->by = self->cy;
1116
5.22M
            }
1117
5.22M
            return code;
1118
5.22M
        }
1119
0
        if (self->pole_count > 0 && self->pole[self->pole_count - 1].type == moveto)
1120
0
            self->pole_count--;
1121
0
        if (self->pole_count > 0 && self->pole[self->pole_count - 1].type != closepath) {
1122
0
            code = t1_hinter__closepath(self);
1123
0
            if (code < 0)
1124
0
                return code;
1125
0
        }
1126
0
        if (!self->have_flex)
1127
0
            t1_hinter__fix_missed_flex(self);
1128
0
    }
1129
5.78k
    code = t1_hinter__add_pole(self, xx, yy, moveto);
1130
5.78k
    if (self->flex_count == 0) {
1131
0
        self->bx = self->cx;
1132
0
        self->by = self->cy;
1133
0
    }
1134
5.78k
    return code;
1135
5.22M
}
1136
1137
static inline void t1_hinter__skip_degenerate_segnment(t1_hinter * self, int npoles)
1138
0
{   /* Degenerate segments amy appear due to import shift with bbox > 4096 */
1139
0
    int contour_beg = self->contour[self->contour_count], i;
1140
1141
0
    if (contour_beg >= self->pole_count - npoles)
1142
0
        return;
1143
0
    for (i = self->pole_count - npoles - 1; i < self->pole_count - 1; i++)
1144
0
        if (self->pole[i].ax != self->cx || self->pole[i].ay != self->cy)
1145
0
            return;
1146
0
    self->pole_count -= npoles;
1147
0
}
1148
1149
int t1_hinter__rlineto(t1_hinter * self, fixed xx, fixed yy)
1150
12.0M
{
1151
12.0M
    t1_hinter__adjust_matrix_precision(self, xx, yy);
1152
12.0M
    if (self->pass_through) {
1153
12.0M
        t1_glyph_space_coord gx = self->cx += xx;
1154
12.0M
        t1_glyph_space_coord gy = self->cy += yy;
1155
12.0M
        fixed fx, fy;
1156
1157
12.0M
        self->path_opened = true;
1158
12.0M
        g2d(self, gx, gy, &fx, &fy);
1159
12.0M
        return gx_path_add_line(self->output_path, fx, fy);
1160
12.0M
    } else {
1161
0
        int code = t1_hinter__add_pole(self, xx, yy, oncurve);
1162
1163
0
        if (code < 0)
1164
0
            return code;
1165
0
        t1_hinter__skip_degenerate_segnment(self, 1);
1166
0
        return 0;
1167
0
    }
1168
12.0M
}
1169
1170
int t1_hinter__rcurveto(t1_hinter * self, fixed xx0, fixed yy0, fixed xx1, fixed yy1, fixed xx2, fixed yy2)
1171
17.1M
{
1172
17.1M
    t1_hinter__adjust_matrix_precision(self, xx0, yy0);
1173
17.1M
    t1_hinter__adjust_matrix_precision(self, xx1, yy1);
1174
17.1M
    t1_hinter__adjust_matrix_precision(self, xx2, yy2);
1175
17.1M
    if (self->pass_through) {
1176
17.1M
        t1_glyph_space_coord gx0 = self->cx += xx0;
1177
17.1M
        t1_glyph_space_coord gy0 = self->cy += yy0;
1178
17.1M
        t1_glyph_space_coord gx1 = self->cx += xx1;
1179
17.1M
        t1_glyph_space_coord gy1 = self->cy += yy1;
1180
17.1M
        t1_glyph_space_coord gx2 = self->cx += xx2;
1181
17.1M
        t1_glyph_space_coord gy2 = self->cy += yy2;
1182
17.1M
        fixed fx0, fy0, fx1, fy1, fx2, fy2;
1183
1184
17.1M
        self->path_opened = true;
1185
17.1M
        g2d(self, gx0, gy0, &fx0, &fy0);
1186
17.1M
        g2d(self, gx1, gy1, &fx1, &fy1);
1187
17.1M
        g2d(self, gx2, gy2, &fx2, &fy2);
1188
17.1M
        return gx_path_add_curve(self->output_path, fx0, fy0, fx1, fy1, fx2, fy2);
1189
17.1M
    } else {
1190
0
        int code;
1191
1192
0
        code = t1_hinter__add_pole(self, xx0, yy0, offcurve);
1193
0
        if (code < 0)
1194
0
            return code;
1195
0
        code = t1_hinter__add_pole(self, xx1, yy1, offcurve);
1196
0
        if (code < 0)
1197
0
            return code;
1198
0
        code = t1_hinter__add_pole(self, xx2, yy2, oncurve);
1199
0
        if (code < 0)
1200
0
            return code;
1201
0
        t1_hinter__skip_degenerate_segnment(self, 3);
1202
0
        return 0;
1203
0
    }
1204
17.1M
}
1205
1206
void t1_hinter__setcurrentpoint(t1_hinter * self, fixed xx, fixed yy)
1207
735
{
1208
735
    t1_hinter__adjust_matrix_precision(self, xx, yy);
1209
735
    if (self->FontType != 2) {
1210
        /* We use this function to set a subglyph origin
1211
           for composite glyphs in Type 2 fonts.
1212
         */
1213
723
        self->cx = xx;
1214
723
        self->cy = yy;
1215
723
    } else if (self->cx != xx || self->cy != yy) {
1216
        /* Type 1 spec reads : "The setcurrentpoint command is used only
1217
           in conjunction with results from OtherSubrs procedures."
1218
           We guess that such cases don't cause a real coordinate change
1219
           (our testbase shows that). But we met a font
1220
           (see comparefiles/type1-ce1_setcurrentpoint.ps) which use
1221
           setcurrentpoint immediately before moveto, with no conjunction
1222
           with OtherSubrs. (The check above is debug purpose only.)
1223
         */
1224
12
        self->cx = xx;
1225
12
        self->cy = yy;
1226
12
    }
1227
735
}
1228
1229
int t1_hinter__closepath(t1_hinter * self)
1230
2.48M
{   if (self->pass_through) {
1231
2.48M
        self->path_opened = false;
1232
2.48M
        return gx_path_close_subpath(self->output_path);
1233
2.48M
    } else {
1234
0
        int contour_beg = self->contour[self->contour_count], code;
1235
1236
0
        if (contour_beg == self->pole_count)
1237
0
            return 0; /* maybe a single trailing moveto */
1238
0
        if (self->bx == self->cx && self->by == self->cy) {
1239
            /* Don't create degenerate segment */
1240
0
            self->pole[self->pole_count - 1].type = closepath;
1241
0
        } else {
1242
0
            t1_glyph_space_coord cx = self->cx, cy = self->cy;
1243
1244
0
            self->cx = self->bx;
1245
0
            self->cy = self->by;
1246
0
            code = t1_hinter__add_pole(self, 0, 0, closepath);
1247
0
            if (code < 0)
1248
0
                return code;
1249
0
            self->cx = cx;
1250
0
            self->cy = cy;
1251
0
        }
1252
0
        self->contour_count++;
1253
0
        if (self->contour_count >= self->max_contour_count)
1254
0
            if(t1_hinter__realloc_array(self->memory, (void **)&self->contour, self->contour0, &self->max_contour_count,
1255
0
                                        sizeof(self->contour0) / count_of(self->contour0), T1_MAX_CONTOURS, s_contour_array))
1256
0
                return_error(gs_error_VMerror);
1257
0
        self->contour[self->contour_count] = self->pole_count;
1258
0
        return 0;
1259
0
    }
1260
2.48M
}
1261
1262
int t1_hinter__end_subglyph(t1_hinter * self)
1263
2.36M
{
1264
2.36M
    if (self->pass_through)
1265
2.36M
        return 0;
1266
0
    self->subglyph_count++;
1267
0
    if (self->subglyph_count >= self->max_subglyph_count)
1268
0
        if(t1_hinter__realloc_array(self->memory, (void **)&self->subglyph, self->subglyph0, &self->max_subglyph_count,
1269
0
                                    sizeof(self->subglyph0) / count_of(self->subglyph0), T1_MAX_SUBGLYPHS, s_subglyph_array))
1270
0
            return_error(gs_error_VMerror);
1271
0
    self->subglyph[self->subglyph_count] = self->contour_count;
1272
0
    return 0;
1273
0
}
1274
1275
static inline int t1_hinter__can_add_hint(t1_hinter * self, t1_hint **hint)
1276
0
{   if (self->hint_count >= self->max_hint_count)
1277
0
        if(t1_hinter__realloc_array(self->memory, (void **)&self->hint, self->hint0, &self->max_hint_count,
1278
0
                                    sizeof(self->hint0) / count_of(self->hint0), T1_MAX_HINTS, s_hint_array))
1279
0
            return_error(gs_error_VMerror);
1280
0
    *hint = &self->hint[self->hint_count];
1281
0
    return 0;
1282
0
}
1283
1284
int t1_hinter__flex_beg(t1_hinter * self)
1285
723
{   if (self->flex_count != 0)
1286
0
        return_error(gs_error_invalidfont);
1287
723
    self->flex_count++;
1288
723
    self->have_flex = true;
1289
723
    if (self->pass_through)
1290
723
        return t1_hinter__rmoveto(self, 0, 0);
1291
0
    return 0;
1292
723
}
1293
1294
int t1_hinter__flex_point(t1_hinter * self)
1295
5.06k
{   if (self->flex_count == 0)
1296
0
        return_error(gs_error_invalidfont);
1297
5.06k
    self->flex_count++;
1298
5.06k
    return 0;
1299
5.06k
}
1300
1301
int t1_hinter__flex_end(t1_hinter * self, fixed flex_height)
1302
723
{   t1_pole *pole0, *pole1, *pole4;
1303
723
    t1_hinter_space_coord ox, oy;
1304
723
    const int32_t div_x = self->g2o_fraction << self->log2_pixels_x;
1305
723
    const int32_t div_y = self->g2o_fraction << self->log2_pixels_y;
1306
1307
723
    if (self->flex_count != 8)
1308
0
        return_error(gs_error_invalidfont);
1309
    /* We've got 8 poles accumulated in pole array. */
1310
723
    pole0 = &self->pole[self->pole_count - 8];
1311
723
    pole1 = &self->pole[self->pole_count - 7];
1312
723
    pole4 = &self->pole[self->pole_count - 4];
1313
723
    g2o(self, pole4->gx - pole1->gx, pole4->gy - pole1->gy, &ox, &oy);
1314
723
    if (any_abs(ox) > div_x * fixed2float(flex_height) / 100 ||
1315
723
        any_abs(oy) > div_y * fixed2float(flex_height) / 100) {
1316
        /* do with curves */
1317
723
        if (self->pass_through) {
1318
723
            fixed fx0, fy0, fx1, fy1, fx2, fy2;
1319
723
            int code;
1320
1321
723
            g2d(self, pole0[2].gx, pole0[2].gy, &fx0, &fy0);
1322
723
            g2d(self, pole0[3].gx, pole0[3].gy, &fx1, &fy1);
1323
723
            g2d(self, pole0[4].gx, pole0[4].gy, &fx2, &fy2);
1324
723
            code = gx_path_add_curve(self->output_path, fx0, fy0, fx1, fy1, fx2, fy2);
1325
723
            if (code < 0)
1326
0
                return code;
1327
723
            g2d(self, pole0[5].gx, pole0[5].gy, &fx0, &fy0);
1328
723
            g2d(self, pole0[6].gx, pole0[6].gy, &fx1, &fy1);
1329
723
            g2d(self, pole0[7].gx, pole0[7].gy, &fx2, &fy2);
1330
723
            self->flex_count = 0;
1331
723
            self->pole_count = 0;
1332
723
            return gx_path_add_curve(self->output_path, fx0, fy0, fx1, fy1, fx2, fy2);
1333
723
        } else {
1334
0
            memmove(pole1, pole1 + 1, (sizeof(self->pole0) / count_of(self->pole0)) * 7);
1335
0
            pole0[1].type = pole0[2].type = offcurve;
1336
0
            pole0[3].type = oncurve;
1337
0
            pole0[4].type = pole0[5].type = offcurve;
1338
0
            pole0[6].type = oncurve;
1339
0
            self->pole_count--;
1340
0
        }
1341
723
    } else {
1342
        /* do with line */
1343
0
        if (self->pass_through) {
1344
0
            fixed fx, fy;
1345
1346
0
            g2d(self, pole0[7].gx, pole0[7].gy, &fx, &fy);
1347
0
            self->flex_count = 0;
1348
0
            self->pole_count = 0;
1349
0
            return gx_path_add_line(self->output_path, fx, fy);
1350
0
        } else {
1351
0
            pole0[1] = pole0[7];
1352
0
            pole0[1].type = oncurve;
1353
0
            self->pole_count -= 6;
1354
0
        }
1355
0
    }
1356
0
    self->flex_count = 0;
1357
0
    return 0;
1358
723
}
1359
1360
static inline int t1_hinter__can_add_hint_range(t1_hinter * self, t1_hint_range **hint_range)
1361
0
{   if (self->hint_range_count >= self->max_hint_range_count)
1362
0
        if(t1_hinter__realloc_array(self->memory, (void **)&self->hint_range, self->hint_range0, &self->max_hint_range_count,
1363
0
                                    sizeof(self->hint_range0) / count_of(self->hint_range0), T1_MAX_HINTS, s_hint_range_array))
1364
0
            return_error(gs_error_VMerror);
1365
0
    *hint_range = &self->hint_range[self->hint_range_count];
1366
0
    return 0;
1367
0
}
1368
1369
static inline int t1_hinter__can_add_hint_applying(t1_hinter * self, t1_hint_applying **hint_applying)
1370
0
{   if (self->hint_applying_count >= self->max_hint_applying_count)
1371
0
        if(t1_hinter__realloc_array(self->memory, (void **)&self->hint_applying, self->hint_applying0, &self->max_hint_applying_count,
1372
0
                                    sizeof(self->hint_applying0) / count_of(self->hint_applying0), T1_MAX_HINTS, s_hint_applying_array))
1373
0
            return_error(gs_error_VMerror);
1374
0
    *hint_applying = &self->hint_applying[self->hint_applying_count];
1375
0
    return 0;
1376
0
}
1377
1378
int t1_hinter__hint_mask(t1_hinter * self, byte *mask)
1379
38.1k
{   int hint_count, i;
1380
1381
38.1k
    if (self->disable_hinting)
1382
38.1k
        return 0;
1383
0
    hint_count = self->hint_count;
1384
1385
0
    for(i = 0; i < hint_count; i++) {
1386
0
        bool activate = (mask != NULL && (mask[i >> 3] & (0x80 >> (i & 7))) != 0);
1387
0
        t1_hint *hint = &self->hint[i];
1388
1389
0
        if (activate) {
1390
0
            if (hint->range_index != -1 &&
1391
0
                (self->hint_range[hint->range_index].end_pole == -1 ||
1392
0
                 self->hint_range[hint->range_index].end_pole == self->pole_count)) {
1393
                 /* continie the range */
1394
0
                self->hint_range[hint->range_index].end_pole = -1;
1395
0
            } else {
1396
                /* add new range */
1397
0
                t1_hint_range *hint_range;
1398
0
                int code = t1_hinter__can_add_hint_range(self, &hint_range);
1399
1400
0
                if (code < 0)
1401
0
                   return code;
1402
0
                hint_range->beg_pole = self->pole_count;
1403
0
                hint_range->end_pole = -1;
1404
0
                hint_range->next = hint->range_index;
1405
0
                hint->range_index = self->hint_range_count;
1406
0
                self->hint_range_count++;
1407
0
            }
1408
0
        } else {
1409
0
            if (hint->range_index != -1 &&
1410
0
                self->hint_range[hint->range_index].end_pole == -1) {
1411
                /* deactivate */
1412
0
                self->hint_range[hint->range_index].end_pole = self->pole_count;
1413
0
            } else
1414
0
                DO_NOTHING;
1415
0
        }
1416
0
    }
1417
0
    return 0;
1418
0
}
1419
1420
int t1_hinter__drop_hints(t1_hinter * self)
1421
883k
{   if (self->disable_hinting)
1422
883k
        return 0;
1423
0
    if (self->primary_hint_count == -1)
1424
0
        self->primary_hint_count = self->hint_range_count;
1425
0
    return t1_hinter__hint_mask(self, NULL);
1426
883k
}
1427
1428
static inline int t1_hinter__stem(t1_hinter * self, enum t1_hint_type type, unsigned short stem3_index
1429
                                                  , fixed v0, fixed v1, int side_mask)
1430
0
{   t1_hint *hint;
1431
0
    t1_glyph_space_coord s = (type == hstem ? self->subglyph_orig_gy : self->subglyph_orig_gx);
1432
0
    t1_glyph_space_coord g0 = s + v0;
1433
0
    t1_glyph_space_coord g1 = s + v0 + v1;
1434
0
    t1_hint_range *range;
1435
0
int i, code;
1436
1437
0
    t1_hinter__adjust_matrix_precision(self, (side_mask & 1 ? g0 : g1), (side_mask & 2 ? g1 : g0));
1438
0
    for (i = 0; i < self->hint_count; i++)
1439
0
        if (self->hint[i].type == type &&
1440
0
                self->hint[i].g0 == g0 && self->hint[i].g1 == g1 &&
1441
0
                self->hint[i].side_mask == side_mask)
1442
0
            break;
1443
0
    if (i < self->hint_count)
1444
0
        hint = &self->hint[i];
1445
0
    else {
1446
0
        code = t1_hinter__can_add_hint(self, &hint);
1447
0
        if (code < 0)
1448
0
            return code;
1449
0
        hint->type = type;
1450
0
        hint->g0 = hint->ag0 = g0;
1451
0
        hint->g1 = hint->ag1 = g1;
1452
0
        hint->aligned0 = hint->aligned1 = unaligned;
1453
0
        hint->q0 = hint->q1 = max_int;
1454
0
        hint->b0 = hint->b1 = false;
1455
0
        hint->stem3_index = stem3_index;
1456
0
        hint->range_index = -1;
1457
0
        hint->side_mask = side_mask;
1458
0
        hint->stem_snap_index0 = hint->stem_snap_index1 = 0;
1459
0
        hint->boundary_length0 = hint->boundary_length1 = 0;
1460
0
    }
1461
0
    code = t1_hinter__can_add_hint_range(self, &range);
1462
0
    if (code < 0)
1463
0
        return code;
1464
0
    range->beg_pole = self->pole_count;
1465
0
    range->end_pole = -1;
1466
0
    range->next = hint->range_index;
1467
0
    hint->range_index = range - self->hint_range;
1468
0
    if (i >= self->hint_count)
1469
0
        self->hint_count++;
1470
0
    self->hint_range_count++;
1471
0
    return 0;
1472
0
}
1473
1474
int t1_hinter__dotsection(t1_hinter * self)
1475
138
{   if (self->pole_count == 0 || self->pole[self->pole_count - 1].type != moveto)
1476
138
        return 0; /* We store beginning dotsection hints only. */
1477
0
    if (self->disable_hinting)
1478
0
        return 0;
1479
0
    return t1_hinter__stem(self, dot, 0, 0, 0, 0);
1480
0
}
1481
1482
int t1_hinter__hstem(t1_hinter * self, fixed x0, fixed x1)
1483
5.43M
{   if (self->disable_hinting)
1484
5.43M
        return 0;
1485
0
    return t1_hinter__stem(self, hstem, 0, x0, x1, 3);
1486
5.43M
}
1487
1488
int t1_hinter__overall_hstem(t1_hinter * self, fixed x0, fixed x1, int side_mask)
1489
0
{   /* True Type autohinting only. */
1490
0
    if (self->disable_hinting)
1491
0
        return 0;
1492
0
    return t1_hinter__stem(self, hstem, 0, x0, x1, side_mask);
1493
0
}
1494
1495
int t1_hinter__vstem(t1_hinter * self, fixed y0, fixed y1)
1496
3.73M
{   if (self->disable_hinting)
1497
3.73M
        return 0;
1498
0
    return t1_hinter__stem(self, vstem, 0, y0, y1, 3);
1499
3.73M
}
1500
1501
int t1_hinter__hstem3(t1_hinter * self, fixed x0, fixed x1, fixed x2, fixed x3, fixed x4, fixed x5)
1502
328
{   int code;
1503
1504
328
    if (self->disable_hinting)
1505
328
        return 0;
1506
0
    code = t1_hinter__stem(self, hstem, 1, x0, x1, 3);
1507
0
    if (code < 0)
1508
0
        return code;
1509
0
    code = t1_hinter__stem(self, hstem, 2, x2, x3, 3);
1510
0
    if (code < 0)
1511
0
        return code;
1512
0
    return t1_hinter__stem(self, hstem, 3, x4, x5, 3);
1513
0
}
1514
1515
int t1_hinter__vstem3(t1_hinter * self, fixed y0, fixed y1, fixed y2, fixed y3, fixed y4, fixed y5)
1516
2.88k
{   int code;
1517
1518
2.88k
    if (self->disable_hinting)
1519
2.88k
        return 0;
1520
0
    code = t1_hinter__stem(self, vstem, 1, y0, y1, 3);
1521
0
    if (code < 0)
1522
0
        return code;
1523
0
    code = t1_hinter__stem(self, vstem, 2, y2, y3, 3);
1524
0
    if (code < 0)
1525
0
        return code;
1526
0
    return t1_hinter__stem(self, vstem, 3, y4, y5, 3);
1527
0
}
1528
1529
/* --------------------- t1_hinter class members - accessories --------------------*/
1530
1531
int t1_hinter__is_x_fitting(t1_hinter * self)
1532
0
{   return self->grid_fit_x;
1533
0
}
1534
1535
/* --------------------- t1_hinter class members - the hinting --------------------*/
1536
1537
static inline int t1_hinter__segment_beg(t1_hinter * self, int pole_index)
1538
0
{   int contour_index = self->pole[pole_index].contour_index;
1539
0
    int beg_contour_pole = self->contour[contour_index];
1540
0
    int end_contour_pole = self->contour[contour_index + 1] - 2;
1541
0
    int prev = ranger_step_b(pole_index, beg_contour_pole, end_contour_pole);
1542
1543
0
    while (self->pole[prev].type == offcurve)
1544
0
        prev = ranger_step_b(prev, beg_contour_pole, end_contour_pole);
1545
0
    return prev;
1546
0
}
1547
1548
static inline int t1_hinter__segment_end(t1_hinter * self, int pole_index)
1549
0
{   int contour_index = self->pole[pole_index].contour_index;
1550
0
    int beg_contour_pole = self->contour[contour_index];
1551
0
    int end_contour_pole = self->contour[contour_index + 1] - 2;
1552
0
    int next = ranger_step_f(pole_index, beg_contour_pole, end_contour_pole);
1553
1554
0
    while (self->pole[next].type == offcurve)
1555
0
        next = ranger_step_f(next, beg_contour_pole, end_contour_pole);
1556
0
    return next;
1557
0
}
1558
1559
static void t1_hinter__compute_y_span(t1_hinter * self)
1560
2.36M
{
1561
2.36M
    int n = self->pole_count - 1;
1562
2.36M
    int i;
1563
1564
2.36M
    if (n > 1) {
1565
        /* For non-space characters ignore the trailing moveto.
1566
           Rather it could give a baseline,
1567
           it is not guaranteedly good,
1568
           and doesn't allow a stable recognition
1569
           of the upper side of a dot, comma, etc.. */
1570
0
        n--;
1571
2.36M
    } else if (n < 0) {
1572
2.36M
        return; /* empty glyph */
1573
2.36M
    }
1574
0
    self->ymin = self->ymax = self->pole[0].gy;
1575
0
    for (i = 1; i < n; i++) {
1576
0
        if (self->ymin > self->pole[i].gy)
1577
0
            self->ymin = self->pole[i].gy;
1578
0
        if (self->ymax < self->pole[i].gy)
1579
0
            self->ymax = self->pole[i].gy;
1580
0
    }
1581
0
    self->ymid = (self->ymax + self->ymin) / 2;
1582
0
}
1583
1584
static void t1_hinter__simplify_representation(t1_hinter * self)
1585
2.36M
{   int i, j;
1586
2.36M
    int last_pole = self->pole_count - 1;
1587
2.36M
    int primary_hint_count = self->primary_hint_count;
1588
1589
2.36M
    if (last_pole > 1 && self->pole[last_pole -1].type == closepath)
1590
0
        last_pole -= 2; /* Skip the trailing moveto. */
1591
2.36M
    if (self->pole_count <= 1)
1592
2.36M
        return; /* An empty glyph (only a trailing moveto). */
1593
    /* Remove hints which are disabled with !grid_fit_x, !grid_fit_y.
1594
     * We can't do before import is completed due to hint mask commands.
1595
     */
1596
0
    if (!self->grid_fit_x || !self->grid_fit_y) {
1597
0
        for (i = j = 0; i < self->hint_count; i++)
1598
0
            if ((self->hint[i].type == vstem && !self->grid_fit_x) ||
1599
0
                (self->hint[i].type == hstem && !self->grid_fit_y)) {
1600
0
                if (i < primary_hint_count)
1601
0
                    self->primary_hint_count--;
1602
0
                continue; /* skip it. */
1603
0
            } else {
1604
0
                if (i != j)  /* for Valgrind */
1605
0
                    self->hint[j] = self->hint[i];
1606
0
                j++;
1607
0
            }
1608
0
        self->hint_count = j;
1609
0
    }
1610
0
    for (i = 0; i < self->hint_range_count; i++) {
1611
0
        t1_hint_range *hint_range = &self->hint_range[i];
1612
1613
0
        j = hint_range->beg_pole;
1614
0
        if (self->pole[j].type == closepath)
1615
0
            hint_range->beg_pole = ++j;
1616
0
        else {
1617
0
            if (self->pole[j].type == offcurve)
1618
0
                hint_range->beg_pole = --j;
1619
0
            if (self->pole[j].type == offcurve)
1620
0
                hint_range->beg_pole = --j;
1621
0
        }
1622
0
        j = hint_range->end_pole;
1623
0
        if (j == -1)
1624
0
            hint_range->end_pole = j = last_pole;
1625
0
        if (self->pole[j].type == offcurve)
1626
0
            hint_range->end_pole = ++j;
1627
0
        if (self->pole[j].type == offcurve)
1628
0
            hint_range->end_pole = ++j;
1629
0
    }
1630
    /*  moveto's were needed to decode path correctly.
1631
        We don't need them so far.
1632
        Replace 'moveto' with 'oncurve' :
1633
    */
1634
0
    for (i = 0; i <= self->contour_count; i++)
1635
0
        if (self->pole[self->contour[i]].type == moveto)
1636
0
            self->pole[self->contour[i]].type = oncurve;
1637
    /*  After the decoding, hint commands refer to the last pole before HR occures.
1638
        Move pointers to the beginning segment pole.
1639
    */
1640
0
    for (j = 0; j < self->hint_range_count; j++) {
1641
0
        int beg_pole = self->hint_range[j].beg_pole;
1642
0
        int contour_index = self->pole[beg_pole].contour_index;
1643
0
        int contour_beg_pole = self->contour[contour_index];
1644
1645
0
        if (beg_pole > contour_beg_pole && beg_pole < last_pole)
1646
0
            self->hint_range[j].beg_pole = t1_hinter__segment_beg(self, beg_pole);
1647
0
    }
1648
0
}
1649
1650
static inline bool t1_hinter__is_small_angle(t1_hinter * self, int pole_index0, int pole_index1,
1651
        long tan_x, long tan_y, int alpha, int alpha_div, int *quality)
1652
0
{   long gx = self->pole[pole_index1].gx - self->pole[pole_index0].gx;
1653
0
    long gy = self->pole[pole_index1].gy - self->pole[pole_index0].gy;
1654
0
    long vp = mul_shift(gx, tan_y, _fixed_shift) - mul_shift(gy, tan_x, _fixed_shift);
1655
0
    long sp = mul_shift(gx, tan_x, _fixed_shift) + mul_shift(gy, tan_y, _fixed_shift);
1656
0
    long vp1 = any_abs(vp), sp1 = any_abs(sp);
1657
1658
0
    if (gx == 0 && gy == 0) {
1659
0
        *quality = max_int;
1660
0
        return false;
1661
0
    }
1662
0
    if (vp1 >= sp1) {
1663
0
        *quality = max_int;
1664
0
        return false;
1665
0
    }
1666
0
    if (vp1 / alpha_div > sp1 / alpha) {
1667
0
        *quality = max_int;
1668
0
        return false;
1669
0
    }
1670
0
    *quality = vp1 * 100 / sp1; /* The best quality is 0. */
1671
0
    return true;
1672
0
}
1673
1674
static inline bool t1_hinter__next_contour_pole(t1_hinter * self, int pole_index)
1675
0
{   int contour_index = self->pole[pole_index].contour_index;
1676
0
    int beg_contour_pole = self->contour[contour_index];
1677
0
    int end_contour_pole = self->contour[contour_index + 1] - 2;
1678
1679
0
    return ranger_step_f(pole_index, beg_contour_pole, end_contour_pole);
1680
0
}
1681
1682
static inline bool t1_hinter__is_good_tangent(t1_hinter * self, int pole_index, long tan_x, long tan_y, int *quality)
1683
0
{   int contour_index = self->pole[pole_index].contour_index;
1684
0
    int beg_contour_pole = self->contour[contour_index];
1685
0
    int end_contour_pole = self->contour[contour_index + 1] - 2, prev, next;
1686
0
    int const alpha = 9, alpha_div = 10;
1687
0
    int quality0, quality1;
1688
0
    bool good0, good1;
1689
1690
0
    prev = ranger_step_b(pole_index, beg_contour_pole, end_contour_pole);
1691
0
    good0 = t1_hinter__is_small_angle(self, prev, pole_index, tan_x, tan_y, alpha, alpha_div, &quality0);
1692
0
    if (quality0 == 0) {
1693
0
        *quality = 0;
1694
0
        return true;
1695
0
    }
1696
0
    next = ranger_step_f(pole_index, beg_contour_pole, end_contour_pole);
1697
0
    good1 = t1_hinter__is_small_angle(self, next, pole_index, tan_x, tan_y, alpha, alpha_div, &quality1);
1698
0
    *quality = min(quality0, quality1);
1699
0
    return good0 || good1;
1700
0
}
1701
1702
static void t1_hinter__compute_type1_stem_ranges(t1_hinter * self)
1703
0
{   int j;
1704
0
    int end_range_pole = self->pole_count - 3;
1705
0
    int primary_hint_count = self->primary_hint_count;
1706
1707
0
    if (self->hint_count == 0)
1708
0
        return;
1709
0
    if (primary_hint_count == -1)
1710
0
        primary_hint_count = self->hint_range_count;
1711
    /* Process primary hints - ranges are entire glyph : */
1712
0
    for(j = 0; j < primary_hint_count; j++)      {
1713
0
        self->hint_range[j].beg_pole = 0;
1714
0
        self->hint_range[j].end_pole = end_range_pole;
1715
0
    }
1716
    /*  Note that ranges of primary hints may include a tail of the hint array
1717
        due to multiple contours. Primary hints have a lesser priority,
1718
        so apply them first, and possibly recover later.
1719
    */
1720
0
}
1721
1722
static void t1_hinter__compute_type2_stem_ranges(t1_hinter * self)
1723
0
{   int i;
1724
1725
0
    for (i = 0; i < self->hint_range_count; i++)
1726
0
        if (self->hint_range[i].end_pole == -1)
1727
0
            self->hint_range[i].end_pole = self->pole_count - 2;
1728
0
}
1729
1730
static bool t1_hinter__is_stem_boundary_near(t1_hinter * self, const t1_hint *hint,
1731
                t1_glyph_space_coord g, int boundary)
1732
0
{
1733
0
    t1_glyph_space_coord const fuzz = self->blue_fuzz; /* comparefiles/tpc2.ps */
1734
1735
0
    return any_abs(g - (boundary ? hint->g1 : hint->g0)) <= fuzz;
1736
0
}
1737
1738
static int t1_hinter__is_stem_hint_applicable(t1_hinter * self, t1_hint *hint, int pole_index, int *quality)
1739
0
{   /* We don't check hint->side_mask because the unused coord should be outside the design bbox. */
1740
0
    int k;
1741
1742
0
    if (hint->type == hstem
1743
0
            && ((k = 1, t1_hinter__is_stem_boundary_near(self, hint, self->pole[pole_index].gy, 0)) ||
1744
0
                (k = 2, t1_hinter__is_stem_boundary_near(self, hint, self->pole[pole_index].gy, 1)))
1745
0
            && t1_hinter__is_good_tangent(self, pole_index, 1, 0, quality))
1746
0
        return k;
1747
0
    if (hint->type == vstem
1748
0
            && ((k = 1, t1_hinter__is_stem_boundary_near(self, hint, self->pole[pole_index].gx, 0)) ||
1749
0
                (k = 2, t1_hinter__is_stem_boundary_near(self, hint, self->pole[pole_index].gx, 1)))
1750
0
            && t1_hinter__is_good_tangent(self, pole_index, 0, 1, quality))
1751
0
        return k;
1752
0
    return 0;
1753
0
}
1754
1755
static t1_zone * t1_hinter__find_zone(t1_hinter * self, t1_glyph_space_coord pole_y, bool curve, bool convex, bool concave)
1756
0
{   bool maybe_top = !curve || convex;
1757
0
    bool maybe_bot = !curve || concave;
1758
0
    int i;
1759
1760
0
    for (i = 0; i < self->zone_count; i++) {
1761
0
        t1_zone *zone = &self->zone[i];
1762
0
        if ((maybe_top && zone->type == topzone) || (maybe_bot && zone->type == botzone))
1763
0
            if (zone->y_min <= pole_y && pole_y <= zone->y_max)
1764
0
                return zone;
1765
0
    }
1766
0
    return NULL;
1767
    /*todo: optimize narrowing the search range */
1768
0
}
1769
1770
static void t1_hinter__align_to_grid__general(t1_hinter * self, int32_t unit,
1771
            t1_glyph_space_coord gx, t1_glyph_space_coord gy,
1772
            t1_hinter_space_coord *pdx, t1_hinter_space_coord *pdy,
1773
            bool align_to_pixels, bool absolute)
1774
0
{
1775
0
    long div_x = rshift(unit, (align_to_pixels ? (int)self->log2_pixels_x : self->log2_subpixels_x));
1776
0
    long div_y = rshift(unit, (align_to_pixels ? (int)self->log2_pixels_y : self->log2_subpixels_y));
1777
0
    t1_hinter_space_coord ox, oy, dx, dy;
1778
1779
0
    g2o(self, gx, gy, &ox, &oy);
1780
0
    if (absolute) {
1781
0
        ox += self->orig_ox;
1782
0
        oy += self->orig_oy;
1783
0
    }
1784
0
    dx = ox % div_x;
1785
0
    dy = oy % div_y; /* So far dx and dy are 19 bits */
1786
0
    if (dx > div_x / 2 )
1787
0
        dx = - div_x + dx;
1788
0
    else if (dx < - div_x / 2)
1789
0
        dx = div_x + dx;
1790
0
    if (dy > div_y / 2)
1791
0
        dy = - div_y + dy;
1792
0
    else if (dy < - div_y / 2)
1793
0
        dy = div_y + dy;
1794
0
    *pdx = dx;
1795
0
    *pdy = dy;
1796
0
}
1797
1798
static void t1_hinter__align_to_grid__final(t1_hinter * self,
1799
            t1_glyph_space_coord *x, t1_glyph_space_coord *y,
1800
            t1_hinter_space_coord dx, t1_hinter_space_coord dy)
1801
0
{
1802
0
    t1_glyph_space_coord gxd, gyd;
1803
1804
0
    o2g(self, dx, dy, &gxd, &gyd);
1805
0
    if (self->grid_fit_x) {
1806
0
        *x -= gxd;
1807
0
        *x = (*x + 7) & ~15; /* Round to suppress small noise : */
1808
0
    }
1809
0
    if (self->grid_fit_y) {
1810
0
        *y -= gyd;
1811
0
        *y = (*y + 7) & ~15; /* Round to suppress small noise : */
1812
0
    }
1813
0
}
1814
1815
static void t1_hinter__hint_stem_snap_range(t1_hinter * self,
1816
                                        t1_glyph_space_coord w0, t1_glyph_space_coord w1, bool horiz,
1817
                                        short *index0, short *index1)
1818
0
{   int k = (horiz ? 0 : 1), i;
1819
0
    bool index0_set = false;
1820
1821
0
    *index0 = 0;
1822
0
    *index1 = -1;
1823
0
    for (i = 0; i < self->stem_snap_count[k]; i++) {
1824
0
        if (w0 > self->stem_snap[k][i])
1825
0
            continue;
1826
0
        if (!index0_set) {
1827
0
            index0_set = true;
1828
0
            *index0 = i;
1829
0
        }
1830
0
        if (w1 < self->stem_snap[k][i])
1831
0
            break;
1832
0
        *index1 = i;
1833
0
    }
1834
0
}
1835
1836
static void t1_hinter__align_to_grid(t1_hinter * self, int32_t unit,
1837
            t1_glyph_space_coord *x, t1_glyph_space_coord *y, bool align_to_pixels)
1838
0
{   if (unit > 0) {
1839
0
        t1_hinter_space_coord dx, dy;
1840
1841
0
        t1_hinter__align_to_grid__general(self, unit, *x, *y, &dx, &dy, align_to_pixels, align_to_pixels);
1842
0
        t1_hinter__align_to_grid__final(self, x, y, dx, dy);
1843
0
    }
1844
0
}
1845
1846
static void t1_hinter_compute_stem_snap_range_hv(t1_hinter * self, int hv)
1847
0
{
1848
0
    const enum t1_hint_type T[] = {hstem, vstem};
1849
0
    int i, j;
1850
0
    enum t1_hint_type t = T[hv];
1851
0
    bool horiz = (t == hstem);
1852
0
    t1_glyph_space_coord pixel_g = (horiz ? self->pixel_gh : self->pixel_gw);
1853
0
    int stem_snap_count = self->stem_snap_count[hv];
1854
1855
0
    memset(self->stem_snap_vote, 0, stem_snap_count * sizeof(self->stem_snap_vote[0]));
1856
0
    for (i = 0; i < self->hint_count; i++) {
1857
0
        if (self->hint[i].type == t) {
1858
0
            t1_glyph_space_coord gw = any_abs(self->hint[i].g1 - self->hint[i].g0);
1859
1860
0
            t1_hinter__hint_stem_snap_range(self, gw - pixel_g + 1, gw + pixel_g - 1, horiz,
1861
0
                &self->hint[i].stem_snap_index0, &self->hint[i].stem_snap_index1);
1862
0
            for (j = self->hint[i].stem_snap_index0; j <= self->hint[i].stem_snap_index1; j++)
1863
0
                self->stem_snap_vote[j]++;
1864
0
        }
1865
0
    }
1866
0
    for (i = 0; i < self->hint_count; i++) {
1867
0
        if (self->hint[i].type == t) {
1868
0
            int m = 0, mj = -1, d, md = pixel_g * 2;
1869
0
            t1_glyph_space_coord gw = any_abs(self->hint[i].g1 - self->hint[i].g0);
1870
1871
0
            for (j = self->hint[i].stem_snap_index0; j <= self->hint[i].stem_snap_index1; j++) {
1872
0
                if (m < self->stem_snap_vote[j]) {
1873
0
                    m = self->stem_snap_vote[j];
1874
0
                    mj = j;
1875
0
                    md = any_abs(gw - pixel_g / 5 - self->stem_snap[hv][mj]);
1876
0
                } else {
1877
0
                    d = any_abs(gw - pixel_g / 5 - self->stem_snap[hv][j]);
1878
0
                    if (md > d) {
1879
0
                        md = d;
1880
0
                        mj = j;
1881
0
                    }
1882
0
                }
1883
0
            }
1884
0
            self->hint[i].stem_snap_index0 = mj;
1885
0
        }
1886
0
    }
1887
0
}
1888
1889
static void t1_hinter_compute_stem_snap_range(t1_hinter * self)
1890
0
{
1891
0
    if (self->stem_snap_count[0] > 1)
1892
0
        t1_hinter_compute_stem_snap_range_hv(self, 0);
1893
0
    if (self->stem_snap_count[1] > 1)
1894
0
        t1_hinter_compute_stem_snap_range_hv(self, 1);
1895
0
}
1896
1897
static void t1_hinter__align_stem_width(t1_hinter * self, t1_glyph_space_coord *pgw, const t1_hint *hint)
1898
0
{
1899
0
    bool horiz = (hint->type == hstem);
1900
0
    t1_glyph_space_coord gw = *pgw;
1901
0
    t1_glyph_space_coord pixel_g = (horiz ? self->pixel_gh : self->pixel_gw);
1902
0
    t1_glyph_space_coord gwe;
1903
1904
0
    if (!self->keep_stem_width || pixel_g == 0)
1905
0
        return;
1906
0
    if (hint->stem_snap_index0 >= 0 && self->stem_snap_count[horiz ? 0 : 1] > 0) {
1907
0
        t1_glyph_space_coord w0 = self->stem_snap[horiz ? 0 : 1][hint->stem_snap_index0];
1908
0
        t1_glyph_space_coord thr0 = pixel_g * 70 / 100, thr1 = pixel_g * 35 / 100;
1909
1910
0
        if (gw - thr0 <= w0 && w0 <= gw + thr1)
1911
0
            gw = w0;
1912
0
    }
1913
0
    gwe = gw % pixel_g;
1914
0
    if (gw >= pixel_g && gwe < pixel_g / 2)
1915
0
        gw -= gwe;
1916
0
    else
1917
0
        gw += pixel_g - gwe;
1918
0
    *pgw = gw;
1919
0
}
1920
1921
static void t1_hinter__align_stem_to_grid(t1_hinter * self, int32_t unit,
1922
            t1_glyph_space_coord *x0, t1_glyph_space_coord *y0,
1923
            t1_glyph_space_coord  x1, t1_glyph_space_coord  y1,
1924
            bool align_to_pixels, const t1_hint *hint)
1925
0
{   /* Implemented for Bug 687578 "T1 hinter disturbs stem width". */
1926
    /* fixme: optimize. */
1927
0
    if (unit > 0) {
1928
0
        bool horiz = (hint->type == hstem);
1929
0
        t1_glyph_space_coord gw = (horiz ? y1 - *y0 : x1 - *x0);
1930
0
        t1_glyph_space_coord GW = any_abs(gw), GW0 = GW;
1931
0
        bool positive = (gw >= 0);
1932
0
        int19 cf = (horiz ? self->heigt_transform_coef_rat : self->width_transform_coef_rat);
1933
0
        t1_hinter_space_coord dx0, dy0, dx1, dy1, dgw;
1934
1935
0
        t1_hinter__align_to_grid__general(self, unit, *x0, *y0, &dx0, &dy0, align_to_pixels, align_to_pixels);
1936
0
        t1_hinter__align_to_grid__general(self, unit,  x1,  y1, &dx1, &dy1, align_to_pixels, align_to_pixels);
1937
0
        t1_hinter__align_stem_width(self, &GW, hint);
1938
0
        dgw = g2o_dist(GW - GW0, cf);
1939
0
        if ((horiz ? (!self->transposed ? self->ctmf.yy : self->ctmf.xy)
1940
0
                   : (!self->transposed ? self->ctmf.xx : self->ctmf.yx)) < 0)
1941
0
            dgw = - dgw;
1942
0
        if (horiz) {
1943
0
            t1_hinter_space_coord ddy1 = (positive ? dy0 - dgw : dy0 + dgw);
1944
0
            t1_hinter_space_coord ddy0 = (positive ? dy1 + dgw : dy1 - dgw);
1945
1946
0
            if (any_abs(dy0 + ddy1) > any_abs(dy1 + ddy0))
1947
0
                dy0 = ddy0;
1948
0
        } else {
1949
0
            t1_hinter_space_coord ddx1 = (positive ? dx0 - dgw : dx0 + dgw);
1950
0
            t1_hinter_space_coord ddx0 = (positive ? dx1 + dgw : dx1 - dgw);
1951
1952
0
            if (any_abs(dx0 + ddx1) > any_abs(dx1 + ddx0))
1953
0
                dx0 = ddx0;
1954
0
        }
1955
0
        t1_hinter__align_to_grid__final(self, x0, y0, dx0, dy0);
1956
0
    }
1957
0
}
1958
1959
#if ADOBE_OVERSHOOT_COMPATIBILIY
1960
static inline t1_hinter_space_coord g2o_dist_blue(t1_hinter * h, t1_glyph_space_coord gw)
1961
{   double W = fixed2float(gw);
1962
    double w = W * (h->resolution * h->font_size * h->base_font_scale - h->BlueScale) + 1;
1963
1964
    return (t1_hinter_space_coord)(w * h->g2o_fraction);
1965
    /* todo : exclude floating point */
1966
}
1967
1968
static void t1_hinter__add_overshoot(t1_hinter * self, t1_zone * zone, t1_glyph_space_coord * x, t1_glyph_space_coord * y)
1969
{   t1_glyph_space_coord gy = *y;
1970
    /* t1_glyph_space_coord gw = any_abs(zone->overshoot_y - zone->y); */
1971
    t1_glyph_space_coord gw = any_abs(gy - zone->y);
1972
    t1_hinter_space_coord ow = g2o_dist_blue(self, gw);
1973
    t1_hinter_space_coord ow1 = ow / self->g2o_fraction * self->g2o_fraction;
1974
    t1_glyph_space_coord gw1 = o2g_dist(self, ow1, self->heigt_transform_coef_inv);
1975
1976
    *y = zone->y + (zone->type == topzone ? gw1 : -gw1);
1977
}
1978
#endif
1979
1980
static enum t1_align_type t1_hinter__compute_aligned_coord(t1_hinter * self,
1981
            t1_glyph_space_coord * gc, int segment_index, fixed t, const t1_hint *hint,
1982
            enum t1_align_type align0)
1983
0
{   /* Returns true, if alignment zone is applied. */
1984
    /* t is 0 or 0.5, and it is always 0 for curves. */
1985
0
    bool horiz = (hint->type == hstem);
1986
0
    enum t1_align_type align = align0;
1987
0
    t1_glyph_space_coord gx = self->pole[segment_index].gx, gx0;
1988
0
    t1_glyph_space_coord gy = self->pole[segment_index].gy, gy0;
1989
0
    t1_glyph_space_coord gc0 = (horiz ? gy : gx);
1990
0
    bool align_by_stem =
1991
0
                align0 == unaligned   /* Force aligning outer boundaries
1992
                                            from the TT spot analyzer. */
1993
0
                && hint->b0 && hint->b1; /* It's a real stem. Contrary
1994
                                            033-52-5873.pdf uses single hint boundaries
1995
                                            to mark top|bottom sides of a glyph,
1996
                                            but their opposite boundaries are dummy coordinates,
1997
                                            which don't correspond to poles. */
1998
1999
    /*  Compute point of specified segment by parameter t : */
2000
0
    if (t) {
2001
0
        int next = t1_hinter__segment_end(self, segment_index);
2002
0
        t1_glyph_space_coord gx1 = self->pole[next].gx;
2003
0
        t1_glyph_space_coord gy1 = self->pole[next].gy;
2004
2005
0
        gx = (gx + gx1) / 2;
2006
0
        gy = (gy + gy1) / 2;
2007
0
    }
2008
0
    gx0 = gx;
2009
0
    gy0 = gy;
2010
0
    if (horiz) {
2011
0
        t1_pole * pole = &self->pole[segment_index];
2012
0
        int contour_index = pole->contour_index;
2013
0
        int beg_contour_pole = self->contour[contour_index];
2014
0
        int end_contour_pole = self->contour[contour_index + 1] - 2;
2015
0
        int prev1 = ranger_step_b(segment_index, beg_contour_pole, end_contour_pole);
2016
0
        int prev2 = ranger_step_b(prev1        , beg_contour_pole, end_contour_pole);
2017
0
        int next1 = ranger_step_f(segment_index, beg_contour_pole, end_contour_pole);
2018
0
        int next2 = ranger_step_f(next1        , beg_contour_pole, end_contour_pole);
2019
0
        bool forwd_horiz = (any_abs(self->pole[next1].gy - pole->gy) <=
2020
0
                max(self->blue_fuzz, any_abs(self->pole[next1].gx - pole->gx) / 10));
2021
0
        bool bckwd_horiz = (any_abs(self->pole[prev1].gy - pole->gy) <=
2022
0
                max(self->blue_fuzz, any_abs(self->pole[prev1].gx - pole->gx) / 10));
2023
0
        bool maximum = (self->pole[next1].gy - pole->gy < 0 &&
2024
0
                        self->pole[prev1].gy - pole->gy < 0);
2025
0
        bool minimum = (self->pole[next1].gy - pole->gy > 0 &&
2026
0
                        self->pole[prev1].gy - pole->gy > 0);
2027
2028
0
        if (forwd_horiz || bckwd_horiz || maximum || minimum) {
2029
0
            bool forwd_curve = (self->pole[next1].type == offcurve);
2030
0
            bool bckwd_curve = (self->pole[prev1].type == offcurve);
2031
0
            bool curve = (bckwd_curve && forwd_curve);
2032
0
            bool convex  = (curve && self->pole[prev2].gy <= pole->gy &&
2033
0
                                     self->pole[next2].gy <= pole->gy);
2034
0
            bool concave = (curve && self->pole[prev2].gy >= pole->gy &&
2035
0
                                     self->pole[next2].gy >= pole->gy);
2036
0
            t1_zone *zone = t1_hinter__find_zone(self, pole->gy, curve || maximum || minimum,
2037
0
                                                convex || maximum, concave || minimum);
2038
2039
0
            if (zone != NULL &&
2040
0
                   (forwd_horiz || bckwd_horiz ||
2041
0
                    (maximum && zone->type == topzone) ||
2042
0
                    (minimum && zone->type == botzone))) {
2043
0
                if (self->suppress_overshoots)
2044
#                   if ADOBE_OVERSHOOT_COMPATIBILIY
2045
                        gy = (zone->type == topzone ? zone->overshoot_y : zone->y);
2046
#                   else
2047
0
                        gy = zone->y;
2048
0
#                   endif
2049
0
                else {
2050
0
                    t1_glyph_space_coord s = zone->y - pole->gy;
2051
0
                    if (zone->type == topzone)
2052
0
                        s = -s;
2053
0
                    if (!curve && s < self->overshoot_threshold)
2054
0
                        gy = zone->y;
2055
0
                    else if (s > self->overshoot_threshold) {
2056
0
                        t1_glyph_space_coord ss = self->overshoot_threshold * 2;
2057
2058
0
                        if (s < ss) /* Enforce overshoot : */
2059
0
                            gy = (zone->type == topzone ? zone->y + ss : zone->y - ss);
2060
0
                        else {
2061
#                           if ADOBE_OVERSHOOT_COMPATIBILIY
2062
                                t1_hinter__add_overshoot(self, zone, &gx, &gy);
2063
#                           endif
2064
0
                        }
2065
0
                    }
2066
0
                }
2067
0
                align = (zone->type == topzone ? topzn : botzn);
2068
0
                align_by_stem = false;
2069
0
            }
2070
0
        }
2071
0
    }
2072
0
    if (align_by_stem) {
2073
0
        t1_glyph_space_coord gx1, gy1;
2074
2075
0
        if (horiz) {
2076
0
            bool b0 = t1_hinter__is_stem_boundary_near(self, hint, gy, 0);
2077
0
            bool b1 = t1_hinter__is_stem_boundary_near(self, hint, gy, 1);
2078
2079
0
            gx1 = gx;
2080
0
            if (b0 && !b1)
2081
0
                gy1 = hint->g1, align_by_stem = true;
2082
0
            else if (!b0 && b1)
2083
0
                gy1 = hint->g0, align_by_stem = true;
2084
0
            else
2085
0
                gy1 = 0; /* Quiet the compiler. */
2086
0
        } else {
2087
0
            bool b0 = t1_hinter__is_stem_boundary_near(self, hint, gx, 0);
2088
0
            bool b1 = t1_hinter__is_stem_boundary_near(self, hint, gx, 1);
2089
2090
0
            gy1 = gy;
2091
0
            if (b0 && !b1)
2092
0
                gx1 = hint->g1, align_by_stem = true;
2093
0
            else if (!b0 && b1)
2094
0
                gx1 = hint->g0, align_by_stem = true;
2095
0
            else
2096
0
                gx1 = 0; /* Quiet the compiler. */
2097
0
        }
2098
0
        if (align_by_stem)
2099
0
            t1_hinter__align_stem_to_grid(self, self->g2o_fraction, &gx, &gy, gx1, gy1,
2100
0
                    CONTRAST_STEMS || self->align_to_pixels, hint);
2101
0
    }
2102
0
    if (!align_by_stem)
2103
0
        t1_hinter__align_to_grid(self, self->g2o_fraction, &gx, &gy,
2104
0
                            CONTRAST_STEMS || self->align_to_pixels);
2105
0
    *gc = gc0 + (horiz ? gy - gy0 : gx - gx0);
2106
0
    return (align == unaligned ? aligned : align);
2107
0
}
2108
2109
0
#define PRESERVE_STEM_SLANT 1 /*   0 - always diminish
2110
                                   1 - preserve iff slanted in design space
2111
                                   2 - always preserve */
2112
2113
static int t1_hinter__find_stem_middle(t1_hinter * self, fixed *t, int pole_index, bool horiz)
2114
0
{
2115
    /* *t = 0 preserves slant; *t = fixed_half deminishes slant (don't apply to curves). */
2116
0
    if (PRESERVE_STEM_SLANT == 2) {
2117
0
        *t = 0;
2118
0
        return pole_index;
2119
0
    } else {
2120
        /* For a better representation of arms with a small slope,
2121
           we align their poles. It appears useful for CJK fonts,
2122
           see comparefiles/japan.ps, Bug687603.ps .
2123
           Otherwise (a slightly rotated glyph, see Openhuis_pdf_zw.pdf)
2124
           we align the arm middle, causing the slope to look smaller
2125
         */
2126
        /* We assume proper glyphs, see Type 1 spec, chapter 4. */
2127
0
        int next = t1_hinter__next_contour_pole(self, pole_index);
2128
0
        const int alpha = 10;
2129
0
        int design_slant;
2130
0
        bool curve = self->pole[next].type == offcurve;
2131
0
        bool continuing = (horiz ? t1_hinter__is_small_angle(self, next, pole_index, 1, 0, alpha, 1, &design_slant)
2132
0
                                 : t1_hinter__is_small_angle(self, next, pole_index, 0, 1, alpha, 1, &design_slant));
2133
2134
0
        if (!PRESERVE_STEM_SLANT || design_slant == 0)
2135
0
            *t = (!curve && continuing ? fixed_half : 0);
2136
0
        else
2137
0
            *t = 0;
2138
0
        return pole_index;
2139
0
    }
2140
0
}
2141
2142
static int t1_hinter__skip_stem(t1_hinter * self, int pole_index, bool horiz)
2143
0
{   /* We assume proper glyphs, see Type 1 spec, chapter 4. */
2144
0
    int i = pole_index;
2145
0
    int next_pole = t1_hinter__next_contour_pole(self, i);
2146
0
    int next_segm = t1_hinter__segment_end(self, i);
2147
0
    long tan_x = (horiz ? 1 : 0);
2148
0
    long tan_y = (horiz ? 0 : 1);
2149
0
    int quality;
2150
2151
0
    while (t1_hinter__is_small_angle(self, i, next_pole, tan_x, tan_y, 1000, 1, &quality) && /* The threshold is taken from scratch. */
2152
0
           t1_hinter__is_small_angle(self, i, next_segm, tan_x, tan_y, 1000, 1, &quality)) {
2153
0
        i = t1_hinter__segment_end(self, i);
2154
0
        if (i == pole_index) {
2155
            /* An invalid glyph with <=2 segments in the contour with no angles. */
2156
0
            break;
2157
0
        }
2158
0
        next_pole = t1_hinter__next_contour_pole(self, i);
2159
0
        next_segm = t1_hinter__segment_end(self, i);
2160
0
    }
2161
0
    return i;
2162
0
}
2163
2164
static void t1_hinter__mark_existing_stems(t1_hinter * self)
2165
0
{   /* fixme: Duplicated code with t1_hinter__align_stem_commands. */
2166
0
    int i, j, jj, k;
2167
2168
0
    for(i = 0; i < self->hint_count; i++)
2169
0
        if (self->hint[i].type == vstem || self->hint[i].type == hstem)
2170
0
            for (k = self->hint[i].range_index; k != -1; k = self->hint_range[k].next) {
2171
0
                int beg_range_pole = self->hint_range[k].beg_pole;
2172
0
                int end_range_pole = self->hint_range[k].end_pole;
2173
0
                int quality;
2174
2175
0
                if (self->pole[beg_range_pole].type == closepath) {
2176
                    /* A workaround for a buggy font from the Bug 687393,
2177
                       which defines a range with 'closepath' only. */
2178
0
                    beg_range_pole++;
2179
0
                    if (beg_range_pole > end_range_pole)
2180
0
                        continue;
2181
0
                }
2182
0
                for (j = beg_range_pole; j <= end_range_pole;) {
2183
0
                    int k = t1_hinter__is_stem_hint_applicable(self, &self->hint[i], j, &quality);
2184
0
                    if (k == 1)
2185
0
                        self->hint[i].b0 = true;
2186
0
                    else if (k == 2)
2187
0
                        self->hint[i].b1 = true;
2188
0
                    {   /* Step to the next pole in the range : */
2189
0
                        jj = j;
2190
0
                        j = t1_hinter__segment_end(self, j);
2191
0
                        if (j <= jj) /* Rolled over contour end ? */
2192
0
                            j = self->contour[self->pole[j].contour_index + 1]; /* Go to the next contour. */
2193
0
                    }
2194
0
                }
2195
0
            }
2196
0
}
2197
2198
static void t1_hinter__add_boundary_length(t1_hinter * self, t1_hint *hint,
2199
                                            int pole_index0, int pole_index1)
2200
0
{   const t1_pole *pole = &self->pole[pole_index0];
2201
0
    int contour_index = pole->contour_index;
2202
0
    int beg_contour_pole = self->contour[contour_index];
2203
0
    int end_contour_pole = self->contour[contour_index + 1] - 2;
2204
0
    int i0 = ranger_step_b(pole_index0, beg_contour_pole, end_contour_pole);
2205
0
    int i1 = ranger_step_f(pole_index1, beg_contour_pole, end_contour_pole);
2206
0
    t1_glyph_space_coord g = (hint->type == hstem ? pole->gy : pole->gx);
2207
2208
0
    if (self->pole[i0].type == oncurve)
2209
0
        i0 = pole_index0;
2210
0
    if (self->pole[i1].type == oncurve)
2211
0
        i1 = pole_index1;
2212
0
    *(any_abs(hint->g0 - g) < any_abs(hint->g1 - g) ? &hint->boundary_length0 : &hint->boundary_length1)
2213
0
        += (hint->type == hstem ? any_abs(self->pole[i0].gx - self->pole[i1].gx)
2214
0
                                : any_abs(self->pole[i0].gy - self->pole[i1].gy));
2215
0
}
2216
2217
static void t1_hinter__align_stem_commands(t1_hinter * self)
2218
0
{   int i, j, jj, k;
2219
2220
0
    for(i = 0; i < self->hint_count; i++) {
2221
0
        self->hint[i].boundary_length0 = self->hint[i].boundary_length1 = 0;
2222
0
        if (self->hint[i].type == vstem || self->hint[i].type == hstem)
2223
0
            for (k = self->hint[i].range_index; k != -1; k = self->hint_range[k].next) {
2224
0
                int beg_range_pole = self->hint_range[k].beg_pole;
2225
0
                int end_range_pole = self->hint_range[k].end_pole;
2226
0
                bool horiz = (self->hint[i].type == hstem);
2227
0
                int quality = max_int;
2228
2229
0
                if (self->pole[beg_range_pole].type == closepath) {
2230
                    /* A workaround for a buggy font from the Bug 687393,
2231
                       which defines a range with 'closepath' only. */
2232
0
                    beg_range_pole++;
2233
0
                    if (beg_range_pole > end_range_pole)
2234
0
                        continue;
2235
0
                }
2236
0
                for (j = beg_range_pole; j <= end_range_pole;) {
2237
0
                    if (self->pole[j].type == closepath) {
2238
0
                        j++;
2239
0
                        continue;
2240
0
                    }
2241
0
                    if (t1_hinter__is_stem_hint_applicable(self, &self->hint[i], j, &quality)) {
2242
0
                        fixed t; /* Type 1 spec implies that it is 0 for curves, 0.5 for bars */
2243
0
                        int segment_index = t1_hinter__find_stem_middle(self, &t, j, horiz);
2244
0
                        t1_glyph_space_coord gc;
2245
0
                        enum t1_align_type align = unaligned;
2246
2247
0
                        if (self->hint[i].side_mask != 3) {
2248
                            /* An overal hint from the True Type autohinter. */
2249
0
                            align = (self->hint[i].side_mask & 2 ? topzn : botzn);
2250
0
                        } else if (self->autohinting && horiz) {
2251
0
                            if (self->pole[segment_index].gy == self->hint[i].g0)
2252
0
                                align = (self->hint[i].g0 > self->hint[i].g1 ? topzn : botzn);
2253
0
                        }
2254
0
                        align = t1_hinter__compute_aligned_coord(self, &gc,
2255
0
                                    segment_index, t, &self->hint[i], align);
2256
                        /* todo: optimize: primary commands don't need to align, if suppressed by secondary ones. */
2257
0
                        t1_hint__set_aligned_coord(&self->hint[i], gc, &self->pole[j], align, quality);
2258
0
                        jj = j;
2259
0
                        j = t1_hinter__skip_stem(self, j, horiz);
2260
0
                        t1_hinter__add_boundary_length(self, &self->hint[i], jj, j);
2261
0
                        if (j < jj) { /* Rolled over contour end ? */
2262
0
                            j = self->contour[self->pole[j].contour_index + 1]; /* Go to the next contour. */
2263
0
                            continue;
2264
0
                        }
2265
0
                    }
2266
0
                    {   /* Step to the next pole in the range : */
2267
0
                        jj = j;
2268
0
                        j = t1_hinter__segment_end(self, j);
2269
0
                        if (j <= jj) /* Rolled over contour end ? */
2270
0
                            j = self->contour[self->pole[j].contour_index + 1]; /* Go to the next contour. */
2271
0
                    }
2272
0
                }
2273
0
            }
2274
0
    }
2275
0
}
2276
2277
static void t1_hinter__unfix_opposite_to_common(t1_hinter * self)
2278
0
{    /* Implemented for Bug 687578 "T1 hinter disturbs stem width". */
2279
0
    int i, j, k, m, n;
2280
0
    t1_glyph_space_coord d, md;
2281
0
    t1_glyph_space_coord *p_ci, *p_cj, *p_agj, agm;
2282
0
    enum t1_align_type *p_aj, *p_ai, *p_oi, *p_oj, am;
2283
2284
0
    for (k = 0; k < 2; k++) { /* g0, g1 */
2285
        /* Since the number of stems in a complex is usually small,
2286
           we don't care about redundant computations. */
2287
0
        for(i = 0; i < self->hint_count; i++) {
2288
0
            if (self->hint[i].type == vstem || self->hint[i].type == hstem) {
2289
0
                p_ai = (!k ? &self->hint[i].aligned0 : &self->hint[i].aligned1);
2290
0
                p_oi = (!k ? &self->hint[i].aligned1 : &self->hint[i].aligned0);
2291
0
                if (*p_ai > weak && *p_ai == *p_oi) {
2292
0
                    p_ci = (!k ? &self->hint[i].g0 : &self->hint[i].g1);
2293
0
                    md = any_abs(self->hint[i].g1 - self->hint[i].g0);
2294
0
                    m = i;
2295
0
                    am = *p_ai;
2296
0
                    agm = (!k ? self->hint[m].ag0 : self->hint[m].ag1);
2297
0
                    n = 0;
2298
0
                    for(j = 0; j < self->hint_count; j++) {
2299
0
                        if (j != i && self->hint[i].type == self->hint[j].type) {
2300
0
                            p_cj = (!k ? &self->hint[j].g0 : &self->hint[j].g1);
2301
0
                            if (*p_ci == *p_cj) {
2302
0
                                n++;
2303
0
                                p_aj = (!k ? &self->hint[j].aligned0 : &self->hint[j].aligned1);
2304
0
                                d = any_abs(self->hint[j].g1 - self->hint[j].g0);
2305
0
                                if (am < *p_aj) {
2306
0
                                    md = d;
2307
0
                                    m = j;
2308
0
                                    am = *p_aj;
2309
0
                                    agm = (!k ? self->hint[m].ag0 : self->hint[m].ag1);
2310
0
                                } if (md < d) {
2311
0
                                    md = d;
2312
0
                                }
2313
0
                            }
2314
0
                        }
2315
0
                    }
2316
0
                    if (n) {
2317
0
                        for(j = 0; j < self->hint_count; j++) {
2318
0
                            p_cj = (!k ? &self->hint[j].g0 : &self->hint[j].g1);
2319
0
                            if (*p_ci == *p_cj) {
2320
0
                                p_aj = (!k ? &self->hint[j].aligned0 : &self->hint[j].aligned1);
2321
0
                                p_oj = (!k ? &self->hint[j].aligned1 : &self->hint[j].aligned0);
2322
0
                                p_agj = (!k ? &self->hint[j].ag0 : &self->hint[j].ag1);
2323
0
                                *p_aj = am;
2324
0
                                if (*p_oj == aligned)
2325
0
                                    *p_oj = weak;
2326
0
                                *p_agj = agm;
2327
0
                            }
2328
0
                        }
2329
0
                    }
2330
0
                }
2331
0
            }
2332
0
        }
2333
0
    }
2334
0
}
2335
2336
static void t1_hinter__compute_opposite_stem_coords(t1_hinter * self)
2337
0
{   int i;
2338
2339
0
    for (i = 0; i < self->hint_count; i++)
2340
0
        if ((self->hint[i].type == vstem || self->hint[i].type == hstem)) {
2341
0
            t1_glyph_space_coord ag0 = self->hint[i].ag0;
2342
0
            t1_glyph_space_coord ag1 = self->hint[i].ag1;
2343
0
            enum t1_align_type aligned0 = self->hint[i].aligned0;
2344
0
            enum t1_align_type aligned1 = self->hint[i].aligned1;
2345
0
            t1_glyph_space_coord gw;
2346
2347
0
            gw = any_abs(self->hint[i].g1 - self->hint[i].g0);
2348
0
            t1_hinter__align_stem_width(self, &gw, &self->hint[i]);
2349
0
            if (self->hint[i].g1 - self->hint[i].g0 < 0)
2350
0
                gw = -gw;
2351
0
            if (aligned0 > aligned1)
2352
0
                ag1 = ag0 + gw;
2353
0
            else if (aligned0 < aligned1)
2354
0
                ag0 = ag1 - gw;
2355
0
            else {
2356
0
                t1_glyph_space_coord d0 = any_abs(ag0 - self->hint[i].g0);
2357
0
                t1_glyph_space_coord d1 = any_abs(ag1 - self->hint[i].g1);
2358
2359
0
                if (aligned0 == topzn || aligned1 == topzn)
2360
0
                    if (gw > 0)
2361
0
                        ag0 = ag1 - gw;
2362
0
                    else
2363
0
                        ag1 = ag0 + gw;
2364
0
                else if (aligned0 == botzn || aligned1 == botzn)
2365
0
                    if (gw < 0)
2366
0
                        ag0 = ag1 - gw;
2367
0
                    else
2368
0
                        ag1 = ag0 + gw;
2369
0
                else if (self->hint[i].type == hstem &&
2370
0
                        min(any_abs(self->hint[i].g0 - self->ymid), any_abs(self->hint[i].g1 - self->ymid)) >
2371
0
                        (self->ymax - self->ymin) / 5) {
2372
0
                    if ((self->hint[i].g1 + self->hint[i].g0) / 2 > self->ymid)
2373
0
                        ag0 = ag1 - gw;
2374
0
                    else
2375
0
                        ag1 = ag0 + gw;
2376
0
                } else {
2377
0
                    if (d0 < d1)
2378
0
                        ag1 = ag0 + gw;
2379
0
                    else
2380
0
                        ag0 = ag1 - gw;
2381
0
                }
2382
0
            }
2383
0
            self->hint[i].ag0 = ag0;
2384
0
            self->hint[i].ag1 = ag1;
2385
0
        }
2386
0
}
2387
2388
static int t1_hinter__store_hint_applying(t1_hinter * self, t1_hint *hint, int pole_index)
2389
0
{
2390
0
    t1_hint_applying *ha;
2391
0
    int code = t1_hinter__can_add_hint_applying(self, &ha);
2392
2393
0
    if (code < 0)
2394
0
        return code;
2395
0
    ha->pole = pole_index;
2396
0
    ha->opposite = -1;
2397
0
    self->hint_applying_count++;
2398
0
    return 0;
2399
0
}
2400
2401
static int t1_hinter__align_stem_poles(t1_hinter * self)
2402
0
{   int i, j, k;
2403
0
    t1_glyph_space_coord const fuzz = self->blue_fuzz; /* comparefiles/tpc2.ps */
2404
0
    int code = 0;
2405
2406
0
    for (i = 0; i < self->hint_count; i++)
2407
0
        if (self->hint[i].type == vstem || self->hint[i].type == hstem) {
2408
0
            t1_hint * hint = &self->hint[i];
2409
0
            t1_glyph_space_coord ag0 = hint->ag0, ag1 = hint->ag1;
2410
0
            bool horiz = (hint->type == hstem);
2411
2412
            /* fixme: optimize: Reduce hint_applying with storing only one side of the hint. */
2413
0
            self->hint_applying_count = 0;
2414
0
            for (k = self->hint[i].range_index; k != -1; k = self->hint_range[k].next) {
2415
0
                int beg_range_pole = self->hint_range[k].beg_pole;
2416
0
                int end_range_pole = self->hint_range[k].end_pole;
2417
2418
0
                for (j = beg_range_pole; j <= end_range_pole; j++) {
2419
0
                    t1_pole * pole = &self->pole[j];
2420
2421
0
                    if (pole->type != oncurve)
2422
0
                        continue;
2423
0
                    if (!horiz && any_abs(pole->gx - hint->g0) <= fuzz)
2424
0
                        code = t1_hinter__store_hint_applying(self, hint, j);
2425
0
                    else if (!horiz && any_abs(pole->gx - hint->g1) <= fuzz)
2426
0
                        code = t1_hinter__store_hint_applying(self, hint, j);
2427
0
                    else if ( horiz && any_abs(pole->gy - hint->g0) <= fuzz)
2428
0
                        code = t1_hinter__store_hint_applying(self, hint, j);
2429
0
                    else if ( horiz && any_abs(pole->gy - hint->g1) <= fuzz)
2430
0
                        code = t1_hinter__store_hint_applying(self, hint, j);
2431
0
                    if (code < 0)
2432
0
                        return code;
2433
0
                }
2434
0
            }
2435
0
            for (k = 0; k < self->hint_applying_count; k++) {
2436
0
                t1_hint_applying *ha0 = &self->hint_applying[k];
2437
0
                int pole_index0 = ha0->pole;
2438
0
                t1_pole *pole0 = &self->pole[pole_index0];
2439
0
                t1_glyph_space_coord g0 = (horiz ? pole0->gy : pole0->gx);
2440
0
                t1_glyph_space_coord t0 = (horiz ? pole0->gx : pole0->gy);
2441
0
                bool gt0 = any_abs(hint->g0 - g0) > any_abs(hint->g1 - g0);
2442
0
                t1_glyph_space_coord d, md = any_abs(hint->g1 - hint->g0) * 5 / 4;
2443
0
                int mj = -1;
2444
2445
0
                for (j = 0; j < self->hint_applying_count; j++) {
2446
0
                    t1_hint_applying *ha1 = &self->hint_applying[j];
2447
0
                    int pole_index1 = ha1->pole;
2448
0
                    t1_pole *pole1 = &self->pole[pole_index1];
2449
0
                    t1_glyph_space_coord g1 = (horiz ? pole1->gy : pole1->gx);
2450
0
                    t1_glyph_space_coord t1 = (horiz ? pole1->gx : pole1->gy);
2451
0
                    bool gt1 = any_abs(hint->g0 - g1) > any_abs(hint->g1 - g1);
2452
2453
0
                    if (gt0 != gt1) {
2454
0
                        d = any_abs(t1 - t0);
2455
0
                        if (md > d) {
2456
0
                            mj = j;
2457
0
                        }
2458
0
                    }
2459
0
                }
2460
0
                if (mj != -1)    {
2461
0
                    ha0->opposite = mj;
2462
0
                    self->hint_applying[mj].opposite = j;
2463
0
                }
2464
0
            }
2465
0
            for (k = 0; k < self->hint_applying_count; k++) {
2466
0
                t1_hint_applying *ha = &self->hint_applying[k];
2467
0
                int pole_index = ha->pole;
2468
0
                t1_pole *pole = &self->pole[pole_index];
2469
0
                t1_glyph_space_coord g0 = (horiz ? pole->gy : pole->gx);
2470
0
                bool gt0 = any_abs(hint->g0 - g0) > any_abs(hint->g1 - g0);
2471
0
                enum t1_align_type align = (!gt0 ? hint->aligned0 : hint->aligned1);
2472
0
                t1_glyph_space_coord ag = (!gt0 ? ag0 : ag1);
2473
0
                t1_glyph_space_coord bl = (!gt0 ? hint->boundary_length1 : hint->boundary_length0); /* opposite */
2474
2475
0
                if (ha->opposite == -1)
2476
0
                    align = weak;
2477
0
                if (!horiz) {
2478
0
                    if (pole->aligned_x < align)
2479
0
                        pole->ax = ag, pole->aligned_x = align, pole->boundary_length_x = bl;
2480
0
                } else {
2481
0
                    if (pole->aligned_y < align)
2482
0
                        pole->ay = ag, pole->aligned_y = align, pole->boundary_length_y = bl;
2483
0
                }
2484
0
            }
2485
0
        }
2486
0
    return 0;
2487
0
}
2488
2489
static t1_hint * t1_hinter__find_vstem_by_center(t1_hinter * self, t1_glyph_space_coord gx)
2490
0
{   /* Find vstem with axis near gx : */
2491
0
    int i;
2492
0
    t1_hint * hint = NULL;
2493
0
    t1_glyph_space_coord dx = fixed_1;
2494
2495
0
    for (i = 0; i < self->hint_count; i++)
2496
0
        if (self->hint[i].type == vstem) {
2497
0
            t1_glyph_space_coord d = any_abs(gx - (self->hint[i].ag0 + self->hint[i].ag1) / 2);
2498
2499
0
            if (dx > d) {
2500
0
                dx = d;
2501
0
                hint = &self->hint[i];
2502
0
            }
2503
0
        }
2504
0
    return hint;
2505
0
}
2506
2507
static void t1_hinter__process_dotsection(t1_hinter * self, int beg_pole, int end_pole)
2508
0
{   /*  Since source outline must have oncurve poles at XY extremes,
2509
        we compute bounding box from poles.
2510
    */
2511
0
    int i;
2512
0
    t1_glyph_space_coord min_gx = self->pole[beg_pole].gx, min_gy = self->pole[beg_pole].gy;
2513
0
    t1_glyph_space_coord max_gx = min_gx, max_gy = min_gy;
2514
0
    t1_glyph_space_coord center_gx, center_gy, center_agx, center_agy;
2515
0
    t1_glyph_space_coord sx, sy;
2516
0
    bool aligned_min_x = false, aligned_min_y = false, aligned_max_x = false, aligned_max_y = false;
2517
0
    bool aligned_x, aligned_y;
2518
2519
0
    for (i = beg_pole + 1; i <= end_pole; i++) {
2520
0
        t1_glyph_space_coord gx = self->pole[i].gx, gy = self->pole[i].gy;
2521
2522
0
        min_gx = min(min_gx, gx);
2523
0
        min_gy = min(min_gy, gy);
2524
0
        max_gx = max(max_gx, gx);
2525
0
        max_gy = max(max_gy, gy);
2526
0
    }
2527
0
    for (i = beg_pole; i <= end_pole; i++) {
2528
0
        if (self->pole[i].gx == min_gx)
2529
0
            aligned_min_x |= self->pole[i].aligned_x;
2530
0
        if (self->pole[i].gy == min_gy)
2531
0
            aligned_min_y |= self->pole[i].aligned_y;
2532
0
        if (self->pole[i].gx == max_gx)
2533
0
            aligned_max_x |= self->pole[i].aligned_x;
2534
0
        if (self->pole[i].gy == max_gy)
2535
0
            aligned_max_y |= self->pole[i].aligned_y;
2536
0
    }
2537
0
    aligned_x = aligned_min_x && aligned_max_x;
2538
0
    aligned_y = aligned_min_y && aligned_max_y;
2539
0
    if (aligned_x && aligned_y)
2540
0
        return; /* The contour was aligned with stem commands - nothing to do. */
2541
0
    center_gx = center_agx = (min_gx + max_gx) / 2;
2542
0
    center_gy = center_agy = (min_gy + max_gy) / 2;
2543
0
    if (!aligned_x) {
2544
        /* Heuristic : apply vstem if it is close to the center : */
2545
0
        t1_hint * hint = t1_hinter__find_vstem_by_center(self, center_gx);
2546
0
        if (hint != NULL) {
2547
0
            center_agx = (hint->ag0 + hint->ag1) / 2; /* Align with vstem */
2548
0
            aligned_x = true;
2549
0
        }
2550
0
    }
2551
0
    t1_hinter__align_to_grid(self, self->g2o_fraction / 2, &center_agx, &center_agy,
2552
0
                                CONTRAST_STEMS || self->align_to_pixels);
2553
0
    sx = center_agx - center_gx;
2554
0
    sy = center_agy - center_gy;
2555
0
    if (aligned_x)
2556
0
        sx = 0;
2557
0
    if (aligned_y)
2558
0
        sy = 0;
2559
    /* Shift the contour (sets alignment flags to prevent interpolation) : */
2560
0
    for (i = beg_pole; i <= end_pole; i++) {
2561
0
        self->pole[i].ax = self->pole[i].gx + sx;
2562
0
        self->pole[i].ay = self->pole[i].gy + sy;
2563
0
        self->pole[i].aligned_x |= !aligned_x; /* Prevent interpolation if we aligned it here. */
2564
0
        self->pole[i].aligned_y |= !aligned_y;
2565
0
    }
2566
0
}
2567
2568
static void t1_hinter__process_dotsections(t1_hinter * self)
2569
0
{   int i;
2570
2571
0
    for(i = 0; i < self->hint_count; i++)
2572
0
        if (self->hint[i].type == dot) {
2573
0
            int pole_index = self->hint_range[self->hint[i].range_index].beg_pole;
2574
0
            int contour_index = self->pole[pole_index].contour_index;
2575
0
            int beg_pole = self->contour[contour_index];
2576
0
            int end_pole = self->contour[contour_index + 1] - 2;
2577
2578
0
            t1_hinter__process_dotsection(self, beg_pole, end_pole);
2579
0
        }
2580
0
}
2581
2582
static void t1_hinter__interpolate_other_poles(t1_hinter * self)
2583
0
{   int i, j, k;
2584
2585
0
    for (k = 0; k<2; k++) { /* X, Y */
2586
0
        t1_glyph_space_coord *p_gc = (!k ? &self->pole[0].gx : &self->pole[0].gy);
2587
0
        t1_glyph_space_coord *p_wc = (!k ? &self->pole[0].gy : &self->pole[0].gx);
2588
0
        t1_glyph_space_coord *p_ac = (!k ? &self->pole[0].ax : &self->pole[0].ay);
2589
0
        t1_glyph_space_coord *p_bl = (!k ? &self->pole[0].boundary_length_x : &self->pole[0].boundary_length_y);
2590
0
        enum t1_align_type *p_f = (!k ? &self->pole[0].aligned_x : &self->pole[0].aligned_y);
2591
0
        int offset_gc = (char *)p_gc - (char *)&self->pole[0];
2592
0
        int offset_wc = (char *)p_wc - (char *)&self->pole[0];
2593
0
        int offset_ac = (char *)p_ac - (char *)&self->pole[0];
2594
0
        int offset_bl = (char *)p_bl - (char *)&self->pole[0];
2595
0
        int offset_f  = (char *)p_f -  (char *)&self->pole[0];
2596
2597
0
        for (i = 0; i < self->contour_count; i++) {
2598
0
            int beg_contour_pole = self->contour[i];
2599
0
            int end_contour_pole = self->contour[i + 1] - 2;
2600
0
            int range_beg;
2601
2602
0
            for (j = beg_contour_pole; j <= end_contour_pole; j++)
2603
0
                if (*member_prt(enum t1_align_type, &self->pole[j], offset_f))
2604
0
                    break;
2605
0
            if (j > end_contour_pole)
2606
0
                continue;
2607
0
            range_beg = j;
2608
0
            do {
2609
0
                int start_pole = j, stop_pole = -1;
2610
0
                t1_glyph_space_coord min_a, max_a;
2611
0
                t1_glyph_space_coord min_g, max_g, g0, g1, a0, a1;
2612
0
                int min_i = start_pole, max_i = start_pole, cut_l, l;
2613
0
                bool moved = false;
2614
2615
0
                do {
2616
0
                    int min_l = 0, max_l = 0;
2617
0
                    int min_w, max_w, w0;
2618
2619
0
                    g0 = *member_prt(t1_glyph_space_coord, &self->pole[start_pole], offset_gc);
2620
0
                    w0 = *member_prt(t1_glyph_space_coord, &self->pole[start_pole], offset_wc);
2621
0
                    a0 = *member_prt(t1_glyph_space_coord, &self->pole[start_pole], offset_ac);
2622
0
                    min_g = g0;
2623
0
                    max_g = g0;
2624
0
                    min_w = max_w = w0;
2625
0
                    for (j = ranger_step_f(start_pole,  beg_contour_pole, end_contour_pole), l = 1;
2626
0
                         j != start_pole;
2627
0
                         j = ranger_step_f(j,  beg_contour_pole, end_contour_pole), l++) {
2628
0
                        t1_glyph_space_coord g = * member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc);
2629
0
                        t1_glyph_space_coord w = * member_prt(t1_glyph_space_coord, &self->pole[j], offset_wc);
2630
2631
0
                        if (min_g > g)
2632
0
                            min_g = g, min_i = j, min_l = l;
2633
0
                        if (max_g < g)
2634
0
                            max_g = g, max_i = j, max_l = l;
2635
0
                        if (min_w > w)
2636
0
                            min_w = w;
2637
0
                        if (max_w < w)
2638
0
                            max_w = w;
2639
0
                        if (*member_prt(enum t1_align_type, &self->pole[j], offset_f))
2640
0
                            break;
2641
0
                        if (j == stop_pole)
2642
0
                            break;
2643
0
                    }
2644
0
                    stop_pole = j;
2645
0
                    cut_l = l;
2646
0
                    g1 = * member_prt(t1_glyph_space_coord, &self->pole[stop_pole], offset_gc);
2647
0
                    a1 = * member_prt(t1_glyph_space_coord, &self->pole[stop_pole], offset_ac);
2648
2649
0
                    if (start_pole != stop_pole)
2650
0
                        if (any_abs(g0 - g1) >= any_abs(a0 - a1) / 10)
2651
0
                            if (any_abs(max_g - min_g) <= any_abs(max_w - min_w) / 4)
2652
0
                                break; /* OK to interpolate. */
2653
                    /* else break at an extremal pole : */
2654
0
                    if (min_i != start_pole && min_l < cut_l && min_g != g0 && min_g != g1)
2655
0
                        stop_pole = min_i, cut_l = min_l;
2656
0
                    if (max_i != start_pole && max_l < cut_l && max_g != g0 && max_g != g1)
2657
0
                        stop_pole = max_i, cut_l = max_l;
2658
0
                } while (cut_l < l);
2659
                    /* Now start_pole and end_pole point to the contour interval to interpolate. */
2660
0
                if (g0 < g1) {
2661
0
                    min_g = g0;
2662
0
                    max_g = g1;
2663
0
                    min_a = a0;
2664
0
                    max_a = a1;
2665
0
                } else {
2666
0
                    min_g = g1;
2667
0
                    max_g = g0;
2668
0
                    min_a = a1;
2669
0
                    max_a = a0;
2670
0
                }
2671
0
                if (min_g == max_g && min_a != max_a) {
2672
                    /* Alignment conflict, choose by boundary_length. */
2673
0
                    if (* member_prt(t1_glyph_space_coord, &self->pole[start_pole], offset_bl) <
2674
0
                        * member_prt(t1_glyph_space_coord, &self->pole[stop_pole], offset_bl))
2675
0
                        min_a = max_a = a1;
2676
0
                    else
2677
0
                        min_a = max_a = a0;
2678
0
                }
2679
0
                for (j = start_pole; ;
2680
0
                     j = ranger_step_f(j,  beg_contour_pole, end_contour_pole)) {
2681
0
                    t1_glyph_space_coord g = * member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc);
2682
2683
0
                    if (g <= min_g)
2684
0
                        * member_prt(t1_glyph_space_coord, &self->pole[j], offset_ac) =
2685
0
                        * member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc) + (min_a - min_g);
2686
0
                    else if (g >= max_g)
2687
0
                        * member_prt(t1_glyph_space_coord, &self->pole[j], offset_ac) =
2688
0
                        * member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc) + (max_a - max_g);
2689
0
                    if(moved && j == stop_pole)
2690
0
                        break;
2691
0
                    moved = true;
2692
0
                }
2693
0
                if (min_g < max_g) {
2694
0
                    int24 div = max_g - min_g;
2695
0
                    int24 mul = max_a - min_a;
2696
                    /*  Due to glyph coordinate definition, div is not smaller than 2^12.
2697
2698
                        In the following cycle we need to compute x*mul/div for 24-bit integers,
2699
                        We replace this expression with x*u/2^12 where u = mul*2^12/div
2700
                        (note that it's an approximation with relative precision 2^-12).
2701
2702
                        If mul or div are big, we drop 5 bits to fit them into int19.
2703
                        Note that it's another approximation with relative precision 2^-14.
2704
                        Let now they are m0 and d.
2705
2706
                        Then we compute :
2707
2708
                        q1 = m0 / d, r1 = m0 % d, m1 = r1 << 12;   // r1 < 2^19, m0 < 2^12
2709
                        q2 = m1 / d, r2 = m1 % d, m2 = r2 << 12;   // r2 < 2^19, m1 < 2^12
2710
                        q3 = m2 / d, r3 = m2 % d, m3 = r3 << 12;   // r3 < 2^19, m2 < 2^12
2711
                        and so on.
2712
2713
                        We have :
2714
2715
                        u = ((q1 + (q2 >> 12) + (q3 >> 24) + ...) << 12
2716
                          = (q1 << 12) + q2 + (q3 >> 12) + ...
2717
                          = (q1 << 12) + q2 .
2718
2719
                        Thus we got pretty nice formula without iterations. Implementing it below.
2720
                    */
2721
0
                    int24 m0 = mul, d = div, q1, q2, r1, m1, u;
2722
2723
0
                    if (m0 >= (1 << 19) || d >= (1 << 19))
2724
0
                        m0 >>= 5, d >>= 5;
2725
0
                    q1 = m0 / d, r1 = m0 % d, m1 = r1 << 12;
2726
0
                    q2 = m1 / d;
2727
0
                    u = (q1 << 12) + q2;
2728
0
                    for (j = ranger_step_f(start_pole,  beg_contour_pole, end_contour_pole); j != stop_pole;
2729
0
                         j = ranger_step_f(j,  beg_contour_pole, end_contour_pole)) {
2730
0
                        t1_glyph_space_coord g = *member_prt(t1_glyph_space_coord, &self->pole[j], offset_gc);
2731
2732
0
                        if (min_g < g && g < max_g) {
2733
0
                            t1_glyph_space_coord *a = member_prt(t1_glyph_space_coord, &self->pole[j], offset_ac);
2734
0
                            t1_glyph_space_coord x = g - min_g;
2735
0
                            t1_glyph_space_coord h = mul_shift(x, u, 12); /* It is x*u/2^12 */
2736
2737
                            /* h = (int24)(x * (double)mul / div + 0.5); Uncomment this to disable our tricks. */
2738
0
                            *a = min_a + h;
2739
0
                        }
2740
0
                    }
2741
0
                }
2742
0
                j = stop_pole;
2743
0
            } while (j != range_beg);
2744
0
        }
2745
0
    }
2746
0
}
2747
2748
static int t1_hinter__export(t1_hinter * self)
2749
0
{   int i, j, code;
2750
0
    fixed fx, fy;
2751
2752
0
    for(i = 0; ; i++) {
2753
0
        int end_pole, beg_pole = self->contour[i];
2754
0
        t1_pole *pole = & self->pole[beg_pole];
2755
2756
0
        g2d(self, pole->ax, pole->ay, &fx, &fy);
2757
0
        code = gx_path_add_point(self->output_path, fx, fy);
2758
0
        if (code < 0)
2759
0
            return code;
2760
0
        if (i >= self->contour_count)
2761
0
            break;
2762
0
        end_pole = self->contour[i + 1] - 2;
2763
0
        for(j = beg_pole + 1; j <= end_pole; j++) {
2764
0
            pole = & self->pole[j];
2765
0
            g2d(self, pole->ax, pole->ay, &fx, &fy);
2766
0
            if (pole->type == oncurve) {
2767
0
                code = gx_path_add_line(self->output_path, fx, fy);
2768
0
                if (code < 0)
2769
0
                    return code;
2770
0
            } else {
2771
0
                int j1 = j + 1, j2 = (j + 2 > end_pole ? beg_pole : j + 2);
2772
0
                fixed fx1, fy1, fx2, fy2;
2773
2774
0
                g2d(self, self->pole[j1].ax, self->pole[j1].ay, &fx1, &fy1);
2775
0
                g2d(self, self->pole[j2].ax, self->pole[j2].ay, &fx2, &fy2);
2776
0
                code = gx_path_add_curve(self->output_path, fx, fy, fx1, fy1, fx2, fy2);
2777
0
                if (code < 0)
2778
0
                    return code;
2779
0
                j+=2;
2780
0
            }
2781
0
        }
2782
0
        code = gx_path_close_subpath(self->output_path);
2783
0
        if (code < 0)
2784
0
            return code;
2785
0
    }
2786
0
    return 0;
2787
0
}
2788
2789
static int t1_hinter__add_trailing_moveto(t1_hinter * self)
2790
2.36M
{   t1_glyph_space_coord gx = self->width_gx, gy = self->width_gy;
2791
2792
#if 0 /* self appears wrong due to several reasons :
2793
         1. With TextAlphaBits=1, AlignToPixels must have no effect.
2794
         2. ashow, awidthshow must add the width before alignment.
2795
         4. In the PDF interpreter, Tc must add before alignment.
2796
         5. Since a character origin is aligned,
2797
            rounding its width doesn't affect subsequent characters.
2798
         6. When the character size is smaller than half pixel width,
2799
            glyph widths rounds to zero, causing overlapped glyphs.
2800
            (Bug 687719 "PDFWRITE corrupts letter spacing/placement").
2801
       */
2802
    if (self->align_to_pixels)
2803
        t1_hinter__align_to_grid(self, self->g2o_fraction, &gx, &gy, self->align_to_pixels);
2804
#endif
2805
2.36M
    return t1_hinter__rmoveto(self, gx - self->cx, gy - self->cy);
2806
2.36M
}
2807
2808
int t1_hinter__endglyph(t1_hinter * self)
2809
2.36M
{   int code = 0;
2810
2811
2.36M
    code = t1_hinter__add_trailing_moveto(self);
2812
2.36M
    if (code < 0)
2813
0
        goto exit;
2814
2.36M
    code = t1_hinter__end_subglyph(self);
2815
2.36M
    if (code < 0)
2816
0
        goto exit;
2817
2.36M
    t1_hinter__adjust_matrix_precision(self, self->orig_gx, self->orig_gy);
2818
2.36M
    t1_hinter__compute_y_span(self);
2819
2.36M
    t1_hinter__simplify_representation(self);
2820
2.36M
    if (!self->disable_hinting && (self->grid_fit_x || self->grid_fit_y)) {
2821
0
        if (self->FontType == 1)
2822
0
            t1_hinter__compute_type1_stem_ranges(self);
2823
0
        else
2824
0
            t1_hinter__compute_type2_stem_ranges(self);
2825
0
        t1_hinter__mark_existing_stems(self);
2826
0
        t1_hinter_compute_stem_snap_range(self);
2827
0
        t1_hinter__align_stem_commands(self);
2828
0
        t1_hinter__unfix_opposite_to_common(self);
2829
0
        t1_hinter__compute_opposite_stem_coords(self);
2830
        /* stem3 was processed in the Type 1 interpreter. */
2831
0
        code = t1_hinter__align_stem_poles(self);
2832
0
        if (code < 0)
2833
0
            goto exit;
2834
0
        t1_hinter__process_dotsections(self);
2835
0
        t1_hinter__interpolate_other_poles(self);
2836
0
    }
2837
2.36M
    if (self->pole_count) {
2838
0
        if (self->fix_contour_sign) {
2839
0
            t1_hinter__fix_contour_signs(self);
2840
0
        }
2841
0
        code = t1_hinter__export(self);
2842
0
    }
2843
2.36M
exit:
2844
2.36M
    t1_hinter__free_arrays(self);
2845
2.36M
    return code;
2846
2.36M
}