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