diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.4-orig/src/autohint/ahglobal.c freetype-2.1.4/src/autohint/ahglobal.c --- freetype-2.1.4-orig/src/autohint/ahglobal.c Fri Mar 21 05:58:56 2003 +++ freetype-2.1.4/src/autohint/ahglobal.c Fri Apr 11 00:31:38 2003 @@ -79,6 +79,7 @@ FT_GlyphSlot glyph; FT_Error error; FT_CharMap charmap; + FT_ULong offset = 0; face = hinter->face; @@ -99,6 +100,8 @@ AH_LOG(( "blue zones computation\n" )); AH_LOG(( "------------------------------------------------\n" )); + Compute_Blues: + for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ ) { const char* p = blue_chars[blue]; @@ -128,12 +131,14 @@ AH_LOG(( "`%c'", *p )); /* load the character in the face -- skip unknown or empty ones */ - glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); + glyph_index = FT_Get_Char_Index( face, offset + (FT_ULong)*p ); if ( glyph_index == 0 ) continue; - error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); - if ( error || glyph->outline.n_points <= 0 ) + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_RECURSE ); + if ( error || + glyph->format != FT_GLYPH_FORMAT_OUTLINE || + glyph->outline.n_points <= 0 ) continue; /* now compute min or max point indices and coordinates */ @@ -219,9 +224,34 @@ } while ( next != idx ); /* now, set the `round' flag depending on the segment's kind */ +#if 0 round = FT_BOOL( FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON || FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON ); +#else + round = TRUE; + + { + FT_Int n = 0, p = prev; + FT_Bool is_top = AH_IS_TOP_BLUE( blue ); + + + while ( ( p = ( p >= last )? first : p + 1 ) != next ) + { + if ( FT_CURVE_TAG( glyph->outline.tags[p] ) == FT_CURVE_TAG_ON ) + { + if ( ( is_top && points[p].y < extremum->y ) || + ( !is_top && points[p].y > extremum->y ) ) + break; + + n++; + } + } + + if ( n >= 2 && p == next ) + round = FALSE; + } +#endif AH_LOG(( "%c ", round ? 'r' : 'f' )); } @@ -280,6 +310,18 @@ AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); } + globals->base_line = globals->blue_refs[ AH_BLUE_SMALL_BOTTOM ]; + + if ( !offset ) + { + offset = 0xFEE0; + globals = &hinter->globals->design_f; + AH_LOG(( "\nblues for CJK full-width-forms:\n" )); + goto Compute_Blues; + } + else + AH_LOG(( "\n" )); + /* reset original face charmap */ FT_Set_Charmap( face, charmap ); error = 0; @@ -302,7 +344,10 @@ FT_Int* p_num_widths; FT_Error error = 0; FT_Pos edge_distance_threshold = 32000; + FT_ULong offset = 0; + + Compute_Widths: globals->num_widths = 0; globals->num_heights = 0; @@ -315,7 +360,7 @@ FT_UInt glyph_index; - glyph_index = FT_Get_Char_Index( hinter->face, 'o' ); + glyph_index = FT_Get_Char_Index( hinter->face, offset + 'o' ); if ( glyph_index == 0 ) return 0; @@ -374,6 +419,13 @@ p_num_widths = &globals->num_widths; } + if ( offset == 0 ) + { + offset = 0xFEE0; + globals = &hinter->globals->design_f; + goto Compute_Widths; + } + /* Now, compute the edge distance threshold as a fraction of the */ /* smallest width in the font. Set it in `hinter.glyph' too! */ if ( edge_distance_threshold == 32000 ) @@ -392,6 +444,172 @@ { return ah_hinter_compute_widths( hinter ) || ah_hinter_compute_blues ( hinter ); + } + + + static const AH_CharFlag + ah_flags_unicode[] = + { + { AH_CHAR_FLAG_LATIN, 0x21, 0x600 }, + { AH_CHAR_FLAG_LATIN, 0x1E00, 0x1F00 }, + { AH_CHAR_FLAG_LATIN, 0x2160, 0x2180 }, + { AH_CHAR_FLAG_LATIN_FULL, 0xFF00, 0xFF60 } + }; + + + static const AH_CharTable + ah_table_unicode = + { + sizeof( ah_flags_unicode ) / sizeof( AH_CharFlag ), + (AH_CharFlag *)ah_flags_unicode + }; + + + FT_LOCAL_DEF( void ) + ah_hinter_compute_char_flags( AH_Hinter hinter ) + { + FT_Memory memory = hinter->memory; + FT_Face face = hinter->face; + AH_CharTable* table = hinter->globals->table; + FT_ULong size, num, i; + FT_Byte* flags; + FT_Byte cflag; + FT_Byte* cur; + FT_Byte* last; + FT_Error error; + FT_CharMap charmap; + + + if ( table ) + return; + + if ( face->num_glyphs <= 0 ) + return; + + if ( FT_NEW_ARRAY( flags, face->num_glyphs + 1 ) ) + return; + + charmap = face->charmap; + if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + goto Exit; + + + size = ah_table_unicode.size; + num = 0; + + for ( i = 0; i < size; i++ ) + { + FT_ULong ucs = ah_table_unicode.flags[i].start; + FT_ULong limit = ah_table_unicode.flags[i].last; + FT_UInt glyph_index; + + cflag = ah_table_unicode.flags[i].char_flag; + while ( ucs <= limit ) + { + glyph_index = FT_Get_Char_Index( face, ucs++ ); + + if ( glyph_index ) + { + num++; + flags[ glyph_index ] = cflag; + } + } + } + + if ( num == 0 ) + goto Exit; + + + cur = flags; + last = flags + face->num_glyphs; + cflag = AH_CHAR_FLAG_NONE; + num = 0; + + while ( ++cur <= last ) + { + if ( cflag != cur[0] ) + { + cflag = cur[0]; + if ( cflag != AH_CHAR_FLAG_NONE ) + num++; + } + } + + size = sizeof( AH_CharTable ) + num * sizeof( AH_CharFlag ); + if ( FT_ALLOC( table, size ) ) + goto Exit; + + table->size = num; + table->flags = (AH_CharFlag *)( table + 1 ); + + + cur = flags + 1; + last = flags + face->num_glyphs; + cflag = AH_CHAR_FLAG_NONE; + num = 0; + + for ( i = 1; cur <= last; i++, cur++ ) + { + if ( cflag != cur[0] ) + { + if ( cflag != AH_CHAR_FLAG_NONE ) + table->flags[num - 1].last = i - 1; + + cflag = cur[0]; + if ( cflag != AH_CHAR_FLAG_NONE ) + { + table->flags[num].char_flag = cflag; + table->flags[num++].start = i; + } + } + } + + if ( cflag != AH_CHAR_FLAG_NONE ) + table->flags[num - 1].last = i - 1; + + hinter->globals->table = table; + + Exit: + FT_Set_Charmap( face, charmap ); + FT_FREE( flags ); + } + + + FT_LOCAL_DEF( FT_Byte ) + ah_hinter_get_char_flag( AH_Hinter hinter, + FT_ULong glyph_index ) + { + AH_CharTable* table = hinter->globals->table; + + + if ( table && table->size > 0 && glyph_index ) + { + AH_CharFlag* cur; + AH_CharFlag* flags = table->flags; + int min = 0; + int max = table->size - 1; + int mid; + + + if ( glyph_index < flags[min].start || + glyph_index > flags[max].last ) + return AH_CHAR_FLAG_NONE; + + while ( min <= max ) + { + mid = ( min + max ) / 2; + cur = flags + mid; + + if ( glyph_index < cur->start ) + max = mid - 1; + else if ( glyph_index > cur->last ) + min = mid + 1; + else + return cur->char_flag; + } + } + + return AH_CHAR_FLAG_NONE; } diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.4-orig/src/autohint/ahglobal.h freetype-2.1.4/src/autohint/ahglobal.h --- freetype-2.1.4-orig/src/autohint/ahglobal.h Mon Jan 13 03:26:10 2003 +++ freetype-2.1.4/src/autohint/ahglobal.h Tue Apr 8 21:31:24 2003 @@ -50,6 +50,13 @@ FT_LOCAL( FT_Error ) ah_hinter_compute_globals( AH_Hinter hinter ); + FT_LOCAL( void ) + ah_hinter_compute_char_flags( AH_Hinter hinter ); + + FT_LOCAL( FT_Byte ) + ah_hinter_get_char_flag( AH_Hinter hinter, + FT_ULong glyph_index ); + FT_END_HEADER diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.4-orig/src/autohint/ahglyph.c freetype-2.1.4/src/autohint/ahglyph.c --- freetype-2.1.4-orig/src/autohint/ahglyph.c Fri Mar 21 05:58:56 2003 +++ freetype-2.1.4/src/autohint/ahglyph.c Fri Apr 25 23:14:34 2003 @@ -52,11 +52,11 @@ printf ( "Table of %s edges:\n", !dimension ? "vertical" : "horizontal" ); printf ( " [ index | pos | dir | link |" - " serif | blue | opos | pos ]\n" ); + " serif | blue | opos | pos | diff ]\n" ); for ( edge = edges; edge < edge_limit; edge++ ) { - printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n", + printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f | %5.2f ]\n", edge - edges, (int)edge->fpos, edge->dir == AH_DIR_UP @@ -72,7 +72,8 @@ edge->serif ? ( edge->serif - edges ) : -1, edge->blue_edge ? 'y' : 'n', edge->opos / 64.0, - edge->pos / 64.0 ); + edge->pos / 64.0, + ( edge->pos - edge->opos ) / 64.0 ); } edges = outline->vert_edges; @@ -361,6 +362,11 @@ FT_Vector* vec = gloader->current.outline.points; char* tag = gloader->current.outline.tags; +#ifdef AH_DEBUG + ah_dump_edges( outline ); + ah_dump_segments( outline ); + printf( "\n" ); +#endif /* we assume that the glyph loader has already been checked for storage */ for ( ; point < point_limit; point++, vec++, tag++ ) @@ -602,12 +608,12 @@ angle_out = ah_angle( &ovec ); delta = angle_in - angle_out; - if ( delta > AH_PI ) - delta = AH_2PI - delta; - if ( delta < 0 ) delta = -delta; + if ( delta > AH_PI ) + delta = AH_2PI - delta; + if ( delta < 2 ) goto Is_Weak_Point; } @@ -894,11 +900,33 @@ segment->last = point; segment->pos = ( min_pos + max_pos ) >> 1; +#if 0 /* a segment is round if either its first or last point */ /* is a control point */ if ( ( segment->first->flags | point->flags ) & AH_FLAG_CONTROL ) segment->flags |= AH_EDGE_ROUND; +#else + { + AH_Point p = segment->first; + AH_Flags f0 = p->flags & AH_FLAG_CONTROL; + AH_Flags f; + + + for ( ; p != point; f0 = f ) + { + p = p->next; + f = p->flags & AH_FLAG_CONTROL; + + if ( !f0 && !f ) + break; + + if ( p == point ) + segment->flags |= AH_EDGE_ROUND; + } + + } +#endif /* compute segment size */ min_pos = max_pos = point->v; @@ -1057,7 +1085,8 @@ /* now compare each segment to the others */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { - FT_Pos best_score; + FT_ULong best_score; + FT_ULong best_len; AH_Segment best_segment; @@ -1068,9 +1097,15 @@ best_segment = seg1->link; if ( best_segment ) + { best_score = seg1->score; + best_len = seg1->len; + } else - best_score = 32000; + { + best_score = 0x7FFFFFFFL; + best_len = 0; + } for ( seg2 = segments; seg2 < segment_limit; seg2++ ) if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 ) @@ -1092,9 +1127,10 @@ continue; { - FT_Pos min = seg1->min_coord; - FT_Pos max = seg1->max_coord; - FT_Pos len, dist, score; + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len, dist; + FT_ULong score; if ( min < seg2->min_coord ) @@ -1103,18 +1139,22 @@ if ( max > seg2->max_coord ) max = seg2->max_coord; - len = max - min; - if ( len >= 8 ) + len = max - min; + if ( len >= 4 ) { dist = seg2->pos - seg1->pos; if ( dist < 0 ) dist = -dist; - score = dist + 3000 / len; + score = (FT_ULong)dist; - if ( score < best_score ) + if ( 8*score < 9*best_score ) { + if ( 8*score > 7*best_score && best_len > 4*len ) + continue; + best_score = score; + best_len = (FT_ULong)len; best_segment = seg2; } } @@ -1125,12 +1165,81 @@ { seg1->link = best_segment; seg1->score = best_score; + seg1->len = best_len; best_segment->num_linked++; } } /* edges 1 */ + { + AH_Segment seg3, seg4, seg5, seg6, serif1, serif4; + FT_Pos pos1, pos2, pos3, pos4; + + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg4 = seg1->link; + + if ( !seg4 || seg4->link != seg1 ) + continue; + + pos1 = seg1->pos; + pos4 = seg4->pos; + + if ( pos1 >= pos4 ) + continue; + + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + seg3 = seg2->link; + + if ( seg2 == seg1 || !seg3 || seg3->link != seg2 ) + continue; + + pos2 = seg2->pos; + pos3 = seg3->pos; + + if ( pos2 >= pos3 || + pos1 > pos2 || + pos3 > pos4 || + seg1->score <= seg2->score ) + continue; + + if ( seg1->len > seg2->len * 2 ) + { + serif1 = seg4; + serif4 = seg1; + seg1 = seg2; + seg4 = seg3; + } + else + { + serif1 = seg3; + serif4 = seg2; + } + + for ( seg5 = segments; seg5 < segment_limit; seg5++ ) + { + seg6 = seg5->link; + + if ( seg6 == seg1 ) + { + seg5->link = 0; + seg5->serif = serif1; + } + else if ( seg6 == seg4 ) + { + seg5->link = 0; + seg5->serif = serif4; + } + } + + break; + } + } + } + /* now, compute the `serif' segments */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { @@ -1139,7 +1248,11 @@ if ( seg2 && seg2->link != seg1 ) { seg1->link = 0; - seg1->serif = seg2->link; + + if ( seg1->score < 4 * seg2->score ) + seg1->serif = seg2->link; + else + seg2->num_linked--; } } @@ -1211,6 +1324,9 @@ FT_Pos dist; + if ( edge->dir != seg->dir ) + continue; + dist = seg->pos - edge->fpos; if ( dist < 0 ) dist = -dist; @@ -1218,6 +1334,34 @@ dist = FT_MulFix( dist, scale ); if ( dist < edge_distance_threshold ) { + AH_Segment link = seg->link; + + + if ( link ) + { + AH_Segment seg1 = edge->first; + AH_Segment link1; + + do + { + link1 = seg1->link; + if ( link1 ) + { + dist = link->pos - link1->pos; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist >= edge_distance_threshold ) + break; + } + } + while ( ( seg1 = seg1->edge_next ) != edge->first ); + + if ( dist >= edge_distance_threshold ) + continue; + } + found = edge; break; } @@ -1243,6 +1387,7 @@ edge->fpos = seg->pos; edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); seg->edge_next = seg; + edge->dir = seg->dir; } else { @@ -1288,8 +1433,6 @@ { FT_Int is_round = 0; /* does it contain round segments? */ FT_Int is_straight = 0; /* does it contain straight segments? */ - FT_Pos ups = 0; /* number of upwards segments */ - FT_Pos downs = 0; /* number of downwards segments */ seg = edge->first; @@ -1305,12 +1448,6 @@ else is_straight++; - /* check for segment direction */ - if ( seg->dir == up_dir ) - ups += seg->max_coord-seg->min_coord; - else - downs += seg->max_coord-seg->min_coord; - /* check for links -- if seg->serif is set, then seg->link must */ /* be ignored */ is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge ); @@ -1376,18 +1513,6 @@ if ( is_round > 0 && is_round >= is_straight ) edge->flags |= AH_EDGE_ROUND; - /* set the edge's main direction */ - edge->dir = AH_DIR_NONE; - - if ( ups > downs ) - edge->dir = up_dir; - - else if ( ups < downs ) - edge->dir = - up_dir; - - else if ( ups == downs ) - edge->dir = 0; /* both up and down !! */ - /* gets rid of serifs if link is set */ /* XXX: This gets rid of many unpleasant artefacts! */ /* Example: the `c' in cour.pfa at size 13 */ @@ -1441,10 +1566,16 @@ AH_Edge edge_limit = edge + outline->num_hedges; AH_Globals globals = &face_globals->design; FT_Fixed y_scale = outline->y_scale; + FT_Pos base_line; FT_Bool blue_active[AH_BLUE_MAX]; + if ( face_globals->char_flag == AH_CHAR_FLAG_LATIN_FULL ) + globals = &face_globals->design_f; + + base_line = globals->base_line; + /* compute which blue zones are active, i.e. have their scaled */ /* size < 3/4 pixels */ { @@ -1485,6 +1616,14 @@ FT_Pos best_dist; /* initial threshold */ + if ( edge->serif ) + { + FT_Pos d = edge->serif->pos - edge->pos; + + if ( ABS( d ) < 128 ) + continue; + } + /* compute the initial threshold as a fraction of the EM size */ best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale ); @@ -1520,7 +1659,7 @@ /* first of all, compare it to the reference position */ - dist = edge->fpos - *blue_pos; + dist = base_line + edge->fpos - *blue_pos; if ( dist < 0 ) dist = -dist; @@ -1542,7 +1681,7 @@ if ( is_top_blue ^ is_under_ref ) { blue_pos = globals->blue_shoots + blue; - dist = edge->fpos - *blue_pos; + dist = base_line + edge->fpos - *blue_pos; if ( dist < 0 ) dist = -dist; @@ -1582,7 +1721,10 @@ FT_Pos delta; - delta = globals->scaled.blue_refs - globals->design.blue_refs; + if ( globals->char_flag == AH_CHAR_FLAG_LATIN_FULL ) + delta = globals->scaled.blue_refs - globals->design_f.blue_refs; + else + delta = globals->scaled.blue_refs - globals->design.blue_refs; for ( ; edge < edge_limit; edge++ ) { diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.4-orig/src/autohint/ahhint.c freetype-2.1.4/src/autohint/ahhint.c --- freetype-2.1.4-orig/src/autohint/ahhint.c Fri Mar 21 05:58:56 2003 +++ freetype-2.1.4/src/autohint/ahhint.c Wed Apr 30 03:12:55 2003 @@ -110,6 +110,8 @@ if ( !hinter->do_stem_adjust ) { /* leave stem widths unchanged */ + if ( dist < 48 ) + dist += ( 48 - dist )/2 ; } else if ( ( vertical && !hinter->do_vert_snapping ) || ( !vertical && !hinter->do_horz_snapping ) ) @@ -117,34 +119,46 @@ /* smooth hinting process, very lightly quantize the stem width */ /* */ - /* leave the widths of serifs alone */ - - if ( ( stem_flags & AH_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) - goto Done_Width; - - else if ( ( base_flags & AH_EDGE_ROUND ) ) - { - if ( dist < 80 ) - dist = 64; - } - else if ( dist < 56 ) - dist = 56; - + if ( hinter->do_blue_hints ) { - FT_Pos delta = dist - globals->stds[vertical]; + /* leave the widths of serifs alone */ + if ( ( stem_flags & AH_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) + goto Done_Width; - if ( delta < 0 ) - delta = -delta; + if ( ( base_flags & AH_EDGE_ROUND ) ) + { + if ( dist < 80 ) + dist = 64; + } + else if ( dist < 56 ) + dist = 56; - if ( delta < 40 ) { - dist = globals->stds[vertical]; - if ( dist < 48 ) - dist = 48; + FT_Pos delta = dist - globals->stds[vertical]; - goto Done_Width; + if ( delta < 0 ) + delta = -delta; + + if ( delta < 40 ) + { + dist = globals->stds[vertical]; + if ( dist < 48 ) + dist = 48; + + goto Done_Width; + } } + } + + if ( dist < 54 ) + { + dist += ( 54 - dist )/2; + } + else + { + FT_Pos delta; + if ( dist < 3 * 64 ) { @@ -154,17 +168,22 @@ if ( delta < 10 ) dist += delta; - else if ( delta < 32 ) + else if ( delta < 20 ) dist += 10; + else if ( delta < 44 ) + dist += delta; + else if ( delta < 54 ) dist += 54; else dist += delta; } +#if 0 else dist = ( dist + 32 ) & -64; +#endif } } else @@ -184,7 +203,7 @@ } else { - dist = ah_snap_width( globals->widths, globals->num_widths, dist ); + dist = ah_snap_width( globals->widths, globals->num_widths, dist ); if ( hinter->flags & AH_HINTER_MONOCHROME ) { @@ -396,6 +415,128 @@ } + static void + ah_hint_normal_stem( AH_Hinter hinter, + AH_Edge edge, + AH_Edge edge2, + AH_Edge anchor, + int vertical ) + { + FT_Pos org_len, cur_len, org_center; + FT_Pos cur_pos1, cur_pos2; + FT_Pos d_off1, u_off1, d_off2, u_off2, delta; + FT_Pos offset; + FT_Pos threshold = 64; + + + if ( !hinter->do_stem_adjust ) + { + if ( ( edge->flags & AH_EDGE_ROUND ) && + ( edge2->flags & AH_EDGE_ROUND ) ) + { + if ( vertical ) + threshold = 64 - AH_LIGHT_MODE_MAX_HORZ_GAP; + else + threshold = 64 - AH_LIGHT_MODE_MAX_VERT_GAP; + } + else + { + if ( vertical ) + threshold = 64 - AH_LIGHT_MODE_MAX_HORZ_GAP/3; + else + threshold = 64 - AH_LIGHT_MODE_MAX_VERT_GAP/3; + } + } + + offset = anchor? anchor->pos - anchor->opos : 0; + org_len = edge2->opos - edge->opos; + cur_len = ah_compute_stem_width( hinter, vertical, org_len, + edge->flags, edge2->flags ); + org_center = ( edge->opos + edge2->opos ) / 2 + offset; + cur_pos1 = org_center - cur_len / 2; + cur_pos2 = cur_pos1 + cur_len; + d_off1 = cur_pos1 - ( cur_pos1 & -64 ); + d_off2 = cur_pos2 - ( cur_pos2 & -64 ); + u_off1 = 64 - d_off1; + u_off2 = 64 - d_off2; + delta = 0; + + + if ( d_off1 == 0 || d_off2 == 0 ) + goto Exit; + + if ( cur_len <= threshold ) + { + if ( d_off2 < cur_len ) + { + if ( u_off1 <= d_off2 ) + delta = u_off1; + else + delta = -d_off2; + } + + goto Exit; + } + + if ( threshold < 64 ) + { + if ( d_off1 >= threshold || u_off1 >= threshold || + d_off2 >= threshold || u_off2 >= threshold ) + goto Exit; + } + + offset = cur_len % 64; + + if ( offset < 32 ) + { + if ( u_off1 <= offset || d_off2 <= offset ) + goto Exit; + } + else + offset = 64 - threshold; + + d_off1 = threshold - u_off1; + u_off1 = u_off1 - offset; + u_off2 = threshold - d_off2; + d_off2 = d_off2 - offset; + + if ( d_off1 <= u_off1 ) + u_off1 = -d_off1; + + if ( d_off2 <= u_off2 ) + u_off2 = -d_off2; + + if ( ABS( u_off1 ) <= ABS( u_off2 ) ) + delta = u_off1; + else + delta = u_off2; + + Exit: +#if AH_LIGHT_MODE_MAX_DELTA_ABS < 32 + if ( !hinter->do_stem_adjust ) + { + if ( delta > AH_LIGHT_MODE_MAX_DELTA_ABS ) + delta = AH_LIGHT_MODE_MAX_DELTA_ABS; + else if ( delta < -AH_LIGHT_MODE_MAX_DELTA_ABS ) + delta = -AH_LIGHT_MODE_MAX_DELTA_ABS; + } +#endif + + cur_pos1 += delta; + + if ( edge->opos < edge2->opos ) + { + edge->pos = cur_pos1; + edge2->pos = cur_pos1 + cur_len; + } + else + { + edge->pos = cur_pos1 + cur_len; + edge2->pos = cur_pos1; + } + } + + /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ @@ -435,7 +576,7 @@ /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ - if ( dimension ) + if ( hinter->do_blue_hints && dimension ) { for ( edge = edges; edge < edge_limit; edge++ ) { @@ -473,8 +614,10 @@ edge2->flags |= AH_EDGE_DONE; } +#if 0 if ( !anchor ) anchor = edge; +#endif } } @@ -507,6 +650,7 @@ continue; } +#if 0 if ( !anchor ) { #ifdef FT_CONFIG_CHESTER_STEM @@ -661,6 +805,15 @@ if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; } +#else + ah_hint_normal_stem( hinter, edge, edge2, anchor, dimension ); + + edge->flags |= AH_EDGE_DONE; + edge2->flags |= AH_EDGE_DONE; + + if ( !anchor && !dimension ) + anchor = edge; +#endif } if ( !has_serifs ) @@ -675,17 +828,12 @@ if ( edge->serif ) ah_align_serif_edge( hinter, edge->serif, edge, dimension ); - else if ( !anchor ) - { - edge->pos = ( edge->opos + 32 ) & -64; - anchor = edge; - } - else - edge->pos = anchor->pos + - ( ( edge->opos-anchor->opos + 32 ) & -64 ); + else if ( anchor ) + edge->pos += anchor->pos - anchor->opos; edge->flags |= AH_EDGE_DONE; +#if 0 if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; @@ -693,6 +841,7 @@ edge[1].flags & AH_EDGE_DONE && edge->pos > edge[1].pos ) edge->pos = edge[1].pos; +#endif } Next_Dimension: @@ -731,6 +880,7 @@ AH_Edge edges; AH_Edge edge_limit; FT_Int dimension; + FT_Bool do_adjust = hinter->do_stem_adjust; edges = outline->horz_edges; @@ -746,7 +896,8 @@ { /* move the points of each segment */ /* in each edge to the edge's position */ - AH_Segment seg = edge->first; + AH_Segment seg = edge->first; + FT_Pos delta = edge->pos - edge->opos; do @@ -758,12 +909,20 @@ { if ( dimension ) { - point->y = edge->pos; + if ( do_adjust ) + point->y = edge->pos; + else + point->y += delta; + point->flags |= AH_FLAG_TOUCH_Y; } else { - point->x = edge->pos; + if ( do_adjust ) + point->x = edge->pos; + else + point->x += delta; + point->flags |= AH_FLAG_TOUCH_X; } @@ -1136,18 +1295,93 @@ /* scale and fit the global metrics */ static void ah_hinter_scale_globals( AH_Hinter hinter, - FT_Fixed x_scale, - FT_Fixed y_scale ) + FT_Size size, + FT_UInt glyph_index ) { FT_Int n; AH_Face_Globals globals = hinter->globals; - AH_Globals design = &globals->design; - AH_Globals scaled = &globals->scaled; + AH_Globals design = &globals->design; + AH_Globals scaled = &globals->scaled; + FT_Fixed x_scale = size->metrics.x_scale; + FT_Fixed y_scale = size->metrics.y_scale; + FT_Pos base = 0; + FT_Byte cflag = ah_hinter_get_char_flag( hinter, glyph_index ); +#ifdef FT_CONFIG_CHESTER_BLUE_SCALE + FT_Pos s_top = scaled->blue_shoots[ AH_BLUE_SMALL_TOP ]; +#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ + + + if ( hinter->do_vert_hints ) + hinter->do_blue_hints = FT_BOOL( cflag == AH_CHAR_FLAG_LATIN || + cflag == AH_CHAR_FLAG_LATIN_FULL ); + else + hinter->do_blue_hints = FALSE; + + if ( cflag == AH_CHAR_FLAG_LATIN_FULL ) + design = &globals->design_f; + +#ifdef FT_CONFIG_CHESTER_BLUE_SCALE + /* try to optimize the y_scale so that the top of non-capital letters + * is aligned on a pixel boundary whenever possible + */ + if ( hinter->do_blue_hints ) + { + base = design->base_line; + s_top = design->blue_shoots[ AH_BLUE_SMALL_TOP ]; + + /* the value of 'shoot' will be -1000 if the font doesn't have */ + /* small latin letters; we simply check the sign here... */ + if ( s_top > 0 ) + { + FT_Pos height = FT_MulFix( s_top - base, y_scale ); + FT_Pos ref = design->blue_refs[ AH_BLUE_SMALL_TOP ]; + FT_Pos fitted; + + + if ( height < 6*64 ) + fitted = s_top = ( height + 44 ) & -64; + else if ( height < 8*64 ) + fitted = s_top = ( height + 38 ) & -64; + else + fitted = s_top = ( height + 32 ) & -64; + + ref = FT_MulFix( ref - base, y_scale ); + + if ( ref <= fitted && fitted <= height ) + fitted = height; + else if ( fitted < ref ) + height = ref; + + if ( fitted > height ) + { + /* adjust y_scale + */ + y_scale = FT_MulDiv( y_scale, fitted, height ); + } + } + + base = ( FT_MulFix( base, y_scale ) + 32 ) & -64; + } +#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ + + + if ( x_scale == globals->x_scale && + y_scale == globals->y_scale && +#ifdef FT_CONFIG_CHESTER_BLUE_SCALE + s_top == scaled->blue_shoots[ AH_BLUE_SMALL_TOP ] && +#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ + cflag == globals->char_flag && + ( hinter->do_stem_adjust ^ globals->adjust_blues ) == 0 ) + { + return; + } /* copy content */ *scaled = *design; + scaled->base_line = base; + /* scale the standard widths & heights */ for ( n = 0; n < design->num_widths; n++ ) scaled->widths[n] = FT_MulFix( design->widths[n], x_scale ); @@ -1158,10 +1392,18 @@ scaled->stds[0] = ( design->num_widths > 0 ) ? scaled->widths[0] : 32000; scaled->stds[1] = ( design->num_heights > 0 ) ? scaled->heights[0] : 32000; + globals->x_scale = x_scale; + globals->y_scale = y_scale; + globals->char_flag = cflag; + globals->adjust_blues = hinter->do_stem_adjust; + + if ( !hinter->do_blue_hints ) + return; + /* scale the blue zones */ for ( n = 0; n < AH_BLUE_MAX; n++ ) { - FT_Pos delta, delta2; + FT_Pos delta, delta1, delta2, pos1, pos2, ref, shoot; delta = design->blue_shoots[n] - design->blue_refs[n]; @@ -1180,22 +1422,59 @@ if ( delta < 0 ) delta2 = -delta2; - scaled->blue_refs[n] = - ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64; - scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2; - } + delta = delta2; + + if ( n == AH_BLUE_SMALL_BOTTOM ) + { + scaled->blue_shoots[n] = base + delta; + scaled->blue_refs[n] = base; + continue; + } +#ifdef FT_CONFIG_CHESTER_BLUE_SCALE + else if ( n == AH_BLUE_SMALL_TOP ) + { + scaled->blue_refs[n] = s_top - delta; + scaled->blue_shoots[n] = s_top; + continue; + } +#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ + + pos1 = design->blue_refs[n] - design->base_line; + pos2 = design->blue_shoots[n] - design->base_line; + pos1 = FT_MulFix( pos1, y_scale ); + pos2 = FT_MulFix( pos2, y_scale ); + ref = ( pos1 + 32 ) & -64; + shoot = ( pos2 + 32 ) & -64; + delta1 = ref - pos1; + delta2 = shoot - pos2; + + if ( !globals->adjust_blues ) + { + if ( ref > pos1 + 16 ) ref = pos1 + 16; + if ( ref < pos1 - 16 ) ref = pos1 - 16; + if ( shoot > pos2 + 16 ) shoot = pos2 + 16; + if ( shoot < pos2 - 16 ) shoot = pos2 - 16; + } + + if ( ABS( delta1 ) < ABS( delta2 ) ) + shoot = ref + delta; + else + ref = shoot - delta; - globals->x_scale = x_scale; - globals->y_scale = y_scale; + scaled->blue_refs[n] = ref; + scaled->blue_shoots[n] = shoot; + } } +#if 0 static void ah_hinter_align( AH_Hinter hinter ) { ah_hinter_align_edge_points( hinter ); ah_hinter_align_points( hinter ); } +#endif /* finalize a hinter object */ @@ -1275,7 +1554,7 @@ hinter->globals = face_globals; if ( globals ) - face_globals->design = *globals; + face_globals->design = face_globals->design_f = *globals; else ah_hinter_compute_globals( hinter ); @@ -1284,6 +1563,8 @@ ah_hinter_done_face_globals; face_globals->face = face; + ah_hinter_compute_char_flags( hinter ); + Exit: return error; } @@ -1297,6 +1578,8 @@ FT_Memory memory = face->memory; + FT_Done_Size( globals->size_EM ); + FT_FREE( globals->table ); FT_FREE( globals ); } @@ -1310,6 +1593,7 @@ FT_Face face = hinter->face; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal internal = slot->internal; + FT_Pos offsetY; FT_Fixed x_scale = hinter->globals->x_scale; FT_Fixed y_scale = hinter->globals->y_scale; FT_Error error; @@ -1318,9 +1602,18 @@ /* load the glyph */ +#ifndef TT_CONFIG_OPTION_BYTECODE_INTERPRETER error = FT_Load_Glyph( face, glyph_index, load_flags ); if ( error ) goto Exit; +#else + if ( glyph_index ) + { + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + goto Exit; + } +#endif /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */ hinter->transformed = internal->glyph_transformed; @@ -1346,8 +1639,12 @@ { case FT_GLYPH_FORMAT_OUTLINE: + offsetY = 0; + if ( depth == 0 && hinter->do_blue_hints ) + offsetY = -hinter->globals->design.base_line; + /* translate glyph outline if we need to */ - if ( hinter->transformed ) + if ( hinter->transformed || offsetY ) { FT_UInt n = slot->outline.n_points; FT_Vector* point = slot->outline.points; @@ -1356,7 +1653,7 @@ for ( ; n > 0; point++, n-- ) { point->x += hinter->trans_delta.x; - point->y += hinter->trans_delta.y; + point->y += hinter->trans_delta.y + offsetY; } } @@ -1398,7 +1695,7 @@ /* perform feature detection */ ah_outline_detect_features( outline ); - if ( hinter->do_vert_hints ) + if ( depth == 0 && hinter->do_blue_hints ) { ah_outline_compute_blue_edges( outline, hinter->globals ); ah_outline_scale_blue_edges( outline, hinter->globals ); @@ -1406,13 +1703,14 @@ /* perform alignment control */ ah_hinter_hint_edges( hinter ); - ah_hinter_align( hinter ); + ah_hinter_align_points( hinter ); /* now save the current outline into the loader's current table */ ah_outline_save( outline, gloader ); /* we now need to hint the metrics according to the change in */ /* width/positioning that occured during the hinting process */ + if ( hinter->do_blue_hints ) { FT_Pos old_advance, old_rsb, old_lsb, new_lsb; AH_Edge edge1 = outline->vert_edges; /* leftmost edge */ @@ -1426,7 +1724,28 @@ new_lsb = edge1->pos; hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64; - hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64; + + if ( hinter->do_stem_adjust ) + hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64; + else + hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 40 ) & -64; + + if ( FT_IS_FIXED_WIDTH( face ) || + ( load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) != 0 ) + { + FT_Pos new_rsb; + + hinter->pp2.x = hinter->pp1.x + old_advance; + new_lsb = edge1->pos - hinter->pp1.x; + new_rsb = hinter->pp2.x - edge2->pos; + + if ( ( old_lsb <= old_rsb && new_lsb > new_rsb + 32 ) || + ( old_rsb > 0 && new_rsb < 0 && new_lsb >= 64 ) ) + { + hinter->pp1.x += 64; + hinter->pp2.x += 64; + } + } #if 0 /* try to fix certain bad advance computations */ @@ -1437,6 +1756,14 @@ /* good, we simply add the glyph to our loader's base */ ah_loader_add( gloader ); + + if ( depth == 0 && hinter->do_blue_hints ) + { + if ( hinter->globals->scaled.base_line != 0 ) + FT_Outline_Translate( &gloader->base.outline, + 0, hinter->globals->scaled.base_line ); + } + break; case FT_GLYPH_FORMAT_COMPOSITE: @@ -1628,6 +1955,234 @@ } +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + +#define AH_MAX_COMPOSITE_RECURSE 5 + + static FT_Error + ah_hinter_check_and_load( AH_Hinter hinter, + FT_UInt glyph_index, + FT_Int32 load_flags, + int depth, + short **num_contours, + short **num_points, + int *num_simple_glyphs, + int *size_array ) + { + FT_Face face = hinter->face; + FT_Memory memory = hinter->memory; + FT_GlyphSlot slot = face->glyph; + FT_Error error = FT_Err_Ok; + + + if ( depth == 0 ) + { + *num_contours = 0; + *num_points = 0; + *num_simple_glyphs = 0; + *size_array = 0; + } + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + + if ( error ) + return error; + + switch ( slot->format ) + { + case FT_GLYPH_FORMAT_OUTLINE: + { + int size_cur = *size_array; + + + if ( depth == 0 ) + return ah_hinter_load( hinter, 0, load_flags, 0 ); + + if ( slot->outline.n_contours == 0 ) + break; + + if ( *num_simple_glyphs >= size_cur ) + { + if ( FT_RENEW_ARRAY( *num_contours, size_cur, size_cur + 16 ) || + FT_RENEW_ARRAY( *num_points, size_cur, size_cur + 16 ) ) + goto Exit; + *size_array += 16; + } + + (*num_contours)[ (*num_simple_glyphs) ] = slot->outline.n_contours; + (*num_points)[ (*num_simple_glyphs)++ ] = slot->outline.n_points; + break; + } + + case FT_GLYPH_FORMAT_COMPOSITE: + if ( depth + 1 >= AH_MAX_COMPOSITE_RECURSE ) + return AH_Err_Invalid_Composite; + + if ( slot->num_subglyphs > 0 ) + { + FT_UInt* indices; + int num_subglyphs = slot->num_subglyphs; + int i; + + + if ( FT_NEW_ARRAY( indices, num_subglyphs ) ) + goto Exit; + + for ( i = 0; i < num_subglyphs; i++ ) + indices[i] = slot->subglyphs[i].index; + + + for ( i = 0; i < num_subglyphs; i++ ) + { + error = ah_hinter_check_and_load( hinter, + indices[i], + load_flags, + depth + 1, + num_contours, + num_points, + num_simple_glyphs, + size_array ); + if ( error ) + { + FT_FREE( indices ); + goto Exit; + } + } + + FT_FREE( indices ); + + if ( depth == 0 ) + { + FT_Size size_EM, size; + FT_Vector* points; + FT_Vector* limit; + int num = *num_simple_glyphs, j; + short n_contours, n_points; + short *array_c, *array_p; + + + if ( num == 0 ) + break; + + size = face->size; + size_EM = hinter->globals->size_EM; + + if ( !size_EM ) + { + error = FT_New_Size( face, &hinter->globals->size_EM ); + if ( error ) + goto Exit; + + size_EM = hinter->globals->size_EM; + FT_Activate_Size( size_EM ); + + error = FT_Set_Pixel_Sizes( face, + face->units_per_EM, + face->units_per_EM ); + if ( error ) + { + FT_Activate_Size( size ); + goto Exit; + } + } + else + FT_Activate_Size( size_EM ); + + + load_flags &= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + load_flags |= FT_LOAD_NO_BITMAP | + FT_LOAD_NO_AUTOHINT | + FT_LOAD_IGNORE_TRANSFORM; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + + FT_Activate_Size( size ); + + if ( error ) + goto Exit; + + + array_c = *num_contours; + array_p = *num_points; + n_contours = 0; + n_points = 0; + + for ( i = 0; i < num; i++ ) + { + n_contours += *array_c++; + n_points += *array_p++; + } + + if ( slot->outline.n_points != n_points || + slot->outline.n_contours != n_contours ) + { + error = AH_Err_Invalid_Composite; + goto Exit; + } + + + points = slot->outline.points; + limit = points + slot->outline.n_points; + + while ( points < limit ) + { + points->x >>= 6; + points->y >>= 6; + points++; + } + + slot->metrics.horiAdvance >>= 6; + slot->metrics.vertAdvance >>= 6; + + array_c = *num_contours; + array_p = *num_points; + + for ( i = 0; i < num - 1; i++ ) + { + slot->outline.n_contours = *array_c++; + slot->outline.n_points = *array_p++; + + error = ah_hinter_load( hinter, 0, load_flags, 1 ); + if ( error ) + goto Exit; + + n_points = slot->outline.n_points; + slot->outline.points += n_points; + slot->outline.tags += n_points; + + slot->outline.contours += slot->outline.n_contours; + n_contours -= slot->outline.n_contours; + + for ( j = 0; j < n_contours; j++ ) + slot->outline.contours[j] -= n_points; + } + + slot->outline.n_contours = *array_c; + slot->outline.n_points = *array_p; + + error = ah_hinter_load( hinter, 0, load_flags, 0 ); + } + } + break; + + default: + error = AH_Err_Unimplemented_Feature; + } + + + Exit: + if ( depth == 0 ) + { + FT_FREE( *num_contours ); + FT_FREE( *num_points ); + } + + return error; + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + /* load and hint a given glyph */ FT_LOCAL_DEF( FT_Error ) ah_hinter_load_glyph( AH_Hinter hinter, @@ -1638,8 +2193,10 @@ { FT_Face face = slot->face; FT_Error error; +#if 0 FT_Fixed x_scale = size->metrics.x_scale; FT_Fixed y_scale = size->metrics.y_scale; +#endif AH_Face_Globals face_globals = FACE_GLOBALS( face ); FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE(load_flags); @@ -1661,6 +2218,7 @@ } +#if 0 #ifdef FT_CONFIG_CHESTER_BLUE_SCALE /* try to optimize the y_scale so that the top of non-capital letters * is aligned on a pixel boundary whenever possible @@ -1696,6 +2254,7 @@ if ( face_globals->x_scale != x_scale || face_globals->y_scale != y_scale ) ah_hinter_scale_globals( hinter, x_scale, y_scale ); +#endif ah_loader_rewind( hinter->loader ); @@ -1720,14 +2279,42 @@ hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); + ah_hinter_scale_globals( hinter, size, glyph_index ); + +#ifndef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + #if 1 - load_flags = FT_LOAD_NO_SCALE - | FT_LOAD_IGNORE_TRANSFORM ; + load_flags &= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM ; #else load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE; #endif error = ah_hinter_load( hinter, glyph_index, load_flags, 0 ); + +#else /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + load_flags &= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + load_flags |= FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM; + + { + short* num_contours; + short* num_points; + int num_simple_glyphs; + int size_array; + + + error = ah_hinter_check_and_load( hinter, + glyph_index, + load_flags, 0, + &num_contours, + &num_points, + &num_simple_glyphs, + &size_array ); + } + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ Exit: return error; diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.4-orig/src/autohint/ahtypes.h freetype-2.1.4/src/autohint/ahtypes.h --- freetype-2.1.4-orig/src/autohint/ahtypes.h Fri Jan 31 08:24:18 2003 +++ freetype-2.1.4/src/autohint/ahtypes.h Wed Apr 30 00:52:53 2003 @@ -48,7 +48,6 @@ #endif /* AH_DEBUG */ - FT_BEGIN_HEADER @@ -286,7 +285,8 @@ AH_Segment link; /* link segment */ AH_Segment serif; /* primary segment for serifs */ FT_Pos num_linked; /* number of linked segments */ - FT_Pos score; + FT_ULong score; + FT_ULong len; } AH_SegmentRec; @@ -415,6 +415,31 @@ typedef FT_Int AH_Hinter_Flags; +#define AH_LIGHT_MODE_MAX_HORZ_GAP 9 +#define AH_LIGHT_MODE_MAX_VERT_GAP 15 +#define AH_LIGHT_MODE_MAX_DELTA_ABS 14 + +#define AH_CHAR_FLAG_NONE 0 +#define AH_CHAR_FLAG_LATIN 1 +#define AH_CHAR_FLAG_LATIN_FULL 2 + + typedef struct AH_CharFlag_ + { + FT_Byte char_flag; + FT_ULong start; + FT_ULong last; + + } AH_CharFlag; + + + typedef struct AH_CharTable_ + { + FT_ULong size; + AH_CharFlag* flags; + + } AH_CharTable; + + /*************************************************************************/ /* */ /* */ @@ -450,6 +475,8 @@ FT_Pos blue_refs [AH_BLUE_MAX]; FT_Pos blue_shoots[AH_BLUE_MAX]; + FT_Pos base_line; + } AH_GlobalsRec, *AH_Globals; @@ -478,11 +505,17 @@ { FT_Face face; AH_GlobalsRec design; + AH_GlobalsRec design_f; AH_GlobalsRec scaled; FT_Fixed x_scale; FT_Fixed y_scale; + FT_Bool adjust_blues; FT_Bool control_overshoot; + AH_CharTable* table; + FT_Byte char_flag; + FT_Size size_EM; + } AH_Face_GlobalsRec, *AH_Face_Globals; @@ -511,6 +544,7 @@ FT_Bool do_horz_snapping; /* disable X stem size snapping */ FT_Bool do_vert_snapping; /* disable Y stem size snapping */ FT_Bool do_stem_adjust; /* disable light stem snapping */ + FT_Bool do_blue_hints; } AH_HinterRec, *AH_Hinter; Only in freetype-2.1.4/src/autohint/: autohint.o