~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/freetype/src/autohint/ahhint.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************/
 
2
/*                                                                         */
 
3
/*  ahhint.c                                                               */
 
4
/*                                                                         */
 
5
/*    Glyph hinter (body).                                                 */
 
6
/*                                                                         */
 
7
/*  Copyright 2000-2001, 2002, 2003, 2004 Catharon Productions Inc.        */
 
8
/*  Author: David Turner                                                   */
 
9
/*                                                                         */
 
10
/*  This file is part of the Catharon Typography Project and shall only    */
 
11
/*  be used, modified, and distributed under the terms of the Catharon     */
 
12
/*  Open Source License that should come with this file under the name     */
 
13
/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
 
14
/*  this file you indicate that you have read the license and              */
 
15
/*  understand and accept it fully.                                        */
 
16
/*                                                                         */
 
17
/*  Note that this license is compatible with the FreeType license.        */
 
18
/*                                                                         */
 
19
/***************************************************************************/
 
20
 
 
21
 
 
22
#include <ft2build.h>
 
23
#include "ahhint.h"
 
24
#include "ahglyph.h"
 
25
#include "ahangles.h"
 
26
#include "aherrors.h"
 
27
#include FT_OUTLINE_H
 
28
 
 
29
 
 
30
#define FACE_GLOBALS( face )  ( (AH_Face_Globals)(face)->autohint.data )
 
31
 
 
32
#define AH_USE_IUP
 
33
#define OPTIM_STEM_SNAP
 
34
 
 
35
 
 
36
  /*************************************************************************/
 
37
  /*************************************************************************/
 
38
  /****                                                                 ****/
 
39
  /****   Hinting routines                                              ****/
 
40
  /****                                                                 ****/
 
41
  /*************************************************************************/
 
42
  /*************************************************************************/
 
43
 
 
44
  /* snap a given width in scaled coordinates to one of the */
 
45
  /* current standard widths                                */
 
46
  static FT_Pos
 
47
  ah_snap_width( FT_Pos*  widths,
 
48
                 FT_Int   count,
 
49
                 FT_Pos   width )
 
50
  {
 
51
    int     n;
 
52
    FT_Pos  best      = 64 + 32 + 2;
 
53
    FT_Pos  reference = width;
 
54
    FT_Pos  scaled;
 
55
 
 
56
 
 
57
    for ( n = 0; n < count; n++ )
 
58
    {
 
59
      FT_Pos  w;
 
60
      FT_Pos  dist;
 
61
 
 
62
 
 
63
      w = widths[n];
 
64
      dist = width - w;
 
65
      if ( dist < 0 )
 
66
        dist = -dist;
 
67
      if ( dist < best )
 
68
      {
 
69
        best      = dist;
 
70
        reference = w;
 
71
      }
 
72
    }
 
73
 
 
74
    scaled = FT_PIX_ROUND( reference );
 
75
 
 
76
    if ( width >= reference )
 
77
    {
 
78
      if ( width < scaled + 48 )
 
79
        width = reference;
 
80
    }
 
81
    else
 
82
    {
 
83
      if ( width > scaled - 48 )
 
84
        width = reference;
 
85
    }
 
86
 
 
87
    return width;
 
88
  }
 
89
 
 
90
 
 
91
  /* compute the snapped width of a given stem */
 
92
 
 
93
#ifdef FT_CONFIG_CHESTER_SERIF
 
94
 
 
95
  static FT_Pos
 
96
  ah_compute_stem_width( AH_Hinter      hinter,
 
97
                         int            vertical,
 
98
                         FT_Pos         width,
 
99
                         AH_Edge_Flags  base_flags,
 
100
                         AH_Edge_Flags  stem_flags )
 
101
  {
 
102
    AH_Globals  globals = &hinter->globals->scaled;
 
103
    FT_Pos      dist    = width;
 
104
    FT_Int      sign    = 0;
 
105
 
 
106
 
 
107
    if ( dist < 0 )
 
108
    {
 
109
      dist = -width;
 
110
      sign = 1;
 
111
    }
 
112
 
 
113
    if ( !hinter->do_stem_adjust )
 
114
    {
 
115
      /* leave stem widths unchanged */
 
116
    }
 
117
    else if ( (  vertical && !hinter->do_vert_snapping ) ||
 
118
              ( !vertical && !hinter->do_horz_snapping ) )
 
119
    {
 
120
      /* smooth hinting process: very lightly quantize the stem width */
 
121
      /*                                                              */
 
122
 
 
123
      /* leave the widths of serifs alone */
 
124
 
 
125
      if ( ( stem_flags & AH_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
 
126
        goto Done_Width;
 
127
 
 
128
      else if ( ( base_flags & AH_EDGE_ROUND ) )
 
129
      {
 
130
        if ( dist < 80 )
 
131
          dist = 64;
 
132
      }
 
133
      else if ( dist < 56 )
 
134
        dist = 56;
 
135
 
 
136
      {
 
137
        FT_Pos  delta = dist - globals->stds[vertical];
 
138
 
 
139
 
 
140
        if ( delta < 0 )
 
141
          delta = -delta;
 
142
 
 
143
        if ( delta < 40 )
 
144
        {
 
145
          dist = globals->stds[vertical];
 
146
          if ( dist < 48 )
 
147
            dist = 48;
 
148
 
 
149
          goto Done_Width;
 
150
        }
 
151
 
 
152
        if ( dist < 3 * 64 )
 
153
        {
 
154
          delta  = dist & 63;
 
155
          dist  &= -64;
 
156
 
 
157
          if ( delta < 10 )
 
158
            dist += delta;
 
159
 
 
160
          else if ( delta < 32 )
 
161
            dist += 10;
 
162
 
 
163
          else if ( delta < 54 )
 
164
            dist += 54;
 
165
 
 
166
          else
 
167
            dist += delta;
 
168
        }
 
169
        else
 
170
          dist = ( dist + 32 ) & ~63;
 
171
      }
 
172
    }
 
173
    else
 
174
    {
 
175
      /* strong hinting process: snap the stem width to integer pixels */
 
176
      /*                                                               */
 
177
      if ( vertical )
 
178
      {
 
179
        dist = ah_snap_width( globals->heights, globals->num_heights, dist );
 
180
 
 
181
        /* in the case of vertical hinting, always round */
 
182
        /* the stem heights to integer pixels            */
 
183
        if ( dist >= 64 )
 
184
          dist = ( dist + 16 ) & ~63;
 
185
        else
 
186
          dist = 64;
 
187
      }
 
188
      else
 
189
      {
 
190
        dist = ah_snap_width( globals->widths, globals->num_widths, dist );
 
191
 
 
192
        if ( hinter->flags & AH_HINTER_MONOCHROME )
 
193
        {
 
194
          /* monochrome horizontal hinting: snap widths to integer pixels */
 
195
          /* with a different threshold                                   */
 
196
          if ( dist < 64 )
 
197
            dist = 64;
 
198
          else
 
199
            dist = ( dist + 32 ) & ~63;
 
200
        }
 
201
        else
 
202
        {
 
203
          /* for horizontal anti-aliased hinting, we adopt a more subtle */
 
204
          /* approach: we strengthen small stems, round stems whose size */
 
205
          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
 
206
          if ( dist < 48 )
 
207
            dist = ( dist + 64 ) >> 1;
 
208
 
 
209
          else if ( dist < 128 )
 
210
            dist = ( dist + 22 ) & ~63;
 
211
          else
 
212
            /* XXX: round otherwise to prevent color fringes in LCD mode */
 
213
            dist = ( dist + 32 ) & ~63;
 
214
        }
 
215
      }
 
216
    }
 
217
 
 
218
  Done_Width:
 
219
    if ( sign )
 
220
      dist = -dist;
 
221
 
 
222
    return dist;
 
223
  }
 
224
 
 
225
#else /* !FT_CONFIG_CHESTER_SERIF */
 
226
 
 
227
  static FT_Pos
 
228
  ah_compute_stem_width( AH_Hinter  hinter,
 
229
                         int        vertical,
 
230
                         FT_Pos     width )
 
231
  {
 
232
    AH_Globals  globals = &hinter->globals->scaled;
 
233
    FT_Pos      dist    = width;
 
234
    FT_Int      sign    = 0;
 
235
 
 
236
 
 
237
    if ( dist < 0 )
 
238
    {
 
239
      dist = -width;
 
240
      sign = 1;
 
241
    }
 
242
 
 
243
    if ( !hinter->do_stem_adjust )
 
244
    {
 
245
      /* leave stem widths unchanged */
 
246
    }
 
247
    else if ( (  vertical && !hinter->do_vert_snapping ) ||
 
248
              ( !vertical && !hinter->do_horz_snapping ) )
 
249
    {
 
250
      /* smooth hinting process: very lightly quantize the stem width */
 
251
      /*                                                              */
 
252
      if ( dist < 64 )
 
253
        dist = 64;
 
254
 
 
255
      {
 
256
        FT_Pos  delta = dist - globals->stds[vertical];
 
257
 
 
258
 
 
259
        if ( delta < 0 )
 
260
          delta = -delta;
 
261
 
 
262
        if ( delta < 40 )
 
263
        {
 
264
          dist = globals->stds[vertical];
 
265
          if ( dist < 48 )
 
266
            dist = 48;
 
267
        }
 
268
 
 
269
        if ( dist < 3 * 64 )
 
270
        {
 
271
          delta  = dist & 63;
 
272
          dist  &= -64;
 
273
 
 
274
          if ( delta < 10 )
 
275
            dist += delta;
 
276
 
 
277
          else if ( delta < 32 )
 
278
            dist += 10;
 
279
 
 
280
          else if ( delta < 54 )
 
281
            dist += 54;
 
282
 
 
283
          else
 
284
            dist += delta;
 
285
        }
 
286
        else
 
287
          dist = ( dist + 32 ) & ~63;
 
288
      }
 
289
    }
 
290
    else
 
291
    {
 
292
      /* strong hinting process: snap the stem width to integer pixels */
 
293
      /*                                                               */
 
294
      if ( vertical )
 
295
      {
 
296
        dist = ah_snap_width( globals->heights, globals->num_heights, dist );
 
297
 
 
298
        /* in the case of vertical hinting, always round */
 
299
        /* the stem heights to integer pixels            */
 
300
        if ( dist >= 64 )
 
301
          dist = ( dist + 16 ) & ~63;
 
302
        else
 
303
          dist = 64;
 
304
      }
 
305
      else
 
306
      {
 
307
        dist = ah_snap_width( globals->widths, globals->num_widths, dist );
 
308
 
 
309
        if ( hinter->flags & AH_HINTER_MONOCHROME )
 
310
        {
 
311
          /* monochrome horizontal hinting: snap widths to integer pixels */
 
312
          /* with a different threshold                                   */
 
313
          if ( dist < 64 )
 
314
            dist = 64;
 
315
          else
 
316
            dist = ( dist + 32 ) & ~63;
 
317
        }
 
318
        else
 
319
        {
 
320
          /* for horizontal anti-aliased hinting, we adopt a more subtle */
 
321
          /* approach: we strengthen small stems, round stems whose size */
 
322
          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
 
323
          if ( dist < 48 )
 
324
            dist = ( dist + 64 ) >> 1;
 
325
 
 
326
          else if ( dist < 128 )
 
327
            dist = ( dist + 22 ) & ~63;
 
328
          else
 
329
            /* XXX: round otherwise to prevent color fringes in LCD mode */
 
330
            dist = ( dist + 32 ) & ~63;
 
331
        }
 
332
      }
 
333
    }
 
334
 
 
335
    if ( sign )
 
336
      dist = -dist;
 
337
 
 
338
    return dist;
 
339
  }
 
340
 
 
341
#endif /* !FT_CONFIG_CHESTER_SERIF */
 
342
 
 
343
 
 
344
  /* align one stem edge relative to the previous stem edge */
 
345
  static void
 
346
  ah_align_linked_edge( AH_Hinter  hinter,
 
347
                        AH_Edge    base_edge,
 
348
                        AH_Edge    stem_edge,
 
349
                        int        vertical )
 
350
  {
 
351
    FT_Pos  dist = stem_edge->opos - base_edge->opos;
 
352
 
 
353
#ifdef FT_CONFIG_CHESTER_SERIF
 
354
 
 
355
    FT_Pos  fitted_width = ah_compute_stem_width( hinter,
 
356
                                                  vertical,
 
357
                                                  dist,
 
358
                                                  base_edge->flags,
 
359
                                                  stem_edge->flags );
 
360
 
 
361
 
 
362
    stem_edge->pos = base_edge->pos + fitted_width;
 
363
 
 
364
#else
 
365
 
 
366
    stem_edge->pos = base_edge->pos +
 
367
                     ah_compute_stem_width( hinter, vertical, dist );
 
368
 
 
369
#endif
 
370
 
 
371
  }
 
372
 
 
373
 
 
374
  static void
 
375
  ah_align_serif_edge( AH_Hinter  hinter,
 
376
                       AH_Edge    base,
 
377
                       AH_Edge    serif,
 
378
                       int        vertical )
 
379
  {
 
380
    FT_Pos  dist;
 
381
    FT_Pos  sign = 1;
 
382
 
 
383
    FT_UNUSED( hinter );
 
384
    FT_UNUSED( vertical );
 
385
 
 
386
 
 
387
    dist = serif->opos - base->opos;
 
388
    if ( dist < 0 )
 
389
    {
 
390
      dist = -dist;
 
391
      sign = -1;
 
392
    }
 
393
 
 
394
#if 0
 
395
    /* do not touch serifs widths! */
 
396
    if ( base->flags & AH_EDGE_DONE )
 
397
    {
 
398
      if ( dist >= 64 )
 
399
        dist = ( dist + 8 ) & ~63;
 
400
 
 
401
      else if ( dist <= 32 && !vertical )
 
402
        dist = ( dist + 33 ) >> 1;
 
403
 
 
404
      else
 
405
        dist = 0;
 
406
    }
 
407
#endif
 
408
 
 
409
    serif->pos = base->pos + sign * dist;
 
410
  }
 
411
 
 
412
 
 
413
  /*************************************************************************/
 
414
  /*************************************************************************/
 
415
  /*************************************************************************/
 
416
  /****                                                                 ****/
 
417
  /****       E D G E   H I N T I N G                                   ****/
 
418
  /****                                                                 ****/
 
419
  /*************************************************************************/
 
420
  /*************************************************************************/
 
421
  /*************************************************************************/
 
422
 
 
423
 
 
424
  FT_LOCAL_DEF( void )
 
425
  ah_hinter_hint_edges( AH_Hinter  hinter )
 
426
  {
 
427
    AH_Edge     edges;
 
428
    AH_Edge     edge_limit;
 
429
    AH_Outline  outline = hinter->glyph;
 
430
    FT_Int      dimension;
 
431
    FT_Int      n_edges;
 
432
 
 
433
 
 
434
    edges      = outline->horz_edges;
 
435
    edge_limit = edges + outline->num_hedges;
 
436
 
 
437
    for ( dimension = 1; dimension >= 0; dimension-- )
 
438
    {
 
439
      AH_Edge  edge;
 
440
      AH_Edge  anchor = 0;
 
441
      int      has_serifs = 0;
 
442
 
 
443
 
 
444
      if ( !hinter->do_horz_hints && !dimension )
 
445
        goto Next_Dimension;
 
446
 
 
447
      if ( !hinter->do_vert_hints && dimension )
 
448
        goto Next_Dimension;
 
449
 
 
450
      /* we begin by aligning all stems relative to the blue zone */
 
451
      /* if needed -- that's only for horizontal edges            */
 
452
      if ( dimension )
 
453
      {
 
454
        for ( edge = edges; edge < edge_limit; edge++ )
 
455
        {
 
456
          FT_Pos*      blue;
 
457
          AH_EdgeRec  *edge1, *edge2;
 
458
 
 
459
 
 
460
          if ( edge->flags & AH_EDGE_DONE )
 
461
            continue;
 
462
 
 
463
          blue  = edge->blue_edge;
 
464
          edge1 = 0;
 
465
          edge2 = edge->link;
 
466
 
 
467
          if ( blue )
 
468
          {
 
469
            edge1 = edge;
 
470
          }
 
471
          else if ( edge2 && edge2->blue_edge )
 
472
          {
 
473
            blue  = edge2->blue_edge;
 
474
            edge1 = edge2;
 
475
            edge2 = edge;
 
476
          }
 
477
 
 
478
          if ( !edge1 )
 
479
            continue;
 
480
 
 
481
          edge1->pos    = blue[0];
 
482
          edge1->flags |= AH_EDGE_DONE;
 
483
 
 
484
          if ( edge2 && !edge2->blue_edge )
 
485
          {
 
486
            ah_align_linked_edge( hinter, edge1, edge2, dimension );
 
487
            edge2->flags |= AH_EDGE_DONE;
 
488
          }
 
489
 
 
490
          if ( !anchor )
 
491
            anchor = edge;
 
492
        }
 
493
      }
 
494
 
 
495
      /* now we will align all stem edges, trying to maintain the */
 
496
      /* relative order of stems in the glyph                     */
 
497
      for ( edge = edges; edge < edge_limit; edge++ )
 
498
      {
 
499
        AH_EdgeRec*  edge2;
 
500
 
 
501
 
 
502
        if ( edge->flags & AH_EDGE_DONE )
 
503
          continue;
 
504
 
 
505
        /* skip all non-stem edges */
 
506
        edge2 = edge->link;
 
507
        if ( !edge2 )
 
508
        {
 
509
          has_serifs++;
 
510
          continue;
 
511
        }
 
512
 
 
513
        /* now align the stem */
 
514
 
 
515
        /* this should not happen, but it's better to be safe */
 
516
        if ( edge2->blue_edge || edge2 < edge )
 
517
        {
 
518
          ah_align_linked_edge( hinter, edge2, edge, dimension );
 
519
          edge->flags |= AH_EDGE_DONE;
 
520
          continue;
 
521
        }
 
522
 
 
523
        if ( !anchor )
 
524
        {
 
525
 
 
526
#ifdef FT_CONFIG_CHESTER_STEM
 
527
 
 
528
          FT_Pos  org_len, org_center, cur_len;
 
529
          FT_Pos  cur_pos1, error1, error2, u_off, d_off;
 
530
 
 
531
 
 
532
          org_len = edge2->opos - edge->opos;
 
533
          cur_len = ah_compute_stem_width( hinter, dimension, org_len,
 
534
                                           edge->flags, edge2->flags );
 
535
 
 
536
          if ( cur_len <= 64 )
 
537
            u_off = d_off = 32;
 
538
          else
 
539
          {
 
540
            u_off = 38;
 
541
            d_off = 26;
 
542
          }
 
543
 
 
544
          if ( cur_len < 96 )
 
545
          {
 
546
            org_center = edge->opos + ( org_len >> 1 );
 
547
 
 
548
            cur_pos1   = FT_PIX_ROUND( org_center );
 
549
 
 
550
            error1 = org_center - ( cur_pos1 - u_off );
 
551
            if ( error1 < 0 )
 
552
              error1 = -error1;
 
553
 
 
554
            error2 = org_center - ( cur_pos1 + d_off );
 
555
            if ( error2 < 0 )
 
556
              error2 = -error2;
 
557
 
 
558
            if ( error1 < error2 )
 
559
              cur_pos1 -= u_off;
 
560
            else
 
561
              cur_pos1 += d_off;
 
562
 
 
563
            edge->pos  = cur_pos1 - cur_len / 2;
 
564
            edge2->pos = cur_pos1 + cur_len / 2;
 
565
 
 
566
          }
 
567
          else
 
568
            edge->pos = FT_PIX_ROUND( edge->opos );
 
569
 
 
570
          anchor = edge;
 
571
 
 
572
          edge->flags |= AH_EDGE_DONE;
 
573
 
 
574
          ah_align_linked_edge( hinter, edge, edge2, dimension );
 
575
 
 
576
#else /* !FT_CONFIG_CHESTER_STEM */
 
577
 
 
578
          edge->pos = FT_PIX_ROUND( edge->opos );
 
579
          anchor    = edge;
 
580
 
 
581
          edge->flags |= AH_EDGE_DONE;
 
582
 
 
583
          ah_align_linked_edge( hinter, edge, edge2, dimension );
 
584
 
 
585
#endif /* !FT_CONFIG_CHESTER_STEM */
 
586
 
 
587
        }
 
588
        else
 
589
        {
 
590
          FT_Pos  org_pos, org_len, org_center, cur_len;
 
591
          FT_Pos  cur_pos1, cur_pos2, delta1, delta2;
 
592
 
 
593
 
 
594
          org_pos    = anchor->pos + ( edge->opos - anchor->opos );
 
595
          org_len    = edge2->opos - edge->opos;
 
596
          org_center = org_pos + ( org_len >> 1 );
 
597
 
 
598
#ifdef FT_CONFIG_CHESTER_SERIF
 
599
 
 
600
          cur_len = ah_compute_stem_width( hinter, dimension, org_len,
 
601
                                           edge->flags, edge2->flags  );
 
602
 
 
603
 
 
604
#else  /* !FT_CONFIG_CHESTER_SERIF */
 
605
 
 
606
          cur_len = ah_compute_stem_width( hinter, dimension, org_len );
 
607
 
 
608
#endif /* !FT_CONFIG_CHESTER_SERIF */
 
609
 
 
610
#ifdef FT_CONFIG_CHESTER_STEM
 
611
 
 
612
          if ( cur_len < 96 )
 
613
          {
 
614
            FT_Pos  u_off, d_off;
 
615
 
 
616
 
 
617
            cur_pos1 = FT_PIX_ROUND( org_center );
 
618
 
 
619
            if (cur_len <= 64 )
 
620
              u_off = d_off = 32;
 
621
            else
 
622
            {
 
623
              u_off = 38;
 
624
              d_off = 26;
 
625
            }
 
626
 
 
627
            delta1 = org_center - ( cur_pos1 - u_off );
 
628
            if ( delta1 < 0 )
 
629
              delta1 = -delta1;
 
630
 
 
631
            delta2 = org_center - ( cur_pos1 + d_off );
 
632
            if ( delta2 < 0 )
 
633
              delta2 = -delta2;
 
634
 
 
635
            if ( delta1 < delta2 )
 
636
              cur_pos1 -= u_off;
 
637
            else
 
638
              cur_pos1 += d_off;
 
639
 
 
640
            edge->pos  = cur_pos1 - cur_len / 2;
 
641
            edge2->pos = cur_pos1 + cur_len / 2;
 
642
          }
 
643
          else
 
644
          {
 
645
            org_pos    = anchor->pos + ( edge->opos - anchor->opos );
 
646
            org_len    = edge2->opos - edge->opos;
 
647
            org_center = org_pos + ( org_len >> 1 );
 
648
 
 
649
            cur_len    = ah_compute_stem_width( hinter, dimension, org_len,
 
650
                                                edge->flags, edge2->flags );
 
651
 
 
652
            cur_pos1   = FT_PIX_ROUND( org_pos );
 
653
            delta1     = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
 
654
            if ( delta1 < 0 )
 
655
              delta1 = -delta1;
 
656
 
 
657
            cur_pos2   = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
 
658
            delta2     = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
 
659
            if ( delta2 < 0 )
 
660
              delta2 = -delta2;
 
661
 
 
662
            edge->pos  = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
 
663
            edge2->pos = edge->pos + cur_len;
 
664
          }
 
665
 
 
666
#else /* !FT_CONFIG_CHESTER_STEM */
 
667
 
 
668
          cur_pos1   = FT_PIX_ROUND( org_pos );
 
669
          delta1     = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
 
670
          if ( delta1 < 0 )
 
671
            delta1 = -delta1;
 
672
 
 
673
          cur_pos2   = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
 
674
          delta2     = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
 
675
          if ( delta2 < 0 )
 
676
            delta2 = -delta2;
 
677
 
 
678
          edge->pos  = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2;
 
679
          edge2->pos = edge->pos + cur_len;
 
680
 
 
681
#endif /* !FT_CONFIG_CHESTER_STEM */
 
682
 
 
683
          edge->flags  |= AH_EDGE_DONE;
 
684
          edge2->flags |= AH_EDGE_DONE;
 
685
 
 
686
          if ( edge > edges && edge->pos < edge[-1].pos )
 
687
            edge->pos = edge[-1].pos;
 
688
        }
 
689
      }
 
690
 
 
691
      /* make sure that lowercase m's maintain their symmetry */
 
692
 
 
693
      /* In general, lowercase m's have six vertical edges if they are sans */
 
694
      /* serif, or twelve if they are avec serif.  This implementation is   */
 
695
      /* based on that assumption, and seems to work very well with most    */
 
696
      /* faces.  However, if for a certain face this assumption is not      */
 
697
      /* true, the m is just rendered like before.  In addition, any stem   */
 
698
      /* correction will only be applied to symmetrical glyphs (even if the */
 
699
      /* glyph is not an m), so the potential for unwanted distortion is    */
 
700
      /* relatively low.                                                    */
 
701
 
 
702
      /* We don't handle horizontal edges since we can't easily assure that */
 
703
      /* the third (lowest) stem aligns with the base line; it might end up */
 
704
      /* one pixel higher or lower.                                         */
 
705
 
 
706
      n_edges = (FT_Int)( edge_limit - edges );
 
707
      if ( !dimension && ( n_edges == 6 || n_edges == 12 ) )
 
708
      {
 
709
        AH_EdgeRec  *edge1, *edge2, *edge3;
 
710
        FT_Pos       dist1, dist2, span, delta;
 
711
 
 
712
 
 
713
        if ( n_edges == 6 )
 
714
        {
 
715
          edge1 = edges;
 
716
          edge2 = edges + 2;
 
717
          edge3 = edges + 4;
 
718
        }
 
719
        else
 
720
        {
 
721
          edge1 = edges + 1;
 
722
          edge2 = edges + 5;
 
723
          edge3 = edges + 9;
 
724
        }
 
725
 
 
726
        dist1 = edge2->opos - edge1->opos;
 
727
        dist2 = edge3->opos - edge2->opos;
 
728
 
 
729
        span = dist1 - dist2;
 
730
        if ( span < 0 )
 
731
          span = -span;
 
732
 
 
733
        if ( span < 8 )
 
734
        {
 
735
          delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
 
736
          edge3->pos -= delta;
 
737
          if ( edge3->link )
 
738
            edge3->link->pos -= delta;
 
739
 
 
740
          /* move the serifs along with the stem */
 
741
          if ( n_edges == 12 )
 
742
          {
 
743
            ( edges + 8 )->pos -= delta;
 
744
            ( edges + 11 )->pos -= delta;
 
745
          }
 
746
 
 
747
          edge3->flags |= AH_EDGE_DONE;
 
748
          if ( edge3->link )
 
749
            edge3->link->flags |= AH_EDGE_DONE;
 
750
        }
 
751
      }
 
752
 
 
753
      if ( !has_serifs )
 
754
        goto Next_Dimension;
 
755
 
 
756
      /* now hint the remaining edges (serifs and single) in order */
 
757
      /* to complete our processing                                */
 
758
      for ( edge = edges; edge < edge_limit; edge++ )
 
759
      {
 
760
        if ( edge->flags & AH_EDGE_DONE )
 
761
          continue;
 
762
 
 
763
        if ( edge->serif )
 
764
          ah_align_serif_edge( hinter, edge->serif, edge, dimension );
 
765
        else if ( !anchor )
 
766
        {
 
767
          edge->pos = FT_PIX_ROUND( edge->opos );
 
768
          anchor    = edge;
 
769
        }
 
770
        else
 
771
          edge->pos = anchor->pos +
 
772
                      FT_PIX_ROUND( edge->opos - anchor->opos );
 
773
 
 
774
        edge->flags |= AH_EDGE_DONE;
 
775
 
 
776
        if ( edge > edges && edge->pos < edge[-1].pos )
 
777
          edge->pos = edge[-1].pos;
 
778
 
 
779
        if ( edge + 1 < edge_limit        &&
 
780
             edge[1].flags & AH_EDGE_DONE &&
 
781
             edge->pos > edge[1].pos      )
 
782
          edge->pos = edge[1].pos;
 
783
      }
 
784
 
 
785
    Next_Dimension:
 
786
      edges      = outline->vert_edges;
 
787
      edge_limit = edges + outline->num_vedges;
 
788
    }
 
789
  }
 
790
 
 
791
 
 
792
  /*************************************************************************/
 
793
  /*************************************************************************/
 
794
  /*************************************************************************/
 
795
  /****                                                                 ****/
 
796
  /****       P O I N T   H I N T I N G                                 ****/
 
797
  /****                                                                 ****/
 
798
  /*************************************************************************/
 
799
  /*************************************************************************/
 
800
  /*************************************************************************/
 
801
 
 
802
  static void
 
803
  ah_hinter_align_edge_points( AH_Hinter  hinter )
 
804
  {
 
805
    AH_Outline  outline = hinter->glyph;
 
806
    AH_Edge     edges;
 
807
    AH_Edge     edge_limit;
 
808
    FT_Int      dimension;
 
809
 
 
810
 
 
811
    edges      = outline->horz_edges;
 
812
    edge_limit = edges + outline->num_hedges;
 
813
 
 
814
    for ( dimension = 1; dimension >= 0; dimension-- )
 
815
    {
 
816
      AH_Edge  edge;
 
817
 
 
818
 
 
819
      edge = edges;
 
820
      for ( ; edge < edge_limit; edge++ )
 
821
      {
 
822
        /* move the points of each segment     */
 
823
        /* in each edge to the edge's position */
 
824
        AH_Segment  seg = edge->first;
 
825
 
 
826
 
 
827
        do
 
828
        {
 
829
          AH_Point  point = seg->first;
 
830
 
 
831
 
 
832
          for (;;)
 
833
          {
 
834
            if ( dimension )
 
835
            {
 
836
              point->y      = edge->pos;
 
837
              point->flags |= AH_FLAG_TOUCH_Y;
 
838
            }
 
839
            else
 
840
            {
 
841
              point->x      = edge->pos;
 
842
              point->flags |= AH_FLAG_TOUCH_X;
 
843
            }
 
844
 
 
845
            if ( point == seg->last )
 
846
              break;
 
847
 
 
848
            point = point->next;
 
849
          }
 
850
 
 
851
          seg = seg->edge_next;
 
852
 
 
853
        } while ( seg != edge->first );
 
854
      }
 
855
 
 
856
      edges      = outline->vert_edges;
 
857
      edge_limit = edges + outline->num_vedges;
 
858
    }
 
859
  }
 
860
 
 
861
 
 
862
  /* hint the strong points -- this is equivalent to the TrueType `IP' */
 
863
  /* hinting instruction                                               */
 
864
  static void
 
865
  ah_hinter_align_strong_points( AH_Hinter  hinter )
 
866
  {
 
867
    AH_Outline  outline = hinter->glyph;
 
868
    FT_Int      dimension;
 
869
    AH_Edge     edges;
 
870
    AH_Edge     edge_limit;
 
871
    AH_Point    points;
 
872
    AH_Point    point_limit;
 
873
    AH_Flags    touch_flag;
 
874
 
 
875
 
 
876
    points      = outline->points;
 
877
    point_limit = points + outline->num_points;
 
878
 
 
879
    edges       = outline->horz_edges;
 
880
    edge_limit  = edges + outline->num_hedges;
 
881
    touch_flag  = AH_FLAG_TOUCH_Y;
 
882
 
 
883
    for ( dimension = 1; dimension >= 0; dimension-- )
 
884
    {
 
885
      AH_Point  point;
 
886
      AH_Edge   edge;
 
887
 
 
888
 
 
889
      if ( edges < edge_limit )
 
890
        for ( point = points; point < point_limit; point++ )
 
891
        {
 
892
          FT_Pos  u, ou, fu;  /* point position */
 
893
          FT_Pos  delta;
 
894
 
 
895
 
 
896
          if ( point->flags & touch_flag )
 
897
            continue;
 
898
 
 
899
#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
 
900
          /* if this point is candidate to weak interpolation, we will  */
 
901
          /* interpolate it after all strong points have been processed */
 
902
          if (  ( point->flags & AH_FLAG_WEAK_INTERPOLATION ) &&
 
903
               !( point->flags & AH_FLAG_INFLECTION )         )
 
904
            continue;
 
905
#endif
 
906
 
 
907
          if ( dimension )
 
908
          {
 
909
            u  = point->fy;
 
910
            ou = point->oy;
 
911
          }
 
912
          else
 
913
          {
 
914
            u  = point->fx;
 
915
            ou = point->ox;
 
916
          }
 
917
 
 
918
          fu = u;
 
919
 
 
920
          /* is the point before the first edge? */
 
921
          edge  = edges;
 
922
          delta = edge->fpos - u;
 
923
          if ( delta >= 0 )
 
924
          {
 
925
            u = edge->pos - ( edge->opos - ou );
 
926
            goto Store_Point;
 
927
          }
 
928
 
 
929
          /* is the point after the last edge? */
 
930
          edge  = edge_limit - 1;
 
931
          delta = u - edge->fpos;
 
932
          if ( delta >= 0 )
 
933
          {
 
934
            u = edge->pos + ( ou - edge->opos );
 
935
            goto Store_Point;
 
936
          }
 
937
 
 
938
#if 1
 
939
          {
 
940
            FT_UInt  min, max, mid;
 
941
            FT_Pos   fpos;
 
942
 
 
943
 
 
944
            /* find enclosing edges */
 
945
            min = 0;
 
946
            max = (FT_UInt)( edge_limit - edges );
 
947
 
 
948
            while ( min < max )
 
949
            {
 
950
              mid  = ( max + min ) >> 1;
 
951
              edge = edges + mid;
 
952
              fpos = edge->fpos;
 
953
 
 
954
              if ( u < fpos )
 
955
                max = mid;
 
956
              else if ( u > fpos )
 
957
                min = mid + 1;
 
958
              else
 
959
              {
 
960
                /* we are on the edge */
 
961
                u = edge->pos;
 
962
                goto Store_Point;
 
963
              }
 
964
            }
 
965
 
 
966
            {
 
967
              AH_Edge  before = edges + min - 1;
 
968
              AH_Edge  after  = edges + min + 0;
 
969
 
 
970
 
 
971
              /* assert( before && after && before != after ) */
 
972
              if ( before->scale == 0 )
 
973
                before->scale = FT_DivFix( after->pos - before->pos,
 
974
                                           after->fpos - before->fpos );
 
975
 
 
976
              u = before->pos + FT_MulFix( fu - before->fpos,
 
977
                                           before->scale );
 
978
            }
 
979
          }
 
980
 
 
981
#else /* !0 */
 
982
 
 
983
          /* otherwise, interpolate the point in between */
 
984
          {
 
985
            AH_Edge  before = 0;
 
986
            AH_Edge  after  = 0;
 
987
 
 
988
 
 
989
            for ( edge = edges; edge < edge_limit; edge++ )
 
990
            {
 
991
              if ( u == edge->fpos )
 
992
              {
 
993
                u = edge->pos;
 
994
                goto Store_Point;
 
995
              }
 
996
              if ( u < edge->fpos )
 
997
                break;
 
998
              before = edge;
 
999
            }
 
1000
 
 
1001
            for ( edge = edge_limit - 1; edge >= edges; edge-- )
 
1002
            {
 
1003
              if ( u == edge->fpos )
 
1004
              {
 
1005
                u = edge->pos;
 
1006
                goto Store_Point;
 
1007
              }
 
1008
              if ( u > edge->fpos )
 
1009
                break;
 
1010
              after = edge;
 
1011
            }
 
1012
 
 
1013
            if ( before->scale == 0 )
 
1014
              before->scale = FT_DivFix( after->pos - before->pos,
 
1015
                                        after->fpos - before->fpos );
 
1016
 
 
1017
            u = before->pos + FT_MulFix( fu - before->fpos,
 
1018
                                        before->scale );
 
1019
          }
 
1020
 
 
1021
#endif /* !0 */
 
1022
 
 
1023
        Store_Point:
 
1024
 
 
1025
          /* save the point position */
 
1026
          if ( dimension )
 
1027
            point->y = u;
 
1028
          else
 
1029
            point->x = u;
 
1030
 
 
1031
          point->flags |= touch_flag;
 
1032
        }
 
1033
 
 
1034
      edges      = outline->vert_edges;
 
1035
      edge_limit = edges + outline->num_vedges;
 
1036
      touch_flag = AH_FLAG_TOUCH_X;
 
1037
    }
 
1038
  }
 
1039
 
 
1040
 
 
1041
#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
 
1042
 
 
1043
  static void
 
1044
  ah_iup_shift( AH_Point  p1,
 
1045
                AH_Point  p2,
 
1046
                AH_Point  ref )
 
1047
  {
 
1048
    AH_Point  p;
 
1049
    FT_Pos    delta = ref->u - ref->v;
 
1050
 
 
1051
 
 
1052
    for ( p = p1; p < ref; p++ )
 
1053
      p->u = p->v + delta;
 
1054
 
 
1055
    for ( p = ref + 1; p <= p2; p++ )
 
1056
      p->u = p->v + delta;
 
1057
  }
 
1058
 
 
1059
 
 
1060
  static void
 
1061
  ah_iup_interp( AH_Point  p1,
 
1062
                 AH_Point  p2,
 
1063
                 AH_Point  ref1,
 
1064
                 AH_Point  ref2 )
 
1065
  {
 
1066
    AH_Point  p;
 
1067
    FT_Pos    u;
 
1068
    FT_Pos    v1 = ref1->v;
 
1069
    FT_Pos    v2 = ref2->v;
 
1070
    FT_Pos    d1 = ref1->u - v1;
 
1071
    FT_Pos    d2 = ref2->u - v2;
 
1072
 
 
1073
 
 
1074
    if ( p1 > p2 )
 
1075
      return;
 
1076
 
 
1077
    if ( v1 == v2 )
 
1078
    {
 
1079
      for ( p = p1; p <= p2; p++ )
 
1080
      {
 
1081
        u = p->v;
 
1082
 
 
1083
        if ( u <= v1 )
 
1084
          u += d1;
 
1085
        else
 
1086
          u += d2;
 
1087
 
 
1088
        p->u = u;
 
1089
      }
 
1090
      return;
 
1091
    }
 
1092
 
 
1093
    if ( v1 < v2 )
 
1094
    {
 
1095
      for ( p = p1; p <= p2; p++ )
 
1096
      {
 
1097
        u = p->v;
 
1098
 
 
1099
        if ( u <= v1 )
 
1100
          u += d1;
 
1101
        else if ( u >= v2 )
 
1102
          u += d2;
 
1103
        else
 
1104
          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
 
1105
 
 
1106
        p->u = u;
 
1107
      }
 
1108
    }
 
1109
    else
 
1110
    {
 
1111
      for ( p = p1; p <= p2; p++ )
 
1112
      {
 
1113
        u = p->v;
 
1114
 
 
1115
        if ( u <= v2 )
 
1116
          u += d2;
 
1117
        else if ( u >= v1 )
 
1118
          u += d1;
 
1119
        else
 
1120
          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
 
1121
 
 
1122
        p->u = u;
 
1123
      }
 
1124
    }
 
1125
  }
 
1126
 
 
1127
 
 
1128
  /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
 
1129
  /* hinting instruction                                                 */
 
1130
  static void
 
1131
  ah_hinter_align_weak_points( AH_Hinter  hinter )
 
1132
  {
 
1133
    AH_Outline  outline = hinter->glyph;
 
1134
    FT_Int      dimension;
 
1135
    AH_Point    points;
 
1136
    AH_Point    point_limit;
 
1137
    AH_Point*   contour_limit;
 
1138
    AH_Flags    touch_flag;
 
1139
 
 
1140
 
 
1141
    points      = outline->points;
 
1142
    point_limit = points + outline->num_points;
 
1143
 
 
1144
    /* PASS 1: Move segment points to edge positions */
 
1145
 
 
1146
    touch_flag = AH_FLAG_TOUCH_Y;
 
1147
 
 
1148
    contour_limit = outline->contours + outline->num_contours;
 
1149
 
 
1150
    ah_setup_uv( outline, AH_UV_OY );
 
1151
 
 
1152
    for ( dimension = 1; dimension >= 0; dimension-- )
 
1153
    {
 
1154
      AH_Point   point;
 
1155
      AH_Point   end_point;
 
1156
      AH_Point   first_point;
 
1157
      AH_Point*  contour;
 
1158
 
 
1159
 
 
1160
      point   = points;
 
1161
      contour = outline->contours;
 
1162
 
 
1163
      for ( ; contour < contour_limit; contour++ )
 
1164
      {
 
1165
        point       = *contour;
 
1166
        end_point   = point->prev;
 
1167
        first_point = point;
 
1168
 
 
1169
        while ( point <= end_point && !( point->flags & touch_flag ) )
 
1170
          point++;
 
1171
 
 
1172
        if ( point <= end_point )
 
1173
        {
 
1174
          AH_Point  first_touched = point;
 
1175
          AH_Point  cur_touched   = point;
 
1176
 
 
1177
 
 
1178
          point++;
 
1179
          while ( point <= end_point )
 
1180
          {
 
1181
            if ( point->flags & touch_flag )
 
1182
            {
 
1183
              /* we found two successive touched points; we interpolate */
 
1184
              /* all contour points between them                        */
 
1185
              ah_iup_interp( cur_touched + 1, point - 1,
 
1186
                             cur_touched, point );
 
1187
              cur_touched = point;
 
1188
            }
 
1189
            point++;
 
1190
          }
 
1191
 
 
1192
          if ( cur_touched == first_touched )
 
1193
          {
 
1194
            /* this is a special case: only one point was touched in the */
 
1195
            /* contour; we thus simply shift the whole contour           */
 
1196
            ah_iup_shift( first_point, end_point, cur_touched );
 
1197
          }
 
1198
          else
 
1199
          {
 
1200
            /* now interpolate after the last touched point to the end */
 
1201
            /* of the contour                                          */
 
1202
            ah_iup_interp( cur_touched + 1, end_point,
 
1203
                           cur_touched, first_touched );
 
1204
 
 
1205
            /* if the first contour point isn't touched, interpolate */
 
1206
            /* from the contour start to the first touched point     */
 
1207
            if ( first_touched > points )
 
1208
              ah_iup_interp( first_point, first_touched - 1,
 
1209
                             cur_touched, first_touched );
 
1210
          }
 
1211
        }
 
1212
      }
 
1213
 
 
1214
      /* now save the interpolated values back to x/y */
 
1215
      if ( dimension )
 
1216
      {
 
1217
        for ( point = points; point < point_limit; point++ )
 
1218
          point->y = point->u;
 
1219
 
 
1220
        touch_flag = AH_FLAG_TOUCH_X;
 
1221
        ah_setup_uv( outline, AH_UV_OX );
 
1222
      }
 
1223
      else
 
1224
      {
 
1225
        for ( point = points; point < point_limit; point++ )
 
1226
          point->x = point->u;
 
1227
 
 
1228
        break;  /* exit loop */
 
1229
      }
 
1230
    }
 
1231
  }
 
1232
 
 
1233
#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
 
1234
 
 
1235
 
 
1236
  FT_LOCAL_DEF( void )
 
1237
  ah_hinter_align_points( AH_Hinter  hinter )
 
1238
  {
 
1239
    ah_hinter_align_edge_points( hinter );
 
1240
 
 
1241
#ifndef AH_OPTION_NO_STRONG_INTERPOLATION
 
1242
    ah_hinter_align_strong_points( hinter );
 
1243
#endif
 
1244
 
 
1245
#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
 
1246
    ah_hinter_align_weak_points( hinter );
 
1247
#endif
 
1248
  }
 
1249
 
 
1250
 
 
1251
  /*************************************************************************/
 
1252
  /*************************************************************************/
 
1253
  /*************************************************************************/
 
1254
  /****                                                                 ****/
 
1255
  /****       H I N T E R   O B J E C T   M E T H O D S                 ****/
 
1256
  /****                                                                 ****/
 
1257
  /*************************************************************************/
 
1258
  /*************************************************************************/
 
1259
  /*************************************************************************/
 
1260
 
 
1261
 
 
1262
  /* scale and fit the global metrics */
 
1263
  static void
 
1264
  ah_hinter_scale_globals( AH_Hinter  hinter,
 
1265
                           FT_Fixed   x_scale,
 
1266
                           FT_Fixed   y_scale )
 
1267
  {
 
1268
    FT_Int           n;
 
1269
    AH_Face_Globals  globals = hinter->globals;
 
1270
    AH_Globals       design  = &globals->design;
 
1271
    AH_Globals       scaled  = &globals->scaled;
 
1272
 
 
1273
 
 
1274
    /* copy content */
 
1275
    *scaled = *design;
 
1276
 
 
1277
    /* scale the standard widths & heights */
 
1278
    for ( n = 0; n < design->num_widths; n++ )
 
1279
      scaled->widths[n] = FT_MulFix( design->widths[n], x_scale );
 
1280
 
 
1281
    for ( n = 0; n < design->num_heights; n++ )
 
1282
      scaled->heights[n] = FT_MulFix( design->heights[n], y_scale );
 
1283
 
 
1284
    scaled->stds[0] = ( design->num_widths  > 0 ) ? scaled->widths[0]  : 32000;
 
1285
    scaled->stds[1] = ( design->num_heights > 0 ) ? scaled->heights[0] : 32000;
 
1286
 
 
1287
    /* scale the blue zones */
 
1288
    for ( n = 0; n < AH_BLUE_MAX; n++ )
 
1289
    {
 
1290
      FT_Pos  delta, delta2;
 
1291
 
 
1292
 
 
1293
      delta = design->blue_shoots[n] - design->blue_refs[n];
 
1294
      delta2 = delta;
 
1295
      if ( delta < 0 )
 
1296
        delta2 = -delta2;
 
1297
      delta2 = FT_MulFix( delta2, y_scale );
 
1298
 
 
1299
      if ( delta2 < 32 )
 
1300
        delta2 = 0;
 
1301
      else if ( delta2 < 64 )
 
1302
        delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
 
1303
      else
 
1304
        delta2 = FT_PIX_ROUND( delta2 );
 
1305
 
 
1306
      if ( delta < 0 )
 
1307
        delta2 = -delta2;
 
1308
 
 
1309
      scaled->blue_refs[n] =
 
1310
        FT_PIX_ROUND( FT_MulFix( design->blue_refs[n], y_scale ) );
 
1311
 
 
1312
      scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2;
 
1313
    }
 
1314
 
 
1315
    globals->x_scale = x_scale;
 
1316
    globals->y_scale = y_scale;
 
1317
  }
 
1318
 
 
1319
 
 
1320
  static void
 
1321
  ah_hinter_align( AH_Hinter  hinter )
 
1322
  {
 
1323
    ah_hinter_align_edge_points( hinter );
 
1324
    ah_hinter_align_points( hinter );
 
1325
  }
 
1326
 
 
1327
 
 
1328
  /* finalize a hinter object */
 
1329
  FT_LOCAL_DEF( void )
 
1330
  ah_hinter_done( AH_Hinter  hinter )
 
1331
  {
 
1332
    if ( hinter )
 
1333
    {
 
1334
      FT_Memory  memory = hinter->memory;
 
1335
 
 
1336
 
 
1337
      ah_loader_done( hinter->loader );
 
1338
      ah_outline_done( hinter->glyph );
 
1339
 
 
1340
      /* note: the `globals' pointer is _not_ owned by the hinter */
 
1341
      /*       but by the current face object; we don't need to   */
 
1342
      /*       release it                                         */
 
1343
      hinter->globals = 0;
 
1344
      hinter->face    = 0;
 
1345
 
 
1346
      FT_FREE( hinter );
 
1347
    }
 
1348
  }
 
1349
 
 
1350
 
 
1351
  /* create a new empty hinter object */
 
1352
  FT_LOCAL_DEF( FT_Error )
 
1353
  ah_hinter_new( FT_Library  library,
 
1354
                 AH_Hinter  *ahinter )
 
1355
  {
 
1356
    AH_Hinter  hinter = 0;
 
1357
    FT_Memory  memory = library->memory;
 
1358
    FT_Error   error;
 
1359
 
 
1360
 
 
1361
    *ahinter = 0;
 
1362
 
 
1363
    /* allocate object */
 
1364
    if ( FT_NEW( hinter ) )
 
1365
      goto Exit;
 
1366
 
 
1367
    hinter->memory = memory;
 
1368
    hinter->flags  = 0;
 
1369
 
 
1370
    /* allocate outline and loader */
 
1371
    error = ah_outline_new( memory, &hinter->glyph )  ||
 
1372
            ah_loader_new ( memory, &hinter->loader ) ||
 
1373
            ah_loader_create_extra( hinter->loader );
 
1374
    if ( error )
 
1375
      goto Exit;
 
1376
 
 
1377
    *ahinter = hinter;
 
1378
 
 
1379
  Exit:
 
1380
    if ( error )
 
1381
      ah_hinter_done( hinter );
 
1382
 
 
1383
    return error;
 
1384
  }
 
1385
 
 
1386
 
 
1387
  /* create a face's autohint globals */
 
1388
  FT_LOCAL_DEF( FT_Error )
 
1389
  ah_hinter_new_face_globals( AH_Hinter   hinter,
 
1390
                              FT_Face     face,
 
1391
                              AH_Globals  globals )
 
1392
  {
 
1393
    FT_Error         error;
 
1394
    FT_Memory        memory = hinter->memory;
 
1395
    AH_Face_Globals  face_globals;
 
1396
 
 
1397
 
 
1398
    if ( FT_NEW( face_globals ) )
 
1399
      goto Exit;
 
1400
 
 
1401
    hinter->face    = face;
 
1402
    hinter->globals = face_globals;
 
1403
 
 
1404
    if ( globals )
 
1405
      face_globals->design = *globals;
 
1406
    else
 
1407
      ah_hinter_compute_globals( hinter );
 
1408
 
 
1409
    face->autohint.data      = face_globals;
 
1410
    face->autohint.finalizer = (FT_Generic_Finalizer)
 
1411
                                 ah_hinter_done_face_globals;
 
1412
    face_globals->face       = face;
 
1413
 
 
1414
  Exit:
 
1415
    return error;
 
1416
  }
 
1417
 
 
1418
 
 
1419
  /* discard a face's autohint globals */
 
1420
  FT_LOCAL_DEF( void )
 
1421
  ah_hinter_done_face_globals( AH_Face_Globals  globals )
 
1422
  {
 
1423
    FT_Face    face   = globals->face;
 
1424
    FT_Memory  memory = face->memory;
 
1425
 
 
1426
 
 
1427
    FT_FREE( globals );
 
1428
  }
 
1429
 
 
1430
 
 
1431
  static FT_Error
 
1432
  ah_hinter_load( AH_Hinter  hinter,
 
1433
                  FT_UInt    glyph_index,
 
1434
                  FT_Int32   load_flags,
 
1435
                  FT_UInt    depth )
 
1436
  {
 
1437
    FT_Face           face     = hinter->face;
 
1438
    FT_GlyphSlot      slot     = face->glyph;
 
1439
    FT_Slot_Internal  internal = slot->internal;
 
1440
    FT_Fixed          x_scale  = hinter->globals->x_scale;
 
1441
    FT_Fixed          y_scale  = hinter->globals->y_scale;
 
1442
    FT_Error          error;
 
1443
    AH_Outline        outline  = hinter->glyph;
 
1444
    AH_Loader         gloader  = hinter->loader;
 
1445
 
 
1446
 
 
1447
    /* load the glyph */
 
1448
    error = FT_Load_Glyph( face, glyph_index, load_flags );
 
1449
    if ( error )
 
1450
      goto Exit;
 
1451
 
 
1452
    /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
 
1453
    hinter->transformed = internal->glyph_transformed;
 
1454
 
 
1455
    if ( hinter->transformed )
 
1456
    {
 
1457
      FT_Matrix  imatrix;
 
1458
 
 
1459
 
 
1460
      imatrix              = internal->glyph_matrix;
 
1461
      hinter->trans_delta  = internal->glyph_delta;
 
1462
      hinter->trans_matrix = imatrix;
 
1463
 
 
1464
      FT_Matrix_Invert( &imatrix );
 
1465
      FT_Vector_Transform( &hinter->trans_delta, &imatrix );
 
1466
    }
 
1467
 
 
1468
    /* set linear horizontal metrics */
 
1469
    slot->linearHoriAdvance = slot->metrics.horiAdvance;
 
1470
    slot->linearVertAdvance = slot->metrics.vertAdvance;
 
1471
 
 
1472
    switch ( slot->format )
 
1473
    {
 
1474
    case FT_GLYPH_FORMAT_OUTLINE:
 
1475
 
 
1476
      /* translate glyph outline if we need to */
 
1477
      if ( hinter->transformed )
 
1478
      {
 
1479
        FT_UInt     n     = slot->outline.n_points;
 
1480
        FT_Vector*  point = slot->outline.points;
 
1481
 
 
1482
 
 
1483
        for ( ; n > 0; point++, n-- )
 
1484
        {
 
1485
          point->x += hinter->trans_delta.x;
 
1486
          point->y += hinter->trans_delta.y;
 
1487
        }
 
1488
      }
 
1489
 
 
1490
      /* copy the outline points in the loader's current               */
 
1491
      /* extra points which is used to keep original glyph coordinates */
 
1492
      error = ah_loader_check_points( gloader, slot->outline.n_points + 4,
 
1493
                                      slot->outline.n_contours );
 
1494
      if ( error )
 
1495
        goto Exit;
 
1496
 
 
1497
      FT_ARRAY_COPY( gloader->current.extra_points, slot->outline.points,
 
1498
                     slot->outline.n_points );
 
1499
 
 
1500
      FT_ARRAY_COPY( gloader->current.outline.contours, slot->outline.contours,
 
1501
                     slot->outline.n_contours );
 
1502
 
 
1503
      FT_ARRAY_COPY( gloader->current.outline.tags, slot->outline.tags,
 
1504
                     slot->outline.n_points );
 
1505
 
 
1506
      gloader->current.outline.n_points   = slot->outline.n_points;
 
1507
      gloader->current.outline.n_contours = slot->outline.n_contours;
 
1508
 
 
1509
      /* compute original horizontal phantom points, ignoring vertical ones */
 
1510
      hinter->pp1.x = 0;
 
1511
      hinter->pp1.y = 0;
 
1512
      hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
 
1513
      hinter->pp2.y = 0;
 
1514
 
 
1515
      /* be sure to check for spacing glyphs */
 
1516
      if ( slot->outline.n_points == 0 )
 
1517
        goto Hint_Metrics;
 
1518
 
 
1519
      /* now load the slot image into the auto-outline and run the */
 
1520
      /* automatic hinting process                                 */
 
1521
      error = ah_outline_load( outline, x_scale, y_scale, face );
 
1522
      if ( error )
 
1523
        goto Exit;
 
1524
 
 
1525
      /* perform feature detection */
 
1526
      ah_outline_detect_features( outline );
 
1527
 
 
1528
      if ( hinter->do_vert_hints )
 
1529
      {
 
1530
        ah_outline_compute_blue_edges( outline, hinter->globals );
 
1531
        ah_outline_scale_blue_edges( outline, hinter->globals );
 
1532
      }
 
1533
 
 
1534
      /* perform alignment control */
 
1535
      ah_hinter_hint_edges( hinter );
 
1536
      ah_hinter_align( hinter );
 
1537
 
 
1538
      /* now save the current outline into the loader's current table */
 
1539
      ah_outline_save( outline, gloader );
 
1540
 
 
1541
      /* we now need to hint the metrics according to the change in */
 
1542
      /* width/positioning that occured during the hinting process  */
 
1543
      if ( outline->num_vedges > 0 )
 
1544
      {
 
1545
        FT_Pos   old_advance, old_rsb, old_lsb, new_lsb, pp1x_uh, pp2x_uh;
 
1546
        AH_Edge  edge1 = outline->vert_edges;     /* leftmost edge  */
 
1547
        AH_Edge  edge2 = edge1 +
 
1548
                         outline->num_vedges - 1; /* rightmost edge */
 
1549
 
 
1550
 
 
1551
        old_advance = hinter->pp2.x;
 
1552
        old_rsb     = old_advance - edge2->opos;
 
1553
        old_lsb     = edge1->opos;
 
1554
        new_lsb     = edge1->pos;
 
1555
 
 
1556
        /* remember unhinted values to later account for rounding errors */
 
1557
 
 
1558
        pp1x_uh = new_lsb    - old_lsb;
 
1559
        pp2x_uh = edge2->pos + old_rsb;
 
1560
 
 
1561
        /* prefer too much space over too little space for very small sizes */
 
1562
 
 
1563
        if ( old_lsb < 24 )
 
1564
          pp1x_uh -= 5;
 
1565
 
 
1566
        if ( old_rsb < 24 )
 
1567
          pp2x_uh += 5;
 
1568
 
 
1569
        hinter->pp1.x = FT_PIX_ROUND( pp1x_uh );
 
1570
        hinter->pp2.x = FT_PIX_ROUND( pp2x_uh );
 
1571
 
 
1572
        slot->lsb_delta = hinter->pp1.x - pp1x_uh;
 
1573
        slot->rsb_delta = hinter->pp2.x - pp2x_uh;
 
1574
 
 
1575
#if 0
 
1576
        /* try to fix certain bad advance computations */
 
1577
        if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
 
1578
          hinter->pp2.x += 64;
 
1579
#endif
 
1580
      }
 
1581
 
 
1582
      else
 
1583
      {
 
1584
        hinter->pp1.x = ( hinter->pp1.x + 32 ) & -64;
 
1585
        hinter->pp2.x = ( hinter->pp2.x + 32 ) & -64;
 
1586
      }
 
1587
 
 
1588
      /* good, we simply add the glyph to our loader's base */
 
1589
      ah_loader_add( gloader );
 
1590
      break;
 
1591
 
 
1592
    case FT_GLYPH_FORMAT_COMPOSITE:
 
1593
      {
 
1594
        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
 
1595
        FT_UInt      num_base_subgs, start_point;
 
1596
        FT_SubGlyph  subglyph;
 
1597
 
 
1598
 
 
1599
        start_point = gloader->base.outline.n_points;
 
1600
 
 
1601
        /* first of all, copy the subglyph descriptors in the glyph loader */
 
1602
        error = ah_loader_check_subglyphs( gloader, num_subglyphs );
 
1603
        if ( error )
 
1604
          goto Exit;
 
1605
 
 
1606
        FT_ARRAY_COPY( gloader->current.subglyphs, slot->subglyphs,
 
1607
                       num_subglyphs );
 
1608
 
 
1609
        gloader->current.num_subglyphs = num_subglyphs;
 
1610
        num_base_subgs = gloader->base.num_subglyphs;
 
1611
 
 
1612
        /* now, read each subglyph independently */
 
1613
        for ( nn = 0; nn < num_subglyphs; nn++ )
 
1614
        {
 
1615
          FT_Vector  pp1, pp2;
 
1616
          FT_Pos     x, y;
 
1617
          FT_UInt    num_points, num_new_points, num_base_points;
 
1618
 
 
1619
 
 
1620
          /* gloader.current.subglyphs can change during glyph loading due */
 
1621
          /* to re-allocation -- we must recompute the current subglyph on */
 
1622
          /* each iteration                                                */
 
1623
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
 
1624
 
 
1625
          pp1 = hinter->pp1;
 
1626
          pp2 = hinter->pp2;
 
1627
 
 
1628
          num_base_points = gloader->base.outline.n_points;
 
1629
 
 
1630
          error = ah_hinter_load( hinter, subglyph->index,
 
1631
                                  load_flags, depth + 1 );
 
1632
          if ( error )
 
1633
            goto Exit;
 
1634
 
 
1635
          /* recompute subglyph pointer */
 
1636
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
 
1637
 
 
1638
          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
 
1639
          {
 
1640
            pp1 = hinter->pp1;
 
1641
            pp2 = hinter->pp2;
 
1642
          }
 
1643
          else
 
1644
          {
 
1645
            hinter->pp1 = pp1;
 
1646
            hinter->pp2 = pp2;
 
1647
          }
 
1648
 
 
1649
          num_points     = gloader->base.outline.n_points;
 
1650
          num_new_points = num_points - num_base_points;
 
1651
 
 
1652
          /* now perform the transform required for this subglyph */
 
1653
 
 
1654
          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
 
1655
                                   FT_SUBGLYPH_FLAG_XY_SCALE |
 
1656
                                   FT_SUBGLYPH_FLAG_2X2      ) )
 
1657
          {
 
1658
            FT_Vector*  cur   = gloader->base.outline.points +
 
1659
                                num_base_points;
 
1660
            FT_Vector*  org   = gloader->base.extra_points +
 
1661
                                num_base_points;
 
1662
            FT_Vector*  limit = cur + num_new_points;
 
1663
 
 
1664
 
 
1665
            for ( ; cur < limit; cur++, org++ )
 
1666
            {
 
1667
              FT_Vector_Transform( cur, &subglyph->transform );
 
1668
              FT_Vector_Transform( org, &subglyph->transform );
 
1669
            }
 
1670
          }
 
1671
 
 
1672
          /* apply offset */
 
1673
 
 
1674
          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
 
1675
          {
 
1676
            FT_Int      k = subglyph->arg1;
 
1677
            FT_UInt     l = subglyph->arg2;
 
1678
            FT_Vector*  p1;
 
1679
            FT_Vector*  p2;
 
1680
 
 
1681
 
 
1682
            if ( start_point + k >= num_base_points         ||
 
1683
                               l >= (FT_UInt)num_new_points )
 
1684
            {
 
1685
              error = AH_Err_Invalid_Composite;
 
1686
              goto Exit;
 
1687
            }
 
1688
 
 
1689
            l += num_base_points;
 
1690
 
 
1691
            /* for now, only use the current point coordinates;    */
 
1692
            /* we may consider another approach in the near future */
 
1693
            p1 = gloader->base.outline.points + start_point + k;
 
1694
            p2 = gloader->base.outline.points + start_point + l;
 
1695
 
 
1696
            x = p1->x - p2->x;
 
1697
            y = p1->y - p2->y;
 
1698
          }
 
1699
          else
 
1700
          {
 
1701
            x = FT_MulFix( subglyph->arg1, x_scale );
 
1702
            y = FT_MulFix( subglyph->arg2, y_scale );
 
1703
 
 
1704
            x = FT_PIX_ROUND(x);
 
1705
            y = FT_PIX_ROUND(y);
 
1706
          }
 
1707
 
 
1708
          {
 
1709
            FT_Outline  dummy = gloader->base.outline;
 
1710
 
 
1711
 
 
1712
            dummy.points  += num_base_points;
 
1713
            dummy.n_points = (short)num_new_points;
 
1714
 
 
1715
            FT_Outline_Translate( &dummy, x, y );
 
1716
          }
 
1717
        }
 
1718
      }
 
1719
      break;
 
1720
 
 
1721
    default:
 
1722
      /* we don't support other formats (yet?) */
 
1723
      error = AH_Err_Unimplemented_Feature;
 
1724
    }
 
1725
 
 
1726
  Hint_Metrics:
 
1727
    if ( depth == 0 )
 
1728
    {
 
1729
      FT_BBox  bbox;
 
1730
 
 
1731
 
 
1732
      /* transform the hinted outline if needed */
 
1733
      if ( hinter->transformed )
 
1734
        FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
 
1735
 
 
1736
      /* we must translate our final outline by -pp1.x and compute */
 
1737
      /* the new metrics                                           */
 
1738
      if ( hinter->pp1.x )
 
1739
        FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
 
1740
 
 
1741
      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
 
1742
      bbox.xMin  = FT_PIX_FLOOR(  bbox.xMin );
 
1743
      bbox.yMin  = FT_PIX_FLOOR(  bbox.yMin );
 
1744
      bbox.xMax  = FT_PIX_CEIL( bbox.xMax );
 
1745
      bbox.yMax  = FT_PIX_CEIL( bbox.yMax );
 
1746
 
 
1747
      slot->metrics.width        = bbox.xMax - bbox.xMin;
 
1748
      slot->metrics.height       = bbox.yMax - bbox.yMin;
 
1749
      slot->metrics.horiBearingX = bbox.xMin;
 
1750
      slot->metrics.horiBearingY = bbox.yMax;
 
1751
 
 
1752
      /* for mono-width fonts (like Andale, Courier, etc.) we need */
 
1753
      /* to keep the original rounded advance width                */
 
1754
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
 
1755
        slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
 
1756
      else
 
1757
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
 
1758
                                               x_scale );
 
1759
 
 
1760
      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
 
1761
 
 
1762
      /* now copy outline into glyph slot */
 
1763
      ah_loader_rewind( slot->internal->loader );
 
1764
      error = ah_loader_copy_points( slot->internal->loader, gloader );
 
1765
      if ( error )
 
1766
        goto Exit;
 
1767
 
 
1768
      slot->outline = slot->internal->loader->base.outline;
 
1769
      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
 
1770
    }
 
1771
 
 
1772
#ifdef DEBUG_HINTER
 
1773
    ah_debug_hinter = hinter;
 
1774
#endif
 
1775
 
 
1776
  Exit:
 
1777
    return error;
 
1778
  }
 
1779
 
 
1780
 
 
1781
  /* load and hint a given glyph */
 
1782
  FT_LOCAL_DEF( FT_Error )
 
1783
  ah_hinter_load_glyph( AH_Hinter     hinter,
 
1784
                        FT_GlyphSlot  slot,
 
1785
                        FT_Size       size,
 
1786
                        FT_UInt       glyph_index,
 
1787
                        FT_Int32      load_flags )
 
1788
  {
 
1789
    FT_Face          face         = slot->face;
 
1790
    FT_Error         error;
 
1791
    FT_Fixed         x_scale      = size->metrics.x_scale;
 
1792
    FT_Fixed         y_scale      = size->metrics.y_scale;
 
1793
    AH_Face_Globals  face_globals = FACE_GLOBALS( face );
 
1794
    FT_Render_Mode   hint_mode    = FT_LOAD_TARGET_MODE( load_flags );
 
1795
 
 
1796
 
 
1797
    /* first of all, we need to check that we're using the correct face and */
 
1798
    /* global hints to load the glyph                                       */
 
1799
    if ( hinter->face != face || hinter->globals != face_globals )
 
1800
    {
 
1801
      hinter->face = face;
 
1802
      if ( !face_globals )
 
1803
      {
 
1804
        error = ah_hinter_new_face_globals( hinter, face, 0 );
 
1805
        if ( error )
 
1806
          goto Exit;
 
1807
 
 
1808
      }
 
1809
      hinter->globals = FACE_GLOBALS( face );
 
1810
      face_globals    = FACE_GLOBALS( face );
 
1811
 
 
1812
    }
 
1813
 
 
1814
#ifdef FT_CONFIG_CHESTER_BLUE_SCALE
 
1815
 
 
1816
   /* try to optimize the y_scale so that the top of non-capital letters
 
1817
    * is aligned on a pixel boundary whenever possible
 
1818
    */
 
1819
    {
 
1820
      AH_Globals  design = &face_globals->design;
 
1821
      FT_Pos      shoot  = design->blue_shoots[AH_BLUE_SMALL_TOP];
 
1822
 
 
1823
 
 
1824
      /* the value of 'shoot' will be -1000 if the font doesn't have */
 
1825
      /* small latin letters; we simply check the sign here...       */
 
1826
      if ( shoot > 0 )
 
1827
      {
 
1828
        FT_Pos  scaled = FT_MulFix( shoot, y_scale );
 
1829
        FT_Pos  fitted = FT_PIX_ROUND( scaled );
 
1830
 
 
1831
 
 
1832
        if ( scaled != fitted )
 
1833
        {
 
1834
         /* adjust y_scale
 
1835
          */
 
1836
          y_scale = FT_MulDiv( y_scale, fitted, scaled );
 
1837
 
 
1838
         /* adust x_scale
 
1839
          */
 
1840
          if ( fitted < scaled )
 
1841
            x_scale -= x_scale / 50;  /* x_scale*0.98 with integers */
 
1842
        }
 
1843
      }
 
1844
    }
 
1845
 
 
1846
#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */
 
1847
 
 
1848
    /* now, we must check the current character pixel size to see if we */
 
1849
    /* need to rescale the global metrics                               */
 
1850
    if ( face_globals->x_scale != x_scale ||
 
1851
         face_globals->y_scale != y_scale )
 
1852
      ah_hinter_scale_globals( hinter, x_scale, y_scale );
 
1853
 
 
1854
    ah_loader_rewind( hinter->loader );
 
1855
 
 
1856
    /* reset hinting flags according to load flags and current render target */
 
1857
    hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
 
1858
    hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
 
1859
 
 
1860
#ifdef DEBUG_HINTER
 
1861
    hinter->do_horz_hints = !ah_debug_disable_vert;  /* not a bug, the meaning */
 
1862
    hinter->do_vert_hints = !ah_debug_disable_horz;  /* of h/v is inverted!    */
 
1863
#endif
 
1864
 
 
1865
    /* we snap the width of vertical stems for the monochrome and         */
 
1866
    /* horizontal LCD rendering targets only.  Corresponds to X snapping. */
 
1867
    hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
 
1868
                                        hint_mode == FT_RENDER_MODE_LCD  );
 
1869
 
 
1870
    /* we snap the width of horizontal stems for the monochrome and     */
 
1871
    /* vertical LCD rendering targets only.  Corresponds to Y snapping. */
 
1872
    hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO   ||
 
1873
                                        hint_mode == FT_RENDER_MODE_LCD_V  );
 
1874
 
 
1875
    hinter->do_stem_adjust   = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
 
1876
 
 
1877
    load_flags |= FT_LOAD_NO_SCALE
 
1878
                | FT_LOAD_IGNORE_TRANSFORM;
 
1879
    load_flags &= ~FT_LOAD_RENDER;
 
1880
 
 
1881
    error = ah_hinter_load( hinter, glyph_index, load_flags, 0 );
 
1882
 
 
1883
  Exit:
 
1884
    return error;
 
1885
  }
 
1886
 
 
1887
 
 
1888
  /* retrieve a face's autohint globals for client applications */
 
1889
  FT_LOCAL_DEF( void )
 
1890
  ah_hinter_get_global_hints( AH_Hinter  hinter,
 
1891
                              FT_Face    face,
 
1892
                              void**     global_hints,
 
1893
                              long*      global_len )
 
1894
  {
 
1895
    AH_Globals  globals = 0;
 
1896
    FT_Memory   memory  = hinter->memory;
 
1897
    FT_Error    error;
 
1898
 
 
1899
 
 
1900
    /* allocate new master globals */
 
1901
    if ( FT_NEW( globals ) )
 
1902
      goto Fail;
 
1903
 
 
1904
    /* compute face globals if needed */
 
1905
    if ( !FACE_GLOBALS( face ) )
 
1906
    {
 
1907
      error = ah_hinter_new_face_globals( hinter, face, 0 );
 
1908
      if ( error )
 
1909
        goto Fail;
 
1910
    }
 
1911
 
 
1912
    *globals      = FACE_GLOBALS( face )->design;
 
1913
    *global_hints = globals;
 
1914
    *global_len   = sizeof( *globals );
 
1915
 
 
1916
    return;
 
1917
 
 
1918
  Fail:
 
1919
    FT_FREE( globals );
 
1920
 
 
1921
    *global_hints = 0;
 
1922
    *global_len   = 0;
 
1923
  }
 
1924
 
 
1925
 
 
1926
  FT_LOCAL_DEF( void )
 
1927
  ah_hinter_done_global_hints( AH_Hinter  hinter,
 
1928
                               void*      global_hints )
 
1929
  {
 
1930
    FT_Memory  memory = hinter->memory;
 
1931
 
 
1932
 
 
1933
    FT_FREE( global_hints );
 
1934
  }
 
1935
 
 
1936
 
 
1937
/* END */