Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/gs/src/gxhintn.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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