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