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