xref: /inferno-os/libfreetype/pshalgo3.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth /***************************************************************************/
2*37da2899SCharles.Forsyth /*                                                                         */
3*37da2899SCharles.Forsyth /*  pshalgo3.c                                                             */
4*37da2899SCharles.Forsyth /*                                                                         */
5*37da2899SCharles.Forsyth /*    PostScript hinting algorithm 3 (body).                               */
6*37da2899SCharles.Forsyth /*                                                                         */
7*37da2899SCharles.Forsyth /*  Copyright 2001, 2002 by                                                */
8*37da2899SCharles.Forsyth /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9*37da2899SCharles.Forsyth /*                                                                         */
10*37da2899SCharles.Forsyth /*  This file is part of the FreeType project, and may only be used        */
11*37da2899SCharles.Forsyth /*  modified and distributed under the terms of the FreeType project       */
12*37da2899SCharles.Forsyth /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13*37da2899SCharles.Forsyth /*  this file you indicate that you have read the license and              */
14*37da2899SCharles.Forsyth /*  understand and accept it fully.                                        */
15*37da2899SCharles.Forsyth /*                                                                         */
16*37da2899SCharles.Forsyth /***************************************************************************/
17*37da2899SCharles.Forsyth 
18*37da2899SCharles.Forsyth 
19*37da2899SCharles.Forsyth #include <ft2build.h>
20*37da2899SCharles.Forsyth #include FT_INTERNAL_OBJECTS_H
21*37da2899SCharles.Forsyth #include FT_INTERNAL_DEBUG_H
22*37da2899SCharles.Forsyth #include "pshalgo3.h"
23*37da2899SCharles.Forsyth 
24*37da2899SCharles.Forsyth 
25*37da2899SCharles.Forsyth #undef  FT_COMPONENT
26*37da2899SCharles.Forsyth #define FT_COMPONENT  trace_pshalgo2
27*37da2899SCharles.Forsyth 
28*37da2899SCharles.Forsyth 
29*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
30*37da2899SCharles.Forsyth   PSH3_Hint_Table  ps3_debug_hint_table = 0;
31*37da2899SCharles.Forsyth   PSH3_HintFunc    ps3_debug_hint_func  = 0;
32*37da2899SCharles.Forsyth   PSH3_Glyph       ps3_debug_glyph      = 0;
33*37da2899SCharles.Forsyth #endif
34*37da2899SCharles.Forsyth 
35*37da2899SCharles.Forsyth 
36*37da2899SCharles.Forsyth #define  COMPUTE_INFLEXS  /* compute inflection points to optimize "S" and others */
37*37da2899SCharles.Forsyth #define  STRONGER         /* slightly increase the contrast of smooth hinting */
38*37da2899SCharles.Forsyth 
39*37da2899SCharles.Forsyth   /*************************************************************************/
40*37da2899SCharles.Forsyth   /*************************************************************************/
41*37da2899SCharles.Forsyth   /*****                                                               *****/
42*37da2899SCharles.Forsyth   /*****                  BASIC HINTS RECORDINGS                       *****/
43*37da2899SCharles.Forsyth   /*****                                                               *****/
44*37da2899SCharles.Forsyth   /*************************************************************************/
45*37da2899SCharles.Forsyth   /*************************************************************************/
46*37da2899SCharles.Forsyth 
47*37da2899SCharles.Forsyth   /* return true iff two stem hints overlap */
48*37da2899SCharles.Forsyth   static FT_Int
psh3_hint_overlap(PSH3_Hint hint1,PSH3_Hint hint2)49*37da2899SCharles.Forsyth   psh3_hint_overlap( PSH3_Hint  hint1,
50*37da2899SCharles.Forsyth                      PSH3_Hint  hint2 )
51*37da2899SCharles.Forsyth   {
52*37da2899SCharles.Forsyth     return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
53*37da2899SCharles.Forsyth              hint2->org_pos + hint2->org_len >= hint1->org_pos );
54*37da2899SCharles.Forsyth   }
55*37da2899SCharles.Forsyth 
56*37da2899SCharles.Forsyth 
57*37da2899SCharles.Forsyth   /* destroy hints table */
58*37da2899SCharles.Forsyth   static void
psh3_hint_table_done(PSH3_Hint_Table table,FT_Memory memory)59*37da2899SCharles.Forsyth   psh3_hint_table_done( PSH3_Hint_Table  table,
60*37da2899SCharles.Forsyth                         FT_Memory        memory )
61*37da2899SCharles.Forsyth   {
62*37da2899SCharles.Forsyth     FT_FREE( table->zones );
63*37da2899SCharles.Forsyth     table->num_zones = 0;
64*37da2899SCharles.Forsyth     table->zone      = 0;
65*37da2899SCharles.Forsyth 
66*37da2899SCharles.Forsyth     FT_FREE( table->sort );
67*37da2899SCharles.Forsyth     FT_FREE( table->hints );
68*37da2899SCharles.Forsyth     table->num_hints   = 0;
69*37da2899SCharles.Forsyth     table->max_hints   = 0;
70*37da2899SCharles.Forsyth     table->sort_global = 0;
71*37da2899SCharles.Forsyth   }
72*37da2899SCharles.Forsyth 
73*37da2899SCharles.Forsyth 
74*37da2899SCharles.Forsyth   /* deactivate all hints in a table */
75*37da2899SCharles.Forsyth   static void
psh3_hint_table_deactivate(PSH3_Hint_Table table)76*37da2899SCharles.Forsyth   psh3_hint_table_deactivate( PSH3_Hint_Table  table )
77*37da2899SCharles.Forsyth   {
78*37da2899SCharles.Forsyth     FT_UInt    count = table->max_hints;
79*37da2899SCharles.Forsyth     PSH3_Hint  hint  = table->hints;
80*37da2899SCharles.Forsyth 
81*37da2899SCharles.Forsyth 
82*37da2899SCharles.Forsyth     for ( ; count > 0; count--, hint++ )
83*37da2899SCharles.Forsyth     {
84*37da2899SCharles.Forsyth       psh3_hint_deactivate( hint );
85*37da2899SCharles.Forsyth       hint->order = -1;
86*37da2899SCharles.Forsyth     }
87*37da2899SCharles.Forsyth   }
88*37da2899SCharles.Forsyth 
89*37da2899SCharles.Forsyth 
90*37da2899SCharles.Forsyth   /* internal function used to record a new hint */
91*37da2899SCharles.Forsyth   static void
psh3_hint_table_record(PSH3_Hint_Table table,FT_UInt idx)92*37da2899SCharles.Forsyth   psh3_hint_table_record( PSH3_Hint_Table  table,
93*37da2899SCharles.Forsyth                           FT_UInt          idx )
94*37da2899SCharles.Forsyth   {
95*37da2899SCharles.Forsyth     PSH3_Hint  hint = table->hints + idx;
96*37da2899SCharles.Forsyth 
97*37da2899SCharles.Forsyth 
98*37da2899SCharles.Forsyth     if ( idx >= table->max_hints )
99*37da2899SCharles.Forsyth     {
100*37da2899SCharles.Forsyth       FT_ERROR(( "psh3_hint_table_record: invalid hint index %d\n", idx ));
101*37da2899SCharles.Forsyth       return;
102*37da2899SCharles.Forsyth     }
103*37da2899SCharles.Forsyth 
104*37da2899SCharles.Forsyth     /* ignore active hints */
105*37da2899SCharles.Forsyth     if ( psh3_hint_is_active( hint ) )
106*37da2899SCharles.Forsyth       return;
107*37da2899SCharles.Forsyth 
108*37da2899SCharles.Forsyth     psh3_hint_activate( hint );
109*37da2899SCharles.Forsyth 
110*37da2899SCharles.Forsyth     /* now scan the current active hint set in order to determine */
111*37da2899SCharles.Forsyth     /* if we are overlapping with another segment                 */
112*37da2899SCharles.Forsyth     {
113*37da2899SCharles.Forsyth       PSH3_Hint*  sorted = table->sort_global;
114*37da2899SCharles.Forsyth       FT_UInt     count  = table->num_hints;
115*37da2899SCharles.Forsyth       PSH3_Hint   hint2;
116*37da2899SCharles.Forsyth 
117*37da2899SCharles.Forsyth 
118*37da2899SCharles.Forsyth       hint->parent = 0;
119*37da2899SCharles.Forsyth       for ( ; count > 0; count--, sorted++ )
120*37da2899SCharles.Forsyth       {
121*37da2899SCharles.Forsyth         hint2 = sorted[0];
122*37da2899SCharles.Forsyth 
123*37da2899SCharles.Forsyth         if ( psh3_hint_overlap( hint, hint2 ) )
124*37da2899SCharles.Forsyth         {
125*37da2899SCharles.Forsyth           hint->parent = hint2;
126*37da2899SCharles.Forsyth           break;
127*37da2899SCharles.Forsyth         }
128*37da2899SCharles.Forsyth       }
129*37da2899SCharles.Forsyth     }
130*37da2899SCharles.Forsyth 
131*37da2899SCharles.Forsyth     if ( table->num_hints < table->max_hints )
132*37da2899SCharles.Forsyth       table->sort_global[table->num_hints++] = hint;
133*37da2899SCharles.Forsyth     else
134*37da2899SCharles.Forsyth       FT_ERROR(( "psh3_hint_table_record: too many sorted hints!  BUG!\n" ));
135*37da2899SCharles.Forsyth   }
136*37da2899SCharles.Forsyth 
137*37da2899SCharles.Forsyth 
138*37da2899SCharles.Forsyth   static void
psh3_hint_table_record_mask(PSH3_Hint_Table table,PS_Mask hint_mask)139*37da2899SCharles.Forsyth   psh3_hint_table_record_mask( PSH3_Hint_Table  table,
140*37da2899SCharles.Forsyth                                PS_Mask          hint_mask )
141*37da2899SCharles.Forsyth   {
142*37da2899SCharles.Forsyth     FT_Int    mask = 0, val = 0;
143*37da2899SCharles.Forsyth     FT_Byte*  cursor = hint_mask->bytes;
144*37da2899SCharles.Forsyth     FT_UInt   idx, limit;
145*37da2899SCharles.Forsyth 
146*37da2899SCharles.Forsyth 
147*37da2899SCharles.Forsyth     limit = hint_mask->num_bits;
148*37da2899SCharles.Forsyth 
149*37da2899SCharles.Forsyth     for ( idx = 0; idx < limit; idx++ )
150*37da2899SCharles.Forsyth     {
151*37da2899SCharles.Forsyth       if ( mask == 0 )
152*37da2899SCharles.Forsyth       {
153*37da2899SCharles.Forsyth         val  = *cursor++;
154*37da2899SCharles.Forsyth         mask = 0x80;
155*37da2899SCharles.Forsyth       }
156*37da2899SCharles.Forsyth 
157*37da2899SCharles.Forsyth       if ( val & mask )
158*37da2899SCharles.Forsyth         psh3_hint_table_record( table, idx );
159*37da2899SCharles.Forsyth 
160*37da2899SCharles.Forsyth       mask >>= 1;
161*37da2899SCharles.Forsyth     }
162*37da2899SCharles.Forsyth   }
163*37da2899SCharles.Forsyth 
164*37da2899SCharles.Forsyth 
165*37da2899SCharles.Forsyth   /* create hints table */
166*37da2899SCharles.Forsyth   static FT_Error
psh3_hint_table_init(PSH3_Hint_Table table,PS_Hint_Table hints,PS_Mask_Table hint_masks,PS_Mask_Table counter_masks,FT_Memory memory)167*37da2899SCharles.Forsyth   psh3_hint_table_init( PSH3_Hint_Table  table,
168*37da2899SCharles.Forsyth                         PS_Hint_Table    hints,
169*37da2899SCharles.Forsyth                         PS_Mask_Table    hint_masks,
170*37da2899SCharles.Forsyth                         PS_Mask_Table    counter_masks,
171*37da2899SCharles.Forsyth                         FT_Memory        memory )
172*37da2899SCharles.Forsyth   {
173*37da2899SCharles.Forsyth     FT_UInt   count = hints->num_hints;
174*37da2899SCharles.Forsyth     FT_Error  error;
175*37da2899SCharles.Forsyth 
176*37da2899SCharles.Forsyth     FT_UNUSED( counter_masks );
177*37da2899SCharles.Forsyth 
178*37da2899SCharles.Forsyth 
179*37da2899SCharles.Forsyth     /* allocate our tables */
180*37da2899SCharles.Forsyth     if ( FT_NEW_ARRAY( table->sort,  2 * count     ) ||
181*37da2899SCharles.Forsyth          FT_NEW_ARRAY( table->hints,     count     ) ||
182*37da2899SCharles.Forsyth          FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
183*37da2899SCharles.Forsyth       goto Exit;
184*37da2899SCharles.Forsyth 
185*37da2899SCharles.Forsyth     table->max_hints   = count;
186*37da2899SCharles.Forsyth     table->sort_global = table->sort + count;
187*37da2899SCharles.Forsyth     table->num_hints   = 0;
188*37da2899SCharles.Forsyth     table->num_zones   = 0;
189*37da2899SCharles.Forsyth     table->zone        = 0;
190*37da2899SCharles.Forsyth 
191*37da2899SCharles.Forsyth     /* now, initialize the "hints" array */
192*37da2899SCharles.Forsyth     {
193*37da2899SCharles.Forsyth       PSH3_Hint  write = table->hints;
194*37da2899SCharles.Forsyth       PS_Hint    read  = hints->hints;
195*37da2899SCharles.Forsyth 
196*37da2899SCharles.Forsyth 
197*37da2899SCharles.Forsyth       for ( ; count > 0; count--, write++, read++ )
198*37da2899SCharles.Forsyth       {
199*37da2899SCharles.Forsyth         write->org_pos = read->pos;
200*37da2899SCharles.Forsyth         write->org_len = read->len;
201*37da2899SCharles.Forsyth         write->flags   = read->flags;
202*37da2899SCharles.Forsyth       }
203*37da2899SCharles.Forsyth     }
204*37da2899SCharles.Forsyth 
205*37da2899SCharles.Forsyth     /* we now need to determine the initial "parent" stems; first  */
206*37da2899SCharles.Forsyth     /* activate the hints that are given by the initial hint masks */
207*37da2899SCharles.Forsyth     if ( hint_masks )
208*37da2899SCharles.Forsyth     {
209*37da2899SCharles.Forsyth       FT_UInt  Count = hint_masks->num_masks;
210*37da2899SCharles.Forsyth       PS_Mask  Mask  = hint_masks->masks;
211*37da2899SCharles.Forsyth 
212*37da2899SCharles.Forsyth 
213*37da2899SCharles.Forsyth       table->hint_masks = hint_masks;
214*37da2899SCharles.Forsyth 
215*37da2899SCharles.Forsyth       for ( ; Count > 0; Count--, Mask++ )
216*37da2899SCharles.Forsyth         psh3_hint_table_record_mask( table, Mask );
217*37da2899SCharles.Forsyth     }
218*37da2899SCharles.Forsyth 
219*37da2899SCharles.Forsyth     /* now, do a linear parse in case some hints were left alone */
220*37da2899SCharles.Forsyth     if ( table->num_hints != table->max_hints )
221*37da2899SCharles.Forsyth     {
222*37da2899SCharles.Forsyth       FT_UInt  Index, Count;
223*37da2899SCharles.Forsyth 
224*37da2899SCharles.Forsyth 
225*37da2899SCharles.Forsyth       FT_ERROR(( "psh3_hint_table_init: missing/incorrect hint masks!\n" ));
226*37da2899SCharles.Forsyth       Count = table->max_hints;
227*37da2899SCharles.Forsyth       for ( Index = 0; Index < Count; Index++ )
228*37da2899SCharles.Forsyth         psh3_hint_table_record( table, Index );
229*37da2899SCharles.Forsyth     }
230*37da2899SCharles.Forsyth 
231*37da2899SCharles.Forsyth   Exit:
232*37da2899SCharles.Forsyth     return error;
233*37da2899SCharles.Forsyth   }
234*37da2899SCharles.Forsyth 
235*37da2899SCharles.Forsyth 
236*37da2899SCharles.Forsyth   static void
psh3_hint_table_activate_mask(PSH3_Hint_Table table,PS_Mask hint_mask)237*37da2899SCharles.Forsyth   psh3_hint_table_activate_mask( PSH3_Hint_Table  table,
238*37da2899SCharles.Forsyth                                  PS_Mask          hint_mask )
239*37da2899SCharles.Forsyth   {
240*37da2899SCharles.Forsyth     FT_Int    mask = 0, val = 0;
241*37da2899SCharles.Forsyth     FT_Byte*  cursor = hint_mask->bytes;
242*37da2899SCharles.Forsyth     FT_UInt   idx, limit, count;
243*37da2899SCharles.Forsyth 
244*37da2899SCharles.Forsyth 
245*37da2899SCharles.Forsyth     limit = hint_mask->num_bits;
246*37da2899SCharles.Forsyth     count = 0;
247*37da2899SCharles.Forsyth 
248*37da2899SCharles.Forsyth     psh3_hint_table_deactivate( table );
249*37da2899SCharles.Forsyth 
250*37da2899SCharles.Forsyth     for ( idx = 0; idx < limit; idx++ )
251*37da2899SCharles.Forsyth     {
252*37da2899SCharles.Forsyth       if ( mask == 0 )
253*37da2899SCharles.Forsyth       {
254*37da2899SCharles.Forsyth         val  = *cursor++;
255*37da2899SCharles.Forsyth         mask = 0x80;
256*37da2899SCharles.Forsyth       }
257*37da2899SCharles.Forsyth 
258*37da2899SCharles.Forsyth       if ( val & mask )
259*37da2899SCharles.Forsyth       {
260*37da2899SCharles.Forsyth         PSH3_Hint  hint = &table->hints[idx];
261*37da2899SCharles.Forsyth 
262*37da2899SCharles.Forsyth 
263*37da2899SCharles.Forsyth         if ( !psh3_hint_is_active( hint ) )
264*37da2899SCharles.Forsyth         {
265*37da2899SCharles.Forsyth           FT_UInt     count2;
266*37da2899SCharles.Forsyth 
267*37da2899SCharles.Forsyth #if 0
268*37da2899SCharles.Forsyth           PSH3_Hint*  sort = table->sort;
269*37da2899SCharles.Forsyth           PSH3_Hint   hint2;
270*37da2899SCharles.Forsyth 
271*37da2899SCharles.Forsyth 
272*37da2899SCharles.Forsyth           for ( count2 = count; count2 > 0; count2--, sort++ )
273*37da2899SCharles.Forsyth           {
274*37da2899SCharles.Forsyth             hint2 = sort[0];
275*37da2899SCharles.Forsyth             if ( psh3_hint_overlap( hint, hint2 ) )
276*37da2899SCharles.Forsyth               FT_ERROR(( "psh3_hint_table_activate_mask:"
277*37da2899SCharles.Forsyth                          " found overlapping hints\n" ))
278*37da2899SCharles.Forsyth           }
279*37da2899SCharles.Forsyth #else
280*37da2899SCharles.Forsyth           count2 = 0;
281*37da2899SCharles.Forsyth #endif
282*37da2899SCharles.Forsyth 
283*37da2899SCharles.Forsyth           if ( count2 == 0 )
284*37da2899SCharles.Forsyth           {
285*37da2899SCharles.Forsyth             psh3_hint_activate( hint );
286*37da2899SCharles.Forsyth             if ( count < table->max_hints )
287*37da2899SCharles.Forsyth               table->sort[count++] = hint;
288*37da2899SCharles.Forsyth             else
289*37da2899SCharles.Forsyth               FT_ERROR(( "psh3_hint_tableactivate_mask:"
290*37da2899SCharles.Forsyth                          " too many active hints\n" ));
291*37da2899SCharles.Forsyth           }
292*37da2899SCharles.Forsyth         }
293*37da2899SCharles.Forsyth       }
294*37da2899SCharles.Forsyth 
295*37da2899SCharles.Forsyth       mask >>= 1;
296*37da2899SCharles.Forsyth     }
297*37da2899SCharles.Forsyth     table->num_hints = count;
298*37da2899SCharles.Forsyth 
299*37da2899SCharles.Forsyth     /* now, sort the hints; they are guaranteed to not overlap */
300*37da2899SCharles.Forsyth     /* so we can compare their "org_pos" field directly        */
301*37da2899SCharles.Forsyth     {
302*37da2899SCharles.Forsyth       FT_Int      i1, i2;
303*37da2899SCharles.Forsyth       PSH3_Hint   hint1, hint2;
304*37da2899SCharles.Forsyth       PSH3_Hint*  sort = table->sort;
305*37da2899SCharles.Forsyth 
306*37da2899SCharles.Forsyth 
307*37da2899SCharles.Forsyth       /* a simple bubble sort will do, since in 99% of cases, the hints */
308*37da2899SCharles.Forsyth       /* will be already sorted -- and the sort will be linear          */
309*37da2899SCharles.Forsyth       for ( i1 = 1; i1 < (FT_Int)count; i1++ )
310*37da2899SCharles.Forsyth       {
311*37da2899SCharles.Forsyth         hint1 = sort[i1];
312*37da2899SCharles.Forsyth         for ( i2 = i1 - 1; i2 >= 0; i2-- )
313*37da2899SCharles.Forsyth         {
314*37da2899SCharles.Forsyth           hint2 = sort[i2];
315*37da2899SCharles.Forsyth 
316*37da2899SCharles.Forsyth           if ( hint2->org_pos < hint1->org_pos )
317*37da2899SCharles.Forsyth             break;
318*37da2899SCharles.Forsyth 
319*37da2899SCharles.Forsyth           sort[i2 + 1] = hint2;
320*37da2899SCharles.Forsyth           sort[i2]     = hint1;
321*37da2899SCharles.Forsyth         }
322*37da2899SCharles.Forsyth       }
323*37da2899SCharles.Forsyth     }
324*37da2899SCharles.Forsyth   }
325*37da2899SCharles.Forsyth 
326*37da2899SCharles.Forsyth 
327*37da2899SCharles.Forsyth   /*************************************************************************/
328*37da2899SCharles.Forsyth   /*************************************************************************/
329*37da2899SCharles.Forsyth   /*****                                                               *****/
330*37da2899SCharles.Forsyth   /*****               HINTS GRID-FITTING AND OPTIMIZATION             *****/
331*37da2899SCharles.Forsyth   /*****                                                               *****/
332*37da2899SCharles.Forsyth   /*************************************************************************/
333*37da2899SCharles.Forsyth   /*************************************************************************/
334*37da2899SCharles.Forsyth 
335*37da2899SCharles.Forsyth   static FT_Pos
psh3_dimension_quantize_len(PSH_Dimension dim,FT_Pos len,FT_Bool do_snapping)336*37da2899SCharles.Forsyth   psh3_dimension_quantize_len( PSH_Dimension  dim,
337*37da2899SCharles.Forsyth                                FT_Pos         len,
338*37da2899SCharles.Forsyth                                FT_Bool        do_snapping )
339*37da2899SCharles.Forsyth   {
340*37da2899SCharles.Forsyth     if ( len <= 64 )
341*37da2899SCharles.Forsyth       len = 64;
342*37da2899SCharles.Forsyth     else
343*37da2899SCharles.Forsyth     {
344*37da2899SCharles.Forsyth       FT_Pos  delta = len - dim->stdw.widths[0].cur;
345*37da2899SCharles.Forsyth 
346*37da2899SCharles.Forsyth 
347*37da2899SCharles.Forsyth       if ( delta < 0 )
348*37da2899SCharles.Forsyth         delta = -delta;
349*37da2899SCharles.Forsyth 
350*37da2899SCharles.Forsyth       if ( delta < 40 )
351*37da2899SCharles.Forsyth       {
352*37da2899SCharles.Forsyth         len = dim->stdw.widths[0].cur;
353*37da2899SCharles.Forsyth         if ( len < 48 )
354*37da2899SCharles.Forsyth           len = 48;
355*37da2899SCharles.Forsyth       }
356*37da2899SCharles.Forsyth 
357*37da2899SCharles.Forsyth       if ( len < 3 * 64 )
358*37da2899SCharles.Forsyth       {
359*37da2899SCharles.Forsyth         delta = ( len & 63 );
360*37da2899SCharles.Forsyth         len  &= -64;
361*37da2899SCharles.Forsyth 
362*37da2899SCharles.Forsyth         if ( delta < 10 )
363*37da2899SCharles.Forsyth           len += delta;
364*37da2899SCharles.Forsyth 
365*37da2899SCharles.Forsyth         else if ( delta < 32 )
366*37da2899SCharles.Forsyth           len += 10;
367*37da2899SCharles.Forsyth 
368*37da2899SCharles.Forsyth         else if ( delta < 54 )
369*37da2899SCharles.Forsyth           len += 54;
370*37da2899SCharles.Forsyth 
371*37da2899SCharles.Forsyth         else
372*37da2899SCharles.Forsyth           len += delta;
373*37da2899SCharles.Forsyth       }
374*37da2899SCharles.Forsyth       else
375*37da2899SCharles.Forsyth         len = ( len + 32 ) & -64;
376*37da2899SCharles.Forsyth     }
377*37da2899SCharles.Forsyth 
378*37da2899SCharles.Forsyth     if ( do_snapping )
379*37da2899SCharles.Forsyth       len = ( len + 32 ) & -64;
380*37da2899SCharles.Forsyth 
381*37da2899SCharles.Forsyth     return  len;
382*37da2899SCharles.Forsyth   }
383*37da2899SCharles.Forsyth 
384*37da2899SCharles.Forsyth 
385*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
386*37da2899SCharles.Forsyth 
387*37da2899SCharles.Forsyth   static void
ps3_simple_scale(PSH3_Hint_Table table,FT_Fixed scale,FT_Fixed delta,FT_Int dimension)388*37da2899SCharles.Forsyth   ps3_simple_scale( PSH3_Hint_Table  table,
389*37da2899SCharles.Forsyth                     FT_Fixed         scale,
390*37da2899SCharles.Forsyth                     FT_Fixed         delta,
391*37da2899SCharles.Forsyth                     FT_Int           dimension )
392*37da2899SCharles.Forsyth   {
393*37da2899SCharles.Forsyth     PSH3_Hint  hint;
394*37da2899SCharles.Forsyth     FT_UInt    count;
395*37da2899SCharles.Forsyth 
396*37da2899SCharles.Forsyth 
397*37da2899SCharles.Forsyth     for ( count = 0; count < table->max_hints; count++ )
398*37da2899SCharles.Forsyth     {
399*37da2899SCharles.Forsyth       hint = table->hints + count;
400*37da2899SCharles.Forsyth 
401*37da2899SCharles.Forsyth       hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
402*37da2899SCharles.Forsyth       hint->cur_len = FT_MulFix( hint->org_len, scale );
403*37da2899SCharles.Forsyth 
404*37da2899SCharles.Forsyth       if ( ps3_debug_hint_func )
405*37da2899SCharles.Forsyth         ps3_debug_hint_func( hint, dimension );
406*37da2899SCharles.Forsyth     }
407*37da2899SCharles.Forsyth   }
408*37da2899SCharles.Forsyth 
409*37da2899SCharles.Forsyth #endif /* DEBUG_HINTER */
410*37da2899SCharles.Forsyth 
411*37da2899SCharles.Forsyth 
412*37da2899SCharles.Forsyth   static FT_Fixed
psh3_hint_snap_stem_side_delta(FT_Fixed pos,FT_Fixed len)413*37da2899SCharles.Forsyth   psh3_hint_snap_stem_side_delta( FT_Fixed  pos,
414*37da2899SCharles.Forsyth                                   FT_Fixed  len )
415*37da2899SCharles.Forsyth   {
416*37da2899SCharles.Forsyth     FT_Fixed  delta1 = ( ( pos + 32 ) & -64 ) - pos;
417*37da2899SCharles.Forsyth     FT_Fixed  delta2 = ( ( pos + len + 32 ) & -64  ) - pos - len;
418*37da2899SCharles.Forsyth 
419*37da2899SCharles.Forsyth 
420*37da2899SCharles.Forsyth     if ( ABS( delta1 ) <= ABS( delta2 ) )
421*37da2899SCharles.Forsyth       return delta1;
422*37da2899SCharles.Forsyth     else
423*37da2899SCharles.Forsyth       return delta2;
424*37da2899SCharles.Forsyth   }
425*37da2899SCharles.Forsyth 
426*37da2899SCharles.Forsyth 
427*37da2899SCharles.Forsyth   static void
psh3_hint_align(PSH3_Hint hint,PSH_Globals globals,FT_Int dimension,PSH3_Glyph glyph)428*37da2899SCharles.Forsyth   psh3_hint_align( PSH3_Hint    hint,
429*37da2899SCharles.Forsyth                    PSH_Globals  globals,
430*37da2899SCharles.Forsyth                    FT_Int       dimension,
431*37da2899SCharles.Forsyth                    PSH3_Glyph   glyph )
432*37da2899SCharles.Forsyth   {
433*37da2899SCharles.Forsyth     PSH_Dimension  dim   = &globals->dimension[dimension];
434*37da2899SCharles.Forsyth     FT_Fixed       scale = dim->scale_mult;
435*37da2899SCharles.Forsyth     FT_Fixed       delta = dim->scale_delta;
436*37da2899SCharles.Forsyth 
437*37da2899SCharles.Forsyth 
438*37da2899SCharles.Forsyth     if ( !psh3_hint_is_fitted( hint ) )
439*37da2899SCharles.Forsyth     {
440*37da2899SCharles.Forsyth       FT_Pos  pos = FT_MulFix( hint->org_pos, scale ) + delta;
441*37da2899SCharles.Forsyth       FT_Pos  len = FT_MulFix( hint->org_len, scale );
442*37da2899SCharles.Forsyth 
443*37da2899SCharles.Forsyth       FT_Int            do_snapping;
444*37da2899SCharles.Forsyth       FT_Pos            fit_len;
445*37da2899SCharles.Forsyth       PSH_AlignmentRec  align;
446*37da2899SCharles.Forsyth 
447*37da2899SCharles.Forsyth 
448*37da2899SCharles.Forsyth       /* ignore stem alignments when requested through the hint flags */
449*37da2899SCharles.Forsyth       if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
450*37da2899SCharles.Forsyth            ( dimension == 1 && !glyph->do_vert_hints ) )
451*37da2899SCharles.Forsyth       {
452*37da2899SCharles.Forsyth         hint->cur_pos = pos;
453*37da2899SCharles.Forsyth         hint->cur_len = len;
454*37da2899SCharles.Forsyth 
455*37da2899SCharles.Forsyth         psh3_hint_set_fitted( hint );
456*37da2899SCharles.Forsyth         return;
457*37da2899SCharles.Forsyth       }
458*37da2899SCharles.Forsyth 
459*37da2899SCharles.Forsyth       /* perform stem snapping when requested */
460*37da2899SCharles.Forsyth       do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
461*37da2899SCharles.Forsyth                     ( dimension == 1 && glyph->do_vert_snapping );
462*37da2899SCharles.Forsyth 
463*37da2899SCharles.Forsyth       hint->cur_len = fit_len = len;
464*37da2899SCharles.Forsyth 
465*37da2899SCharles.Forsyth       /* check blue zones for horizontal stems */
466*37da2899SCharles.Forsyth       align.align     = PSH_BLUE_ALIGN_NONE;
467*37da2899SCharles.Forsyth       align.align_bot = align.align_top = 0;
468*37da2899SCharles.Forsyth 
469*37da2899SCharles.Forsyth       if ( dimension == 1 )
470*37da2899SCharles.Forsyth         psh_blues_snap_stem( &globals->blues,
471*37da2899SCharles.Forsyth                              hint->org_pos + hint->org_len,
472*37da2899SCharles.Forsyth                              hint->org_pos,
473*37da2899SCharles.Forsyth                              &align );
474*37da2899SCharles.Forsyth 
475*37da2899SCharles.Forsyth       switch ( align.align )
476*37da2899SCharles.Forsyth       {
477*37da2899SCharles.Forsyth       case PSH_BLUE_ALIGN_TOP:
478*37da2899SCharles.Forsyth         /* the top of the stem is aligned against a blue zone */
479*37da2899SCharles.Forsyth         hint->cur_pos = align.align_top - fit_len;
480*37da2899SCharles.Forsyth         break;
481*37da2899SCharles.Forsyth 
482*37da2899SCharles.Forsyth       case PSH_BLUE_ALIGN_BOT:
483*37da2899SCharles.Forsyth         /* the bottom of the stem is aligned against a blue zone */
484*37da2899SCharles.Forsyth         hint->cur_pos = align.align_bot;
485*37da2899SCharles.Forsyth         break;
486*37da2899SCharles.Forsyth 
487*37da2899SCharles.Forsyth       case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
488*37da2899SCharles.Forsyth         /* both edges of the stem are aligned against blue zones */
489*37da2899SCharles.Forsyth         hint->cur_pos = align.align_bot;
490*37da2899SCharles.Forsyth         hint->cur_len = align.align_top - align.align_bot;
491*37da2899SCharles.Forsyth         break;
492*37da2899SCharles.Forsyth 
493*37da2899SCharles.Forsyth       default:
494*37da2899SCharles.Forsyth         {
495*37da2899SCharles.Forsyth           PSH3_Hint  parent = hint->parent;
496*37da2899SCharles.Forsyth 
497*37da2899SCharles.Forsyth 
498*37da2899SCharles.Forsyth           if ( parent )
499*37da2899SCharles.Forsyth           {
500*37da2899SCharles.Forsyth             FT_Pos  par_org_center, par_cur_center;
501*37da2899SCharles.Forsyth             FT_Pos  cur_org_center, cur_delta;
502*37da2899SCharles.Forsyth 
503*37da2899SCharles.Forsyth 
504*37da2899SCharles.Forsyth             /* ensure that parent is already fitted */
505*37da2899SCharles.Forsyth             if ( !psh3_hint_is_fitted( parent ) )
506*37da2899SCharles.Forsyth               psh3_hint_align( parent, globals, dimension, glyph );
507*37da2899SCharles.Forsyth 
508*37da2899SCharles.Forsyth             par_org_center = parent->org_pos + ( parent->org_len >> 1 );
509*37da2899SCharles.Forsyth             par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
510*37da2899SCharles.Forsyth             cur_org_center = hint->org_pos   + ( hint->org_len   >> 1 );
511*37da2899SCharles.Forsyth 
512*37da2899SCharles.Forsyth             cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
513*37da2899SCharles.Forsyth             pos       = par_cur_center + cur_delta - ( len >> 1 );
514*37da2899SCharles.Forsyth           }
515*37da2899SCharles.Forsyth 
516*37da2899SCharles.Forsyth           hint->cur_pos = pos;
517*37da2899SCharles.Forsyth           hint->cur_len = fit_len;
518*37da2899SCharles.Forsyth 
519*37da2899SCharles.Forsyth           if ( len <= 64 )
520*37da2899SCharles.Forsyth           {
521*37da2899SCharles.Forsyth             /* the stem is less than one pixel, we will center it */
522*37da2899SCharles.Forsyth             /* around the nearest pixel center                    */
523*37da2899SCharles.Forsyth             /*                                                    */
524*37da2899SCharles.Forsyth             pos = ( pos + ( (len >> 1) & -64 ) );
525*37da2899SCharles.Forsyth             len = 64;
526*37da2899SCharles.Forsyth           }
527*37da2899SCharles.Forsyth           else
528*37da2899SCharles.Forsyth           {
529*37da2899SCharles.Forsyth             len = psh3_dimension_quantize_len( dim, len, 0 );
530*37da2899SCharles.Forsyth           }
531*37da2899SCharles.Forsyth 
532*37da2899SCharles.Forsyth           /* now that we have a good hinted stem width, try to position */
533*37da2899SCharles.Forsyth           /* the stem along a pixel grid integer coordinate             */
534*37da2899SCharles.Forsyth           hint->cur_pos = pos + psh3_hint_snap_stem_side_delta( pos, len );
535*37da2899SCharles.Forsyth           hint->cur_len = len;
536*37da2899SCharles.Forsyth         }
537*37da2899SCharles.Forsyth       }
538*37da2899SCharles.Forsyth 
539*37da2899SCharles.Forsyth       if ( do_snapping )
540*37da2899SCharles.Forsyth       {
541*37da2899SCharles.Forsyth         pos = hint->cur_pos;
542*37da2899SCharles.Forsyth         len = hint->cur_len;
543*37da2899SCharles.Forsyth 
544*37da2899SCharles.Forsyth         if ( len < 64 )
545*37da2899SCharles.Forsyth           len = 64;
546*37da2899SCharles.Forsyth         else
547*37da2899SCharles.Forsyth           len = ( len + 32 ) & -64;
548*37da2899SCharles.Forsyth 
549*37da2899SCharles.Forsyth         switch ( align.align )
550*37da2899SCharles.Forsyth         {
551*37da2899SCharles.Forsyth           case PSH_BLUE_ALIGN_TOP:
552*37da2899SCharles.Forsyth             hint->cur_pos = align.align_top - len;
553*37da2899SCharles.Forsyth             hint->cur_len = len;
554*37da2899SCharles.Forsyth             break;
555*37da2899SCharles.Forsyth 
556*37da2899SCharles.Forsyth           case PSH_BLUE_ALIGN_BOT:
557*37da2899SCharles.Forsyth             hint->cur_len = len;
558*37da2899SCharles.Forsyth             break;
559*37da2899SCharles.Forsyth 
560*37da2899SCharles.Forsyth           case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
561*37da2899SCharles.Forsyth             /* don't touch */
562*37da2899SCharles.Forsyth             break;
563*37da2899SCharles.Forsyth 
564*37da2899SCharles.Forsyth 
565*37da2899SCharles.Forsyth           default:
566*37da2899SCharles.Forsyth             hint->cur_len = len;
567*37da2899SCharles.Forsyth             if ( len & 64 )
568*37da2899SCharles.Forsyth               pos = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
569*37da2899SCharles.Forsyth             else
570*37da2899SCharles.Forsyth               pos = ( pos + ( len >> 1 ) + 32 ) & -64;
571*37da2899SCharles.Forsyth 
572*37da2899SCharles.Forsyth             hint->cur_pos = pos - ( len >> 1 );
573*37da2899SCharles.Forsyth             hint->cur_len = len;
574*37da2899SCharles.Forsyth         }
575*37da2899SCharles.Forsyth       }
576*37da2899SCharles.Forsyth 
577*37da2899SCharles.Forsyth       psh3_hint_set_fitted( hint );
578*37da2899SCharles.Forsyth 
579*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
580*37da2899SCharles.Forsyth       if ( ps3_debug_hint_func )
581*37da2899SCharles.Forsyth         ps3_debug_hint_func( hint, dimension );
582*37da2899SCharles.Forsyth #endif
583*37da2899SCharles.Forsyth     }
584*37da2899SCharles.Forsyth   }
585*37da2899SCharles.Forsyth 
586*37da2899SCharles.Forsyth 
587*37da2899SCharles.Forsyth   static void
psh3_hint_table_align_hints(PSH3_Hint_Table table,PSH_Globals globals,FT_Int dimension,PSH3_Glyph glyph)588*37da2899SCharles.Forsyth   psh3_hint_table_align_hints( PSH3_Hint_Table  table,
589*37da2899SCharles.Forsyth                                PSH_Globals      globals,
590*37da2899SCharles.Forsyth                                FT_Int           dimension,
591*37da2899SCharles.Forsyth                                PSH3_Glyph       glyph )
592*37da2899SCharles.Forsyth   {
593*37da2899SCharles.Forsyth     PSH3_Hint      hint;
594*37da2899SCharles.Forsyth     FT_UInt        count;
595*37da2899SCharles.Forsyth 
596*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
597*37da2899SCharles.Forsyth 
598*37da2899SCharles.Forsyth     PSH_Dimension  dim   = &globals->dimension[dimension];
599*37da2899SCharles.Forsyth     FT_Fixed       scale = dim->scale_mult;
600*37da2899SCharles.Forsyth     FT_Fixed       delta = dim->scale_delta;
601*37da2899SCharles.Forsyth 
602*37da2899SCharles.Forsyth 
603*37da2899SCharles.Forsyth     if ( ps_debug_no_vert_hints && dimension == 0 )
604*37da2899SCharles.Forsyth     {
605*37da2899SCharles.Forsyth       ps3_simple_scale( table, scale, delta, dimension );
606*37da2899SCharles.Forsyth       return;
607*37da2899SCharles.Forsyth     }
608*37da2899SCharles.Forsyth 
609*37da2899SCharles.Forsyth     if ( ps_debug_no_horz_hints && dimension == 1 )
610*37da2899SCharles.Forsyth     {
611*37da2899SCharles.Forsyth       ps3_simple_scale( table, scale, delta, dimension );
612*37da2899SCharles.Forsyth       return;
613*37da2899SCharles.Forsyth     }
614*37da2899SCharles.Forsyth 
615*37da2899SCharles.Forsyth #endif /* DEBUG_HINTER*/
616*37da2899SCharles.Forsyth 
617*37da2899SCharles.Forsyth     hint  = table->hints;
618*37da2899SCharles.Forsyth     count = table->max_hints;
619*37da2899SCharles.Forsyth 
620*37da2899SCharles.Forsyth     for ( ; count > 0; count--, hint++ )
621*37da2899SCharles.Forsyth       psh3_hint_align( hint, globals, dimension, glyph );
622*37da2899SCharles.Forsyth   }
623*37da2899SCharles.Forsyth 
624*37da2899SCharles.Forsyth 
625*37da2899SCharles.Forsyth   /*************************************************************************/
626*37da2899SCharles.Forsyth   /*************************************************************************/
627*37da2899SCharles.Forsyth   /*****                                                               *****/
628*37da2899SCharles.Forsyth   /*****                POINTS INTERPOLATION ROUTINES                  *****/
629*37da2899SCharles.Forsyth   /*****                                                               *****/
630*37da2899SCharles.Forsyth   /*************************************************************************/
631*37da2899SCharles.Forsyth   /*************************************************************************/
632*37da2899SCharles.Forsyth 
633*37da2899SCharles.Forsyth #define PSH3_ZONE_MIN  -3200000L
634*37da2899SCharles.Forsyth #define PSH3_ZONE_MAX  +3200000L
635*37da2899SCharles.Forsyth 
636*37da2899SCharles.Forsyth #define xxDEBUG_ZONES
637*37da2899SCharles.Forsyth 
638*37da2899SCharles.Forsyth 
639*37da2899SCharles.Forsyth #ifdef DEBUG_ZONES
640*37da2899SCharles.Forsyth 
641*37da2899SCharles.Forsyth #include <stdio.h>
642*37da2899SCharles.Forsyth 
643*37da2899SCharles.Forsyth   static void
psh3_print_zone(PSH3_Zone zone)644*37da2899SCharles.Forsyth   psh3_print_zone( PSH3_Zone  zone )
645*37da2899SCharles.Forsyth   {
646*37da2899SCharles.Forsyth     printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
647*37da2899SCharles.Forsyth              zone->scale / 65536.0,
648*37da2899SCharles.Forsyth              zone->delta / 64.0,
649*37da2899SCharles.Forsyth              zone->min,
650*37da2899SCharles.Forsyth              zone->max );
651*37da2899SCharles.Forsyth   }
652*37da2899SCharles.Forsyth 
653*37da2899SCharles.Forsyth #else
654*37da2899SCharles.Forsyth 
655*37da2899SCharles.Forsyth #define psh3_print_zone( x )  do { } while ( 0 )
656*37da2899SCharles.Forsyth 
657*37da2899SCharles.Forsyth #endif /* DEBUG_ZONES */
658*37da2899SCharles.Forsyth 
659*37da2899SCharles.Forsyth 
660*37da2899SCharles.Forsyth   /*************************************************************************/
661*37da2899SCharles.Forsyth   /*************************************************************************/
662*37da2899SCharles.Forsyth   /*****                                                               *****/
663*37da2899SCharles.Forsyth   /*****                    HINTER GLYPH MANAGEMENT                    *****/
664*37da2899SCharles.Forsyth   /*****                                                               *****/
665*37da2899SCharles.Forsyth   /*************************************************************************/
666*37da2899SCharles.Forsyth   /*************************************************************************/
667*37da2899SCharles.Forsyth 
668*37da2899SCharles.Forsyth #ifdef COMPUTE_INFLEXS
669*37da2899SCharles.Forsyth 
670*37da2899SCharles.Forsyth   /* compute all inflex points in a given glyph */
671*37da2899SCharles.Forsyth   static void
psh3_glyph_compute_inflections(PSH3_Glyph glyph)672*37da2899SCharles.Forsyth   psh3_glyph_compute_inflections( PSH3_Glyph  glyph )
673*37da2899SCharles.Forsyth   {
674*37da2899SCharles.Forsyth     FT_UInt  n;
675*37da2899SCharles.Forsyth 
676*37da2899SCharles.Forsyth 
677*37da2899SCharles.Forsyth     for ( n = 0; n < glyph->num_contours; n++ )
678*37da2899SCharles.Forsyth     {
679*37da2899SCharles.Forsyth       PSH3_Point  first, start, end, before, after;
680*37da2899SCharles.Forsyth       FT_Angle    angle_in, angle_seg, angle_out;
681*37da2899SCharles.Forsyth       FT_Angle    diff_in, diff_out;
682*37da2899SCharles.Forsyth       FT_Int      finished = 0;
683*37da2899SCharles.Forsyth 
684*37da2899SCharles.Forsyth 
685*37da2899SCharles.Forsyth       /* we need at least 4 points to create an inflection point */
686*37da2899SCharles.Forsyth       if ( glyph->contours[n].count < 4 )
687*37da2899SCharles.Forsyth         continue;
688*37da2899SCharles.Forsyth 
689*37da2899SCharles.Forsyth       /* compute first segment in contour */
690*37da2899SCharles.Forsyth       first = glyph->contours[n].start;
691*37da2899SCharles.Forsyth 
692*37da2899SCharles.Forsyth       start = end = first;
693*37da2899SCharles.Forsyth       do
694*37da2899SCharles.Forsyth       {
695*37da2899SCharles.Forsyth         end = end->next;
696*37da2899SCharles.Forsyth         if ( end == first )
697*37da2899SCharles.Forsyth           goto Skip;
698*37da2899SCharles.Forsyth 
699*37da2899SCharles.Forsyth       } while ( PSH3_POINT_EQUAL_ORG( end, first ) );
700*37da2899SCharles.Forsyth 
701*37da2899SCharles.Forsyth       angle_seg = PSH3_POINT_ANGLE( start, end );
702*37da2899SCharles.Forsyth 
703*37da2899SCharles.Forsyth       /* extend the segment start whenever possible */
704*37da2899SCharles.Forsyth       before = start;
705*37da2899SCharles.Forsyth       do
706*37da2899SCharles.Forsyth       {
707*37da2899SCharles.Forsyth         do
708*37da2899SCharles.Forsyth         {
709*37da2899SCharles.Forsyth           start  = before;
710*37da2899SCharles.Forsyth           before = before->prev;
711*37da2899SCharles.Forsyth           if ( before == first )
712*37da2899SCharles.Forsyth             goto Skip;
713*37da2899SCharles.Forsyth 
714*37da2899SCharles.Forsyth         } while ( PSH3_POINT_EQUAL_ORG( before, start ) );
715*37da2899SCharles.Forsyth 
716*37da2899SCharles.Forsyth         angle_in = PSH3_POINT_ANGLE( before, start );
717*37da2899SCharles.Forsyth 
718*37da2899SCharles.Forsyth       } while ( angle_in == angle_seg );
719*37da2899SCharles.Forsyth 
720*37da2899SCharles.Forsyth       first   = start;
721*37da2899SCharles.Forsyth       diff_in = FT_Angle_Diff( angle_in, angle_seg );
722*37da2899SCharles.Forsyth 
723*37da2899SCharles.Forsyth       /* now, process all segments in the contour */
724*37da2899SCharles.Forsyth       do
725*37da2899SCharles.Forsyth       {
726*37da2899SCharles.Forsyth         /* first, extend current segment's end whenever possible */
727*37da2899SCharles.Forsyth         after = end;
728*37da2899SCharles.Forsyth         do
729*37da2899SCharles.Forsyth         {
730*37da2899SCharles.Forsyth           do
731*37da2899SCharles.Forsyth           {
732*37da2899SCharles.Forsyth             end   = after;
733*37da2899SCharles.Forsyth             after = after->next;
734*37da2899SCharles.Forsyth             if ( after == first )
735*37da2899SCharles.Forsyth               finished = 1;
736*37da2899SCharles.Forsyth 
737*37da2899SCharles.Forsyth           } while ( PSH3_POINT_EQUAL_ORG( end, after ) );
738*37da2899SCharles.Forsyth 
739*37da2899SCharles.Forsyth           angle_out = PSH3_POINT_ANGLE( end, after );
740*37da2899SCharles.Forsyth 
741*37da2899SCharles.Forsyth         } while ( angle_out == angle_seg );
742*37da2899SCharles.Forsyth 
743*37da2899SCharles.Forsyth         diff_out = FT_Angle_Diff( angle_seg, angle_out );
744*37da2899SCharles.Forsyth 
745*37da2899SCharles.Forsyth         if ( ( diff_in ^ diff_out ) < 0 )
746*37da2899SCharles.Forsyth         {
747*37da2899SCharles.Forsyth           /* diff_in and diff_out have different signs, we have */
748*37da2899SCharles.Forsyth           /* inflection points here...                          */
749*37da2899SCharles.Forsyth 
750*37da2899SCharles.Forsyth           do
751*37da2899SCharles.Forsyth           {
752*37da2899SCharles.Forsyth             psh3_point_set_inflex( start );
753*37da2899SCharles.Forsyth             start = start->next;
754*37da2899SCharles.Forsyth           }
755*37da2899SCharles.Forsyth           while ( start != end );
756*37da2899SCharles.Forsyth 
757*37da2899SCharles.Forsyth           psh3_point_set_inflex( start );
758*37da2899SCharles.Forsyth         }
759*37da2899SCharles.Forsyth 
760*37da2899SCharles.Forsyth         start     = end;
761*37da2899SCharles.Forsyth         end       = after;
762*37da2899SCharles.Forsyth         angle_seg = angle_out;
763*37da2899SCharles.Forsyth         diff_in   = diff_out;
764*37da2899SCharles.Forsyth 
765*37da2899SCharles.Forsyth       } while ( !finished );
766*37da2899SCharles.Forsyth 
767*37da2899SCharles.Forsyth     Skip:
768*37da2899SCharles.Forsyth       ;
769*37da2899SCharles.Forsyth     }
770*37da2899SCharles.Forsyth   }
771*37da2899SCharles.Forsyth 
772*37da2899SCharles.Forsyth #endif /* COMPUTE_INFLEXS */
773*37da2899SCharles.Forsyth 
774*37da2899SCharles.Forsyth 
775*37da2899SCharles.Forsyth   static void
psh3_glyph_done(PSH3_Glyph glyph)776*37da2899SCharles.Forsyth   psh3_glyph_done( PSH3_Glyph  glyph )
777*37da2899SCharles.Forsyth   {
778*37da2899SCharles.Forsyth     FT_Memory  memory = glyph->memory;
779*37da2899SCharles.Forsyth 
780*37da2899SCharles.Forsyth 
781*37da2899SCharles.Forsyth     psh3_hint_table_done( &glyph->hint_tables[1], memory );
782*37da2899SCharles.Forsyth     psh3_hint_table_done( &glyph->hint_tables[0], memory );
783*37da2899SCharles.Forsyth 
784*37da2899SCharles.Forsyth     FT_FREE( glyph->points );
785*37da2899SCharles.Forsyth     FT_FREE( glyph->contours );
786*37da2899SCharles.Forsyth 
787*37da2899SCharles.Forsyth     glyph->num_points   = 0;
788*37da2899SCharles.Forsyth     glyph->num_contours = 0;
789*37da2899SCharles.Forsyth 
790*37da2899SCharles.Forsyth     glyph->memory = 0;
791*37da2899SCharles.Forsyth   }
792*37da2899SCharles.Forsyth 
793*37da2899SCharles.Forsyth 
794*37da2899SCharles.Forsyth   static int
psh3_compute_dir(FT_Pos dx,FT_Pos dy)795*37da2899SCharles.Forsyth   psh3_compute_dir( FT_Pos  dx,
796*37da2899SCharles.Forsyth                     FT_Pos  dy )
797*37da2899SCharles.Forsyth   {
798*37da2899SCharles.Forsyth     FT_Pos  ax, ay;
799*37da2899SCharles.Forsyth     int     result = PSH3_DIR_NONE;
800*37da2899SCharles.Forsyth 
801*37da2899SCharles.Forsyth 
802*37da2899SCharles.Forsyth     ax = ( dx >= 0 ) ? dx : -dx;
803*37da2899SCharles.Forsyth     ay = ( dy >= 0 ) ? dy : -dy;
804*37da2899SCharles.Forsyth 
805*37da2899SCharles.Forsyth     if ( ay * 12 < ax )
806*37da2899SCharles.Forsyth     {
807*37da2899SCharles.Forsyth       /* |dy| <<< |dx|  means a near-horizontal segment */
808*37da2899SCharles.Forsyth       result = ( dx >= 0 ) ? PSH3_DIR_RIGHT : PSH3_DIR_LEFT;
809*37da2899SCharles.Forsyth     }
810*37da2899SCharles.Forsyth     else if ( ax * 12 < ay )
811*37da2899SCharles.Forsyth     {
812*37da2899SCharles.Forsyth       /* |dx| <<< |dy|  means a near-vertical segment */
813*37da2899SCharles.Forsyth       result = ( dy >= 0 ) ? PSH3_DIR_UP : PSH3_DIR_DOWN;
814*37da2899SCharles.Forsyth     }
815*37da2899SCharles.Forsyth 
816*37da2899SCharles.Forsyth     return result;
817*37da2899SCharles.Forsyth   }
818*37da2899SCharles.Forsyth 
819*37da2899SCharles.Forsyth 
820*37da2899SCharles.Forsyth   /* load outline point coordinates into hinter glyph */
821*37da2899SCharles.Forsyth   static void
psh3_glyph_load_points(PSH3_Glyph glyph,FT_Int dimension)822*37da2899SCharles.Forsyth   psh3_glyph_load_points( PSH3_Glyph  glyph,
823*37da2899SCharles.Forsyth                           FT_Int      dimension )
824*37da2899SCharles.Forsyth   {
825*37da2899SCharles.Forsyth     FT_Vector*  vec   = glyph->outline->points;
826*37da2899SCharles.Forsyth     PSH3_Point  point = glyph->points;
827*37da2899SCharles.Forsyth     FT_UInt     count = glyph->num_points;
828*37da2899SCharles.Forsyth 
829*37da2899SCharles.Forsyth 
830*37da2899SCharles.Forsyth     for ( ; count > 0; count--, point++, vec++ )
831*37da2899SCharles.Forsyth     {
832*37da2899SCharles.Forsyth       point->flags2 = 0;
833*37da2899SCharles.Forsyth       point->hint   = NULL;
834*37da2899SCharles.Forsyth       if ( dimension == 0 )
835*37da2899SCharles.Forsyth       {
836*37da2899SCharles.Forsyth         point->org_u = vec->x;
837*37da2899SCharles.Forsyth         point->org_v = vec->y;
838*37da2899SCharles.Forsyth       }
839*37da2899SCharles.Forsyth       else
840*37da2899SCharles.Forsyth       {
841*37da2899SCharles.Forsyth         point->org_u = vec->y;
842*37da2899SCharles.Forsyth         point->org_v = vec->x;
843*37da2899SCharles.Forsyth       }
844*37da2899SCharles.Forsyth 
845*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
846*37da2899SCharles.Forsyth       point->org_x = vec->x;
847*37da2899SCharles.Forsyth       point->org_y = vec->y;
848*37da2899SCharles.Forsyth #endif
849*37da2899SCharles.Forsyth 
850*37da2899SCharles.Forsyth     }
851*37da2899SCharles.Forsyth   }
852*37da2899SCharles.Forsyth 
853*37da2899SCharles.Forsyth 
854*37da2899SCharles.Forsyth   /* save hinted point coordinates back to outline */
855*37da2899SCharles.Forsyth   static void
psh3_glyph_save_points(PSH3_Glyph glyph,FT_Int dimension)856*37da2899SCharles.Forsyth   psh3_glyph_save_points( PSH3_Glyph  glyph,
857*37da2899SCharles.Forsyth                           FT_Int      dimension )
858*37da2899SCharles.Forsyth   {
859*37da2899SCharles.Forsyth     FT_UInt     n;
860*37da2899SCharles.Forsyth     PSH3_Point  point = glyph->points;
861*37da2899SCharles.Forsyth     FT_Vector*  vec   = glyph->outline->points;
862*37da2899SCharles.Forsyth     char*       tags  = glyph->outline->tags;
863*37da2899SCharles.Forsyth 
864*37da2899SCharles.Forsyth 
865*37da2899SCharles.Forsyth     for ( n = 0; n < glyph->num_points; n++ )
866*37da2899SCharles.Forsyth     {
867*37da2899SCharles.Forsyth       if ( dimension == 0 )
868*37da2899SCharles.Forsyth         vec[n].x = point->cur_u;
869*37da2899SCharles.Forsyth       else
870*37da2899SCharles.Forsyth         vec[n].y = point->cur_u;
871*37da2899SCharles.Forsyth 
872*37da2899SCharles.Forsyth       if ( psh3_point_is_strong( point ) )
873*37da2899SCharles.Forsyth         tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
874*37da2899SCharles.Forsyth 
875*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
876*37da2899SCharles.Forsyth 
877*37da2899SCharles.Forsyth       if ( dimension == 0 )
878*37da2899SCharles.Forsyth       {
879*37da2899SCharles.Forsyth         point->cur_x   = point->cur_u;
880*37da2899SCharles.Forsyth         point->flags_x = point->flags2 | point->flags;
881*37da2899SCharles.Forsyth       }
882*37da2899SCharles.Forsyth       else
883*37da2899SCharles.Forsyth       {
884*37da2899SCharles.Forsyth         point->cur_y   = point->cur_u;
885*37da2899SCharles.Forsyth         point->flags_y = point->flags2 | point->flags;
886*37da2899SCharles.Forsyth       }
887*37da2899SCharles.Forsyth 
888*37da2899SCharles.Forsyth #endif
889*37da2899SCharles.Forsyth 
890*37da2899SCharles.Forsyth       point++;
891*37da2899SCharles.Forsyth     }
892*37da2899SCharles.Forsyth   }
893*37da2899SCharles.Forsyth 
894*37da2899SCharles.Forsyth 
895*37da2899SCharles.Forsyth   static FT_Error
psh3_glyph_init(PSH3_Glyph glyph,FT_Outline * outline,PS_Hints ps_hints,PSH_Globals globals)896*37da2899SCharles.Forsyth   psh3_glyph_init( PSH3_Glyph   glyph,
897*37da2899SCharles.Forsyth                    FT_Outline*  outline,
898*37da2899SCharles.Forsyth                    PS_Hints     ps_hints,
899*37da2899SCharles.Forsyth                    PSH_Globals  globals )
900*37da2899SCharles.Forsyth   {
901*37da2899SCharles.Forsyth     FT_Error   error;
902*37da2899SCharles.Forsyth     FT_Memory  memory;
903*37da2899SCharles.Forsyth 
904*37da2899SCharles.Forsyth 
905*37da2899SCharles.Forsyth     /* clear all fields */
906*37da2899SCharles.Forsyth     FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
907*37da2899SCharles.Forsyth 
908*37da2899SCharles.Forsyth     memory = globals->memory;
909*37da2899SCharles.Forsyth 
910*37da2899SCharles.Forsyth     /* allocate and setup points + contours arrays */
911*37da2899SCharles.Forsyth     if ( FT_NEW_ARRAY( glyph->points,   outline->n_points   ) ||
912*37da2899SCharles.Forsyth          FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
913*37da2899SCharles.Forsyth       goto Exit;
914*37da2899SCharles.Forsyth 
915*37da2899SCharles.Forsyth     glyph->num_points   = outline->n_points;
916*37da2899SCharles.Forsyth     glyph->num_contours = outline->n_contours;
917*37da2899SCharles.Forsyth 
918*37da2899SCharles.Forsyth     {
919*37da2899SCharles.Forsyth       FT_UInt       first = 0, next, n;
920*37da2899SCharles.Forsyth       PSH3_Point    points  = glyph->points;
921*37da2899SCharles.Forsyth       PSH3_Contour  contour = glyph->contours;
922*37da2899SCharles.Forsyth 
923*37da2899SCharles.Forsyth 
924*37da2899SCharles.Forsyth       for ( n = 0; n < glyph->num_contours; n++ )
925*37da2899SCharles.Forsyth       {
926*37da2899SCharles.Forsyth         FT_Int      count;
927*37da2899SCharles.Forsyth         PSH3_Point  point;
928*37da2899SCharles.Forsyth 
929*37da2899SCharles.Forsyth 
930*37da2899SCharles.Forsyth         next  = outline->contours[n] + 1;
931*37da2899SCharles.Forsyth         count = next - first;
932*37da2899SCharles.Forsyth 
933*37da2899SCharles.Forsyth         contour->start = points + first;
934*37da2899SCharles.Forsyth         contour->count = (FT_UInt)count;
935*37da2899SCharles.Forsyth 
936*37da2899SCharles.Forsyth         if ( count > 0 )
937*37da2899SCharles.Forsyth         {
938*37da2899SCharles.Forsyth           point = points + first;
939*37da2899SCharles.Forsyth 
940*37da2899SCharles.Forsyth           point->prev    = points + next - 1;
941*37da2899SCharles.Forsyth           point->contour = contour;
942*37da2899SCharles.Forsyth 
943*37da2899SCharles.Forsyth           for ( ; count > 1; count-- )
944*37da2899SCharles.Forsyth           {
945*37da2899SCharles.Forsyth             point[0].next = point + 1;
946*37da2899SCharles.Forsyth             point[1].prev = point;
947*37da2899SCharles.Forsyth             point++;
948*37da2899SCharles.Forsyth             point->contour = contour;
949*37da2899SCharles.Forsyth           }
950*37da2899SCharles.Forsyth           point->next = points + first;
951*37da2899SCharles.Forsyth         }
952*37da2899SCharles.Forsyth 
953*37da2899SCharles.Forsyth         contour++;
954*37da2899SCharles.Forsyth         first = next;
955*37da2899SCharles.Forsyth       }
956*37da2899SCharles.Forsyth     }
957*37da2899SCharles.Forsyth 
958*37da2899SCharles.Forsyth     {
959*37da2899SCharles.Forsyth       PSH3_Point  points = glyph->points;
960*37da2899SCharles.Forsyth       PSH3_Point  point  = points;
961*37da2899SCharles.Forsyth       FT_Vector*  vec    = outline->points;
962*37da2899SCharles.Forsyth       FT_UInt     n;
963*37da2899SCharles.Forsyth 
964*37da2899SCharles.Forsyth 
965*37da2899SCharles.Forsyth       for ( n = 0; n < glyph->num_points; n++, point++ )
966*37da2899SCharles.Forsyth       {
967*37da2899SCharles.Forsyth         FT_Int  n_prev = point->prev - points;
968*37da2899SCharles.Forsyth         FT_Int  n_next = point->next - points;
969*37da2899SCharles.Forsyth         FT_Pos  dxi, dyi, dxo, dyo;
970*37da2899SCharles.Forsyth 
971*37da2899SCharles.Forsyth 
972*37da2899SCharles.Forsyth         if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
973*37da2899SCharles.Forsyth           point->flags = PSH3_POINT_OFF;
974*37da2899SCharles.Forsyth 
975*37da2899SCharles.Forsyth         dxi = vec[n].x - vec[n_prev].x;
976*37da2899SCharles.Forsyth         dyi = vec[n].y - vec[n_prev].y;
977*37da2899SCharles.Forsyth 
978*37da2899SCharles.Forsyth         point->dir_in = (FT_Char)psh3_compute_dir( dxi, dyi );
979*37da2899SCharles.Forsyth 
980*37da2899SCharles.Forsyth         dxo = vec[n_next].x - vec[n].x;
981*37da2899SCharles.Forsyth         dyo = vec[n_next].y - vec[n].y;
982*37da2899SCharles.Forsyth 
983*37da2899SCharles.Forsyth         point->dir_out = (FT_Char)psh3_compute_dir( dxo, dyo );
984*37da2899SCharles.Forsyth 
985*37da2899SCharles.Forsyth         /* detect smooth points */
986*37da2899SCharles.Forsyth         if ( point->flags & PSH3_POINT_OFF )
987*37da2899SCharles.Forsyth           point->flags |= PSH3_POINT_SMOOTH;
988*37da2899SCharles.Forsyth         else if ( point->dir_in  != PSH3_DIR_NONE ||
989*37da2899SCharles.Forsyth                   point->dir_out != PSH3_DIR_NONE )
990*37da2899SCharles.Forsyth         {
991*37da2899SCharles.Forsyth           if ( point->dir_in == point->dir_out )
992*37da2899SCharles.Forsyth             point->flags |= PSH3_POINT_SMOOTH;
993*37da2899SCharles.Forsyth         }
994*37da2899SCharles.Forsyth         else
995*37da2899SCharles.Forsyth         {
996*37da2899SCharles.Forsyth           FT_Angle  angle_in, angle_out, diff;
997*37da2899SCharles.Forsyth 
998*37da2899SCharles.Forsyth 
999*37da2899SCharles.Forsyth           angle_in  = FT_Atan2( dxi, dyi );
1000*37da2899SCharles.Forsyth           angle_out = FT_Atan2( dxo, dyo );
1001*37da2899SCharles.Forsyth 
1002*37da2899SCharles.Forsyth           diff = angle_in - angle_out;
1003*37da2899SCharles.Forsyth           if ( diff < 0 )
1004*37da2899SCharles.Forsyth             diff = -diff;
1005*37da2899SCharles.Forsyth 
1006*37da2899SCharles.Forsyth           if ( diff > FT_ANGLE_PI )
1007*37da2899SCharles.Forsyth             diff = FT_ANGLE_2PI - diff;
1008*37da2899SCharles.Forsyth 
1009*37da2899SCharles.Forsyth           if ( diff < FT_ANGLE_PI / 16 )
1010*37da2899SCharles.Forsyth             point->flags |= PSH3_POINT_SMOOTH;
1011*37da2899SCharles.Forsyth         }
1012*37da2899SCharles.Forsyth       }
1013*37da2899SCharles.Forsyth     }
1014*37da2899SCharles.Forsyth 
1015*37da2899SCharles.Forsyth     glyph->memory  = memory;
1016*37da2899SCharles.Forsyth     glyph->outline = outline;
1017*37da2899SCharles.Forsyth     glyph->globals = globals;
1018*37da2899SCharles.Forsyth 
1019*37da2899SCharles.Forsyth #ifdef COMPUTE_INFLEXS
1020*37da2899SCharles.Forsyth     psh3_glyph_load_points( glyph, 0 );
1021*37da2899SCharles.Forsyth     psh3_glyph_compute_inflections( glyph );
1022*37da2899SCharles.Forsyth #endif /* COMPUTE_INFLEXS */
1023*37da2899SCharles.Forsyth 
1024*37da2899SCharles.Forsyth     /* now deal with hints tables */
1025*37da2899SCharles.Forsyth     error = psh3_hint_table_init( &glyph->hint_tables [0],
1026*37da2899SCharles.Forsyth                                   &ps_hints->dimension[0].hints,
1027*37da2899SCharles.Forsyth                                   &ps_hints->dimension[0].masks,
1028*37da2899SCharles.Forsyth                                   &ps_hints->dimension[0].counters,
1029*37da2899SCharles.Forsyth                                   memory );
1030*37da2899SCharles.Forsyth     if ( error )
1031*37da2899SCharles.Forsyth       goto Exit;
1032*37da2899SCharles.Forsyth 
1033*37da2899SCharles.Forsyth     error = psh3_hint_table_init( &glyph->hint_tables [1],
1034*37da2899SCharles.Forsyth                                   &ps_hints->dimension[1].hints,
1035*37da2899SCharles.Forsyth                                   &ps_hints->dimension[1].masks,
1036*37da2899SCharles.Forsyth                                   &ps_hints->dimension[1].counters,
1037*37da2899SCharles.Forsyth                                   memory );
1038*37da2899SCharles.Forsyth     if ( error )
1039*37da2899SCharles.Forsyth       goto Exit;
1040*37da2899SCharles.Forsyth 
1041*37da2899SCharles.Forsyth   Exit:
1042*37da2899SCharles.Forsyth     return error;
1043*37da2899SCharles.Forsyth   }
1044*37da2899SCharles.Forsyth 
1045*37da2899SCharles.Forsyth 
1046*37da2899SCharles.Forsyth   /* compute all extrema in a glyph for a given dimension */
1047*37da2899SCharles.Forsyth   static void
psh3_glyph_compute_extrema(PSH3_Glyph glyph)1048*37da2899SCharles.Forsyth   psh3_glyph_compute_extrema( PSH3_Glyph  glyph )
1049*37da2899SCharles.Forsyth   {
1050*37da2899SCharles.Forsyth     FT_UInt  n;
1051*37da2899SCharles.Forsyth 
1052*37da2899SCharles.Forsyth 
1053*37da2899SCharles.Forsyth     /* first of all, compute all local extrema */
1054*37da2899SCharles.Forsyth     for ( n = 0; n < glyph->num_contours; n++ )
1055*37da2899SCharles.Forsyth     {
1056*37da2899SCharles.Forsyth       PSH3_Point  first = glyph->contours[n].start;
1057*37da2899SCharles.Forsyth       PSH3_Point  point, before, after;
1058*37da2899SCharles.Forsyth 
1059*37da2899SCharles.Forsyth 
1060*37da2899SCharles.Forsyth       point  = first;
1061*37da2899SCharles.Forsyth       before = point;
1062*37da2899SCharles.Forsyth       after  = point;
1063*37da2899SCharles.Forsyth 
1064*37da2899SCharles.Forsyth       do
1065*37da2899SCharles.Forsyth       {
1066*37da2899SCharles.Forsyth         before = before->prev;
1067*37da2899SCharles.Forsyth         if ( before == first )
1068*37da2899SCharles.Forsyth           goto Skip;
1069*37da2899SCharles.Forsyth 
1070*37da2899SCharles.Forsyth       } while ( before->org_u == point->org_u );
1071*37da2899SCharles.Forsyth 
1072*37da2899SCharles.Forsyth       first = point = before->next;
1073*37da2899SCharles.Forsyth 
1074*37da2899SCharles.Forsyth       for (;;)
1075*37da2899SCharles.Forsyth       {
1076*37da2899SCharles.Forsyth         after = point;
1077*37da2899SCharles.Forsyth         do
1078*37da2899SCharles.Forsyth         {
1079*37da2899SCharles.Forsyth           after = after->next;
1080*37da2899SCharles.Forsyth           if ( after == first )
1081*37da2899SCharles.Forsyth             goto Next;
1082*37da2899SCharles.Forsyth 
1083*37da2899SCharles.Forsyth         } while ( after->org_u == point->org_u );
1084*37da2899SCharles.Forsyth 
1085*37da2899SCharles.Forsyth         if ( before->org_u < point->org_u )
1086*37da2899SCharles.Forsyth         {
1087*37da2899SCharles.Forsyth           if ( after->org_u < point->org_u )
1088*37da2899SCharles.Forsyth           {
1089*37da2899SCharles.Forsyth             /* local maximum */
1090*37da2899SCharles.Forsyth             goto Extremum;
1091*37da2899SCharles.Forsyth           }
1092*37da2899SCharles.Forsyth         }
1093*37da2899SCharles.Forsyth         else /* before->org_u > point->org_u */
1094*37da2899SCharles.Forsyth         {
1095*37da2899SCharles.Forsyth           if ( after->org_u > point->org_u )
1096*37da2899SCharles.Forsyth           {
1097*37da2899SCharles.Forsyth             /* local minimum */
1098*37da2899SCharles.Forsyth           Extremum:
1099*37da2899SCharles.Forsyth             do
1100*37da2899SCharles.Forsyth             {
1101*37da2899SCharles.Forsyth               psh3_point_set_extremum( point );
1102*37da2899SCharles.Forsyth               point = point->next;
1103*37da2899SCharles.Forsyth 
1104*37da2899SCharles.Forsyth             } while ( point != after );
1105*37da2899SCharles.Forsyth           }
1106*37da2899SCharles.Forsyth         }
1107*37da2899SCharles.Forsyth 
1108*37da2899SCharles.Forsyth         before = after->prev;
1109*37da2899SCharles.Forsyth         point  = after;
1110*37da2899SCharles.Forsyth 
1111*37da2899SCharles.Forsyth       } /* for  */
1112*37da2899SCharles.Forsyth 
1113*37da2899SCharles.Forsyth     Next:
1114*37da2899SCharles.Forsyth       ;
1115*37da2899SCharles.Forsyth     }
1116*37da2899SCharles.Forsyth 
1117*37da2899SCharles.Forsyth     /* for each extrema, determine its direction along the */
1118*37da2899SCharles.Forsyth     /* orthogonal axis                                     */
1119*37da2899SCharles.Forsyth     for ( n = 0; n < glyph->num_points; n++ )
1120*37da2899SCharles.Forsyth     {
1121*37da2899SCharles.Forsyth       PSH3_Point  point, before, after;
1122*37da2899SCharles.Forsyth 
1123*37da2899SCharles.Forsyth 
1124*37da2899SCharles.Forsyth       point  = &glyph->points[n];
1125*37da2899SCharles.Forsyth       before = point;
1126*37da2899SCharles.Forsyth       after  = point;
1127*37da2899SCharles.Forsyth 
1128*37da2899SCharles.Forsyth       if ( psh3_point_is_extremum( point ) )
1129*37da2899SCharles.Forsyth       {
1130*37da2899SCharles.Forsyth         do
1131*37da2899SCharles.Forsyth         {
1132*37da2899SCharles.Forsyth           before = before->prev;
1133*37da2899SCharles.Forsyth           if ( before == point )
1134*37da2899SCharles.Forsyth             goto Skip;
1135*37da2899SCharles.Forsyth 
1136*37da2899SCharles.Forsyth         } while ( before->org_v == point->org_v );
1137*37da2899SCharles.Forsyth 
1138*37da2899SCharles.Forsyth         do
1139*37da2899SCharles.Forsyth         {
1140*37da2899SCharles.Forsyth           after = after->next;
1141*37da2899SCharles.Forsyth           if ( after == point )
1142*37da2899SCharles.Forsyth             goto Skip;
1143*37da2899SCharles.Forsyth 
1144*37da2899SCharles.Forsyth         } while ( after->org_v == point->org_v );
1145*37da2899SCharles.Forsyth       }
1146*37da2899SCharles.Forsyth 
1147*37da2899SCharles.Forsyth       if ( before->org_v < point->org_v &&
1148*37da2899SCharles.Forsyth            after->org_v  > point->org_v )
1149*37da2899SCharles.Forsyth       {
1150*37da2899SCharles.Forsyth         psh3_point_set_positive( point );
1151*37da2899SCharles.Forsyth       }
1152*37da2899SCharles.Forsyth       else if ( before->org_v > point->org_v &&
1153*37da2899SCharles.Forsyth                 after->org_v  < point->org_v )
1154*37da2899SCharles.Forsyth       {
1155*37da2899SCharles.Forsyth         psh3_point_set_negative( point );
1156*37da2899SCharles.Forsyth       }
1157*37da2899SCharles.Forsyth 
1158*37da2899SCharles.Forsyth     Skip:
1159*37da2899SCharles.Forsyth       ;
1160*37da2899SCharles.Forsyth     }
1161*37da2899SCharles.Forsyth   }
1162*37da2899SCharles.Forsyth 
1163*37da2899SCharles.Forsyth 
1164*37da2899SCharles.Forsyth #define PSH3_STRONG_THRESHOLD  30
1165*37da2899SCharles.Forsyth 
1166*37da2899SCharles.Forsyth 
1167*37da2899SCharles.Forsyth   /* major_dir is the direction for points on the bottom/left of the stem; */
1168*37da2899SCharles.Forsyth   /* Points on the top/right of the stem will have a direction of          */
1169*37da2899SCharles.Forsyth   /* -major_dir.                                                           */
1170*37da2899SCharles.Forsyth 
1171*37da2899SCharles.Forsyth   static void
psh3_hint_table_find_strong_point(PSH3_Hint_Table table,PSH3_Point point,FT_Int major_dir)1172*37da2899SCharles.Forsyth   psh3_hint_table_find_strong_point( PSH3_Hint_Table  table,
1173*37da2899SCharles.Forsyth                                      PSH3_Point       point,
1174*37da2899SCharles.Forsyth                                      FT_Int           major_dir )
1175*37da2899SCharles.Forsyth   {
1176*37da2899SCharles.Forsyth     PSH3_Hint*  sort      = table->sort;
1177*37da2899SCharles.Forsyth     FT_UInt     num_hints = table->num_hints;
1178*37da2899SCharles.Forsyth     FT_Int      point_dir = 0;
1179*37da2899SCharles.Forsyth 
1180*37da2899SCharles.Forsyth 
1181*37da2899SCharles.Forsyth     if ( PSH3_DIR_COMPARE( point->dir_in, major_dir ) )
1182*37da2899SCharles.Forsyth       point_dir = point->dir_in;
1183*37da2899SCharles.Forsyth 
1184*37da2899SCharles.Forsyth     else if ( PSH3_DIR_COMPARE( point->dir_out, major_dir ) )
1185*37da2899SCharles.Forsyth       point_dir = point->dir_out;
1186*37da2899SCharles.Forsyth 
1187*37da2899SCharles.Forsyth     if ( point_dir )
1188*37da2899SCharles.Forsyth     {
1189*37da2899SCharles.Forsyth       FT_UInt  flag;
1190*37da2899SCharles.Forsyth 
1191*37da2899SCharles.Forsyth 
1192*37da2899SCharles.Forsyth       for ( ; num_hints > 0; num_hints--, sort++ )
1193*37da2899SCharles.Forsyth       {
1194*37da2899SCharles.Forsyth         PSH3_Hint  hint = sort[0];
1195*37da2899SCharles.Forsyth         FT_Pos     d;
1196*37da2899SCharles.Forsyth 
1197*37da2899SCharles.Forsyth 
1198*37da2899SCharles.Forsyth         if ( point_dir == major_dir )
1199*37da2899SCharles.Forsyth         {
1200*37da2899SCharles.Forsyth           flag = PSH3_POINT_EDGE_MIN;
1201*37da2899SCharles.Forsyth           d    = point->org_u - hint->org_pos;
1202*37da2899SCharles.Forsyth 
1203*37da2899SCharles.Forsyth           if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
1204*37da2899SCharles.Forsyth           {
1205*37da2899SCharles.Forsyth           Is_Strong:
1206*37da2899SCharles.Forsyth             psh3_point_set_strong( point );
1207*37da2899SCharles.Forsyth             point->flags2 |= flag;
1208*37da2899SCharles.Forsyth             point->hint    = hint;
1209*37da2899SCharles.Forsyth             break;
1210*37da2899SCharles.Forsyth           }
1211*37da2899SCharles.Forsyth         }
1212*37da2899SCharles.Forsyth         else if ( point_dir == -major_dir )
1213*37da2899SCharles.Forsyth         {
1214*37da2899SCharles.Forsyth           flag  = PSH3_POINT_EDGE_MAX;
1215*37da2899SCharles.Forsyth           d     = point->org_u - hint->org_pos - hint->org_len;
1216*37da2899SCharles.Forsyth 
1217*37da2899SCharles.Forsyth           if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
1218*37da2899SCharles.Forsyth             goto Is_Strong;
1219*37da2899SCharles.Forsyth         }
1220*37da2899SCharles.Forsyth       }
1221*37da2899SCharles.Forsyth     }
1222*37da2899SCharles.Forsyth 
1223*37da2899SCharles.Forsyth #if 1
1224*37da2899SCharles.Forsyth     else if ( psh3_point_is_extremum( point ) )
1225*37da2899SCharles.Forsyth     {
1226*37da2899SCharles.Forsyth       /* treat extrema as special cases for stem edge alignment */
1227*37da2899SCharles.Forsyth       FT_UInt  min_flag, max_flag;
1228*37da2899SCharles.Forsyth 
1229*37da2899SCharles.Forsyth 
1230*37da2899SCharles.Forsyth       if ( major_dir == PSH3_DIR_HORIZONTAL )
1231*37da2899SCharles.Forsyth       {
1232*37da2899SCharles.Forsyth         min_flag = PSH3_POINT_POSITIVE;
1233*37da2899SCharles.Forsyth         max_flag = PSH3_POINT_NEGATIVE;
1234*37da2899SCharles.Forsyth       }
1235*37da2899SCharles.Forsyth       else
1236*37da2899SCharles.Forsyth       {
1237*37da2899SCharles.Forsyth         min_flag = PSH3_POINT_NEGATIVE;
1238*37da2899SCharles.Forsyth         max_flag = PSH3_POINT_POSITIVE;
1239*37da2899SCharles.Forsyth       }
1240*37da2899SCharles.Forsyth 
1241*37da2899SCharles.Forsyth       for ( ; num_hints > 0; num_hints--, sort++ )
1242*37da2899SCharles.Forsyth       {
1243*37da2899SCharles.Forsyth         PSH3_Hint  hint = sort[0];
1244*37da2899SCharles.Forsyth         FT_Pos     d, flag;
1245*37da2899SCharles.Forsyth 
1246*37da2899SCharles.Forsyth 
1247*37da2899SCharles.Forsyth         if ( point->flags2 & min_flag )
1248*37da2899SCharles.Forsyth         {
1249*37da2899SCharles.Forsyth           flag = PSH3_POINT_EDGE_MIN;
1250*37da2899SCharles.Forsyth           d    = point->org_u - hint->org_pos;
1251*37da2899SCharles.Forsyth 
1252*37da2899SCharles.Forsyth           if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
1253*37da2899SCharles.Forsyth           {
1254*37da2899SCharles.Forsyth           Is_Strong2:
1255*37da2899SCharles.Forsyth             point->flags2 |= flag;
1256*37da2899SCharles.Forsyth             point->hint    = hint;
1257*37da2899SCharles.Forsyth             psh3_point_set_strong( point );
1258*37da2899SCharles.Forsyth             break;
1259*37da2899SCharles.Forsyth           }
1260*37da2899SCharles.Forsyth         }
1261*37da2899SCharles.Forsyth         else if ( point->flags2 & max_flag )
1262*37da2899SCharles.Forsyth         {
1263*37da2899SCharles.Forsyth           flag = PSH3_POINT_EDGE_MAX;
1264*37da2899SCharles.Forsyth           d    = point->org_u - hint->org_pos - hint->org_len;
1265*37da2899SCharles.Forsyth 
1266*37da2899SCharles.Forsyth           if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
1267*37da2899SCharles.Forsyth             goto Is_Strong2;
1268*37da2899SCharles.Forsyth         }
1269*37da2899SCharles.Forsyth 
1270*37da2899SCharles.Forsyth         if ( point->org_u >= hint->org_pos                 &&
1271*37da2899SCharles.Forsyth              point->org_u <= hint->org_pos + hint->org_len )
1272*37da2899SCharles.Forsyth         {
1273*37da2899SCharles.Forsyth           point->hint = hint;
1274*37da2899SCharles.Forsyth         }
1275*37da2899SCharles.Forsyth       }
1276*37da2899SCharles.Forsyth     }
1277*37da2899SCharles.Forsyth 
1278*37da2899SCharles.Forsyth #endif /* 1 */
1279*37da2899SCharles.Forsyth   }
1280*37da2899SCharles.Forsyth 
1281*37da2899SCharles.Forsyth 
1282*37da2899SCharles.Forsyth   /* find strong points in a glyph */
1283*37da2899SCharles.Forsyth   static void
psh3_glyph_find_strong_points(PSH3_Glyph glyph,FT_Int dimension)1284*37da2899SCharles.Forsyth   psh3_glyph_find_strong_points( PSH3_Glyph  glyph,
1285*37da2899SCharles.Forsyth                                  FT_Int      dimension )
1286*37da2899SCharles.Forsyth   {
1287*37da2899SCharles.Forsyth     /* a point is strong if it is located on a stem                   */
1288*37da2899SCharles.Forsyth     /* edge and has an "in" or "out" tangent to the hint's direction  */
1289*37da2899SCharles.Forsyth     {
1290*37da2899SCharles.Forsyth       PSH3_Hint_Table  table     = &glyph->hint_tables[dimension];
1291*37da2899SCharles.Forsyth       PS_Mask          mask      = table->hint_masks->masks;
1292*37da2899SCharles.Forsyth       FT_UInt          num_masks = table->hint_masks->num_masks;
1293*37da2899SCharles.Forsyth       FT_UInt          first     = 0;
1294*37da2899SCharles.Forsyth       FT_Int           major_dir = dimension == 0 ? PSH3_DIR_VERTICAL
1295*37da2899SCharles.Forsyth                                                   : PSH3_DIR_HORIZONTAL;
1296*37da2899SCharles.Forsyth 
1297*37da2899SCharles.Forsyth 
1298*37da2899SCharles.Forsyth       /* process secondary hints to "selected" points */
1299*37da2899SCharles.Forsyth       if ( num_masks > 1 && glyph->num_points > 0 )
1300*37da2899SCharles.Forsyth       {
1301*37da2899SCharles.Forsyth         first = mask->end_point;
1302*37da2899SCharles.Forsyth         mask++;
1303*37da2899SCharles.Forsyth         for ( ; num_masks > 1; num_masks--, mask++ )
1304*37da2899SCharles.Forsyth         {
1305*37da2899SCharles.Forsyth           FT_UInt  next;
1306*37da2899SCharles.Forsyth           FT_Int   count;
1307*37da2899SCharles.Forsyth 
1308*37da2899SCharles.Forsyth 
1309*37da2899SCharles.Forsyth           next  = mask->end_point;
1310*37da2899SCharles.Forsyth           count = next - first;
1311*37da2899SCharles.Forsyth           if ( count > 0 )
1312*37da2899SCharles.Forsyth           {
1313*37da2899SCharles.Forsyth             PSH3_Point  point = glyph->points + first;
1314*37da2899SCharles.Forsyth 
1315*37da2899SCharles.Forsyth 
1316*37da2899SCharles.Forsyth             psh3_hint_table_activate_mask( table, mask );
1317*37da2899SCharles.Forsyth 
1318*37da2899SCharles.Forsyth             for ( ; count > 0; count--, point++ )
1319*37da2899SCharles.Forsyth               psh3_hint_table_find_strong_point( table, point, major_dir );
1320*37da2899SCharles.Forsyth           }
1321*37da2899SCharles.Forsyth           first = next;
1322*37da2899SCharles.Forsyth         }
1323*37da2899SCharles.Forsyth       }
1324*37da2899SCharles.Forsyth 
1325*37da2899SCharles.Forsyth       /* process primary hints for all points */
1326*37da2899SCharles.Forsyth       if ( num_masks == 1 )
1327*37da2899SCharles.Forsyth       {
1328*37da2899SCharles.Forsyth         FT_UInt     count = glyph->num_points;
1329*37da2899SCharles.Forsyth         PSH3_Point  point = glyph->points;
1330*37da2899SCharles.Forsyth 
1331*37da2899SCharles.Forsyth 
1332*37da2899SCharles.Forsyth         psh3_hint_table_activate_mask( table, table->hint_masks->masks );
1333*37da2899SCharles.Forsyth         for ( ; count > 0; count--, point++ )
1334*37da2899SCharles.Forsyth         {
1335*37da2899SCharles.Forsyth           if ( !psh3_point_is_strong( point ) )
1336*37da2899SCharles.Forsyth             psh3_hint_table_find_strong_point( table, point, major_dir );
1337*37da2899SCharles.Forsyth         }
1338*37da2899SCharles.Forsyth       }
1339*37da2899SCharles.Forsyth 
1340*37da2899SCharles.Forsyth       /* now, certain points may have been attached to hint and */
1341*37da2899SCharles.Forsyth       /* not marked as strong; update their flags then          */
1342*37da2899SCharles.Forsyth       {
1343*37da2899SCharles.Forsyth         FT_UInt     count = glyph->num_points;
1344*37da2899SCharles.Forsyth         PSH3_Point  point = glyph->points;
1345*37da2899SCharles.Forsyth 
1346*37da2899SCharles.Forsyth 
1347*37da2899SCharles.Forsyth         for ( ; count > 0; count--, point++ )
1348*37da2899SCharles.Forsyth           if ( point->hint && !psh3_point_is_strong( point ) )
1349*37da2899SCharles.Forsyth             psh3_point_set_strong( point );
1350*37da2899SCharles.Forsyth       }
1351*37da2899SCharles.Forsyth     }
1352*37da2899SCharles.Forsyth   }
1353*37da2899SCharles.Forsyth 
1354*37da2899SCharles.Forsyth 
1355*37da2899SCharles.Forsyth   /* interpolate strong points with the help of hinted coordinates */
1356*37da2899SCharles.Forsyth   static void
psh3_glyph_interpolate_strong_points(PSH3_Glyph glyph,FT_Int dimension)1357*37da2899SCharles.Forsyth   psh3_glyph_interpolate_strong_points( PSH3_Glyph  glyph,
1358*37da2899SCharles.Forsyth                                         FT_Int      dimension )
1359*37da2899SCharles.Forsyth   {
1360*37da2899SCharles.Forsyth     PSH_Dimension  dim   = &glyph->globals->dimension[dimension];
1361*37da2899SCharles.Forsyth     FT_Fixed       scale = dim->scale_mult;
1362*37da2899SCharles.Forsyth 
1363*37da2899SCharles.Forsyth 
1364*37da2899SCharles.Forsyth     {
1365*37da2899SCharles.Forsyth       FT_UInt     count = glyph->num_points;
1366*37da2899SCharles.Forsyth       PSH3_Point  point = glyph->points;
1367*37da2899SCharles.Forsyth 
1368*37da2899SCharles.Forsyth 
1369*37da2899SCharles.Forsyth       for ( ; count > 0; count--, point++ )
1370*37da2899SCharles.Forsyth       {
1371*37da2899SCharles.Forsyth         PSH3_Hint  hint = point->hint;
1372*37da2899SCharles.Forsyth 
1373*37da2899SCharles.Forsyth 
1374*37da2899SCharles.Forsyth         if ( hint )
1375*37da2899SCharles.Forsyth         {
1376*37da2899SCharles.Forsyth           FT_Pos  delta;
1377*37da2899SCharles.Forsyth 
1378*37da2899SCharles.Forsyth 
1379*37da2899SCharles.Forsyth           if ( psh3_point_is_edge_min( point ) )
1380*37da2899SCharles.Forsyth           {
1381*37da2899SCharles.Forsyth             point->cur_u = hint->cur_pos;
1382*37da2899SCharles.Forsyth           }
1383*37da2899SCharles.Forsyth           else if ( psh3_point_is_edge_max( point ) )
1384*37da2899SCharles.Forsyth           {
1385*37da2899SCharles.Forsyth             point->cur_u = hint->cur_pos + hint->cur_len;
1386*37da2899SCharles.Forsyth           }
1387*37da2899SCharles.Forsyth           else
1388*37da2899SCharles.Forsyth           {
1389*37da2899SCharles.Forsyth             delta = point->org_u - hint->org_pos;
1390*37da2899SCharles.Forsyth 
1391*37da2899SCharles.Forsyth             if ( delta <= 0 )
1392*37da2899SCharles.Forsyth               point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
1393*37da2899SCharles.Forsyth 
1394*37da2899SCharles.Forsyth             else if ( delta >= hint->org_len )
1395*37da2899SCharles.Forsyth               point->cur_u = hint->cur_pos + hint->cur_len +
1396*37da2899SCharles.Forsyth                                FT_MulFix( delta - hint->org_len, scale );
1397*37da2899SCharles.Forsyth 
1398*37da2899SCharles.Forsyth             else if ( hint->org_len > 0 )
1399*37da2899SCharles.Forsyth               point->cur_u = hint->cur_pos +
1400*37da2899SCharles.Forsyth                                FT_MulDiv( delta, hint->cur_len,
1401*37da2899SCharles.Forsyth                                           hint->org_len );
1402*37da2899SCharles.Forsyth             else
1403*37da2899SCharles.Forsyth               point->cur_u = hint->cur_pos;
1404*37da2899SCharles.Forsyth           }
1405*37da2899SCharles.Forsyth           psh3_point_set_fitted( point );
1406*37da2899SCharles.Forsyth         }
1407*37da2899SCharles.Forsyth       }
1408*37da2899SCharles.Forsyth     }
1409*37da2899SCharles.Forsyth   }
1410*37da2899SCharles.Forsyth 
1411*37da2899SCharles.Forsyth 
1412*37da2899SCharles.Forsyth   static void
psh3_glyph_interpolate_normal_points(PSH3_Glyph glyph,FT_Int dimension)1413*37da2899SCharles.Forsyth   psh3_glyph_interpolate_normal_points( PSH3_Glyph  glyph,
1414*37da2899SCharles.Forsyth                                         FT_Int      dimension )
1415*37da2899SCharles.Forsyth   {
1416*37da2899SCharles.Forsyth 
1417*37da2899SCharles.Forsyth #if 1
1418*37da2899SCharles.Forsyth 
1419*37da2899SCharles.Forsyth     PSH_Dimension  dim   = &glyph->globals->dimension[dimension];
1420*37da2899SCharles.Forsyth     FT_Fixed       scale = dim->scale_mult;
1421*37da2899SCharles.Forsyth 
1422*37da2899SCharles.Forsyth 
1423*37da2899SCharles.Forsyth     /* first technique: a point is strong if it is a local extrema */
1424*37da2899SCharles.Forsyth     {
1425*37da2899SCharles.Forsyth       FT_UInt     count = glyph->num_points;
1426*37da2899SCharles.Forsyth       PSH3_Point  point = glyph->points;
1427*37da2899SCharles.Forsyth 
1428*37da2899SCharles.Forsyth 
1429*37da2899SCharles.Forsyth       for ( ; count > 0; count--, point++ )
1430*37da2899SCharles.Forsyth       {
1431*37da2899SCharles.Forsyth         if ( psh3_point_is_strong( point ) )
1432*37da2899SCharles.Forsyth           continue;
1433*37da2899SCharles.Forsyth 
1434*37da2899SCharles.Forsyth         /* sometimes, some local extremas are smooth points */
1435*37da2899SCharles.Forsyth         if ( psh3_point_is_smooth( point ) )
1436*37da2899SCharles.Forsyth         {
1437*37da2899SCharles.Forsyth           if ( point->dir_in == PSH3_DIR_NONE  ||
1438*37da2899SCharles.Forsyth                point->dir_in != point->dir_out )
1439*37da2899SCharles.Forsyth             continue;
1440*37da2899SCharles.Forsyth 
1441*37da2899SCharles.Forsyth           if ( !psh3_point_is_extremum( point )   &&
1442*37da2899SCharles.Forsyth                !psh3_point_is_inflex( point ) )
1443*37da2899SCharles.Forsyth             continue;
1444*37da2899SCharles.Forsyth 
1445*37da2899SCharles.Forsyth           point->flags &= ~PSH3_POINT_SMOOTH;
1446*37da2899SCharles.Forsyth         }
1447*37da2899SCharles.Forsyth 
1448*37da2899SCharles.Forsyth         /* find best enclosing point coordinates */
1449*37da2899SCharles.Forsyth         {
1450*37da2899SCharles.Forsyth           PSH3_Point  before = 0;
1451*37da2899SCharles.Forsyth           PSH3_Point  after  = 0;
1452*37da2899SCharles.Forsyth 
1453*37da2899SCharles.Forsyth           FT_Pos      diff_before = -32000;
1454*37da2899SCharles.Forsyth           FT_Pos      diff_after  =  32000;
1455*37da2899SCharles.Forsyth           FT_Pos      u = point->org_u;
1456*37da2899SCharles.Forsyth 
1457*37da2899SCharles.Forsyth           FT_Int      count2 = glyph->num_points;
1458*37da2899SCharles.Forsyth           PSH3_Point  cur    = glyph->points;
1459*37da2899SCharles.Forsyth 
1460*37da2899SCharles.Forsyth 
1461*37da2899SCharles.Forsyth           for ( ; count2 > 0; count2--, cur++ )
1462*37da2899SCharles.Forsyth           {
1463*37da2899SCharles.Forsyth             if ( psh3_point_is_strong( cur ) )
1464*37da2899SCharles.Forsyth             {
1465*37da2899SCharles.Forsyth               FT_Pos  diff = cur->org_u - u;;
1466*37da2899SCharles.Forsyth 
1467*37da2899SCharles.Forsyth 
1468*37da2899SCharles.Forsyth               if ( diff <= 0 )
1469*37da2899SCharles.Forsyth               {
1470*37da2899SCharles.Forsyth                 if ( diff > diff_before )
1471*37da2899SCharles.Forsyth                 {
1472*37da2899SCharles.Forsyth                   diff_before = diff;
1473*37da2899SCharles.Forsyth                   before      = cur;
1474*37da2899SCharles.Forsyth                 }
1475*37da2899SCharles.Forsyth               }
1476*37da2899SCharles.Forsyth               else if ( diff >= 0 )
1477*37da2899SCharles.Forsyth               {
1478*37da2899SCharles.Forsyth                 if ( diff < diff_after )
1479*37da2899SCharles.Forsyth                 {
1480*37da2899SCharles.Forsyth                   diff_after = diff;
1481*37da2899SCharles.Forsyth                   after      = cur;
1482*37da2899SCharles.Forsyth                 }
1483*37da2899SCharles.Forsyth               }
1484*37da2899SCharles.Forsyth             }
1485*37da2899SCharles.Forsyth           }
1486*37da2899SCharles.Forsyth 
1487*37da2899SCharles.Forsyth           if ( !before )
1488*37da2899SCharles.Forsyth           {
1489*37da2899SCharles.Forsyth             if ( !after )
1490*37da2899SCharles.Forsyth               continue;
1491*37da2899SCharles.Forsyth 
1492*37da2899SCharles.Forsyth             /* we are before the first strong point coordinate; */
1493*37da2899SCharles.Forsyth             /* simply translate the point                       */
1494*37da2899SCharles.Forsyth             point->cur_u = after->cur_u +
1495*37da2899SCharles.Forsyth                            FT_MulFix( point->org_u - after->org_u, scale );
1496*37da2899SCharles.Forsyth           }
1497*37da2899SCharles.Forsyth           else if ( !after )
1498*37da2899SCharles.Forsyth           {
1499*37da2899SCharles.Forsyth             /* we are after the last strong point coordinate; */
1500*37da2899SCharles.Forsyth             /* simply translate the point                     */
1501*37da2899SCharles.Forsyth             point->cur_u = before->cur_u +
1502*37da2899SCharles.Forsyth                            FT_MulFix( point->org_u - before->org_u, scale );
1503*37da2899SCharles.Forsyth           }
1504*37da2899SCharles.Forsyth           else
1505*37da2899SCharles.Forsyth           {
1506*37da2899SCharles.Forsyth             if ( diff_before == 0 )
1507*37da2899SCharles.Forsyth               point->cur_u = before->cur_u;
1508*37da2899SCharles.Forsyth 
1509*37da2899SCharles.Forsyth             else if ( diff_after == 0 )
1510*37da2899SCharles.Forsyth               point->cur_u = after->cur_u;
1511*37da2899SCharles.Forsyth 
1512*37da2899SCharles.Forsyth             else
1513*37da2899SCharles.Forsyth               point->cur_u = before->cur_u +
1514*37da2899SCharles.Forsyth                              FT_MulDiv( u - before->org_u,
1515*37da2899SCharles.Forsyth                                         after->cur_u - before->cur_u,
1516*37da2899SCharles.Forsyth                                         after->org_u - before->org_u );
1517*37da2899SCharles.Forsyth           }
1518*37da2899SCharles.Forsyth 
1519*37da2899SCharles.Forsyth           psh3_point_set_fitted( point );
1520*37da2899SCharles.Forsyth         }
1521*37da2899SCharles.Forsyth       }
1522*37da2899SCharles.Forsyth     }
1523*37da2899SCharles.Forsyth 
1524*37da2899SCharles.Forsyth #endif /* 1 */
1525*37da2899SCharles.Forsyth 
1526*37da2899SCharles.Forsyth   }
1527*37da2899SCharles.Forsyth 
1528*37da2899SCharles.Forsyth 
1529*37da2899SCharles.Forsyth   /* interpolate other points */
1530*37da2899SCharles.Forsyth   static void
psh3_glyph_interpolate_other_points(PSH3_Glyph glyph,FT_Int dimension)1531*37da2899SCharles.Forsyth   psh3_glyph_interpolate_other_points( PSH3_Glyph  glyph,
1532*37da2899SCharles.Forsyth                                        FT_Int      dimension )
1533*37da2899SCharles.Forsyth   {
1534*37da2899SCharles.Forsyth     PSH_Dimension  dim          = &glyph->globals->dimension[dimension];
1535*37da2899SCharles.Forsyth     FT_Fixed       scale        = dim->scale_mult;
1536*37da2899SCharles.Forsyth     FT_Fixed       delta        = dim->scale_delta;
1537*37da2899SCharles.Forsyth     PSH3_Contour   contour      = glyph->contours;
1538*37da2899SCharles.Forsyth     FT_UInt        num_contours = glyph->num_contours;
1539*37da2899SCharles.Forsyth 
1540*37da2899SCharles.Forsyth 
1541*37da2899SCharles.Forsyth     for ( ; num_contours > 0; num_contours--, contour++ )
1542*37da2899SCharles.Forsyth     {
1543*37da2899SCharles.Forsyth       PSH3_Point  start = contour->start;
1544*37da2899SCharles.Forsyth       PSH3_Point  first, next, point;
1545*37da2899SCharles.Forsyth       FT_UInt     fit_count;
1546*37da2899SCharles.Forsyth 
1547*37da2899SCharles.Forsyth 
1548*37da2899SCharles.Forsyth       /* count the number of strong points in this contour */
1549*37da2899SCharles.Forsyth       next      = start + contour->count;
1550*37da2899SCharles.Forsyth       fit_count = 0;
1551*37da2899SCharles.Forsyth       first     = 0;
1552*37da2899SCharles.Forsyth 
1553*37da2899SCharles.Forsyth       for ( point = start; point < next; point++ )
1554*37da2899SCharles.Forsyth         if ( psh3_point_is_fitted( point ) )
1555*37da2899SCharles.Forsyth         {
1556*37da2899SCharles.Forsyth           if ( !first )
1557*37da2899SCharles.Forsyth             first = point;
1558*37da2899SCharles.Forsyth 
1559*37da2899SCharles.Forsyth           fit_count++;
1560*37da2899SCharles.Forsyth         }
1561*37da2899SCharles.Forsyth 
1562*37da2899SCharles.Forsyth       /* if there are less than 2 fitted points in the contour, we */
1563*37da2899SCharles.Forsyth       /* simply scale and eventually translate the contour points  */
1564*37da2899SCharles.Forsyth       if ( fit_count < 2 )
1565*37da2899SCharles.Forsyth       {
1566*37da2899SCharles.Forsyth         if ( fit_count == 1 )
1567*37da2899SCharles.Forsyth           delta = first->cur_u - FT_MulFix( first->org_u, scale );
1568*37da2899SCharles.Forsyth 
1569*37da2899SCharles.Forsyth         for ( point = start; point < next; point++ )
1570*37da2899SCharles.Forsyth           if ( point != first )
1571*37da2899SCharles.Forsyth             point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
1572*37da2899SCharles.Forsyth 
1573*37da2899SCharles.Forsyth         goto Next_Contour;
1574*37da2899SCharles.Forsyth       }
1575*37da2899SCharles.Forsyth 
1576*37da2899SCharles.Forsyth       /* there are more than 2 strong points in this contour; we */
1577*37da2899SCharles.Forsyth       /* need to interpolate weak points between them            */
1578*37da2899SCharles.Forsyth       start = first;
1579*37da2899SCharles.Forsyth       do
1580*37da2899SCharles.Forsyth       {
1581*37da2899SCharles.Forsyth         point = first;
1582*37da2899SCharles.Forsyth 
1583*37da2899SCharles.Forsyth         /* skip consecutive fitted points */
1584*37da2899SCharles.Forsyth         for (;;)
1585*37da2899SCharles.Forsyth         {
1586*37da2899SCharles.Forsyth           next = first->next;
1587*37da2899SCharles.Forsyth           if ( next == start )
1588*37da2899SCharles.Forsyth             goto Next_Contour;
1589*37da2899SCharles.Forsyth 
1590*37da2899SCharles.Forsyth           if ( !psh3_point_is_fitted( next ) )
1591*37da2899SCharles.Forsyth             break;
1592*37da2899SCharles.Forsyth 
1593*37da2899SCharles.Forsyth           first = next;
1594*37da2899SCharles.Forsyth         }
1595*37da2899SCharles.Forsyth 
1596*37da2899SCharles.Forsyth         /* find next fitted point after unfitted one */
1597*37da2899SCharles.Forsyth         for (;;)
1598*37da2899SCharles.Forsyth         {
1599*37da2899SCharles.Forsyth           next = next->next;
1600*37da2899SCharles.Forsyth           if ( psh3_point_is_fitted( next ) )
1601*37da2899SCharles.Forsyth             break;
1602*37da2899SCharles.Forsyth         }
1603*37da2899SCharles.Forsyth 
1604*37da2899SCharles.Forsyth         /* now interpolate between them */
1605*37da2899SCharles.Forsyth         {
1606*37da2899SCharles.Forsyth           FT_Pos    org_a, org_ab, cur_a, cur_ab;
1607*37da2899SCharles.Forsyth           FT_Pos    org_c, org_ac, cur_c;
1608*37da2899SCharles.Forsyth           FT_Fixed  scale_ab;
1609*37da2899SCharles.Forsyth 
1610*37da2899SCharles.Forsyth 
1611*37da2899SCharles.Forsyth           if ( first->org_u <= next->org_u )
1612*37da2899SCharles.Forsyth           {
1613*37da2899SCharles.Forsyth             org_a  = first->org_u;
1614*37da2899SCharles.Forsyth             cur_a  = first->cur_u;
1615*37da2899SCharles.Forsyth             org_ab = next->org_u - org_a;
1616*37da2899SCharles.Forsyth             cur_ab = next->cur_u - cur_a;
1617*37da2899SCharles.Forsyth           }
1618*37da2899SCharles.Forsyth           else
1619*37da2899SCharles.Forsyth           {
1620*37da2899SCharles.Forsyth             org_a  = next->org_u;
1621*37da2899SCharles.Forsyth             cur_a  = next->cur_u;
1622*37da2899SCharles.Forsyth             org_ab = first->org_u - org_a;
1623*37da2899SCharles.Forsyth             cur_ab = first->cur_u - cur_a;
1624*37da2899SCharles.Forsyth           }
1625*37da2899SCharles.Forsyth 
1626*37da2899SCharles.Forsyth           scale_ab = 0x10000L;
1627*37da2899SCharles.Forsyth           if ( org_ab > 0 )
1628*37da2899SCharles.Forsyth             scale_ab = FT_DivFix( cur_ab, org_ab );
1629*37da2899SCharles.Forsyth 
1630*37da2899SCharles.Forsyth           point = first->next;
1631*37da2899SCharles.Forsyth           do
1632*37da2899SCharles.Forsyth           {
1633*37da2899SCharles.Forsyth             org_c  = point->org_u;
1634*37da2899SCharles.Forsyth             org_ac = org_c - org_a;
1635*37da2899SCharles.Forsyth 
1636*37da2899SCharles.Forsyth             if ( org_ac <= 0 )
1637*37da2899SCharles.Forsyth             {
1638*37da2899SCharles.Forsyth               /* on the left of the interpolation zone */
1639*37da2899SCharles.Forsyth               cur_c = cur_a + FT_MulFix( org_ac, scale );
1640*37da2899SCharles.Forsyth             }
1641*37da2899SCharles.Forsyth             else if ( org_ac >= org_ab )
1642*37da2899SCharles.Forsyth             {
1643*37da2899SCharles.Forsyth               /* on the right on the interpolation zone */
1644*37da2899SCharles.Forsyth               cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
1645*37da2899SCharles.Forsyth             }
1646*37da2899SCharles.Forsyth             else
1647*37da2899SCharles.Forsyth             {
1648*37da2899SCharles.Forsyth               /* within the interpolation zone */
1649*37da2899SCharles.Forsyth               cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
1650*37da2899SCharles.Forsyth             }
1651*37da2899SCharles.Forsyth 
1652*37da2899SCharles.Forsyth             point->cur_u = cur_c;
1653*37da2899SCharles.Forsyth 
1654*37da2899SCharles.Forsyth             point = point->next;
1655*37da2899SCharles.Forsyth 
1656*37da2899SCharles.Forsyth           } while ( point != next );
1657*37da2899SCharles.Forsyth         }
1658*37da2899SCharles.Forsyth 
1659*37da2899SCharles.Forsyth         /* keep going until all points in the contours have been processed */
1660*37da2899SCharles.Forsyth         first = next;
1661*37da2899SCharles.Forsyth 
1662*37da2899SCharles.Forsyth       } while ( first != start );
1663*37da2899SCharles.Forsyth 
1664*37da2899SCharles.Forsyth     Next_Contour:
1665*37da2899SCharles.Forsyth       ;
1666*37da2899SCharles.Forsyth     }
1667*37da2899SCharles.Forsyth   }
1668*37da2899SCharles.Forsyth 
1669*37da2899SCharles.Forsyth 
1670*37da2899SCharles.Forsyth   /*************************************************************************/
1671*37da2899SCharles.Forsyth   /*************************************************************************/
1672*37da2899SCharles.Forsyth   /*****                                                               *****/
1673*37da2899SCharles.Forsyth   /*****                     HIGH-LEVEL INTERFACE                      *****/
1674*37da2899SCharles.Forsyth   /*****                                                               *****/
1675*37da2899SCharles.Forsyth   /*************************************************************************/
1676*37da2899SCharles.Forsyth   /*************************************************************************/
1677*37da2899SCharles.Forsyth 
1678*37da2899SCharles.Forsyth   FT_Error
ps3_hints_apply(PS_Hints ps_hints,FT_Outline * outline,PSH_Globals globals,FT_Render_Mode hint_mode)1679*37da2899SCharles.Forsyth   ps3_hints_apply( PS_Hints        ps_hints,
1680*37da2899SCharles.Forsyth                    FT_Outline*     outline,
1681*37da2899SCharles.Forsyth                    PSH_Globals     globals,
1682*37da2899SCharles.Forsyth                    FT_Render_Mode  hint_mode )
1683*37da2899SCharles.Forsyth   {
1684*37da2899SCharles.Forsyth     PSH3_GlyphRec  glyphrec;
1685*37da2899SCharles.Forsyth     PSH3_Glyph     glyph = &glyphrec;
1686*37da2899SCharles.Forsyth     FT_Error       error;
1687*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
1688*37da2899SCharles.Forsyth     FT_Memory      memory;
1689*37da2899SCharles.Forsyth #endif
1690*37da2899SCharles.Forsyth     FT_Int         dimension;
1691*37da2899SCharles.Forsyth 
1692*37da2899SCharles.Forsyth 
1693*37da2899SCharles.Forsyth #ifdef DEBUG_HINTER
1694*37da2899SCharles.Forsyth 
1695*37da2899SCharles.Forsyth     memory = globals->memory;
1696*37da2899SCharles.Forsyth 
1697*37da2899SCharles.Forsyth     if ( ps3_debug_glyph )
1698*37da2899SCharles.Forsyth     {
1699*37da2899SCharles.Forsyth       psh3_glyph_done( ps3_debug_glyph );
1700*37da2899SCharles.Forsyth       FT_FREE( ps3_debug_glyph );
1701*37da2899SCharles.Forsyth     }
1702*37da2899SCharles.Forsyth 
1703*37da2899SCharles.Forsyth     if ( FT_NEW( glyph ) )
1704*37da2899SCharles.Forsyth       return error;
1705*37da2899SCharles.Forsyth 
1706*37da2899SCharles.Forsyth     ps3_debug_glyph = glyph;
1707*37da2899SCharles.Forsyth 
1708*37da2899SCharles.Forsyth #endif /* DEBUG_HINTER */
1709*37da2899SCharles.Forsyth 
1710*37da2899SCharles.Forsyth     error = psh3_glyph_init( glyph, outline, ps_hints, globals );
1711*37da2899SCharles.Forsyth     if ( error )
1712*37da2899SCharles.Forsyth       goto Exit;
1713*37da2899SCharles.Forsyth 
1714*37da2899SCharles.Forsyth     glyph->do_horz_hints = 1;
1715*37da2899SCharles.Forsyth     glyph->do_vert_hints = 1;
1716*37da2899SCharles.Forsyth 
1717*37da2899SCharles.Forsyth     glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
1718*37da2899SCharles.Forsyth                                        hint_mode == FT_RENDER_MODE_LCD  );
1719*37da2899SCharles.Forsyth 
1720*37da2899SCharles.Forsyth     glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO  ||
1721*37da2899SCharles.Forsyth                                        hint_mode == FT_RENDER_MODE_LCD_V );
1722*37da2899SCharles.Forsyth 
1723*37da2899SCharles.Forsyth     for ( dimension = 0; dimension < 2; dimension++ )
1724*37da2899SCharles.Forsyth     {
1725*37da2899SCharles.Forsyth       /* load outline coordinates into glyph */
1726*37da2899SCharles.Forsyth       psh3_glyph_load_points( glyph, dimension );
1727*37da2899SCharles.Forsyth 
1728*37da2899SCharles.Forsyth       /* compute local extrema */
1729*37da2899SCharles.Forsyth       psh3_glyph_compute_extrema( glyph );
1730*37da2899SCharles.Forsyth 
1731*37da2899SCharles.Forsyth       /* compute aligned stem/hints positions */
1732*37da2899SCharles.Forsyth       psh3_hint_table_align_hints( &glyph->hint_tables[dimension],
1733*37da2899SCharles.Forsyth                                    glyph->globals,
1734*37da2899SCharles.Forsyth                                    dimension,
1735*37da2899SCharles.Forsyth                                    glyph );
1736*37da2899SCharles.Forsyth 
1737*37da2899SCharles.Forsyth       /* find strong points, align them, then interpolate others */
1738*37da2899SCharles.Forsyth       psh3_glyph_find_strong_points( glyph, dimension );
1739*37da2899SCharles.Forsyth       psh3_glyph_interpolate_strong_points( glyph, dimension );
1740*37da2899SCharles.Forsyth       psh3_glyph_interpolate_normal_points( glyph, dimension );
1741*37da2899SCharles.Forsyth       psh3_glyph_interpolate_other_points( glyph, dimension );
1742*37da2899SCharles.Forsyth 
1743*37da2899SCharles.Forsyth       /* save hinted coordinates back to outline */
1744*37da2899SCharles.Forsyth       psh3_glyph_save_points( glyph, dimension );
1745*37da2899SCharles.Forsyth     }
1746*37da2899SCharles.Forsyth 
1747*37da2899SCharles.Forsyth   Exit:
1748*37da2899SCharles.Forsyth 
1749*37da2899SCharles.Forsyth #ifndef DEBUG_HINTER
1750*37da2899SCharles.Forsyth     psh3_glyph_done( glyph );
1751*37da2899SCharles.Forsyth #endif
1752*37da2899SCharles.Forsyth 
1753*37da2899SCharles.Forsyth     return error;
1754*37da2899SCharles.Forsyth   }
1755*37da2899SCharles.Forsyth 
1756*37da2899SCharles.Forsyth 
1757*37da2899SCharles.Forsyth /* END */
1758