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