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