xref: /inferno-os/libfreetype/ahhint.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth /***************************************************************************/
2*37da2899SCharles.Forsyth /*                                                                         */
3*37da2899SCharles.Forsyth /*  ahhint.c                                                               */
4*37da2899SCharles.Forsyth /*                                                                         */
5*37da2899SCharles.Forsyth /*    Glyph hinter (body).                                                 */
6*37da2899SCharles.Forsyth /*                                                                         */
7*37da2899SCharles.Forsyth /*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
8*37da2899SCharles.Forsyth /*  Author: David Turner                                                   */
9*37da2899SCharles.Forsyth /*                                                                         */
10*37da2899SCharles.Forsyth /*  This file is part of the Catharon Typography Project and shall only    */
11*37da2899SCharles.Forsyth /*  be used, modified, and distributed under the terms of the Catharon     */
12*37da2899SCharles.Forsyth /*  Open Source License that should come with this file under the name     */
13*37da2899SCharles.Forsyth /*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
14*37da2899SCharles.Forsyth /*  this file you indicate that you have read the license and              */
15*37da2899SCharles.Forsyth /*  understand and accept it fully.                                        */
16*37da2899SCharles.Forsyth /*                                                                         */
17*37da2899SCharles.Forsyth /*  Note that this license is compatible with the FreeType license.        */
18*37da2899SCharles.Forsyth /*                                                                         */
19*37da2899SCharles.Forsyth /***************************************************************************/
20*37da2899SCharles.Forsyth 
21*37da2899SCharles.Forsyth 
22*37da2899SCharles.Forsyth #include <ft2build.h>
23*37da2899SCharles.Forsyth #include "ahhint.h"
24*37da2899SCharles.Forsyth #include "ahglyph.h"
25*37da2899SCharles.Forsyth #include "ahangles.h"
26*37da2899SCharles.Forsyth #include "aherrors.h"
27*37da2899SCharles.Forsyth #include FT_OUTLINE_H
28*37da2899SCharles.Forsyth 
29*37da2899SCharles.Forsyth 
30*37da2899SCharles.Forsyth #define FACE_GLOBALS( face )  ((AH_Face_Globals)(face)->autohint.data)
31*37da2899SCharles.Forsyth 
32*37da2899SCharles.Forsyth #define AH_USE_IUP
33*37da2899SCharles.Forsyth #define OPTIM_STEM_SNAP
34*37da2899SCharles.Forsyth 
35*37da2899SCharles.Forsyth   /*************************************************************************/
36*37da2899SCharles.Forsyth   /*************************************************************************/
37*37da2899SCharles.Forsyth   /****                                                                 ****/
38*37da2899SCharles.Forsyth   /****   Hinting routines                                              ****/
39*37da2899SCharles.Forsyth   /****                                                                 ****/
40*37da2899SCharles.Forsyth   /*************************************************************************/
41*37da2899SCharles.Forsyth   /*************************************************************************/
42*37da2899SCharles.Forsyth 
43*37da2899SCharles.Forsyth   /* snap a given width in scaled coordinates to one of the */
44*37da2899SCharles.Forsyth   /* current standard widths                                */
45*37da2899SCharles.Forsyth   static FT_Pos
ah_snap_width(FT_Pos * widths,FT_Int count,FT_Pos width)46*37da2899SCharles.Forsyth   ah_snap_width( FT_Pos*  widths,
47*37da2899SCharles.Forsyth                  FT_Int   count,
48*37da2899SCharles.Forsyth                  FT_Pos   width )
49*37da2899SCharles.Forsyth   {
50*37da2899SCharles.Forsyth     int     n;
51*37da2899SCharles.Forsyth     FT_Pos  best      = 64 + 32 + 2;
52*37da2899SCharles.Forsyth     FT_Pos  reference = width;
53*37da2899SCharles.Forsyth     FT_Pos  scaled;
54*37da2899SCharles.Forsyth 
55*37da2899SCharles.Forsyth 
56*37da2899SCharles.Forsyth     for ( n = 0; n < count; n++ )
57*37da2899SCharles.Forsyth     {
58*37da2899SCharles.Forsyth       FT_Pos  w;
59*37da2899SCharles.Forsyth       FT_Pos  dist;
60*37da2899SCharles.Forsyth 
61*37da2899SCharles.Forsyth 
62*37da2899SCharles.Forsyth       w = widths[n];
63*37da2899SCharles.Forsyth       dist = width - w;
64*37da2899SCharles.Forsyth       if ( dist < 0 )
65*37da2899SCharles.Forsyth         dist = -dist;
66*37da2899SCharles.Forsyth       if ( dist < best )
67*37da2899SCharles.Forsyth       {
68*37da2899SCharles.Forsyth         best      = dist;
69*37da2899SCharles.Forsyth         reference = w;
70*37da2899SCharles.Forsyth       }
71*37da2899SCharles.Forsyth     }
72*37da2899SCharles.Forsyth 
73*37da2899SCharles.Forsyth     scaled = (reference+32) & -64;
74*37da2899SCharles.Forsyth 
75*37da2899SCharles.Forsyth     if ( width >= reference )
76*37da2899SCharles.Forsyth     {
77*37da2899SCharles.Forsyth       if ( width < scaled + 48 )
78*37da2899SCharles.Forsyth         width = reference;
79*37da2899SCharles.Forsyth     }
80*37da2899SCharles.Forsyth     else
81*37da2899SCharles.Forsyth     {
82*37da2899SCharles.Forsyth       if ( width > scaled - 48 )
83*37da2899SCharles.Forsyth         width = reference;
84*37da2899SCharles.Forsyth     }
85*37da2899SCharles.Forsyth 
86*37da2899SCharles.Forsyth     return width;
87*37da2899SCharles.Forsyth   }
88*37da2899SCharles.Forsyth 
89*37da2899SCharles.Forsyth 
90*37da2899SCharles.Forsyth   /* compute the snapped width of a given stem */
91*37da2899SCharles.Forsyth   static FT_Pos
ah_compute_stem_width(AH_Hinter hinter,int vertical,FT_Pos width)92*37da2899SCharles.Forsyth   ah_compute_stem_width( AH_Hinter  hinter,
93*37da2899SCharles.Forsyth                          int        vertical,
94*37da2899SCharles.Forsyth                          FT_Pos     width )
95*37da2899SCharles.Forsyth   {
96*37da2899SCharles.Forsyth     AH_Globals  globals = &hinter->globals->scaled;
97*37da2899SCharles.Forsyth     FT_Pos      dist    = width;
98*37da2899SCharles.Forsyth     FT_Int      sign    = 0;
99*37da2899SCharles.Forsyth 
100*37da2899SCharles.Forsyth 
101*37da2899SCharles.Forsyth     if ( dist < 0 )
102*37da2899SCharles.Forsyth     {
103*37da2899SCharles.Forsyth       dist = -width;
104*37da2899SCharles.Forsyth       sign = 1;
105*37da2899SCharles.Forsyth     }
106*37da2899SCharles.Forsyth 
107*37da2899SCharles.Forsyth     if ( (  vertical && !hinter->do_vert_snapping ) ||
108*37da2899SCharles.Forsyth          ( !vertical && !hinter->do_horz_snapping ) )
109*37da2899SCharles.Forsyth     {
110*37da2899SCharles.Forsyth       /* smooth hinting process, very lightly quantize the stem width */
111*37da2899SCharles.Forsyth       /*                                                              */
112*37da2899SCharles.Forsyth       if ( dist < 64 )
113*37da2899SCharles.Forsyth         dist = 64;
114*37da2899SCharles.Forsyth 
115*37da2899SCharles.Forsyth       {
116*37da2899SCharles.Forsyth         FT_Pos  delta = dist - globals->stds[vertical];
117*37da2899SCharles.Forsyth 
118*37da2899SCharles.Forsyth 
119*37da2899SCharles.Forsyth         if ( delta < 0 )
120*37da2899SCharles.Forsyth           delta = -delta;
121*37da2899SCharles.Forsyth 
122*37da2899SCharles.Forsyth         if ( delta < 40 )
123*37da2899SCharles.Forsyth         {
124*37da2899SCharles.Forsyth           dist = globals->stds[vertical];
125*37da2899SCharles.Forsyth           if ( dist < 48 )
126*37da2899SCharles.Forsyth             dist = 48;
127*37da2899SCharles.Forsyth         }
128*37da2899SCharles.Forsyth 
129*37da2899SCharles.Forsyth         if ( dist < 3 * 64 )
130*37da2899SCharles.Forsyth         {
131*37da2899SCharles.Forsyth           delta = ( dist & 63 );
132*37da2899SCharles.Forsyth           dist &= -64;
133*37da2899SCharles.Forsyth 
134*37da2899SCharles.Forsyth           if ( delta < 10 )
135*37da2899SCharles.Forsyth             dist += delta;
136*37da2899SCharles.Forsyth 
137*37da2899SCharles.Forsyth           else if ( delta < 32 )
138*37da2899SCharles.Forsyth             dist += 10;
139*37da2899SCharles.Forsyth 
140*37da2899SCharles.Forsyth           else if ( delta < 54 )
141*37da2899SCharles.Forsyth             dist += 54;
142*37da2899SCharles.Forsyth 
143*37da2899SCharles.Forsyth           else
144*37da2899SCharles.Forsyth             dist += delta;
145*37da2899SCharles.Forsyth         }
146*37da2899SCharles.Forsyth         else
147*37da2899SCharles.Forsyth           dist = ( dist + 32 ) & -64;
148*37da2899SCharles.Forsyth       }
149*37da2899SCharles.Forsyth     }
150*37da2899SCharles.Forsyth     else
151*37da2899SCharles.Forsyth     {
152*37da2899SCharles.Forsyth       /* strong hinting process, snap the stem width to integer pixels */
153*37da2899SCharles.Forsyth       /*                                                               */
154*37da2899SCharles.Forsyth       if ( vertical )
155*37da2899SCharles.Forsyth       {
156*37da2899SCharles.Forsyth         dist = ah_snap_width( globals->heights, globals->num_heights, dist );
157*37da2899SCharles.Forsyth 
158*37da2899SCharles.Forsyth         /* in the case of vertical hinting, always round */
159*37da2899SCharles.Forsyth         /* the stem heights to integer pixels            */
160*37da2899SCharles.Forsyth         if ( dist >= 64 )
161*37da2899SCharles.Forsyth           dist = ( dist + 16 ) & -64;
162*37da2899SCharles.Forsyth         else
163*37da2899SCharles.Forsyth           dist = 64;
164*37da2899SCharles.Forsyth       }
165*37da2899SCharles.Forsyth       else
166*37da2899SCharles.Forsyth       {
167*37da2899SCharles.Forsyth         dist = ah_snap_width( globals->widths,  globals->num_widths, dist );
168*37da2899SCharles.Forsyth 
169*37da2899SCharles.Forsyth         if ( hinter->flags & AH_HINTER_MONOCHROME )
170*37da2899SCharles.Forsyth         {
171*37da2899SCharles.Forsyth           /* monochrome horizontal hinting: snap widths to integer pixels */
172*37da2899SCharles.Forsyth           /* with a different threshold                                   */
173*37da2899SCharles.Forsyth           if ( dist < 64 )
174*37da2899SCharles.Forsyth             dist = 64;
175*37da2899SCharles.Forsyth           else
176*37da2899SCharles.Forsyth             dist = ( dist + 32 ) & -64;
177*37da2899SCharles.Forsyth         }
178*37da2899SCharles.Forsyth         else
179*37da2899SCharles.Forsyth         {
180*37da2899SCharles.Forsyth           /* for horizontal anti-aliased hinting, we adopt a more subtle */
181*37da2899SCharles.Forsyth           /* approach: we strengthen small stems, round stems whose size */
182*37da2899SCharles.Forsyth           /* is between 1 and 2 pixels to an integer, otherwise nothing  */
183*37da2899SCharles.Forsyth           if ( dist < 48 )
184*37da2899SCharles.Forsyth             dist = ( dist + 64 ) >> 1;
185*37da2899SCharles.Forsyth 
186*37da2899SCharles.Forsyth           else if ( dist < 128 )
187*37da2899SCharles.Forsyth             dist = ( dist + 22 ) & -64;
188*37da2899SCharles.Forsyth           else
189*37da2899SCharles.Forsyth             /* XXX: round otherwise, prevent color fringes in LCD mode */
190*37da2899SCharles.Forsyth             dist = ( dist + 32 ) & -64;
191*37da2899SCharles.Forsyth         }
192*37da2899SCharles.Forsyth       }
193*37da2899SCharles.Forsyth     }
194*37da2899SCharles.Forsyth 
195*37da2899SCharles.Forsyth     if ( sign )
196*37da2899SCharles.Forsyth       dist = -dist;
197*37da2899SCharles.Forsyth 
198*37da2899SCharles.Forsyth     return dist;
199*37da2899SCharles.Forsyth   }
200*37da2899SCharles.Forsyth 
201*37da2899SCharles.Forsyth 
202*37da2899SCharles.Forsyth   /* align one stem edge relative to the previous stem edge */
203*37da2899SCharles.Forsyth   static void
ah_align_linked_edge(AH_Hinter hinter,AH_Edge base_edge,AH_Edge stem_edge,int vertical)204*37da2899SCharles.Forsyth   ah_align_linked_edge( AH_Hinter  hinter,
205*37da2899SCharles.Forsyth                         AH_Edge    base_edge,
206*37da2899SCharles.Forsyth                         AH_Edge    stem_edge,
207*37da2899SCharles.Forsyth                         int        vertical )
208*37da2899SCharles.Forsyth   {
209*37da2899SCharles.Forsyth     FT_Pos  dist = stem_edge->opos - base_edge->opos;
210*37da2899SCharles.Forsyth 
211*37da2899SCharles.Forsyth 
212*37da2899SCharles.Forsyth     stem_edge->pos = base_edge->pos +
213*37da2899SCharles.Forsyth                      ah_compute_stem_width( hinter, vertical, dist );
214*37da2899SCharles.Forsyth   }
215*37da2899SCharles.Forsyth 
216*37da2899SCharles.Forsyth 
217*37da2899SCharles.Forsyth   static void
ah_align_serif_edge(AH_Hinter hinter,AH_Edge base,AH_Edge serif,int vertical)218*37da2899SCharles.Forsyth   ah_align_serif_edge( AH_Hinter  hinter,
219*37da2899SCharles.Forsyth                        AH_Edge    base,
220*37da2899SCharles.Forsyth                        AH_Edge    serif,
221*37da2899SCharles.Forsyth                        int        vertical )
222*37da2899SCharles.Forsyth   {
223*37da2899SCharles.Forsyth     FT_Pos  dist;
224*37da2899SCharles.Forsyth     FT_Pos  sign = 1;
225*37da2899SCharles.Forsyth 
226*37da2899SCharles.Forsyth     FT_UNUSED( hinter );
227*37da2899SCharles.Forsyth 
228*37da2899SCharles.Forsyth 
229*37da2899SCharles.Forsyth     dist = serif->opos - base->opos;
230*37da2899SCharles.Forsyth     if ( dist < 0 )
231*37da2899SCharles.Forsyth     {
232*37da2899SCharles.Forsyth       dist = -dist;
233*37da2899SCharles.Forsyth       sign = -1;
234*37da2899SCharles.Forsyth     }
235*37da2899SCharles.Forsyth 
236*37da2899SCharles.Forsyth     /* do not touch serifs widths !! */
237*37da2899SCharles.Forsyth #if 0
238*37da2899SCharles.Forsyth     if ( base->flags & AH_EDGE_DONE )
239*37da2899SCharles.Forsyth     {
240*37da2899SCharles.Forsyth       if ( dist >= 64 )
241*37da2899SCharles.Forsyth         dist = (dist+8) & -64;
242*37da2899SCharles.Forsyth 
243*37da2899SCharles.Forsyth       else if ( dist <= 32 && !vertical )
244*37da2899SCharles.Forsyth         dist = ( dist + 33 ) >> 1;
245*37da2899SCharles.Forsyth       else
246*37da2899SCharles.Forsyth         dist = 0;
247*37da2899SCharles.Forsyth     }
248*37da2899SCharles.Forsyth #endif
249*37da2899SCharles.Forsyth 
250*37da2899SCharles.Forsyth     serif->pos = base->pos + sign * dist;
251*37da2899SCharles.Forsyth   }
252*37da2899SCharles.Forsyth 
253*37da2899SCharles.Forsyth 
254*37da2899SCharles.Forsyth   /*************************************************************************/
255*37da2899SCharles.Forsyth   /*************************************************************************/
256*37da2899SCharles.Forsyth   /*************************************************************************/
257*37da2899SCharles.Forsyth   /****                                                                 ****/
258*37da2899SCharles.Forsyth   /****       E D G E   H I N T I N G                                   ****/
259*37da2899SCharles.Forsyth   /****                                                                 ****/
260*37da2899SCharles.Forsyth   /*************************************************************************/
261*37da2899SCharles.Forsyth   /*************************************************************************/
262*37da2899SCharles.Forsyth   /*************************************************************************/
263*37da2899SCharles.Forsyth 
264*37da2899SCharles.Forsyth 
265*37da2899SCharles.Forsyth   /* Another alternative edge hinting algorithm */
266*37da2899SCharles.Forsyth   static void
ah_hint_edges_3(AH_Hinter hinter)267*37da2899SCharles.Forsyth   ah_hint_edges_3( AH_Hinter  hinter )
268*37da2899SCharles.Forsyth   {
269*37da2899SCharles.Forsyth     AH_Edge     edges;
270*37da2899SCharles.Forsyth     AH_Edge     edge_limit;
271*37da2899SCharles.Forsyth     AH_Outline  outline = hinter->glyph;
272*37da2899SCharles.Forsyth     FT_Int      dimension;
273*37da2899SCharles.Forsyth 
274*37da2899SCharles.Forsyth 
275*37da2899SCharles.Forsyth     edges      = outline->horz_edges;
276*37da2899SCharles.Forsyth     edge_limit = edges + outline->num_hedges;
277*37da2899SCharles.Forsyth 
278*37da2899SCharles.Forsyth     for ( dimension = 1; dimension >= 0; dimension-- )
279*37da2899SCharles.Forsyth     {
280*37da2899SCharles.Forsyth       AH_Edge  edge;
281*37da2899SCharles.Forsyth       AH_Edge  anchor = 0;
282*37da2899SCharles.Forsyth       int      has_serifs = 0;
283*37da2899SCharles.Forsyth 
284*37da2899SCharles.Forsyth 
285*37da2899SCharles.Forsyth       if ( !hinter->do_horz_hints && !dimension )
286*37da2899SCharles.Forsyth         goto Next_Dimension;
287*37da2899SCharles.Forsyth 
288*37da2899SCharles.Forsyth       if ( !hinter->do_vert_hints && dimension )
289*37da2899SCharles.Forsyth         goto Next_Dimension;
290*37da2899SCharles.Forsyth 
291*37da2899SCharles.Forsyth       /* we begin by aligning all stems relative to the blue zone */
292*37da2899SCharles.Forsyth       /* if needed -- that's only for horizontal edges            */
293*37da2899SCharles.Forsyth       if ( dimension )
294*37da2899SCharles.Forsyth       {
295*37da2899SCharles.Forsyth         for ( edge = edges; edge < edge_limit; edge++ )
296*37da2899SCharles.Forsyth         {
297*37da2899SCharles.Forsyth           FT_Pos*      blue;
298*37da2899SCharles.Forsyth           AH_EdgeRec  *edge1, *edge2;
299*37da2899SCharles.Forsyth 
300*37da2899SCharles.Forsyth 
301*37da2899SCharles.Forsyth           if ( edge->flags & AH_EDGE_DONE )
302*37da2899SCharles.Forsyth             continue;
303*37da2899SCharles.Forsyth 
304*37da2899SCharles.Forsyth           blue  = edge->blue_edge;
305*37da2899SCharles.Forsyth           edge1 = 0;
306*37da2899SCharles.Forsyth           edge2 = edge->link;
307*37da2899SCharles.Forsyth 
308*37da2899SCharles.Forsyth           if ( blue )
309*37da2899SCharles.Forsyth           {
310*37da2899SCharles.Forsyth             edge1 = edge;
311*37da2899SCharles.Forsyth           }
312*37da2899SCharles.Forsyth           else if (edge2 && edge2->blue_edge)
313*37da2899SCharles.Forsyth           {
314*37da2899SCharles.Forsyth             blue  = edge2->blue_edge;
315*37da2899SCharles.Forsyth             edge1 = edge2;
316*37da2899SCharles.Forsyth             edge2 = edge;
317*37da2899SCharles.Forsyth           }
318*37da2899SCharles.Forsyth 
319*37da2899SCharles.Forsyth           if ( !edge1 )
320*37da2899SCharles.Forsyth             continue;
321*37da2899SCharles.Forsyth 
322*37da2899SCharles.Forsyth           edge1->pos    = blue[0];
323*37da2899SCharles.Forsyth           edge1->flags |= AH_EDGE_DONE;
324*37da2899SCharles.Forsyth 
325*37da2899SCharles.Forsyth           if ( edge2 && !edge2->blue_edge )
326*37da2899SCharles.Forsyth           {
327*37da2899SCharles.Forsyth             ah_align_linked_edge( hinter, edge1, edge2, dimension );
328*37da2899SCharles.Forsyth             edge2->flags |= AH_EDGE_DONE;
329*37da2899SCharles.Forsyth           }
330*37da2899SCharles.Forsyth 
331*37da2899SCharles.Forsyth           if ( !anchor )
332*37da2899SCharles.Forsyth             anchor = edge;
333*37da2899SCharles.Forsyth         }
334*37da2899SCharles.Forsyth       }
335*37da2899SCharles.Forsyth 
336*37da2899SCharles.Forsyth       /* now, we will align all stem edges, trying to maintain the */
337*37da2899SCharles.Forsyth       /* relative order of stems in the glyph..                    */
338*37da2899SCharles.Forsyth       for ( edge = edges; edge < edge_limit; edge++ )
339*37da2899SCharles.Forsyth       {
340*37da2899SCharles.Forsyth         AH_EdgeRec*  edge2;
341*37da2899SCharles.Forsyth 
342*37da2899SCharles.Forsyth 
343*37da2899SCharles.Forsyth         if ( edge->flags & AH_EDGE_DONE )
344*37da2899SCharles.Forsyth           continue;
345*37da2899SCharles.Forsyth 
346*37da2899SCharles.Forsyth         /* skip all non-stem edges */
347*37da2899SCharles.Forsyth         edge2 = edge->link;
348*37da2899SCharles.Forsyth         if ( !edge2 )
349*37da2899SCharles.Forsyth         {
350*37da2899SCharles.Forsyth           has_serifs++;
351*37da2899SCharles.Forsyth           continue;
352*37da2899SCharles.Forsyth         }
353*37da2899SCharles.Forsyth 
354*37da2899SCharles.Forsyth         /* now, align the stem */
355*37da2899SCharles.Forsyth 
356*37da2899SCharles.Forsyth         /* this should not happen, but it's better to be safe. */
357*37da2899SCharles.Forsyth         if ( edge2->blue_edge || edge2 < edge )
358*37da2899SCharles.Forsyth         {
359*37da2899SCharles.Forsyth 
360*37da2899SCharles.Forsyth           ah_align_linked_edge( hinter, edge2, edge, dimension );
361*37da2899SCharles.Forsyth           edge->flags |= AH_EDGE_DONE;
362*37da2899SCharles.Forsyth           continue;
363*37da2899SCharles.Forsyth         }
364*37da2899SCharles.Forsyth 
365*37da2899SCharles.Forsyth         if ( !anchor )
366*37da2899SCharles.Forsyth         {
367*37da2899SCharles.Forsyth           edge->pos = ( edge->opos + 32 ) & -64;
368*37da2899SCharles.Forsyth           anchor    = edge;
369*37da2899SCharles.Forsyth 
370*37da2899SCharles.Forsyth           edge->flags |= AH_EDGE_DONE;
371*37da2899SCharles.Forsyth 
372*37da2899SCharles.Forsyth           ah_align_linked_edge( hinter, edge, edge2, dimension );
373*37da2899SCharles.Forsyth         }
374*37da2899SCharles.Forsyth         else
375*37da2899SCharles.Forsyth         {
376*37da2899SCharles.Forsyth           FT_Pos   org_pos, org_len, org_center, cur_len;
377*37da2899SCharles.Forsyth           FT_Pos   cur_pos1, cur_pos2, delta1, delta2;
378*37da2899SCharles.Forsyth 
379*37da2899SCharles.Forsyth 
380*37da2899SCharles.Forsyth           org_pos    = anchor->pos + (edge->opos - anchor->opos);
381*37da2899SCharles.Forsyth           org_len    = edge2->opos - edge->opos;
382*37da2899SCharles.Forsyth           org_center = org_pos + ( org_len >> 1 );
383*37da2899SCharles.Forsyth 
384*37da2899SCharles.Forsyth           cur_len    = ah_compute_stem_width( hinter, dimension, org_len );
385*37da2899SCharles.Forsyth 
386*37da2899SCharles.Forsyth           cur_pos1   = ( org_pos + 32 ) & -64;
387*37da2899SCharles.Forsyth           delta1     = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
388*37da2899SCharles.Forsyth           if ( delta1 < 0 )
389*37da2899SCharles.Forsyth             delta1 = -delta1;
390*37da2899SCharles.Forsyth 
391*37da2899SCharles.Forsyth           cur_pos2   = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len;
392*37da2899SCharles.Forsyth           delta2     = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
393*37da2899SCharles.Forsyth           if ( delta2 < 0 )
394*37da2899SCharles.Forsyth             delta2 = -delta2;
395*37da2899SCharles.Forsyth 
396*37da2899SCharles.Forsyth           edge->pos  = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2;
397*37da2899SCharles.Forsyth           edge2->pos = edge->pos + cur_len;
398*37da2899SCharles.Forsyth 
399*37da2899SCharles.Forsyth           edge->flags  |= AH_EDGE_DONE;
400*37da2899SCharles.Forsyth           edge2->flags |= AH_EDGE_DONE;
401*37da2899SCharles.Forsyth 
402*37da2899SCharles.Forsyth           if ( edge > edges && edge->pos < edge[-1].pos )
403*37da2899SCharles.Forsyth             edge->pos = edge[-1].pos;
404*37da2899SCharles.Forsyth         }
405*37da2899SCharles.Forsyth       }
406*37da2899SCharles.Forsyth 
407*37da2899SCharles.Forsyth       if ( !has_serifs )
408*37da2899SCharles.Forsyth         goto Next_Dimension;
409*37da2899SCharles.Forsyth 
410*37da2899SCharles.Forsyth       /* now, hint the remaining edges (serifs and single) in order */
411*37da2899SCharles.Forsyth       /* to complete our processing                                 */
412*37da2899SCharles.Forsyth       for ( edge = edges; edge < edge_limit; edge++ )
413*37da2899SCharles.Forsyth       {
414*37da2899SCharles.Forsyth         if ( edge->flags & AH_EDGE_DONE )
415*37da2899SCharles.Forsyth           continue;
416*37da2899SCharles.Forsyth 
417*37da2899SCharles.Forsyth         if ( edge->serif )
418*37da2899SCharles.Forsyth           ah_align_serif_edge( hinter, edge->serif, edge, dimension );
419*37da2899SCharles.Forsyth         else if ( !anchor )
420*37da2899SCharles.Forsyth         {
421*37da2899SCharles.Forsyth           edge->pos = ( edge->opos + 32 ) & -64;
422*37da2899SCharles.Forsyth           anchor    = edge;
423*37da2899SCharles.Forsyth         }
424*37da2899SCharles.Forsyth         else
425*37da2899SCharles.Forsyth           edge->pos = anchor->pos +
426*37da2899SCharles.Forsyth                       ( ( edge->opos-anchor->opos + 32 ) & -64 );
427*37da2899SCharles.Forsyth 
428*37da2899SCharles.Forsyth         edge->flags |= AH_EDGE_DONE;
429*37da2899SCharles.Forsyth 
430*37da2899SCharles.Forsyth         if ( edge > edges && edge->pos < edge[-1].pos )
431*37da2899SCharles.Forsyth           edge->pos = edge[-1].pos;
432*37da2899SCharles.Forsyth 
433*37da2899SCharles.Forsyth         if ( edge + 1 < edge_limit        &&
434*37da2899SCharles.Forsyth              edge[1].flags & AH_EDGE_DONE &&
435*37da2899SCharles.Forsyth              edge->pos > edge[1].pos      )
436*37da2899SCharles.Forsyth           edge->pos = edge[1].pos;
437*37da2899SCharles.Forsyth       }
438*37da2899SCharles.Forsyth 
439*37da2899SCharles.Forsyth     Next_Dimension:
440*37da2899SCharles.Forsyth       edges      = outline->vert_edges;
441*37da2899SCharles.Forsyth       edge_limit = edges + outline->num_vedges;
442*37da2899SCharles.Forsyth     }
443*37da2899SCharles.Forsyth   }
444*37da2899SCharles.Forsyth 
445*37da2899SCharles.Forsyth 
446*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
ah_hinter_hint_edges(AH_Hinter hinter)447*37da2899SCharles.Forsyth   ah_hinter_hint_edges( AH_Hinter  hinter )
448*37da2899SCharles.Forsyth   {
449*37da2899SCharles.Forsyth     /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help      */
450*37da2899SCharles.Forsyth     /* reduce the problem of the disappearing eye in the `e' of Times... */
451*37da2899SCharles.Forsyth     /* also, creates some artifacts near the blue zones?                 */
452*37da2899SCharles.Forsyth     {
453*37da2899SCharles.Forsyth       ah_hint_edges_3( hinter );
454*37da2899SCharles.Forsyth     }
455*37da2899SCharles.Forsyth   }
456*37da2899SCharles.Forsyth 
457*37da2899SCharles.Forsyth 
458*37da2899SCharles.Forsyth   /*************************************************************************/
459*37da2899SCharles.Forsyth   /*************************************************************************/
460*37da2899SCharles.Forsyth   /*************************************************************************/
461*37da2899SCharles.Forsyth   /****                                                                 ****/
462*37da2899SCharles.Forsyth   /****       P O I N T   H I N T I N G                                 ****/
463*37da2899SCharles.Forsyth   /****                                                                 ****/
464*37da2899SCharles.Forsyth   /*************************************************************************/
465*37da2899SCharles.Forsyth   /*************************************************************************/
466*37da2899SCharles.Forsyth   /*************************************************************************/
467*37da2899SCharles.Forsyth 
468*37da2899SCharles.Forsyth   static void
ah_hinter_align_edge_points(AH_Hinter hinter)469*37da2899SCharles.Forsyth   ah_hinter_align_edge_points( AH_Hinter  hinter )
470*37da2899SCharles.Forsyth   {
471*37da2899SCharles.Forsyth     AH_Outline  outline = hinter->glyph;
472*37da2899SCharles.Forsyth     AH_Edge     edges;
473*37da2899SCharles.Forsyth     AH_Edge     edge_limit;
474*37da2899SCharles.Forsyth     FT_Int      dimension;
475*37da2899SCharles.Forsyth 
476*37da2899SCharles.Forsyth 
477*37da2899SCharles.Forsyth     edges      = outline->horz_edges;
478*37da2899SCharles.Forsyth     edge_limit = edges + outline->num_hedges;
479*37da2899SCharles.Forsyth 
480*37da2899SCharles.Forsyth     for ( dimension = 1; dimension >= 0; dimension-- )
481*37da2899SCharles.Forsyth     {
482*37da2899SCharles.Forsyth       AH_Edge  edge;
483*37da2899SCharles.Forsyth 
484*37da2899SCharles.Forsyth 
485*37da2899SCharles.Forsyth       edge = edges;
486*37da2899SCharles.Forsyth       for ( ; edge < edge_limit; edge++ )
487*37da2899SCharles.Forsyth       {
488*37da2899SCharles.Forsyth         /* move the points of each segment     */
489*37da2899SCharles.Forsyth         /* in each edge to the edge's position */
490*37da2899SCharles.Forsyth         AH_Segment  seg = edge->first;
491*37da2899SCharles.Forsyth 
492*37da2899SCharles.Forsyth 
493*37da2899SCharles.Forsyth         do
494*37da2899SCharles.Forsyth         {
495*37da2899SCharles.Forsyth           AH_Point  point = seg->first;
496*37da2899SCharles.Forsyth 
497*37da2899SCharles.Forsyth 
498*37da2899SCharles.Forsyth           for (;;)
499*37da2899SCharles.Forsyth           {
500*37da2899SCharles.Forsyth             if ( dimension )
501*37da2899SCharles.Forsyth             {
502*37da2899SCharles.Forsyth               point->y      = edge->pos;
503*37da2899SCharles.Forsyth               point->flags |= AH_FLAG_TOUCH_Y;
504*37da2899SCharles.Forsyth             }
505*37da2899SCharles.Forsyth             else
506*37da2899SCharles.Forsyth             {
507*37da2899SCharles.Forsyth               point->x      = edge->pos;
508*37da2899SCharles.Forsyth               point->flags |= AH_FLAG_TOUCH_X;
509*37da2899SCharles.Forsyth             }
510*37da2899SCharles.Forsyth 
511*37da2899SCharles.Forsyth             if ( point == seg->last )
512*37da2899SCharles.Forsyth               break;
513*37da2899SCharles.Forsyth 
514*37da2899SCharles.Forsyth             point = point->next;
515*37da2899SCharles.Forsyth           }
516*37da2899SCharles.Forsyth 
517*37da2899SCharles.Forsyth           seg = seg->edge_next;
518*37da2899SCharles.Forsyth 
519*37da2899SCharles.Forsyth         } while ( seg != edge->first );
520*37da2899SCharles.Forsyth       }
521*37da2899SCharles.Forsyth 
522*37da2899SCharles.Forsyth       edges      = outline->vert_edges;
523*37da2899SCharles.Forsyth       edge_limit = edges + outline->num_vedges;
524*37da2899SCharles.Forsyth     }
525*37da2899SCharles.Forsyth   }
526*37da2899SCharles.Forsyth 
527*37da2899SCharles.Forsyth 
528*37da2899SCharles.Forsyth   /* hint the strong points -- this is equivalent to the TrueType `IP' */
529*37da2899SCharles.Forsyth   static void
ah_hinter_align_strong_points(AH_Hinter hinter)530*37da2899SCharles.Forsyth   ah_hinter_align_strong_points( AH_Hinter  hinter )
531*37da2899SCharles.Forsyth   {
532*37da2899SCharles.Forsyth     AH_Outline  outline = hinter->glyph;
533*37da2899SCharles.Forsyth     FT_Int      dimension;
534*37da2899SCharles.Forsyth     AH_Edge     edges;
535*37da2899SCharles.Forsyth     AH_Edge     edge_limit;
536*37da2899SCharles.Forsyth     AH_Point    points;
537*37da2899SCharles.Forsyth     AH_Point    point_limit;
538*37da2899SCharles.Forsyth     AH_Flags    touch_flag;
539*37da2899SCharles.Forsyth 
540*37da2899SCharles.Forsyth 
541*37da2899SCharles.Forsyth     points      = outline->points;
542*37da2899SCharles.Forsyth     point_limit = points + outline->num_points;
543*37da2899SCharles.Forsyth 
544*37da2899SCharles.Forsyth     edges       = outline->horz_edges;
545*37da2899SCharles.Forsyth     edge_limit  = edges + outline->num_hedges;
546*37da2899SCharles.Forsyth     touch_flag  = AH_FLAG_TOUCH_Y;
547*37da2899SCharles.Forsyth 
548*37da2899SCharles.Forsyth     for ( dimension = 1; dimension >= 0; dimension-- )
549*37da2899SCharles.Forsyth     {
550*37da2899SCharles.Forsyth       AH_Point  point;
551*37da2899SCharles.Forsyth       AH_Edge   edge;
552*37da2899SCharles.Forsyth 
553*37da2899SCharles.Forsyth 
554*37da2899SCharles.Forsyth       if ( edges < edge_limit )
555*37da2899SCharles.Forsyth         for ( point = points; point < point_limit; point++ )
556*37da2899SCharles.Forsyth         {
557*37da2899SCharles.Forsyth           FT_Pos  u, ou, fu;  /* point position */
558*37da2899SCharles.Forsyth           FT_Pos  delta;
559*37da2899SCharles.Forsyth 
560*37da2899SCharles.Forsyth 
561*37da2899SCharles.Forsyth           if ( point->flags & touch_flag )
562*37da2899SCharles.Forsyth             continue;
563*37da2899SCharles.Forsyth 
564*37da2899SCharles.Forsyth #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
565*37da2899SCharles.Forsyth           /* if this point is candidate to weak interpolation, we will  */
566*37da2899SCharles.Forsyth           /* interpolate it after all strong points have been processed */
567*37da2899SCharles.Forsyth           if (  ( point->flags & AH_FLAG_WEAK_INTERPOLATION ) &&
568*37da2899SCharles.Forsyth                !( point->flags & AH_FLAG_INFLECTION )         )
569*37da2899SCharles.Forsyth             continue;
570*37da2899SCharles.Forsyth #endif
571*37da2899SCharles.Forsyth 
572*37da2899SCharles.Forsyth           if ( dimension )
573*37da2899SCharles.Forsyth           {
574*37da2899SCharles.Forsyth             u  = point->fy;
575*37da2899SCharles.Forsyth             ou = point->oy;
576*37da2899SCharles.Forsyth           }
577*37da2899SCharles.Forsyth           else
578*37da2899SCharles.Forsyth           {
579*37da2899SCharles.Forsyth             u  = point->fx;
580*37da2899SCharles.Forsyth             ou = point->ox;
581*37da2899SCharles.Forsyth           }
582*37da2899SCharles.Forsyth 
583*37da2899SCharles.Forsyth           fu = u;
584*37da2899SCharles.Forsyth 
585*37da2899SCharles.Forsyth           /* is the point before the first edge? */
586*37da2899SCharles.Forsyth           edge  = edges;
587*37da2899SCharles.Forsyth           delta = edge->fpos - u;
588*37da2899SCharles.Forsyth           if ( delta >= 0 )
589*37da2899SCharles.Forsyth           {
590*37da2899SCharles.Forsyth             u = edge->pos - ( edge->opos - ou );
591*37da2899SCharles.Forsyth             goto Store_Point;
592*37da2899SCharles.Forsyth           }
593*37da2899SCharles.Forsyth 
594*37da2899SCharles.Forsyth           /* is the point after the last edge ? */
595*37da2899SCharles.Forsyth           edge  = edge_limit - 1;
596*37da2899SCharles.Forsyth           delta = u - edge->fpos;
597*37da2899SCharles.Forsyth           if ( delta >= 0 )
598*37da2899SCharles.Forsyth           {
599*37da2899SCharles.Forsyth             u = edge->pos + ( ou - edge->opos );
600*37da2899SCharles.Forsyth             goto Store_Point;
601*37da2899SCharles.Forsyth           }
602*37da2899SCharles.Forsyth 
603*37da2899SCharles.Forsyth           /* otherwise, interpolate the point in between */
604*37da2899SCharles.Forsyth           {
605*37da2899SCharles.Forsyth             AH_Edge  before = 0;
606*37da2899SCharles.Forsyth             AH_Edge  after  = 0;
607*37da2899SCharles.Forsyth 
608*37da2899SCharles.Forsyth 
609*37da2899SCharles.Forsyth             for ( edge = edges; edge < edge_limit; edge++ )
610*37da2899SCharles.Forsyth             {
611*37da2899SCharles.Forsyth               if ( u == edge->fpos )
612*37da2899SCharles.Forsyth               {
613*37da2899SCharles.Forsyth                 u = edge->pos;
614*37da2899SCharles.Forsyth                 goto Store_Point;
615*37da2899SCharles.Forsyth               }
616*37da2899SCharles.Forsyth               if ( u < edge->fpos )
617*37da2899SCharles.Forsyth                 break;
618*37da2899SCharles.Forsyth               before = edge;
619*37da2899SCharles.Forsyth             }
620*37da2899SCharles.Forsyth 
621*37da2899SCharles.Forsyth             for ( edge = edge_limit - 1; edge >= edges; edge-- )
622*37da2899SCharles.Forsyth             {
623*37da2899SCharles.Forsyth               if ( u == edge->fpos )
624*37da2899SCharles.Forsyth               {
625*37da2899SCharles.Forsyth                 u = edge->pos;
626*37da2899SCharles.Forsyth                 goto Store_Point;
627*37da2899SCharles.Forsyth               }
628*37da2899SCharles.Forsyth               if ( u > edge->fpos )
629*37da2899SCharles.Forsyth                 break;
630*37da2899SCharles.Forsyth               after = edge;
631*37da2899SCharles.Forsyth             }
632*37da2899SCharles.Forsyth 
633*37da2899SCharles.Forsyth             /* assert( before && after && before != after ) */
634*37da2899SCharles.Forsyth             u = before->pos + FT_MulDiv( fu - before->fpos,
635*37da2899SCharles.Forsyth                                          after->pos - before->pos,
636*37da2899SCharles.Forsyth                                          after->fpos - before->fpos );
637*37da2899SCharles.Forsyth           }
638*37da2899SCharles.Forsyth 
639*37da2899SCharles.Forsyth         Store_Point:
640*37da2899SCharles.Forsyth 
641*37da2899SCharles.Forsyth           /* save the point position */
642*37da2899SCharles.Forsyth           if ( dimension )
643*37da2899SCharles.Forsyth             point->y = u;
644*37da2899SCharles.Forsyth           else
645*37da2899SCharles.Forsyth             point->x = u;
646*37da2899SCharles.Forsyth 
647*37da2899SCharles.Forsyth           point->flags |= touch_flag;
648*37da2899SCharles.Forsyth         }
649*37da2899SCharles.Forsyth 
650*37da2899SCharles.Forsyth       edges      = outline->vert_edges;
651*37da2899SCharles.Forsyth       edge_limit = edges + outline->num_vedges;
652*37da2899SCharles.Forsyth       touch_flag = AH_FLAG_TOUCH_X;
653*37da2899SCharles.Forsyth     }
654*37da2899SCharles.Forsyth   }
655*37da2899SCharles.Forsyth 
656*37da2899SCharles.Forsyth 
657*37da2899SCharles.Forsyth #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
658*37da2899SCharles.Forsyth 
659*37da2899SCharles.Forsyth   static void
ah_iup_shift(AH_Point p1,AH_Point p2,AH_Point ref)660*37da2899SCharles.Forsyth   ah_iup_shift( AH_Point  p1,
661*37da2899SCharles.Forsyth                 AH_Point  p2,
662*37da2899SCharles.Forsyth                 AH_Point  ref )
663*37da2899SCharles.Forsyth   {
664*37da2899SCharles.Forsyth     AH_Point  p;
665*37da2899SCharles.Forsyth     FT_Pos    delta = ref->u - ref->v;
666*37da2899SCharles.Forsyth 
667*37da2899SCharles.Forsyth 
668*37da2899SCharles.Forsyth     for ( p = p1; p < ref; p++ )
669*37da2899SCharles.Forsyth       p->u = p->v + delta;
670*37da2899SCharles.Forsyth 
671*37da2899SCharles.Forsyth     for ( p = ref + 1; p <= p2; p++ )
672*37da2899SCharles.Forsyth       p->u = p->v + delta;
673*37da2899SCharles.Forsyth   }
674*37da2899SCharles.Forsyth 
675*37da2899SCharles.Forsyth 
676*37da2899SCharles.Forsyth   static void
ah_iup_interp(AH_Point p1,AH_Point p2,AH_Point ref1,AH_Point ref2)677*37da2899SCharles.Forsyth   ah_iup_interp( AH_Point  p1,
678*37da2899SCharles.Forsyth                  AH_Point  p2,
679*37da2899SCharles.Forsyth                  AH_Point  ref1,
680*37da2899SCharles.Forsyth                  AH_Point  ref2 )
681*37da2899SCharles.Forsyth   {
682*37da2899SCharles.Forsyth     AH_Point  p;
683*37da2899SCharles.Forsyth     FT_Pos    u;
684*37da2899SCharles.Forsyth     FT_Pos    v1 = ref1->v;
685*37da2899SCharles.Forsyth     FT_Pos    v2 = ref2->v;
686*37da2899SCharles.Forsyth     FT_Pos    d1 = ref1->u - v1;
687*37da2899SCharles.Forsyth     FT_Pos    d2 = ref2->u - v2;
688*37da2899SCharles.Forsyth 
689*37da2899SCharles.Forsyth 
690*37da2899SCharles.Forsyth     if ( p1 > p2 )
691*37da2899SCharles.Forsyth       return;
692*37da2899SCharles.Forsyth 
693*37da2899SCharles.Forsyth     if ( v1 == v2 )
694*37da2899SCharles.Forsyth     {
695*37da2899SCharles.Forsyth       for ( p = p1; p <= p2; p++ )
696*37da2899SCharles.Forsyth       {
697*37da2899SCharles.Forsyth         u = p->v;
698*37da2899SCharles.Forsyth 
699*37da2899SCharles.Forsyth         if ( u <= v1 )
700*37da2899SCharles.Forsyth           u += d1;
701*37da2899SCharles.Forsyth         else
702*37da2899SCharles.Forsyth           u += d2;
703*37da2899SCharles.Forsyth 
704*37da2899SCharles.Forsyth         p->u = u;
705*37da2899SCharles.Forsyth       }
706*37da2899SCharles.Forsyth       return;
707*37da2899SCharles.Forsyth     }
708*37da2899SCharles.Forsyth 
709*37da2899SCharles.Forsyth     if ( v1 < v2 )
710*37da2899SCharles.Forsyth     {
711*37da2899SCharles.Forsyth       for ( p = p1; p <= p2; p++ )
712*37da2899SCharles.Forsyth       {
713*37da2899SCharles.Forsyth         u = p->v;
714*37da2899SCharles.Forsyth 
715*37da2899SCharles.Forsyth         if ( u <= v1 )
716*37da2899SCharles.Forsyth           u += d1;
717*37da2899SCharles.Forsyth         else if ( u >= v2 )
718*37da2899SCharles.Forsyth           u += d2;
719*37da2899SCharles.Forsyth         else
720*37da2899SCharles.Forsyth           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
721*37da2899SCharles.Forsyth 
722*37da2899SCharles.Forsyth         p->u = u;
723*37da2899SCharles.Forsyth       }
724*37da2899SCharles.Forsyth     }
725*37da2899SCharles.Forsyth     else
726*37da2899SCharles.Forsyth     {
727*37da2899SCharles.Forsyth       for ( p = p1; p <= p2; p++ )
728*37da2899SCharles.Forsyth       {
729*37da2899SCharles.Forsyth         u = p->v;
730*37da2899SCharles.Forsyth 
731*37da2899SCharles.Forsyth         if ( u <= v2 )
732*37da2899SCharles.Forsyth           u += d2;
733*37da2899SCharles.Forsyth         else if ( u >= v1 )
734*37da2899SCharles.Forsyth           u += d1;
735*37da2899SCharles.Forsyth         else
736*37da2899SCharles.Forsyth           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
737*37da2899SCharles.Forsyth 
738*37da2899SCharles.Forsyth         p->u = u;
739*37da2899SCharles.Forsyth       }
740*37da2899SCharles.Forsyth     }
741*37da2899SCharles.Forsyth   }
742*37da2899SCharles.Forsyth 
743*37da2899SCharles.Forsyth 
744*37da2899SCharles.Forsyth   /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
745*37da2899SCharles.Forsyth   static void
ah_hinter_align_weak_points(AH_Hinter hinter)746*37da2899SCharles.Forsyth   ah_hinter_align_weak_points( AH_Hinter  hinter )
747*37da2899SCharles.Forsyth   {
748*37da2899SCharles.Forsyth     AH_Outline  outline = hinter->glyph;
749*37da2899SCharles.Forsyth     FT_Int      dimension;
750*37da2899SCharles.Forsyth     AH_Point    points;
751*37da2899SCharles.Forsyth     AH_Point    point_limit;
752*37da2899SCharles.Forsyth     AH_Point*   contour_limit;
753*37da2899SCharles.Forsyth     AH_Flags    touch_flag;
754*37da2899SCharles.Forsyth 
755*37da2899SCharles.Forsyth 
756*37da2899SCharles.Forsyth     points      = outline->points;
757*37da2899SCharles.Forsyth     point_limit = points + outline->num_points;
758*37da2899SCharles.Forsyth 
759*37da2899SCharles.Forsyth     /* PASS 1: Move segment points to edge positions */
760*37da2899SCharles.Forsyth 
761*37da2899SCharles.Forsyth     touch_flag = AH_FLAG_TOUCH_Y;
762*37da2899SCharles.Forsyth 
763*37da2899SCharles.Forsyth     contour_limit = outline->contours + outline->num_contours;
764*37da2899SCharles.Forsyth 
765*37da2899SCharles.Forsyth     ah_setup_uv( outline, AH_UV_OY );
766*37da2899SCharles.Forsyth 
767*37da2899SCharles.Forsyth     for ( dimension = 1; dimension >= 0; dimension-- )
768*37da2899SCharles.Forsyth     {
769*37da2899SCharles.Forsyth       AH_Point   point;
770*37da2899SCharles.Forsyth       AH_Point   end_point;
771*37da2899SCharles.Forsyth       AH_Point   first_point;
772*37da2899SCharles.Forsyth       AH_Point*  contour;
773*37da2899SCharles.Forsyth 
774*37da2899SCharles.Forsyth 
775*37da2899SCharles.Forsyth       point   = points;
776*37da2899SCharles.Forsyth       contour = outline->contours;
777*37da2899SCharles.Forsyth 
778*37da2899SCharles.Forsyth       for ( ; contour < contour_limit; contour++ )
779*37da2899SCharles.Forsyth       {
780*37da2899SCharles.Forsyth         point       = *contour;
781*37da2899SCharles.Forsyth         end_point   = point->prev;
782*37da2899SCharles.Forsyth         first_point = point;
783*37da2899SCharles.Forsyth 
784*37da2899SCharles.Forsyth         while ( point <= end_point && !( point->flags & touch_flag ) )
785*37da2899SCharles.Forsyth           point++;
786*37da2899SCharles.Forsyth 
787*37da2899SCharles.Forsyth         if ( point <= end_point )
788*37da2899SCharles.Forsyth         {
789*37da2899SCharles.Forsyth           AH_Point  first_touched = point;
790*37da2899SCharles.Forsyth           AH_Point  cur_touched   = point;
791*37da2899SCharles.Forsyth 
792*37da2899SCharles.Forsyth 
793*37da2899SCharles.Forsyth           point++;
794*37da2899SCharles.Forsyth           while ( point <= end_point )
795*37da2899SCharles.Forsyth           {
796*37da2899SCharles.Forsyth             if ( point->flags & touch_flag )
797*37da2899SCharles.Forsyth             {
798*37da2899SCharles.Forsyth               /* we found two successive touched points; we interpolate */
799*37da2899SCharles.Forsyth               /* all contour points between them                        */
800*37da2899SCharles.Forsyth               ah_iup_interp( cur_touched + 1, point - 1,
801*37da2899SCharles.Forsyth                              cur_touched, point );
802*37da2899SCharles.Forsyth               cur_touched = point;
803*37da2899SCharles.Forsyth             }
804*37da2899SCharles.Forsyth             point++;
805*37da2899SCharles.Forsyth           }
806*37da2899SCharles.Forsyth 
807*37da2899SCharles.Forsyth           if ( cur_touched == first_touched )
808*37da2899SCharles.Forsyth           {
809*37da2899SCharles.Forsyth             /* this is a special case: only one point was touched in the */
810*37da2899SCharles.Forsyth             /* contour; we thus simply shift the whole contour           */
811*37da2899SCharles.Forsyth             ah_iup_shift( first_point, end_point, cur_touched );
812*37da2899SCharles.Forsyth           }
813*37da2899SCharles.Forsyth           else
814*37da2899SCharles.Forsyth           {
815*37da2899SCharles.Forsyth             /* now interpolate after the last touched point to the end */
816*37da2899SCharles.Forsyth             /* of the contour                                          */
817*37da2899SCharles.Forsyth             ah_iup_interp( cur_touched + 1, end_point,
818*37da2899SCharles.Forsyth                            cur_touched, first_touched );
819*37da2899SCharles.Forsyth 
820*37da2899SCharles.Forsyth             /* if the first contour point isn't touched, interpolate */
821*37da2899SCharles.Forsyth             /* from the contour start to the first touched point     */
822*37da2899SCharles.Forsyth             if ( first_touched > points )
823*37da2899SCharles.Forsyth               ah_iup_interp( first_point, first_touched - 1,
824*37da2899SCharles.Forsyth                              cur_touched, first_touched );
825*37da2899SCharles.Forsyth           }
826*37da2899SCharles.Forsyth         }
827*37da2899SCharles.Forsyth       }
828*37da2899SCharles.Forsyth 
829*37da2899SCharles.Forsyth       /* now save the interpolated values back to x/y */
830*37da2899SCharles.Forsyth       if ( dimension )
831*37da2899SCharles.Forsyth       {
832*37da2899SCharles.Forsyth         for ( point = points; point < point_limit; point++ )
833*37da2899SCharles.Forsyth           point->y = point->u;
834*37da2899SCharles.Forsyth 
835*37da2899SCharles.Forsyth         touch_flag = AH_FLAG_TOUCH_X;
836*37da2899SCharles.Forsyth         ah_setup_uv( outline, AH_UV_OX );
837*37da2899SCharles.Forsyth       }
838*37da2899SCharles.Forsyth       else
839*37da2899SCharles.Forsyth       {
840*37da2899SCharles.Forsyth         for ( point = points; point < point_limit; point++ )
841*37da2899SCharles.Forsyth           point->x = point->u;
842*37da2899SCharles.Forsyth 
843*37da2899SCharles.Forsyth         break;  /* exit loop */
844*37da2899SCharles.Forsyth       }
845*37da2899SCharles.Forsyth     }
846*37da2899SCharles.Forsyth   }
847*37da2899SCharles.Forsyth 
848*37da2899SCharles.Forsyth #endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
849*37da2899SCharles.Forsyth 
850*37da2899SCharles.Forsyth 
851*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
ah_hinter_align_points(AH_Hinter hinter)852*37da2899SCharles.Forsyth   ah_hinter_align_points( AH_Hinter  hinter )
853*37da2899SCharles.Forsyth   {
854*37da2899SCharles.Forsyth     ah_hinter_align_edge_points( hinter );
855*37da2899SCharles.Forsyth 
856*37da2899SCharles.Forsyth #ifndef AH_OPTION_NO_STRONG_INTERPOLATION
857*37da2899SCharles.Forsyth     ah_hinter_align_strong_points( hinter );
858*37da2899SCharles.Forsyth #endif
859*37da2899SCharles.Forsyth 
860*37da2899SCharles.Forsyth #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
861*37da2899SCharles.Forsyth     ah_hinter_align_weak_points( hinter );
862*37da2899SCharles.Forsyth #endif
863*37da2899SCharles.Forsyth   }
864*37da2899SCharles.Forsyth 
865*37da2899SCharles.Forsyth 
866*37da2899SCharles.Forsyth   /*************************************************************************/
867*37da2899SCharles.Forsyth   /*************************************************************************/
868*37da2899SCharles.Forsyth   /*************************************************************************/
869*37da2899SCharles.Forsyth   /****                                                                 ****/
870*37da2899SCharles.Forsyth   /****       H I N T E R   O B J E C T   M E T H O D S                 ****/
871*37da2899SCharles.Forsyth   /****                                                                 ****/
872*37da2899SCharles.Forsyth   /*************************************************************************/
873*37da2899SCharles.Forsyth   /*************************************************************************/
874*37da2899SCharles.Forsyth   /*************************************************************************/
875*37da2899SCharles.Forsyth 
876*37da2899SCharles.Forsyth 
877*37da2899SCharles.Forsyth   /* scale and fit the global metrics */
878*37da2899SCharles.Forsyth   static void
ah_hinter_scale_globals(AH_Hinter hinter,FT_Fixed x_scale,FT_Fixed y_scale)879*37da2899SCharles.Forsyth   ah_hinter_scale_globals( AH_Hinter  hinter,
880*37da2899SCharles.Forsyth                            FT_Fixed   x_scale,
881*37da2899SCharles.Forsyth                            FT_Fixed   y_scale )
882*37da2899SCharles.Forsyth   {
883*37da2899SCharles.Forsyth     FT_Int           n;
884*37da2899SCharles.Forsyth     AH_Face_Globals  globals = hinter->globals;
885*37da2899SCharles.Forsyth     AH_Globals       design = &globals->design;
886*37da2899SCharles.Forsyth     AH_Globals       scaled = &globals->scaled;
887*37da2899SCharles.Forsyth 
888*37da2899SCharles.Forsyth 
889*37da2899SCharles.Forsyth     /* copy content */
890*37da2899SCharles.Forsyth     *scaled = *design;
891*37da2899SCharles.Forsyth 
892*37da2899SCharles.Forsyth     /* scale the standard widths & heights */
893*37da2899SCharles.Forsyth     for ( n = 0; n < design->num_widths; n++ )
894*37da2899SCharles.Forsyth       scaled->widths[n] = FT_MulFix( design->widths[n], x_scale );
895*37da2899SCharles.Forsyth 
896*37da2899SCharles.Forsyth     for ( n = 0; n < design->num_heights; n++ )
897*37da2899SCharles.Forsyth       scaled->heights[n] = FT_MulFix( design->heights[n], y_scale );
898*37da2899SCharles.Forsyth 
899*37da2899SCharles.Forsyth     scaled->stds[0] = ( design->num_widths  > 0 ) ? scaled->widths[0]  : 32000;
900*37da2899SCharles.Forsyth     scaled->stds[1] = ( design->num_heights > 0 ) ? scaled->heights[0] : 32000;
901*37da2899SCharles.Forsyth 
902*37da2899SCharles.Forsyth     /* scale the blue zones */
903*37da2899SCharles.Forsyth     for ( n = 0; n < AH_BLUE_MAX; n++ )
904*37da2899SCharles.Forsyth     {
905*37da2899SCharles.Forsyth       FT_Pos  delta, delta2;
906*37da2899SCharles.Forsyth 
907*37da2899SCharles.Forsyth 
908*37da2899SCharles.Forsyth       delta = design->blue_shoots[n] - design->blue_refs[n];
909*37da2899SCharles.Forsyth       delta2 = delta;
910*37da2899SCharles.Forsyth       if ( delta < 0 )
911*37da2899SCharles.Forsyth         delta2 = -delta2;
912*37da2899SCharles.Forsyth       delta2 = FT_MulFix( delta2, y_scale );
913*37da2899SCharles.Forsyth 
914*37da2899SCharles.Forsyth       if ( delta2 < 32 )
915*37da2899SCharles.Forsyth         delta2 = 0;
916*37da2899SCharles.Forsyth       else if ( delta2 < 64 )
917*37da2899SCharles.Forsyth         delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & -32 );
918*37da2899SCharles.Forsyth       else
919*37da2899SCharles.Forsyth         delta2 = ( delta2 + 32 ) & -64;
920*37da2899SCharles.Forsyth 
921*37da2899SCharles.Forsyth       if ( delta < 0 )
922*37da2899SCharles.Forsyth         delta2 = -delta2;
923*37da2899SCharles.Forsyth 
924*37da2899SCharles.Forsyth       scaled->blue_refs[n] =
925*37da2899SCharles.Forsyth         ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64;
926*37da2899SCharles.Forsyth       scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2;
927*37da2899SCharles.Forsyth     }
928*37da2899SCharles.Forsyth 
929*37da2899SCharles.Forsyth     globals->x_scale = x_scale;
930*37da2899SCharles.Forsyth     globals->y_scale = y_scale;
931*37da2899SCharles.Forsyth   }
932*37da2899SCharles.Forsyth 
933*37da2899SCharles.Forsyth 
934*37da2899SCharles.Forsyth   static void
ah_hinter_align(AH_Hinter hinter)935*37da2899SCharles.Forsyth   ah_hinter_align( AH_Hinter  hinter )
936*37da2899SCharles.Forsyth   {
937*37da2899SCharles.Forsyth     ah_hinter_align_edge_points( hinter );
938*37da2899SCharles.Forsyth     ah_hinter_align_points( hinter );
939*37da2899SCharles.Forsyth   }
940*37da2899SCharles.Forsyth 
941*37da2899SCharles.Forsyth 
942*37da2899SCharles.Forsyth   /* finalize a hinter object */
943*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
ah_hinter_done(AH_Hinter hinter)944*37da2899SCharles.Forsyth   ah_hinter_done( AH_Hinter  hinter )
945*37da2899SCharles.Forsyth   {
946*37da2899SCharles.Forsyth     if ( hinter )
947*37da2899SCharles.Forsyth     {
948*37da2899SCharles.Forsyth       FT_Memory  memory = hinter->memory;
949*37da2899SCharles.Forsyth 
950*37da2899SCharles.Forsyth 
951*37da2899SCharles.Forsyth       ah_loader_done( hinter->loader );
952*37da2899SCharles.Forsyth       ah_outline_done( hinter->glyph );
953*37da2899SCharles.Forsyth 
954*37da2899SCharles.Forsyth       /* note: the `globals' pointer is _not_ owned by the hinter */
955*37da2899SCharles.Forsyth       /*       but by the current face object, we don't need to   */
956*37da2899SCharles.Forsyth       /*       release it                                         */
957*37da2899SCharles.Forsyth       hinter->globals = 0;
958*37da2899SCharles.Forsyth       hinter->face    = 0;
959*37da2899SCharles.Forsyth 
960*37da2899SCharles.Forsyth       FT_FREE( hinter );
961*37da2899SCharles.Forsyth     }
962*37da2899SCharles.Forsyth   }
963*37da2899SCharles.Forsyth 
964*37da2899SCharles.Forsyth 
965*37da2899SCharles.Forsyth   /* create a new empty hinter object */
966*37da2899SCharles.Forsyth   FT_LOCAL_DEF( FT_Error )
ah_hinter_new(FT_Library library,AH_Hinter * ahinter)967*37da2899SCharles.Forsyth   ah_hinter_new( FT_Library  library,
968*37da2899SCharles.Forsyth                  AH_Hinter  *ahinter )
969*37da2899SCharles.Forsyth   {
970*37da2899SCharles.Forsyth     AH_Hinter  hinter = 0;
971*37da2899SCharles.Forsyth     FT_Memory  memory = library->memory;
972*37da2899SCharles.Forsyth     FT_Error   error;
973*37da2899SCharles.Forsyth 
974*37da2899SCharles.Forsyth 
975*37da2899SCharles.Forsyth     *ahinter = 0;
976*37da2899SCharles.Forsyth 
977*37da2899SCharles.Forsyth     /* allocate object */
978*37da2899SCharles.Forsyth     if ( FT_NEW( hinter ) )
979*37da2899SCharles.Forsyth       goto Exit;
980*37da2899SCharles.Forsyth 
981*37da2899SCharles.Forsyth     hinter->memory = memory;
982*37da2899SCharles.Forsyth     hinter->flags  = 0;
983*37da2899SCharles.Forsyth 
984*37da2899SCharles.Forsyth     /* allocate outline and loader */
985*37da2899SCharles.Forsyth     error = ah_outline_new( memory, &hinter->glyph )  ||
986*37da2899SCharles.Forsyth             ah_loader_new ( memory, &hinter->loader ) ||
987*37da2899SCharles.Forsyth             ah_loader_create_extra( hinter->loader );
988*37da2899SCharles.Forsyth     if ( error )
989*37da2899SCharles.Forsyth       goto Exit;
990*37da2899SCharles.Forsyth 
991*37da2899SCharles.Forsyth     *ahinter = hinter;
992*37da2899SCharles.Forsyth 
993*37da2899SCharles.Forsyth   Exit:
994*37da2899SCharles.Forsyth     if ( error )
995*37da2899SCharles.Forsyth       ah_hinter_done( hinter );
996*37da2899SCharles.Forsyth 
997*37da2899SCharles.Forsyth     return error;
998*37da2899SCharles.Forsyth   }
999*37da2899SCharles.Forsyth 
1000*37da2899SCharles.Forsyth 
1001*37da2899SCharles.Forsyth   /* create a face's autohint globals */
1002*37da2899SCharles.Forsyth   FT_LOCAL_DEF( FT_Error )
ah_hinter_new_face_globals(AH_Hinter hinter,FT_Face face,AH_Globals globals)1003*37da2899SCharles.Forsyth   ah_hinter_new_face_globals( AH_Hinter   hinter,
1004*37da2899SCharles.Forsyth                               FT_Face     face,
1005*37da2899SCharles.Forsyth                               AH_Globals  globals )
1006*37da2899SCharles.Forsyth   {
1007*37da2899SCharles.Forsyth     FT_Error         error;
1008*37da2899SCharles.Forsyth     FT_Memory        memory = hinter->memory;
1009*37da2899SCharles.Forsyth     AH_Face_Globals  face_globals;
1010*37da2899SCharles.Forsyth 
1011*37da2899SCharles.Forsyth 
1012*37da2899SCharles.Forsyth     if ( FT_NEW( face_globals ) )
1013*37da2899SCharles.Forsyth       goto Exit;
1014*37da2899SCharles.Forsyth 
1015*37da2899SCharles.Forsyth     hinter->face    = face;
1016*37da2899SCharles.Forsyth     hinter->globals = face_globals;
1017*37da2899SCharles.Forsyth 
1018*37da2899SCharles.Forsyth     if ( globals )
1019*37da2899SCharles.Forsyth       face_globals->design = *globals;
1020*37da2899SCharles.Forsyth     else
1021*37da2899SCharles.Forsyth       ah_hinter_compute_globals( hinter );
1022*37da2899SCharles.Forsyth 
1023*37da2899SCharles.Forsyth     face->autohint.data      = face_globals;
1024*37da2899SCharles.Forsyth     face->autohint.finalizer = (FT_Generic_Finalizer)
1025*37da2899SCharles.Forsyth                                  ah_hinter_done_face_globals;
1026*37da2899SCharles.Forsyth     face_globals->face       = face;
1027*37da2899SCharles.Forsyth 
1028*37da2899SCharles.Forsyth   Exit:
1029*37da2899SCharles.Forsyth     return error;
1030*37da2899SCharles.Forsyth   }
1031*37da2899SCharles.Forsyth 
1032*37da2899SCharles.Forsyth 
1033*37da2899SCharles.Forsyth   /* discard a face's autohint globals */
1034*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
ah_hinter_done_face_globals(AH_Face_Globals globals)1035*37da2899SCharles.Forsyth   ah_hinter_done_face_globals( AH_Face_Globals  globals )
1036*37da2899SCharles.Forsyth   {
1037*37da2899SCharles.Forsyth     FT_Face    face   = globals->face;
1038*37da2899SCharles.Forsyth     FT_Memory  memory = face->memory;
1039*37da2899SCharles.Forsyth 
1040*37da2899SCharles.Forsyth 
1041*37da2899SCharles.Forsyth     FT_FREE( globals );
1042*37da2899SCharles.Forsyth   }
1043*37da2899SCharles.Forsyth 
1044*37da2899SCharles.Forsyth 
1045*37da2899SCharles.Forsyth   static FT_Error
ah_hinter_load(AH_Hinter hinter,FT_UInt glyph_index,FT_Int32 load_flags,FT_UInt depth)1046*37da2899SCharles.Forsyth   ah_hinter_load( AH_Hinter  hinter,
1047*37da2899SCharles.Forsyth                   FT_UInt    glyph_index,
1048*37da2899SCharles.Forsyth                   FT_Int32   load_flags,
1049*37da2899SCharles.Forsyth                   FT_UInt    depth )
1050*37da2899SCharles.Forsyth   {
1051*37da2899SCharles.Forsyth     FT_Face           face     = hinter->face;
1052*37da2899SCharles.Forsyth     FT_GlyphSlot      slot     = face->glyph;
1053*37da2899SCharles.Forsyth     FT_Slot_Internal  internal = slot->internal;
1054*37da2899SCharles.Forsyth     FT_Fixed          x_scale  = face->size->metrics.x_scale;
1055*37da2899SCharles.Forsyth     FT_Fixed          y_scale  = face->size->metrics.y_scale;
1056*37da2899SCharles.Forsyth     FT_Error          error;
1057*37da2899SCharles.Forsyth     AH_Outline        outline  = hinter->glyph;
1058*37da2899SCharles.Forsyth     AH_Loader         gloader  = hinter->loader;
1059*37da2899SCharles.Forsyth 
1060*37da2899SCharles.Forsyth 
1061*37da2899SCharles.Forsyth     /* load the glyph */
1062*37da2899SCharles.Forsyth     error = FT_Load_Glyph( face, glyph_index, load_flags );
1063*37da2899SCharles.Forsyth     if ( error )
1064*37da2899SCharles.Forsyth       goto Exit;
1065*37da2899SCharles.Forsyth 
1066*37da2899SCharles.Forsyth     /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
1067*37da2899SCharles.Forsyth     hinter->transformed = internal->glyph_transformed;
1068*37da2899SCharles.Forsyth 
1069*37da2899SCharles.Forsyth     if ( hinter->transformed )
1070*37da2899SCharles.Forsyth     {
1071*37da2899SCharles.Forsyth       FT_Matrix  imatrix;
1072*37da2899SCharles.Forsyth 
1073*37da2899SCharles.Forsyth 
1074*37da2899SCharles.Forsyth       imatrix              = internal->glyph_matrix;
1075*37da2899SCharles.Forsyth       hinter->trans_delta  = internal->glyph_delta;
1076*37da2899SCharles.Forsyth       hinter->trans_matrix = imatrix;
1077*37da2899SCharles.Forsyth 
1078*37da2899SCharles.Forsyth       FT_Matrix_Invert( &imatrix );
1079*37da2899SCharles.Forsyth       FT_Vector_Transform( &hinter->trans_delta, &imatrix );
1080*37da2899SCharles.Forsyth     }
1081*37da2899SCharles.Forsyth 
1082*37da2899SCharles.Forsyth     /* set linear horizontal metrics */
1083*37da2899SCharles.Forsyth     slot->linearHoriAdvance = slot->metrics.horiAdvance;
1084*37da2899SCharles.Forsyth     slot->linearVertAdvance = slot->metrics.vertAdvance;
1085*37da2899SCharles.Forsyth 
1086*37da2899SCharles.Forsyth     switch ( slot->format )
1087*37da2899SCharles.Forsyth     {
1088*37da2899SCharles.Forsyth     case FT_GLYPH_FORMAT_OUTLINE:
1089*37da2899SCharles.Forsyth 
1090*37da2899SCharles.Forsyth       /* translate glyph outline if we need to */
1091*37da2899SCharles.Forsyth       if ( hinter->transformed )
1092*37da2899SCharles.Forsyth       {
1093*37da2899SCharles.Forsyth         FT_UInt     n     = slot->outline.n_points;
1094*37da2899SCharles.Forsyth         FT_Vector*  point = slot->outline.points;
1095*37da2899SCharles.Forsyth 
1096*37da2899SCharles.Forsyth 
1097*37da2899SCharles.Forsyth         for ( ; n > 0; point++, n-- )
1098*37da2899SCharles.Forsyth         {
1099*37da2899SCharles.Forsyth           point->x += hinter->trans_delta.x;
1100*37da2899SCharles.Forsyth           point->y += hinter->trans_delta.y;
1101*37da2899SCharles.Forsyth         }
1102*37da2899SCharles.Forsyth       }
1103*37da2899SCharles.Forsyth 
1104*37da2899SCharles.Forsyth       /* copy the outline points in the loader's current                */
1105*37da2899SCharles.Forsyth       /* extra points, which is used to keep original glyph coordinates */
1106*37da2899SCharles.Forsyth       error = ah_loader_check_points( gloader, slot->outline.n_points + 2,
1107*37da2899SCharles.Forsyth                                       slot->outline.n_contours );
1108*37da2899SCharles.Forsyth       if ( error )
1109*37da2899SCharles.Forsyth         goto Exit;
1110*37da2899SCharles.Forsyth 
1111*37da2899SCharles.Forsyth       FT_MEM_COPY( gloader->current.extra_points, slot->outline.points,
1112*37da2899SCharles.Forsyth                    slot->outline.n_points * sizeof ( FT_Vector ) );
1113*37da2899SCharles.Forsyth 
1114*37da2899SCharles.Forsyth       FT_MEM_COPY( gloader->current.outline.contours, slot->outline.contours,
1115*37da2899SCharles.Forsyth                    slot->outline.n_contours * sizeof ( short ) );
1116*37da2899SCharles.Forsyth 
1117*37da2899SCharles.Forsyth       FT_MEM_COPY( gloader->current.outline.tags, slot->outline.tags,
1118*37da2899SCharles.Forsyth                    slot->outline.n_points * sizeof ( char ) );
1119*37da2899SCharles.Forsyth 
1120*37da2899SCharles.Forsyth       gloader->current.outline.n_points   = slot->outline.n_points;
1121*37da2899SCharles.Forsyth       gloader->current.outline.n_contours = slot->outline.n_contours;
1122*37da2899SCharles.Forsyth 
1123*37da2899SCharles.Forsyth       /* compute original phantom points */
1124*37da2899SCharles.Forsyth       hinter->pp1.x = 0;
1125*37da2899SCharles.Forsyth       hinter->pp1.y = 0;
1126*37da2899SCharles.Forsyth       hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
1127*37da2899SCharles.Forsyth       hinter->pp2.y = 0;
1128*37da2899SCharles.Forsyth 
1129*37da2899SCharles.Forsyth       /* be sure to check for spacing glyphs */
1130*37da2899SCharles.Forsyth       if ( slot->outline.n_points == 0 )
1131*37da2899SCharles.Forsyth         goto Hint_Metrics;
1132*37da2899SCharles.Forsyth 
1133*37da2899SCharles.Forsyth       /* now, load the slot image into the auto-outline, and run the */
1134*37da2899SCharles.Forsyth       /* automatic hinting process                                   */
1135*37da2899SCharles.Forsyth       error = ah_outline_load( outline, face );   /* XXX: change to slot */
1136*37da2899SCharles.Forsyth       if ( error )
1137*37da2899SCharles.Forsyth         goto Exit;
1138*37da2899SCharles.Forsyth 
1139*37da2899SCharles.Forsyth       /* perform feature detection */
1140*37da2899SCharles.Forsyth       ah_outline_detect_features( outline );
1141*37da2899SCharles.Forsyth 
1142*37da2899SCharles.Forsyth       if ( hinter->do_vert_hints )
1143*37da2899SCharles.Forsyth       {
1144*37da2899SCharles.Forsyth         ah_outline_compute_blue_edges( outline, hinter->globals );
1145*37da2899SCharles.Forsyth         ah_outline_scale_blue_edges( outline, hinter->globals );
1146*37da2899SCharles.Forsyth       }
1147*37da2899SCharles.Forsyth 
1148*37da2899SCharles.Forsyth       /* perform alignment control */
1149*37da2899SCharles.Forsyth       ah_hinter_hint_edges( hinter );
1150*37da2899SCharles.Forsyth       ah_hinter_align( hinter );
1151*37da2899SCharles.Forsyth 
1152*37da2899SCharles.Forsyth       /* now save the current outline into the loader's current table */
1153*37da2899SCharles.Forsyth       ah_outline_save( outline, gloader );
1154*37da2899SCharles.Forsyth 
1155*37da2899SCharles.Forsyth       /* we now need to hint the metrics according to the change in */
1156*37da2899SCharles.Forsyth       /* width/positioning that occured during the hinting process  */
1157*37da2899SCharles.Forsyth       {
1158*37da2899SCharles.Forsyth         FT_Pos   old_advance, old_rsb, old_lsb, new_lsb;
1159*37da2899SCharles.Forsyth         AH_Edge  edge1 = outline->vert_edges;     /* leftmost edge  */
1160*37da2899SCharles.Forsyth         AH_Edge  edge2 = edge1 +
1161*37da2899SCharles.Forsyth                          outline->num_vedges - 1; /* rightmost edge */
1162*37da2899SCharles.Forsyth 
1163*37da2899SCharles.Forsyth 
1164*37da2899SCharles.Forsyth         old_advance = hinter->pp2.x;
1165*37da2899SCharles.Forsyth         old_rsb     = old_advance - edge2->opos;
1166*37da2899SCharles.Forsyth         old_lsb     = edge1->opos;
1167*37da2899SCharles.Forsyth         new_lsb     = edge1->pos;
1168*37da2899SCharles.Forsyth 
1169*37da2899SCharles.Forsyth         hinter->pp1.x = ( ( new_lsb    - old_lsb ) + 32 ) & -64;
1170*37da2899SCharles.Forsyth         hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64;
1171*37da2899SCharles.Forsyth 
1172*37da2899SCharles.Forsyth         /* try to fix certain bad advance computations */
1173*37da2899SCharles.Forsyth         if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
1174*37da2899SCharles.Forsyth           hinter->pp2.x += 64;
1175*37da2899SCharles.Forsyth       }
1176*37da2899SCharles.Forsyth 
1177*37da2899SCharles.Forsyth       /* good, we simply add the glyph to our loader's base */
1178*37da2899SCharles.Forsyth       ah_loader_add( gloader );
1179*37da2899SCharles.Forsyth       break;
1180*37da2899SCharles.Forsyth 
1181*37da2899SCharles.Forsyth     case FT_GLYPH_FORMAT_COMPOSITE:
1182*37da2899SCharles.Forsyth       {
1183*37da2899SCharles.Forsyth         FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
1184*37da2899SCharles.Forsyth         FT_UInt      num_base_subgs, start_point;
1185*37da2899SCharles.Forsyth         FT_SubGlyph  subglyph;
1186*37da2899SCharles.Forsyth 
1187*37da2899SCharles.Forsyth 
1188*37da2899SCharles.Forsyth         start_point   = gloader->base.outline.n_points;
1189*37da2899SCharles.Forsyth 
1190*37da2899SCharles.Forsyth         /* first of all, copy the subglyph descriptors in the glyph loader */
1191*37da2899SCharles.Forsyth         error = ah_loader_check_subglyphs( gloader, num_subglyphs );
1192*37da2899SCharles.Forsyth         if ( error )
1193*37da2899SCharles.Forsyth           goto Exit;
1194*37da2899SCharles.Forsyth 
1195*37da2899SCharles.Forsyth         FT_MEM_COPY( gloader->current.subglyphs, slot->subglyphs,
1196*37da2899SCharles.Forsyth                      num_subglyphs * sizeof ( FT_SubGlyph ) );
1197*37da2899SCharles.Forsyth 
1198*37da2899SCharles.Forsyth         gloader->current.num_subglyphs = num_subglyphs;
1199*37da2899SCharles.Forsyth         num_base_subgs = gloader->base.num_subglyphs;
1200*37da2899SCharles.Forsyth 
1201*37da2899SCharles.Forsyth         /* now, read each subglyph independently */
1202*37da2899SCharles.Forsyth         for ( nn = 0; nn < num_subglyphs; nn++ )
1203*37da2899SCharles.Forsyth         {
1204*37da2899SCharles.Forsyth           FT_Vector  pp1, pp2;
1205*37da2899SCharles.Forsyth           FT_Pos     x, y;
1206*37da2899SCharles.Forsyth           FT_UInt    num_points, num_new_points, num_base_points;
1207*37da2899SCharles.Forsyth 
1208*37da2899SCharles.Forsyth 
1209*37da2899SCharles.Forsyth           /* gloader.current.subglyphs can change during glyph loading due */
1210*37da2899SCharles.Forsyth           /* to re-allocation -- we must recompute the current subglyph on */
1211*37da2899SCharles.Forsyth           /* each iteration                                                */
1212*37da2899SCharles.Forsyth           subglyph = gloader->base.subglyphs + num_base_subgs + nn;
1213*37da2899SCharles.Forsyth 
1214*37da2899SCharles.Forsyth           pp1 = hinter->pp1;
1215*37da2899SCharles.Forsyth           pp2 = hinter->pp2;
1216*37da2899SCharles.Forsyth 
1217*37da2899SCharles.Forsyth           num_base_points = gloader->base.outline.n_points;
1218*37da2899SCharles.Forsyth 
1219*37da2899SCharles.Forsyth           error = ah_hinter_load( hinter, subglyph->index,
1220*37da2899SCharles.Forsyth                                   load_flags, depth + 1 );
1221*37da2899SCharles.Forsyth           if ( error )
1222*37da2899SCharles.Forsyth             goto Exit;
1223*37da2899SCharles.Forsyth 
1224*37da2899SCharles.Forsyth           /* recompute subglyph pointer */
1225*37da2899SCharles.Forsyth           subglyph = gloader->base.subglyphs + num_base_subgs + nn;
1226*37da2899SCharles.Forsyth 
1227*37da2899SCharles.Forsyth           if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
1228*37da2899SCharles.Forsyth           {
1229*37da2899SCharles.Forsyth             pp1 = hinter->pp1;
1230*37da2899SCharles.Forsyth             pp2 = hinter->pp2;
1231*37da2899SCharles.Forsyth           }
1232*37da2899SCharles.Forsyth           else
1233*37da2899SCharles.Forsyth           {
1234*37da2899SCharles.Forsyth             hinter->pp1 = pp1;
1235*37da2899SCharles.Forsyth             hinter->pp2 = pp2;
1236*37da2899SCharles.Forsyth           }
1237*37da2899SCharles.Forsyth 
1238*37da2899SCharles.Forsyth           num_points     = gloader->base.outline.n_points;
1239*37da2899SCharles.Forsyth           num_new_points = num_points - num_base_points;
1240*37da2899SCharles.Forsyth 
1241*37da2899SCharles.Forsyth           /* now perform the transform required for this subglyph */
1242*37da2899SCharles.Forsyth 
1243*37da2899SCharles.Forsyth           if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
1244*37da2899SCharles.Forsyth                                    FT_SUBGLYPH_FLAG_XY_SCALE |
1245*37da2899SCharles.Forsyth                                    FT_SUBGLYPH_FLAG_2X2      ) )
1246*37da2899SCharles.Forsyth           {
1247*37da2899SCharles.Forsyth             FT_Vector*  cur   = gloader->base.outline.points +
1248*37da2899SCharles.Forsyth                                 num_base_points;
1249*37da2899SCharles.Forsyth             FT_Vector*  org   = gloader->base.extra_points +
1250*37da2899SCharles.Forsyth                                 num_base_points;
1251*37da2899SCharles.Forsyth             FT_Vector*  limit = cur + num_new_points;
1252*37da2899SCharles.Forsyth 
1253*37da2899SCharles.Forsyth 
1254*37da2899SCharles.Forsyth             for ( ; cur < limit; cur++, org++ )
1255*37da2899SCharles.Forsyth             {
1256*37da2899SCharles.Forsyth               FT_Vector_Transform( cur, &subglyph->transform );
1257*37da2899SCharles.Forsyth               FT_Vector_Transform( org, &subglyph->transform );
1258*37da2899SCharles.Forsyth             }
1259*37da2899SCharles.Forsyth           }
1260*37da2899SCharles.Forsyth 
1261*37da2899SCharles.Forsyth           /* apply offset */
1262*37da2899SCharles.Forsyth 
1263*37da2899SCharles.Forsyth           if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
1264*37da2899SCharles.Forsyth           {
1265*37da2899SCharles.Forsyth             FT_Int      k = subglyph->arg1;
1266*37da2899SCharles.Forsyth             FT_UInt     l = subglyph->arg2;
1267*37da2899SCharles.Forsyth             FT_Vector*  p1;
1268*37da2899SCharles.Forsyth             FT_Vector*  p2;
1269*37da2899SCharles.Forsyth 
1270*37da2899SCharles.Forsyth 
1271*37da2899SCharles.Forsyth             if ( start_point + k >= num_base_points          ||
1272*37da2899SCharles.Forsyth                                l >= (FT_UInt)num_new_points  )
1273*37da2899SCharles.Forsyth             {
1274*37da2899SCharles.Forsyth               error = AH_Err_Invalid_Composite;
1275*37da2899SCharles.Forsyth               goto Exit;
1276*37da2899SCharles.Forsyth             }
1277*37da2899SCharles.Forsyth 
1278*37da2899SCharles.Forsyth             l += num_base_points;
1279*37da2899SCharles.Forsyth 
1280*37da2899SCharles.Forsyth             /* for now, only use the current point coordinates     */
1281*37da2899SCharles.Forsyth             /* we may consider another approach in the near future */
1282*37da2899SCharles.Forsyth             p1 = gloader->base.outline.points + start_point + k;
1283*37da2899SCharles.Forsyth             p2 = gloader->base.outline.points + start_point + l;
1284*37da2899SCharles.Forsyth 
1285*37da2899SCharles.Forsyth             x = p1->x - p2->x;
1286*37da2899SCharles.Forsyth             y = p1->y - p2->y;
1287*37da2899SCharles.Forsyth           }
1288*37da2899SCharles.Forsyth           else
1289*37da2899SCharles.Forsyth           {
1290*37da2899SCharles.Forsyth             x = FT_MulFix( subglyph->arg1, x_scale );
1291*37da2899SCharles.Forsyth             y = FT_MulFix( subglyph->arg2, y_scale );
1292*37da2899SCharles.Forsyth 
1293*37da2899SCharles.Forsyth             x = ( x + 32 ) & -64;
1294*37da2899SCharles.Forsyth             y = ( y + 32 ) & -64;
1295*37da2899SCharles.Forsyth           }
1296*37da2899SCharles.Forsyth 
1297*37da2899SCharles.Forsyth           {
1298*37da2899SCharles.Forsyth             FT_Outline  dummy = gloader->base.outline;
1299*37da2899SCharles.Forsyth 
1300*37da2899SCharles.Forsyth 
1301*37da2899SCharles.Forsyth             dummy.points  += num_base_points;
1302*37da2899SCharles.Forsyth             dummy.n_points = (short)num_new_points;
1303*37da2899SCharles.Forsyth 
1304*37da2899SCharles.Forsyth             FT_Outline_Translate( &dummy, x, y );
1305*37da2899SCharles.Forsyth           }
1306*37da2899SCharles.Forsyth         }
1307*37da2899SCharles.Forsyth       }
1308*37da2899SCharles.Forsyth       break;
1309*37da2899SCharles.Forsyth 
1310*37da2899SCharles.Forsyth     default:
1311*37da2899SCharles.Forsyth       /* we don't support other formats (yet?) */
1312*37da2899SCharles.Forsyth       error = AH_Err_Unimplemented_Feature;
1313*37da2899SCharles.Forsyth     }
1314*37da2899SCharles.Forsyth 
1315*37da2899SCharles.Forsyth   Hint_Metrics:
1316*37da2899SCharles.Forsyth     if ( depth == 0 )
1317*37da2899SCharles.Forsyth     {
1318*37da2899SCharles.Forsyth       FT_BBox  bbox;
1319*37da2899SCharles.Forsyth 
1320*37da2899SCharles.Forsyth 
1321*37da2899SCharles.Forsyth       /* transform the hinted outline if needed */
1322*37da2899SCharles.Forsyth       if ( hinter->transformed )
1323*37da2899SCharles.Forsyth         FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
1324*37da2899SCharles.Forsyth 
1325*37da2899SCharles.Forsyth       /* we must translate our final outline by -pp1.x, and compute */
1326*37da2899SCharles.Forsyth       /* the new metrics                                            */
1327*37da2899SCharles.Forsyth       if ( hinter->pp1.x )
1328*37da2899SCharles.Forsyth         FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
1329*37da2899SCharles.Forsyth 
1330*37da2899SCharles.Forsyth       FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
1331*37da2899SCharles.Forsyth       bbox.xMin &= -64;
1332*37da2899SCharles.Forsyth       bbox.yMin &= -64;
1333*37da2899SCharles.Forsyth       bbox.xMax  = ( bbox.xMax + 63 ) & -64;
1334*37da2899SCharles.Forsyth       bbox.yMax  = ( bbox.yMax + 63 ) & -64;
1335*37da2899SCharles.Forsyth 
1336*37da2899SCharles.Forsyth       slot->metrics.width        = bbox.xMax - bbox.xMin;
1337*37da2899SCharles.Forsyth       slot->metrics.height       = bbox.yMax - bbox.yMin;
1338*37da2899SCharles.Forsyth       slot->metrics.horiBearingX = bbox.xMin;
1339*37da2899SCharles.Forsyth       slot->metrics.horiBearingY = bbox.yMax;
1340*37da2899SCharles.Forsyth 
1341*37da2899SCharles.Forsyth       /* for mono-width fonts (like Andale, Courier, etc.), we need */
1342*37da2899SCharles.Forsyth       /* to keep the original rounded advance width                 */
1343*37da2899SCharles.Forsyth       if ( !FT_IS_FIXED_WIDTH( slot->face ) )
1344*37da2899SCharles.Forsyth         slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
1345*37da2899SCharles.Forsyth       else
1346*37da2899SCharles.Forsyth         slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
1347*37da2899SCharles.Forsyth                                                x_scale );
1348*37da2899SCharles.Forsyth 
1349*37da2899SCharles.Forsyth       slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + 32 ) & -64;
1350*37da2899SCharles.Forsyth 
1351*37da2899SCharles.Forsyth       /* now copy outline into glyph slot */
1352*37da2899SCharles.Forsyth       ah_loader_rewind( slot->internal->loader );
1353*37da2899SCharles.Forsyth       error = ah_loader_copy_points( slot->internal->loader, gloader );
1354*37da2899SCharles.Forsyth       if ( error )
1355*37da2899SCharles.Forsyth         goto Exit;
1356*37da2899SCharles.Forsyth 
1357*37da2899SCharles.Forsyth       slot->outline = slot->internal->loader->base.outline;
1358*37da2899SCharles.Forsyth       slot->format  = FT_GLYPH_FORMAT_OUTLINE;
1359*37da2899SCharles.Forsyth     }
1360*37da2899SCharles.Forsyth 
1361*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
1362*37da2899SCharles.Forsyth     ah_debug_hinter = hinter;
1363*37da2899SCharles.Forsyth #endif
1364*37da2899SCharles.Forsyth 
1365*37da2899SCharles.Forsyth   Exit:
1366*37da2899SCharles.Forsyth     return error;
1367*37da2899SCharles.Forsyth   }
1368*37da2899SCharles.Forsyth 
1369*37da2899SCharles.Forsyth 
1370*37da2899SCharles.Forsyth   /* load and hint a given glyph */
1371*37da2899SCharles.Forsyth   FT_LOCAL_DEF( FT_Error )
ah_hinter_load_glyph(AH_Hinter hinter,FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)1372*37da2899SCharles.Forsyth   ah_hinter_load_glyph( AH_Hinter     hinter,
1373*37da2899SCharles.Forsyth                         FT_GlyphSlot  slot,
1374*37da2899SCharles.Forsyth                         FT_Size       size,
1375*37da2899SCharles.Forsyth                         FT_UInt       glyph_index,
1376*37da2899SCharles.Forsyth                         FT_Int32      load_flags )
1377*37da2899SCharles.Forsyth   {
1378*37da2899SCharles.Forsyth     FT_Face          face         = slot->face;
1379*37da2899SCharles.Forsyth     FT_Error         error;
1380*37da2899SCharles.Forsyth     FT_Fixed         x_scale      = size->metrics.x_scale;
1381*37da2899SCharles.Forsyth     FT_Fixed         y_scale      = size->metrics.y_scale;
1382*37da2899SCharles.Forsyth     AH_Face_Globals  face_globals = FACE_GLOBALS( face );
1383*37da2899SCharles.Forsyth     FT_Render_Mode   hint_mode    = FT_LOAD_TARGET_MODE(load_flags);
1384*37da2899SCharles.Forsyth 
1385*37da2899SCharles.Forsyth 
1386*37da2899SCharles.Forsyth     /* first of all, we need to check that we're using the correct face and */
1387*37da2899SCharles.Forsyth     /* global hints to load the glyph                                       */
1388*37da2899SCharles.Forsyth     if ( hinter->face != face || hinter->globals != face_globals )
1389*37da2899SCharles.Forsyth     {
1390*37da2899SCharles.Forsyth       hinter->face = face;
1391*37da2899SCharles.Forsyth       if ( !face_globals )
1392*37da2899SCharles.Forsyth       {
1393*37da2899SCharles.Forsyth         error = ah_hinter_new_face_globals( hinter, face, 0 );
1394*37da2899SCharles.Forsyth         if ( error )
1395*37da2899SCharles.Forsyth           goto Exit;
1396*37da2899SCharles.Forsyth 
1397*37da2899SCharles.Forsyth       }
1398*37da2899SCharles.Forsyth       hinter->globals = FACE_GLOBALS( face );
1399*37da2899SCharles.Forsyth       face_globals    = FACE_GLOBALS( face );
1400*37da2899SCharles.Forsyth 
1401*37da2899SCharles.Forsyth     }
1402*37da2899SCharles.Forsyth 
1403*37da2899SCharles.Forsyth     /* now, we must check the current character pixel size to see if we */
1404*37da2899SCharles.Forsyth     /* need to rescale the global metrics                               */
1405*37da2899SCharles.Forsyth     if ( face_globals->x_scale != x_scale ||
1406*37da2899SCharles.Forsyth          face_globals->y_scale != y_scale )
1407*37da2899SCharles.Forsyth       ah_hinter_scale_globals( hinter, x_scale, y_scale );
1408*37da2899SCharles.Forsyth 
1409*37da2899SCharles.Forsyth     ah_loader_rewind( hinter->loader );
1410*37da2899SCharles.Forsyth 
1411*37da2899SCharles.Forsyth     /* reset hinting flags according to load flags and current render target */
1412*37da2899SCharles.Forsyth     hinter->do_horz_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
1413*37da2899SCharles.Forsyth     hinter->do_vert_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
1414*37da2899SCharles.Forsyth 
1415*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
1416*37da2899SCharles.Forsyth     hinter->do_horz_hints = !ah_debug_disable_vert;  /* not a bug, the meaning */
1417*37da2899SCharles.Forsyth     hinter->do_vert_hints = !ah_debug_disable_horz;  /* of h/v is inverted!    */
1418*37da2899SCharles.Forsyth #endif
1419*37da2899SCharles.Forsyth 
1420*37da2899SCharles.Forsyth     /* we snap the width of vertical stems for the monochrome and         */
1421*37da2899SCharles.Forsyth     /* horizontal LCD rendering targets only.  Corresponds to X snapping. */
1422*37da2899SCharles.Forsyth     hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
1423*37da2899SCharles.Forsyth                                         hint_mode == FT_RENDER_MODE_LCD  );
1424*37da2899SCharles.Forsyth 
1425*37da2899SCharles.Forsyth     /* we snap the width of horizontal stems for the monochrome and     */
1426*37da2899SCharles.Forsyth     /* vertical LCD rendering targets only.  Corresponds to Y snapping. */
1427*37da2899SCharles.Forsyth     hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO   ||
1428*37da2899SCharles.Forsyth                                         hint_mode == FT_RENDER_MODE_LCD_V  );
1429*37da2899SCharles.Forsyth 
1430*37da2899SCharles.Forsyth #if 1
1431*37da2899SCharles.Forsyth     load_flags  = FT_LOAD_NO_SCALE
1432*37da2899SCharles.Forsyth                 | FT_LOAD_IGNORE_TRANSFORM ;
1433*37da2899SCharles.Forsyth #else
1434*37da2899SCharles.Forsyth     load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE;
1435*37da2899SCharles.Forsyth #endif
1436*37da2899SCharles.Forsyth 
1437*37da2899SCharles.Forsyth     error = ah_hinter_load( hinter, glyph_index, load_flags, 0 );
1438*37da2899SCharles.Forsyth 
1439*37da2899SCharles.Forsyth   Exit:
1440*37da2899SCharles.Forsyth     return error;
1441*37da2899SCharles.Forsyth   }
1442*37da2899SCharles.Forsyth 
1443*37da2899SCharles.Forsyth 
1444*37da2899SCharles.Forsyth   /* retrieve a face's autohint globals for client applications */
1445*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
ah_hinter_get_global_hints(AH_Hinter hinter,FT_Face face,void ** global_hints,long * global_len)1446*37da2899SCharles.Forsyth   ah_hinter_get_global_hints( AH_Hinter  hinter,
1447*37da2899SCharles.Forsyth                               FT_Face    face,
1448*37da2899SCharles.Forsyth                               void**     global_hints,
1449*37da2899SCharles.Forsyth                               long*      global_len )
1450*37da2899SCharles.Forsyth   {
1451*37da2899SCharles.Forsyth     AH_Globals  globals = 0;
1452*37da2899SCharles.Forsyth     FT_Memory   memory  = hinter->memory;
1453*37da2899SCharles.Forsyth     FT_Error    error;
1454*37da2899SCharles.Forsyth 
1455*37da2899SCharles.Forsyth 
1456*37da2899SCharles.Forsyth     /* allocate new master globals */
1457*37da2899SCharles.Forsyth     if ( FT_NEW( globals ) )
1458*37da2899SCharles.Forsyth       goto Fail;
1459*37da2899SCharles.Forsyth 
1460*37da2899SCharles.Forsyth     /* compute face globals if needed */
1461*37da2899SCharles.Forsyth     if ( !FACE_GLOBALS( face ) )
1462*37da2899SCharles.Forsyth     {
1463*37da2899SCharles.Forsyth       error = ah_hinter_new_face_globals( hinter, face, 0 );
1464*37da2899SCharles.Forsyth       if ( error )
1465*37da2899SCharles.Forsyth         goto Fail;
1466*37da2899SCharles.Forsyth     }
1467*37da2899SCharles.Forsyth 
1468*37da2899SCharles.Forsyth     *globals      = FACE_GLOBALS( face )->design;
1469*37da2899SCharles.Forsyth     *global_hints = globals;
1470*37da2899SCharles.Forsyth     *global_len   = sizeof( *globals );
1471*37da2899SCharles.Forsyth 
1472*37da2899SCharles.Forsyth     return;
1473*37da2899SCharles.Forsyth 
1474*37da2899SCharles.Forsyth   Fail:
1475*37da2899SCharles.Forsyth     FT_FREE( globals );
1476*37da2899SCharles.Forsyth 
1477*37da2899SCharles.Forsyth     *global_hints = 0;
1478*37da2899SCharles.Forsyth     *global_len   = 0;
1479*37da2899SCharles.Forsyth   }
1480*37da2899SCharles.Forsyth 
1481*37da2899SCharles.Forsyth 
1482*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
ah_hinter_done_global_hints(AH_Hinter hinter,void * global_hints)1483*37da2899SCharles.Forsyth   ah_hinter_done_global_hints( AH_Hinter  hinter,
1484*37da2899SCharles.Forsyth                                void*      global_hints )
1485*37da2899SCharles.Forsyth   {
1486*37da2899SCharles.Forsyth     FT_Memory  memory = hinter->memory;
1487*37da2899SCharles.Forsyth 
1488*37da2899SCharles.Forsyth 
1489*37da2899SCharles.Forsyth     FT_FREE( global_hints );
1490*37da2899SCharles.Forsyth   }
1491*37da2899SCharles.Forsyth 
1492*37da2899SCharles.Forsyth 
1493*37da2899SCharles.Forsyth /* END */
1494