1*37da2899SCharles.Forsyth /***************************************************************************/ 2*37da2899SCharles.Forsyth /* */ 3*37da2899SCharles.Forsyth /* ahglobal.c */ 4*37da2899SCharles.Forsyth /* */ 5*37da2899SCharles.Forsyth /* Routines used to compute global metrics automatically (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 FT_INTERNAL_DEBUG_H 24*37da2899SCharles.Forsyth #include "ahglobal.h" 25*37da2899SCharles.Forsyth #include "ahglyph.h" 26*37da2899SCharles.Forsyth 27*37da2899SCharles.Forsyth 28*37da2899SCharles.Forsyth #define MAX_TEST_CHARACTERS 12 29*37da2899SCharles.Forsyth 30*37da2899SCharles.Forsyth static 31*37da2899SCharles.Forsyth const char* blue_chars[AH_BLUE_MAX] = 32*37da2899SCharles.Forsyth { 33*37da2899SCharles.Forsyth "THEZOCQS", 34*37da2899SCharles.Forsyth "HEZLOCUS", 35*37da2899SCharles.Forsyth "xzroesc", 36*37da2899SCharles.Forsyth "xzroesc", 37*37da2899SCharles.Forsyth "pqgjy" 38*37da2899SCharles.Forsyth }; 39*37da2899SCharles.Forsyth 40*37da2899SCharles.Forsyth 41*37da2899SCharles.Forsyth /* simple insertion sort */ 42*37da2899SCharles.Forsyth static void sort_values(FT_Int count,FT_Pos * table)43*37da2899SCharles.Forsyth sort_values( FT_Int count, 44*37da2899SCharles.Forsyth FT_Pos* table ) 45*37da2899SCharles.Forsyth { 46*37da2899SCharles.Forsyth FT_Int i, j; 47*37da2899SCharles.Forsyth FT_Pos swap; 48*37da2899SCharles.Forsyth 49*37da2899SCharles.Forsyth 50*37da2899SCharles.Forsyth for ( i = 1; i < count; i++ ) 51*37da2899SCharles.Forsyth { 52*37da2899SCharles.Forsyth for ( j = i; j > 0; j-- ) 53*37da2899SCharles.Forsyth { 54*37da2899SCharles.Forsyth if ( table[j] > table[j - 1] ) 55*37da2899SCharles.Forsyth break; 56*37da2899SCharles.Forsyth 57*37da2899SCharles.Forsyth swap = table[j]; 58*37da2899SCharles.Forsyth table[j] = table[j - 1]; 59*37da2899SCharles.Forsyth table[j - 1] = swap; 60*37da2899SCharles.Forsyth } 61*37da2899SCharles.Forsyth } 62*37da2899SCharles.Forsyth } 63*37da2899SCharles.Forsyth 64*37da2899SCharles.Forsyth 65*37da2899SCharles.Forsyth static FT_Error ah_hinter_compute_blues(AH_Hinter hinter)66*37da2899SCharles.Forsyth ah_hinter_compute_blues( AH_Hinter hinter ) 67*37da2899SCharles.Forsyth { 68*37da2899SCharles.Forsyth AH_Blue blue; 69*37da2899SCharles.Forsyth AH_Globals globals = &hinter->globals->design; 70*37da2899SCharles.Forsyth FT_Pos flats [MAX_TEST_CHARACTERS]; 71*37da2899SCharles.Forsyth FT_Pos rounds[MAX_TEST_CHARACTERS]; 72*37da2899SCharles.Forsyth FT_Int num_flats; 73*37da2899SCharles.Forsyth FT_Int num_rounds; 74*37da2899SCharles.Forsyth 75*37da2899SCharles.Forsyth FT_Face face; 76*37da2899SCharles.Forsyth FT_GlyphSlot glyph; 77*37da2899SCharles.Forsyth FT_Error error; 78*37da2899SCharles.Forsyth FT_CharMap charmap; 79*37da2899SCharles.Forsyth 80*37da2899SCharles.Forsyth 81*37da2899SCharles.Forsyth face = hinter->face; 82*37da2899SCharles.Forsyth glyph = face->glyph; 83*37da2899SCharles.Forsyth 84*37da2899SCharles.Forsyth /* save current charmap */ 85*37da2899SCharles.Forsyth charmap = face->charmap; 86*37da2899SCharles.Forsyth 87*37da2899SCharles.Forsyth /* do we have a Unicode charmap in there? */ 88*37da2899SCharles.Forsyth error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); 89*37da2899SCharles.Forsyth if ( error ) 90*37da2899SCharles.Forsyth goto Exit; 91*37da2899SCharles.Forsyth 92*37da2899SCharles.Forsyth /* we compute the blues simply by loading each character from the */ 93*37da2899SCharles.Forsyth /* 'blue_chars[blues]' string, then compute its top-most and */ 94*37da2899SCharles.Forsyth /* bottom-most points */ 95*37da2899SCharles.Forsyth 96*37da2899SCharles.Forsyth AH_LOG(( "blue zones computation\n" )); 97*37da2899SCharles.Forsyth AH_LOG(( "------------------------------------------------\n" )); 98*37da2899SCharles.Forsyth 99*37da2899SCharles.Forsyth for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ ) 100*37da2899SCharles.Forsyth { 101*37da2899SCharles.Forsyth const char* p = blue_chars[blue]; 102*37da2899SCharles.Forsyth const char* limit = p + MAX_TEST_CHARACTERS; 103*37da2899SCharles.Forsyth FT_Pos *blue_ref, *blue_shoot; 104*37da2899SCharles.Forsyth 105*37da2899SCharles.Forsyth 106*37da2899SCharles.Forsyth AH_LOG(( "blue %3d: ", blue )); 107*37da2899SCharles.Forsyth 108*37da2899SCharles.Forsyth num_flats = 0; 109*37da2899SCharles.Forsyth num_rounds = 0; 110*37da2899SCharles.Forsyth 111*37da2899SCharles.Forsyth for ( ; p < limit; p++ ) 112*37da2899SCharles.Forsyth { 113*37da2899SCharles.Forsyth FT_UInt glyph_index; 114*37da2899SCharles.Forsyth FT_Vector* extremum; 115*37da2899SCharles.Forsyth FT_Vector* points; 116*37da2899SCharles.Forsyth FT_Vector* point_limit; 117*37da2899SCharles.Forsyth FT_Vector* point; 118*37da2899SCharles.Forsyth FT_Bool round; 119*37da2899SCharles.Forsyth 120*37da2899SCharles.Forsyth 121*37da2899SCharles.Forsyth /* exit if we reach the end of the string */ 122*37da2899SCharles.Forsyth if ( !*p ) 123*37da2899SCharles.Forsyth break; 124*37da2899SCharles.Forsyth 125*37da2899SCharles.Forsyth AH_LOG(( "`%c'", *p )); 126*37da2899SCharles.Forsyth 127*37da2899SCharles.Forsyth /* load the character in the face -- skip unknown or empty ones */ 128*37da2899SCharles.Forsyth glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); 129*37da2899SCharles.Forsyth if ( glyph_index == 0 ) 130*37da2899SCharles.Forsyth continue; 131*37da2899SCharles.Forsyth 132*37da2899SCharles.Forsyth error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); 133*37da2899SCharles.Forsyth if ( error || glyph->outline.n_points <= 0 ) 134*37da2899SCharles.Forsyth continue; 135*37da2899SCharles.Forsyth 136*37da2899SCharles.Forsyth /* now compute min or max point indices and coordinates */ 137*37da2899SCharles.Forsyth points = glyph->outline.points; 138*37da2899SCharles.Forsyth point_limit = points + glyph->outline.n_points; 139*37da2899SCharles.Forsyth point = points; 140*37da2899SCharles.Forsyth extremum = point; 141*37da2899SCharles.Forsyth point++; 142*37da2899SCharles.Forsyth 143*37da2899SCharles.Forsyth if ( AH_IS_TOP_BLUE( blue ) ) 144*37da2899SCharles.Forsyth { 145*37da2899SCharles.Forsyth for ( ; point < point_limit; point++ ) 146*37da2899SCharles.Forsyth if ( point->y > extremum->y ) 147*37da2899SCharles.Forsyth extremum = point; 148*37da2899SCharles.Forsyth } 149*37da2899SCharles.Forsyth else 150*37da2899SCharles.Forsyth { 151*37da2899SCharles.Forsyth for ( ; point < point_limit; point++ ) 152*37da2899SCharles.Forsyth if ( point->y < extremum->y ) 153*37da2899SCharles.Forsyth extremum = point; 154*37da2899SCharles.Forsyth } 155*37da2899SCharles.Forsyth 156*37da2899SCharles.Forsyth AH_LOG(( "%5d", (int)extremum->y )); 157*37da2899SCharles.Forsyth 158*37da2899SCharles.Forsyth /* now, check whether the point belongs to a straight or round */ 159*37da2899SCharles.Forsyth /* segment; we first need to find in which contour the extremum */ 160*37da2899SCharles.Forsyth /* lies, then see its previous and next points */ 161*37da2899SCharles.Forsyth { 162*37da2899SCharles.Forsyth FT_Int idx = (FT_Int)( extremum - points ); 163*37da2899SCharles.Forsyth FT_Int n; 164*37da2899SCharles.Forsyth FT_Int first, last, prev, next, end; 165*37da2899SCharles.Forsyth FT_Pos dist; 166*37da2899SCharles.Forsyth 167*37da2899SCharles.Forsyth 168*37da2899SCharles.Forsyth last = -1; 169*37da2899SCharles.Forsyth first = 0; 170*37da2899SCharles.Forsyth 171*37da2899SCharles.Forsyth for ( n = 0; n < glyph->outline.n_contours; n++ ) 172*37da2899SCharles.Forsyth { 173*37da2899SCharles.Forsyth end = glyph->outline.contours[n]; 174*37da2899SCharles.Forsyth if ( end >= idx ) 175*37da2899SCharles.Forsyth { 176*37da2899SCharles.Forsyth last = end; 177*37da2899SCharles.Forsyth break; 178*37da2899SCharles.Forsyth } 179*37da2899SCharles.Forsyth first = end + 1; 180*37da2899SCharles.Forsyth } 181*37da2899SCharles.Forsyth 182*37da2899SCharles.Forsyth /* XXX: should never happen! */ 183*37da2899SCharles.Forsyth if ( last < 0 ) 184*37da2899SCharles.Forsyth continue; 185*37da2899SCharles.Forsyth 186*37da2899SCharles.Forsyth /* now look for the previous and next points that are not on the */ 187*37da2899SCharles.Forsyth /* same Y coordinate. Threshold the `closeness'... */ 188*37da2899SCharles.Forsyth 189*37da2899SCharles.Forsyth prev = idx; 190*37da2899SCharles.Forsyth next = prev; 191*37da2899SCharles.Forsyth 192*37da2899SCharles.Forsyth do 193*37da2899SCharles.Forsyth { 194*37da2899SCharles.Forsyth if ( prev > first ) 195*37da2899SCharles.Forsyth prev--; 196*37da2899SCharles.Forsyth else 197*37da2899SCharles.Forsyth prev = last; 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsyth dist = points[prev].y - extremum->y; 200*37da2899SCharles.Forsyth if ( dist < -5 || dist > 5 ) 201*37da2899SCharles.Forsyth break; 202*37da2899SCharles.Forsyth 203*37da2899SCharles.Forsyth } while ( prev != idx ); 204*37da2899SCharles.Forsyth 205*37da2899SCharles.Forsyth do 206*37da2899SCharles.Forsyth { 207*37da2899SCharles.Forsyth if ( next < last ) 208*37da2899SCharles.Forsyth next++; 209*37da2899SCharles.Forsyth else 210*37da2899SCharles.Forsyth next = first; 211*37da2899SCharles.Forsyth 212*37da2899SCharles.Forsyth dist = points[next].y - extremum->y; 213*37da2899SCharles.Forsyth if ( dist < -5 || dist > 5 ) 214*37da2899SCharles.Forsyth break; 215*37da2899SCharles.Forsyth 216*37da2899SCharles.Forsyth } while ( next != idx ); 217*37da2899SCharles.Forsyth 218*37da2899SCharles.Forsyth /* now, set the `round' flag depending on the segment's kind */ 219*37da2899SCharles.Forsyth round = FT_BOOL( 220*37da2899SCharles.Forsyth FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON || 221*37da2899SCharles.Forsyth FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON ); 222*37da2899SCharles.Forsyth 223*37da2899SCharles.Forsyth AH_LOG(( "%c ", round ? 'r' : 'f' )); 224*37da2899SCharles.Forsyth } 225*37da2899SCharles.Forsyth 226*37da2899SCharles.Forsyth if ( round ) 227*37da2899SCharles.Forsyth rounds[num_rounds++] = extremum->y; 228*37da2899SCharles.Forsyth else 229*37da2899SCharles.Forsyth flats[num_flats++] = extremum->y; 230*37da2899SCharles.Forsyth } 231*37da2899SCharles.Forsyth 232*37da2899SCharles.Forsyth AH_LOG(( "\n" )); 233*37da2899SCharles.Forsyth 234*37da2899SCharles.Forsyth /* we have computed the contents of the `rounds' and `flats' tables, */ 235*37da2899SCharles.Forsyth /* now determine the reference and overshoot position of the blue; */ 236*37da2899SCharles.Forsyth /* we simply take the median value after a simple short */ 237*37da2899SCharles.Forsyth sort_values( num_rounds, rounds ); 238*37da2899SCharles.Forsyth sort_values( num_flats, flats ); 239*37da2899SCharles.Forsyth 240*37da2899SCharles.Forsyth blue_ref = globals->blue_refs + blue; 241*37da2899SCharles.Forsyth blue_shoot = globals->blue_shoots + blue; 242*37da2899SCharles.Forsyth if ( num_flats == 0 && num_rounds == 0 ) 243*37da2899SCharles.Forsyth { 244*37da2899SCharles.Forsyth *blue_ref = -10000; 245*37da2899SCharles.Forsyth *blue_shoot = -10000; 246*37da2899SCharles.Forsyth } 247*37da2899SCharles.Forsyth else if ( num_flats == 0 ) 248*37da2899SCharles.Forsyth { 249*37da2899SCharles.Forsyth *blue_ref = 250*37da2899SCharles.Forsyth *blue_shoot = rounds[num_rounds / 2]; 251*37da2899SCharles.Forsyth } 252*37da2899SCharles.Forsyth else if ( num_rounds == 0 ) 253*37da2899SCharles.Forsyth { 254*37da2899SCharles.Forsyth *blue_ref = 255*37da2899SCharles.Forsyth *blue_shoot = flats[num_flats / 2]; 256*37da2899SCharles.Forsyth } 257*37da2899SCharles.Forsyth else 258*37da2899SCharles.Forsyth { 259*37da2899SCharles.Forsyth *blue_ref = flats[num_flats / 2]; 260*37da2899SCharles.Forsyth *blue_shoot = rounds[num_rounds / 2]; 261*37da2899SCharles.Forsyth } 262*37da2899SCharles.Forsyth 263*37da2899SCharles.Forsyth /* there are sometimes problems: if the overshoot position of top */ 264*37da2899SCharles.Forsyth /* zones is under its reference position, or the opposite for bottom */ 265*37da2899SCharles.Forsyth /* zones. We must thus check everything there and correct the errors */ 266*37da2899SCharles.Forsyth if ( *blue_shoot != *blue_ref ) 267*37da2899SCharles.Forsyth { 268*37da2899SCharles.Forsyth FT_Pos ref = *blue_ref; 269*37da2899SCharles.Forsyth FT_Pos shoot = *blue_shoot; 270*37da2899SCharles.Forsyth FT_Bool over_ref = FT_BOOL( shoot > ref ); 271*37da2899SCharles.Forsyth 272*37da2899SCharles.Forsyth 273*37da2899SCharles.Forsyth if ( AH_IS_TOP_BLUE( blue ) ^ over_ref ) 274*37da2899SCharles.Forsyth *blue_shoot = *blue_ref = ( shoot + ref ) / 2; 275*37da2899SCharles.Forsyth } 276*37da2899SCharles.Forsyth 277*37da2899SCharles.Forsyth AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); 278*37da2899SCharles.Forsyth } 279*37da2899SCharles.Forsyth 280*37da2899SCharles.Forsyth /* reset original face charmap */ 281*37da2899SCharles.Forsyth FT_Set_Charmap( face, charmap ); 282*37da2899SCharles.Forsyth error = 0; 283*37da2899SCharles.Forsyth 284*37da2899SCharles.Forsyth Exit: 285*37da2899SCharles.Forsyth return error; 286*37da2899SCharles.Forsyth } 287*37da2899SCharles.Forsyth 288*37da2899SCharles.Forsyth 289*37da2899SCharles.Forsyth static FT_Error ah_hinter_compute_widths(AH_Hinter hinter)290*37da2899SCharles.Forsyth ah_hinter_compute_widths( AH_Hinter hinter ) 291*37da2899SCharles.Forsyth { 292*37da2899SCharles.Forsyth /* scan the array of segments in each direction */ 293*37da2899SCharles.Forsyth AH_Outline outline = hinter->glyph; 294*37da2899SCharles.Forsyth AH_Segment segments; 295*37da2899SCharles.Forsyth AH_Segment limit; 296*37da2899SCharles.Forsyth AH_Globals globals = &hinter->globals->design; 297*37da2899SCharles.Forsyth FT_Pos* widths; 298*37da2899SCharles.Forsyth FT_Int dimension; 299*37da2899SCharles.Forsyth FT_Int* p_num_widths; 300*37da2899SCharles.Forsyth FT_Error error = 0; 301*37da2899SCharles.Forsyth FT_Pos edge_distance_threshold = 32000; 302*37da2899SCharles.Forsyth 303*37da2899SCharles.Forsyth 304*37da2899SCharles.Forsyth globals->num_widths = 0; 305*37da2899SCharles.Forsyth globals->num_heights = 0; 306*37da2899SCharles.Forsyth 307*37da2899SCharles.Forsyth /* For now, compute the standard width and height from the `o' */ 308*37da2899SCharles.Forsyth /* character. I started computing the stem width of the `i' and the */ 309*37da2899SCharles.Forsyth /* stem height of the "-", but it wasn't too good. Moreover, we now */ 310*37da2899SCharles.Forsyth /* have a single character that gives us standard width and height. */ 311*37da2899SCharles.Forsyth { 312*37da2899SCharles.Forsyth FT_UInt glyph_index; 313*37da2899SCharles.Forsyth 314*37da2899SCharles.Forsyth 315*37da2899SCharles.Forsyth glyph_index = FT_Get_Char_Index( hinter->face, 'o' ); 316*37da2899SCharles.Forsyth if ( glyph_index == 0 ) 317*37da2899SCharles.Forsyth return 0; 318*37da2899SCharles.Forsyth 319*37da2899SCharles.Forsyth error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE ); 320*37da2899SCharles.Forsyth if ( error ) 321*37da2899SCharles.Forsyth goto Exit; 322*37da2899SCharles.Forsyth 323*37da2899SCharles.Forsyth error = ah_outline_load( hinter->glyph, hinter->face ); 324*37da2899SCharles.Forsyth if ( error ) 325*37da2899SCharles.Forsyth goto Exit; 326*37da2899SCharles.Forsyth 327*37da2899SCharles.Forsyth ah_outline_compute_segments( hinter->glyph ); 328*37da2899SCharles.Forsyth ah_outline_link_segments( hinter->glyph ); 329*37da2899SCharles.Forsyth } 330*37da2899SCharles.Forsyth 331*37da2899SCharles.Forsyth segments = outline->horz_segments; 332*37da2899SCharles.Forsyth limit = segments + outline->num_hsegments; 333*37da2899SCharles.Forsyth widths = globals->heights; 334*37da2899SCharles.Forsyth p_num_widths = &globals->num_heights; 335*37da2899SCharles.Forsyth 336*37da2899SCharles.Forsyth for ( dimension = 1; dimension >= 0; dimension-- ) 337*37da2899SCharles.Forsyth { 338*37da2899SCharles.Forsyth AH_Segment seg = segments; 339*37da2899SCharles.Forsyth AH_Segment link; 340*37da2899SCharles.Forsyth FT_Int num_widths = 0; 341*37da2899SCharles.Forsyth 342*37da2899SCharles.Forsyth 343*37da2899SCharles.Forsyth for ( ; seg < limit; seg++ ) 344*37da2899SCharles.Forsyth { 345*37da2899SCharles.Forsyth link = seg->link; 346*37da2899SCharles.Forsyth /* we only consider stem segments there! */ 347*37da2899SCharles.Forsyth if ( link && link->link == seg && link > seg ) 348*37da2899SCharles.Forsyth { 349*37da2899SCharles.Forsyth FT_Pos dist; 350*37da2899SCharles.Forsyth 351*37da2899SCharles.Forsyth 352*37da2899SCharles.Forsyth dist = seg->pos - link->pos; 353*37da2899SCharles.Forsyth if ( dist < 0 ) 354*37da2899SCharles.Forsyth dist = -dist; 355*37da2899SCharles.Forsyth 356*37da2899SCharles.Forsyth if ( num_widths < AH_MAX_WIDTHS ) 357*37da2899SCharles.Forsyth widths[num_widths++] = dist; 358*37da2899SCharles.Forsyth } 359*37da2899SCharles.Forsyth } 360*37da2899SCharles.Forsyth 361*37da2899SCharles.Forsyth sort_values( num_widths, widths ); 362*37da2899SCharles.Forsyth *p_num_widths = num_widths; 363*37da2899SCharles.Forsyth 364*37da2899SCharles.Forsyth /* we will now try to find the smallest width */ 365*37da2899SCharles.Forsyth if ( num_widths > 0 && widths[0] < edge_distance_threshold ) 366*37da2899SCharles.Forsyth edge_distance_threshold = widths[0]; 367*37da2899SCharles.Forsyth 368*37da2899SCharles.Forsyth segments = outline->vert_segments; 369*37da2899SCharles.Forsyth limit = segments + outline->num_vsegments; 370*37da2899SCharles.Forsyth widths = globals->widths; 371*37da2899SCharles.Forsyth p_num_widths = &globals->num_widths; 372*37da2899SCharles.Forsyth } 373*37da2899SCharles.Forsyth 374*37da2899SCharles.Forsyth /* Now, compute the edge distance threshold as a fraction of the */ 375*37da2899SCharles.Forsyth /* smallest width in the font. Set it in `hinter.glyph' too! */ 376*37da2899SCharles.Forsyth if ( edge_distance_threshold == 32000 ) 377*37da2899SCharles.Forsyth edge_distance_threshold = 50; 378*37da2899SCharles.Forsyth 379*37da2899SCharles.Forsyth /* let's try 20% */ 380*37da2899SCharles.Forsyth hinter->glyph->edge_distance_threshold = edge_distance_threshold / 5; 381*37da2899SCharles.Forsyth 382*37da2899SCharles.Forsyth Exit: 383*37da2899SCharles.Forsyth return error; 384*37da2899SCharles.Forsyth } 385*37da2899SCharles.Forsyth 386*37da2899SCharles.Forsyth 387*37da2899SCharles.Forsyth FT_LOCAL_DEF( FT_Error ) ah_hinter_compute_globals(AH_Hinter hinter)388*37da2899SCharles.Forsyth ah_hinter_compute_globals( AH_Hinter hinter ) 389*37da2899SCharles.Forsyth { 390*37da2899SCharles.Forsyth return ah_hinter_compute_widths( hinter ) || 391*37da2899SCharles.Forsyth ah_hinter_compute_blues ( hinter ); 392*37da2899SCharles.Forsyth } 393*37da2899SCharles.Forsyth 394*37da2899SCharles.Forsyth 395*37da2899SCharles.Forsyth /* END */ 396