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