diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.5-orig/src/autohint/ahglobal.c freetype-2.1.5/src/autohint/ahglobal.c --- freetype-2.1.5-orig/src/autohint/ahglobal.c Wed May 28 14:52:05 2003 +++ freetype-2.1.5/src/autohint/ahglobal.c Wed Sep 24 13:07:51 2003 @@ -30,7 +30,7 @@ /* cf. AH_BLUE_XXX constants in ahtypes.h */ static - const char* blue_chars[AH_BLUE_MAX] = + const char* blue_chars_latin[AH_BLUE_MAX] = { "THEZOCQS", "HEZLOCUS", @@ -43,6 +43,35 @@ }; + typedef struct AH_BlueTable_ + { + FT_ULong offset_blue_chars; + const char** blue_chars; + FT_ULong char_for_widths; + + } AH_BlueTable; + + + static const AH_BlueTable blue_table[AH_CHAR_TYPE_COUNT] = + { + { 0, blue_chars_latin, (FT_ULong)'o' }, + { 0xFEE0L, blue_chars_latin, 0xFF4FL }, + { 0, 0, 0 }, + { 0, 0, 0 } + }; + + +#ifdef AH_DEBUG + static const char* blue_names[AH_CHAR_TYPE_COUNT] = + { + "general latinate chars", + "CJK fullwidth latin chars", + 0, + 0 + }; +#endif + + /* simple insertion sort */ static void sort_values( FT_Int count, @@ -71,7 +100,7 @@ ah_hinter_compute_blues( AH_Hinter hinter ) { AH_Blue blue; - AH_Globals globals = &hinter->globals->design; + AH_Globals globals = hinter->globals->designs; FT_Pos flats [MAX_TEST_CHARACTERS]; FT_Pos rounds[MAX_TEST_CHARACTERS]; FT_Int num_flats; @@ -81,6 +110,9 @@ FT_GlyphSlot glyph; FT_Error error; FT_CharMap charmap; + FT_ULong offset; + FT_Byte type; + const char** blue_chars; face = hinter->face; @@ -97,8 +129,19 @@ /* we compute the blues simply by loading each character from the */ /* 'blue_chars[blues]' string, then compute its top-most or */ /* bottom-most points (depending on `AH_IS_TOP_BLUE') */ + type = AH_CHAR_TYPE_LATINATE; - AH_LOG(( "blue zones computation\n" )); + Compute_Blues: + globals->has_blues = FALSE; + globals->baseline = 0; + + offset = blue_table[type].offset_blue_chars; + blue_chars = blue_table[type].blue_chars; + + if ( !blue_chars ) + goto Next_Type; + + AH_LOG(( "blue zones computation for %s\n", blue_names[type] )); AH_LOG(( "------------------------------------------------\n" )); for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ ) @@ -131,7 +174,7 @@ 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; @@ -221,10 +264,30 @@ } while ( next != idx ); - /* now, set the `round' flag depending on the segment's kind */ - 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 ); + /* now, set the `round' flag depending on whether there exists */ + /* a extremum line segment within the current zone. */ + 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; + } AH_LOG(( "%c ", round ? 'r' : 'f' )); } @@ -281,6 +344,30 @@ } AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); + + if ( num_flats > 0 || num_rounds > 0 ) + globals->has_blues = TRUE; + } + + globals->baseline = globals->blue_refs[AH_BLUE_SMALL_BOTTOM]; + + if ( globals->baseline > -10000 ) + { + for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ ) + { + if ( globals->blue_refs[blue] > -10000 ) + { + globals->blue_refs[blue] -= globals->baseline; + globals->blue_shoots[blue] -= globals->baseline; + } + } + } + + Next_Type: + if ( ++type < AH_CHAR_TYPE_COUNT ) + { + globals++; + goto Compute_Blues; } /* reset original face charmap */ @@ -299,13 +386,23 @@ AH_Outline outline = hinter->glyph; AH_Segment segments; AH_Segment limit; - AH_Globals globals = &hinter->globals->design; + AH_Globals globals = hinter->globals->designs; FT_Pos* widths; FT_Int dimension; FT_Int* p_num_widths; FT_Error error = 0; FT_Pos edge_distance_threshold = 32000; + FT_Byte type; + FT_ULong char_for_widths; + + + type = AH_CHAR_TYPE_LATINATE; + Compute_Widths: + char_for_widths = blue_table[type].char_for_widths; + + if ( !char_for_widths ) + goto Next_Type; globals->num_widths = 0; globals->num_heights = 0; @@ -318,18 +415,18 @@ FT_UInt glyph_index; - glyph_index = FT_Get_Char_Index( hinter->face, 'o' ); + glyph_index = FT_Get_Char_Index( hinter->face, char_for_widths ); if ( glyph_index == 0 ) - return 0; + goto Next_Type; error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE ); if ( error ) - goto Exit; + goto Next_Type; error = ah_outline_load( hinter->glyph, 0x10000L, 0x10000L, hinter->face ); if ( error ) - goto Exit; + goto Next_Type; ah_outline_compute_segments( hinter->glyph ); ah_outline_link_segments( hinter->glyph ); @@ -378,6 +475,13 @@ p_num_widths = &globals->num_widths; } + Next_Type: + if ( type++ < AH_CHAR_TYPE_COUNT ) + { + globals++; + 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 ) @@ -386,8 +490,7 @@ /* let's try 20% */ hinter->glyph->edge_distance_threshold = edge_distance_threshold / 5; - Exit: - return error; + return 0; } @@ -396,6 +499,192 @@ { return ah_hinter_compute_widths( hinter ) || ah_hinter_compute_blues ( hinter ); + } + + + static const AH_CharType + ah_types_for_unicode[] = + { + /* Latin, Greek, Cyrillic */ + { AH_CHAR_TYPE_LATINATE, 0x21L, 0x52FL }, + + /* Hebrew */ + { AH_CHAR_TYPE_LATINATE, 0x5D0L, 0x600L }, + + /* Latin, Greek */ + { AH_CHAR_TYPE_LATINATE, 0x1E00L, 0x2000L }, + + /* CJK fullwidth Latin */ + { AH_CHAR_TYPE_LATIN_FULLWIDTH, 0xFF00L, 0xFF60L } + }; + + + static const AH_CharTypeTable + ah_types_table_unicode = + { + sizeof( ah_types_for_unicode ) / sizeof( AH_CharType ), + (AH_CharType *)ah_types_for_unicode + }; + + + FT_LOCAL_DEF( void ) + ah_hinter_compute_char_table( AH_Hinter hinter ) + { + FT_Memory memory = hinter->memory; + FT_Face face = hinter->face; + AH_CharTypeTable* table = hinter->globals->table; + FT_ULong num_glyphs = face->num_glyphs; + FT_Byte* types; + FT_Error error; + FT_CharMap charmap; + + + if ( table ) + return; + + if ( num_glyphs <= 0 ) + return; + + if ( FT_NEW_ARRAY( types, num_glyphs ) ) + return; + + FT_MEM_SET( types, AH_CHAR_TYPE_OTHER, num_glyphs ); + + charmap = face->charmap; + if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + goto Exit; + + + { + FT_Bool empty = TRUE; + FT_ULong i; + + + for ( i = 0; i < ah_types_table_unicode.size; i++ ) + { + FT_UInt glyph_index; + FT_ULong start = ah_types_table_unicode.types[i].start; + FT_ULong last = ah_types_table_unicode.types[i].last; + FT_Byte type = ah_types_table_unicode.types[i].type; + FT_ULong ucs = FT_Get_Next_Char( face, start - 1, &glyph_index ); + + + while ( ucs && ucs <= last ) + { + if ( glyph_index < num_glyphs ) + { + empty = FALSE; + types[glyph_index] = type; + } + + ucs = FT_Get_Next_Char( face, ucs, &glyph_index ); + } + } + + if ( empty ) + goto Exit; + } + + + { + FT_Byte* cur = types; + FT_Byte* last = types + num_glyphs - 1; + FT_Byte type = AH_CHAR_TYPE_OTHER; + FT_ULong num = 0; + FT_ULong alloc_size; + + + while ( ++cur <= last ) + { + if ( *cur != type ) + { + type = *cur; + + if ( type < AH_CHAR_TYPE_OTHER ) + num++; + } + } + + alloc_size = sizeof( AH_CharTypeTable ) + num * sizeof( AH_CharType ); + if ( FT_ALLOC( table, alloc_size ) ) + goto Exit; + + table->size = num; + table->types = (AH_CharType *)( table + 1 ); + } + + + { + FT_Byte* cur = types + 1; + FT_Byte* last = types + face->num_glyphs - 1; + FT_Byte type = AH_CHAR_TYPE_OTHER; + FT_ULong num = 0; + FT_ULong i; + + + for ( i = 1; cur <= last; i++, cur++ ) + { + if ( *cur != type ) + { + if ( type < AH_CHAR_TYPE_OTHER ) + table->types[num - 1].last = i - 1; + + type = *cur; + if ( type < AH_CHAR_TYPE_OTHER ) + { + table->types[num].type = type; + table->types[num++].start = i; + } + } + } + + if ( type < AH_CHAR_TYPE_OTHER ) + table->types[num - 1].last = i - 1; + } + + hinter->globals->table = table; + + Exit: + FT_Set_Charmap( face, charmap ); + FT_FREE( types ); + } + + + FT_LOCAL_DEF( FT_Byte ) + ah_hinter_get_char_type( AH_Hinter hinter, + FT_ULong glyph_index ) + { + AH_CharTypeTable* table = hinter->globals->table; + + + if ( table && table->size > 0 && glyph_index ) + { + AH_CharType* cur; + AH_CharType* types = table->types; + FT_ULong min = 0; + FT_ULong max = table->size - 1; + FT_ULong mid; + + + if ( glyph_index < types[min].start || + glyph_index > types[max].last ) + return AH_CHAR_TYPE_OTHER; + + while ( min <= max ) + { + mid = ( min + max ) / 2; + cur = types + mid; + + if ( glyph_index < cur->start ) + max = mid - 1; + else if ( glyph_index > cur->last ) + min = mid + 1; + else + return cur->type; + } + } + + return AH_CHAR_TYPE_OTHER; } diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.5-orig/src/autohint/ahglobal.h freetype-2.1.5/src/autohint/ahglobal.h --- freetype-2.1.5-orig/src/autohint/ahglobal.h Tue Apr 22 16:49:24 2003 +++ freetype-2.1.5/src/autohint/ahglobal.h Sat Sep 20 05:10:18 2003 @@ -51,6 +51,14 @@ ah_hinter_compute_globals( AH_Hinter hinter ); + FT_LOCAL( void ) + ah_hinter_compute_char_table( AH_Hinter hinter ); + + + FT_LOCAL( FT_Byte ) + ah_hinter_get_char_type( AH_Hinter hinter, + FT_ULong glyph_index ); + FT_END_HEADER #endif /* __AHGLOBAL_H__ */ diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.5-orig/src/autohint/ahglyph.c freetype-2.1.5/src/autohint/ahglyph.c --- freetype-2.1.5-orig/src/autohint/ahglyph.c Wed May 28 14:52:05 2003 +++ freetype-2.1.5/src/autohint/ahglyph.c Wed Sep 24 12:26:43 2003 @@ -22,7 +22,6 @@ #include #include "ahglyph.h" -#include "ahangles.h" #include "ahglobal.h" #include "aherrors.h" @@ -52,11 +51,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 | %6d | %c | %5.2f | %5.2f | %5.2f ]\n", edge - edges, (int)edge->fpos, edge->dir == AH_DIR_UP @@ -72,7 +71,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; @@ -370,6 +370,12 @@ char* tag = gloader->current.outline.tags; +#ifdef AH_DEBUG + ah_dump_segments( outline ); + ah_dump_edges( outline ); + printf( "\n" ); + #endif + /* we assume that the glyph loader has already been checked for storage */ for ( ; point < point_limit; point++, vec++, tag++ ) { @@ -594,6 +600,7 @@ point->out_dir = ah_compute_direction( ovec.x, ovec.y ); +#if 0 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION if ( point->flags & ( AH_FLAG_CONIC | AH_FLAG_CUBIC ) ) { @@ -624,6 +631,7 @@ else if ( point->in_dir == -point->out_dir ) goto Is_Weak_Point; #endif +#endif } } } @@ -709,6 +717,7 @@ } +#if 0 /* compute all inflex points in a given glyph */ static void ah_outline_compute_inflections( AH_Outline outline ) @@ -822,6 +831,54 @@ ; } } +#endif + + + /* compute all strong points in a given glyph */ + static void + ah_outline_compute_strongs( AH_Outline outline ) + { + AH_Point* contour = outline->contours; + AH_Point* contour_limit = contour + outline->num_contours; + + + /* load original coordinates in (u,v) */ + ah_setup_uv( outline, AH_UV_FXY ); + + for ( ; contour < contour_limit; contour++ ) + { + FT_Pos dx1, dx2, dy1, dy2; + AH_Point point = contour[0]; + AH_Point first = point; + AH_Point before; + AH_Point after; + + + after = point->next; + before = point->prev; + dx1 = point->u - before->u; + dy1 = point->v - before->v; + + do + { + dx2 = after->u - point->u; + dy2 = after->v - point->v; + + if ( dx1 == 0 || dx2 == 0 || ( dx1 ^ dx2 ) < 0 ) + point->flags |= AH_FLAG_STRONG_X; + + if ( dy1 == 0 || dy2 == 0 || ( dy1 ^ dy2 ) < 0 ) + point->flags |= AH_FLAG_STRONG_Y; + + before = point; + point = after; + after = after->next; + dx1 = dx2; + dy1 = dy2; + + } while ( point != first ); + } + } FT_LOCAL_DEF( void ) @@ -925,11 +982,34 @@ 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 + /* a segment is round if it doesn't have successive */ + /* on-curve points. */ + { + AH_Point pt = segment->first; + AH_Flags f0 = pt->flags & AH_FLAG_CONTROL; + AH_Flags f1; + + + for ( ; pt != point; f0 = f1 ) + { + pt = pt->next; + f1 = pt->flags & AH_FLAG_CONTROL; + + if ( !f0 && !f1 ) + break; + + if ( pt == point ) + segment->flags |= AH_EDGE_ROUND; + } + } +#endif /* compute segment size */ min_pos = max_pos = point->v; @@ -972,7 +1052,10 @@ segment->first = point; segment->last = point; segment->contour = contour; - segment->score = 32000; + segment->score1 = 0x7FFFFFFFL; + segment->score2 = 0x7FFFFFFFL; + segment->length = 0; + segment->sign = 0; segment->link = NULL; on_edge = 1; @@ -1035,7 +1118,10 @@ segment->first = min_point; segment->last = min_point; segment->pos = min_pos; - segment->score = 32000; + segment->score1 = 0x7FFFFFFFL; + segment->score2 = 0x7FFFFFFFL; + segment->length = 0; + segment->sign = 0; segment->link = NULL; num_segments++; @@ -1053,7 +1139,10 @@ segment->first = max_point; segment->last = max_point; segment->pos = max_pos; - segment->score = 32000; + segment->score1 = 0x7FFFFFFFL; + segment->score2 = 0x7FFFFFFFL; + segment->length = 0; + segment->sign = 0; segment->link = NULL; num_segments++; @@ -1080,11 +1169,13 @@ AH_Segment segment_limit; AH_Direction major_dir; int dimension; + FT_Pos score_limit; segments = outline->horz_segments; segment_limit = segments + outline->num_hsegments; major_dir = outline->horz_major_dir; + score_limit = FT_DivFix( 64*3*9, outline->y_scale ); for ( dimension = 1; dimension >= 0; dimension-- ) { @@ -1203,20 +1294,28 @@ max = seg2->max_coord; len = max - min; - if ( len >= 8 ) + if ( len >= 4 ) { - score = dist + 3000 / len; + score = 8*dist; - if ( score < seg1->score ) + if ( score < seg1->score1 && + !( score > seg1->score2 && 4*len < seg1->length ) ) { - seg1->score = score; - seg1->link = seg2; + seg1->score1 = 9*dist; + seg1->score2 = 7*dist; + seg1->length = len; + seg1->sign = -1; + seg1->link = seg2; } - if ( score < seg2->score ) + if ( score < seg2->score1 && + !( score > seg2->score2 && 4*len < seg2->length ) ) { - seg2->score = score; - seg2->link = seg1; + seg2->score1 = 9*dist; + seg2->score2 = 7*dist; + seg2->length = len; + seg2->sign = +1; + seg2->link = seg1; } } } @@ -1225,6 +1324,73 @@ #endif /* 1 */ /* now, compute the `serif' segments */ + { + AH_Segment seg, link1, link2; + FT_Pos pos1, pos2; + + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + if ( seg1->sign >= 0 || seg1->score1 >= score_limit ) + continue; + + link1 = seg1->link; + if ( link1->link != seg1 ) + continue; + + pos1 = seg1->pos; + pos2 = link1->pos; + + + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + if ( seg2->sign >= 0 || + seg2->score1 <= seg1->score1 || seg2->pos > pos1 ) + continue; + + link2 = seg2->link; + if ( link2->link != seg2 ) + continue; + + if ( link2->pos < pos2 || + seg1->score1*4 <= seg2->score1 ) + continue; + + /* seg2->pos < pos1 < pos2 < seg2->link->pos */ + + if ( seg1->length < seg2->length*2 ) + { + seg1->link = link1->link = 0; + seg1->sign = link1->sign = 0; + } + else + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AH_Segment link = seg->link; + + + if ( link == seg2 ) + { + seg->sign = 0; + seg->link = 0; + seg->serif = link1; + } + else if ( link == link2 ) + { + seg->sign = 0; + seg->link = 0; + seg->serif = seg1; + } + } + } + + break; + } + } + } + + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { seg2 = seg1->link; @@ -1234,8 +1400,13 @@ seg2->num_linked++; if ( seg2->link != seg1 ) { - seg1->link = 0; - seg1->serif = seg2->link; + seg1->link = 0; + + if ( seg2->score1 < score_limit || + seg1->score1 < seg2->score1*4 ) + seg1->serif = seg2->link; + else + seg2->num_linked--; } } } @@ -1243,6 +1414,7 @@ segments = outline->vert_segments; segment_limit = segments + outline->num_vsegments; major_dir = outline->vert_major_dir; + score_limit = FT_DivFix( 64*3*9, outline->x_scale ); } } @@ -1310,12 +1482,46 @@ FT_Pos dist; + if ( edge->dir != seg->dir ) + continue; + dist = seg->pos - edge->fpos; if ( dist < 0 ) dist = -dist; if ( dist < edge_distance_threshold ) { + AH_Segment link = seg->link; + + + /* check if all linked segments of the candidate edge */ + /* can make a single edge. */ + 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; } @@ -1341,6 +1547,7 @@ edge->fpos = seg->pos; edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); seg->edge_next = seg; + edge->dir = seg->dir; } else { @@ -1391,8 +1598,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; @@ -1408,12 +1613,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 ); @@ -1479,18 +1678,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 */ @@ -1523,7 +1710,7 @@ ah_outline_compute_segments ( outline ); ah_outline_link_segments ( outline ); ah_outline_compute_edges ( outline ); - ah_outline_compute_inflections( outline ); + ah_outline_compute_strongs ( outline ); } @@ -1542,12 +1729,15 @@ { AH_Edge edge = outline->horz_edges; AH_Edge edge_limit = edge + outline->num_hedges; - AH_Globals globals = &face_globals->design; + AH_Globals globals = &face_globals->designs[face_globals->cur_type]; FT_Fixed y_scale = outline->y_scale; FT_Bool blue_active[AH_BLUE_MAX]; + if ( !globals->has_blues ) + return; + /* compute which blue zones are active, i.e. have their scaled */ /* size < 3/4 pixels */ { @@ -1588,6 +1778,18 @@ FT_Pos best_dist; /* initial threshold */ + if ( edge->serif ) + { + FT_Pos dist = edge->serif->pos - edge->pos; + + + if ( dist < 0 ) + dist = -dist; + + if ( dist < 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 ); @@ -1686,7 +1888,11 @@ FT_Pos delta; - delta = globals->scaled.blue_refs - globals->design.blue_refs; + if ( !globals->scaled.has_blues ) + return; + + delta = globals->scaled.blue_refs - + globals->designs[globals->cur_type].blue_refs; for ( ; edge < edge_limit; edge++ ) { diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.5-orig/src/autohint/ahhint.c freetype-2.1.5/src/autohint/ahhint.c --- freetype-2.1.5-orig/src/autohint/ahhint.c Mon Aug 18 08:00:59 2003 +++ freetype-2.1.5/src/autohint/ahhint.c Wed Nov 5 15:59:55 2003 @@ -22,9 +22,9 @@ #include #include "ahhint.h" #include "ahglyph.h" -#include "ahangles.h" #include "aherrors.h" #include FT_OUTLINE_H +#include FT_TRUETYPE_TABLES_H #define FACE_GLOBALS( face ) ( (AH_Face_Globals)(face)->autohint.data ) @@ -112,7 +112,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 ) ) @@ -120,6 +121,7 @@ /* smooth hinting process: very lightly quantize the stem width */ /* */ +#if 0 /* leave the widths of serifs alone */ if ( ( stem_flags & AH_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) @@ -132,24 +134,35 @@ } else if ( dist < 56 ) dist = 56; +#endif { - FT_Pos delta = dist - globals->stds[vertical]; + FT_Pos delta; - if ( delta < 0 ) - delta = -delta; - - if ( delta < 40 ) + if ( ( vertical && globals->num_heights > 0 ) || + ( !vertical && globals->num_widths > 0 ) ) { - dist = globals->stds[vertical]; - if ( dist < 48 ) - dist = 48; + delta = dist - globals->stds[vertical]; + + if ( delta < 0 ) + delta = -delta; - goto Done_Width; + if ( delta < 40 ) + { + dist = globals->stds[vertical]; + if ( dist < 48 ) + dist = 48; + + goto Done_Width; + } } - if ( dist < 3 * 64 ) + if ( dist < 54 ) + { + dist += ( 54 - dist )/2 ; + } + else if ( dist < 3 * 64 ) { delta = dist & 63; dist &= -64; @@ -157,17 +170,18 @@ if ( delta < 10 ) dist += delta; - else if ( delta < 32 ) + else if ( delta < 22 ) dist += 10; + else if ( delta < 42 ) + dist += delta; + else if ( delta < 54 ) dist += 54; else dist += delta; } - else - dist = ( dist + 32 ) & -64; } } else @@ -409,6 +423,129 @@ serif->pos = base->pos + sign * dist; } + + static FT_Pos + ah_hint_normal_stem( AH_Hinter hinter, + AH_Edge edge, + AH_Edge edge2, + FT_Pos anchor, + FT_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; + } + } + + 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 + anchor; + 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 1 + 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; + } + + return delta; + } + /*************************************************************************/ /*************************************************************************/ @@ -438,6 +575,7 @@ { AH_Edge edge; AH_Edge anchor = 0; + FT_Pos delta = 0; int has_serifs = 0; @@ -449,7 +587,7 @@ /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ - if ( dimension ) + if ( dimension && hinter->do_blue_hints ) { for ( edge = edges; edge < edge_limit; edge++ ) { @@ -486,14 +624,10 @@ ah_align_linked_edge( hinter, edge1, edge2, dimension ); edge2->flags |= AH_EDGE_DONE; } - - if ( !anchor ) - anchor = edge; } } - /* now we will align all stem edges, trying to maintain the */ - /* relative order of stems in the glyph */ + /* now we will align all stem edges. */ for ( edge = edges; edge < edge_limit; edge++ ) { AH_EdgeRec* edge2; @@ -520,6 +654,7 @@ continue; } +#if 0 if ( !anchor ) { @@ -686,6 +821,93 @@ if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; } +#else /* 1 */ + + if ( !dimension && !anchor ) + { + if ( hinter->globals->is_fixedpitch && !hinter->composite ) + { + AH_Edge left = edge; + AH_Edge right = edge_limit - 1; + AH_EdgeRec left1, left2, right1, right2; + FT_Pos target, center1, center2; + FT_Pos delta1, delta2, d1, d2; + + + while ( right > left && !right->link ) + right--; + + left1 = *left; + left2 = *left->link; + right1 = *right->link; + right2 = *right; + + delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x )/2; + target = left->opos + ( right->opos - left->opos )/2 + delta - 16; + + delta1 = delta; + delta1 += ah_hint_normal_stem( hinter, left, left->link, + delta1, 0 ); + + if ( left->link != right ) + ah_hint_normal_stem( hinter, right->link, right, delta1, 0 ); + + center1 = left->pos + ( right->pos - left->pos )/2; + + if ( center1 >= target ) + delta2 = delta - 32; + else + delta2 = delta + 32; + + delta2 += ah_hint_normal_stem( hinter, &left1, &left2, delta2, 0 ); + + if ( delta1 != delta2 ) + { + if ( left->link != right ) + ah_hint_normal_stem( hinter, &right1, &right2, delta2, 0 ); + + center2 = left1.pos + ( right2.pos - left1.pos )/2; + + d1 = center1 - target; + d2 = center2 - target; + + if ( ABS( d2 ) < ABS( d1 ) ) + { + left->pos = left1.pos; + left->link->pos = left2.pos; + + if ( left->link != right ) + { + right->link->pos = right1.pos; + right->pos = right2.pos; + } + + delta1 = delta2; + } + } + + delta = delta1; + right->link->flags |= AH_EDGE_DONE; + right->flags |= AH_EDGE_DONE; + } + else + { + delta = ah_hint_normal_stem( hinter, edge, edge2, 0, 0 ); + } + + anchor = edge; + } + else + { + ah_hint_normal_stem( hinter, edge, edge2, + delta, dimension ); + anchor = edge; + } + + edge->flags |= AH_EDGE_DONE; + edge2->flags |= AH_EDGE_DONE; + +#endif /* 1 */ } /* make sure that lowercase m's maintain their symmetry */ @@ -704,7 +926,8 @@ /* one pixel higher or lower. */ n_edges = edge_limit - edges; - if ( !dimension && ( n_edges == 6 || n_edges == 12 ) ) + if ( hinter->do_blue_hints && + !dimension && ( n_edges == 6 || n_edges == 12 ) ) { AH_EdgeRec *edge1, *edge2, *edge3; FT_Pos dist1, dist2, span, delta; @@ -730,7 +953,9 @@ if ( span < 0 ) span = -span; - if ( span < 8 ) + if ( edge1->link == edge1 + 1 && + edge2->link == edge2 + 1 && + edge3->link == edge3 + 1 && span < 8 ) { delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); edge3->pos -= delta; @@ -761,25 +986,48 @@ continue; if ( edge->serif ) - ah_align_serif_edge( hinter, edge->serif, edge, dimension ); - else if ( !anchor ) { - edge->pos = ( edge->opos + 32 ) & -64; - anchor = edge; + ah_align_serif_edge( hinter, edge->serif, edge, dimension ); + edge->flags |= AH_EDGE_DONE; + has_serifs--; } - else - edge->pos = anchor->pos + - ( ( edge->opos-anchor->opos + 32 ) & -64 ); + } + + if ( !has_serifs ) + goto Next_Dimension; + + for ( edge = edges; edge < edge_limit; edge++ ) + { + AH_Edge before, after; - edge->flags |= AH_EDGE_DONE; - if ( edge > edges && edge->pos < edge[-1].pos ) - edge->pos = edge[-1].pos; + if ( edge->flags & AH_EDGE_DONE ) + continue; + + before = after = edge; + + while ( --before >= edges ) + if ( before->flags & AH_EDGE_DONE ) + break; + + while ( ++after < edge_limit ) + if ( after->flags & AH_EDGE_DONE ) + break; + + if ( before >= edges || after < edge_limit ) + { + if ( before < edges ) + edge->pos = edge->opos + ( after->pos - after->opos ); + + else if ( after >= edge_limit ) + edge->pos = edge->opos + ( before->pos - before->opos ); - if ( edge + 1 < edge_limit && - edge[1].flags & AH_EDGE_DONE && - edge->pos > edge[1].pos ) - edge->pos = edge[1].pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->fpos - before->fpos, + after->pos - before->pos, + after->fpos - before->fpos ); + } } Next_Dimension: @@ -806,10 +1054,12 @@ AH_Edge edges; AH_Edge edge_limit; FT_Int dimension; + FT_Bool snapping; edges = outline->horz_edges; edge_limit = edges + outline->num_hedges; + snapping = hinter->do_vert_snapping; for ( dimension = 1; dimension >= 0; dimension-- ) { @@ -821,7 +1071,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 @@ -829,23 +1080,47 @@ AH_Point point = seg->first; - for (;;) + if ( snapping ) { - if ( dimension ) + for (;;) { - point->y = edge->pos; - point->flags |= AH_FLAG_TOUCH_Y; + if ( dimension ) + { + point->y = edge->pos; + point->flags |= AH_FLAG_TOUCH_Y; + } + else + { + point->x = edge->pos; + point->flags |= AH_FLAG_TOUCH_X; + } + + if ( point == seg->last ) + break; + + point = point->next; } - else + } + else + { + for (;;) { - point->x = edge->pos; - point->flags |= AH_FLAG_TOUCH_X; - } + if ( dimension ) + { + point->y += delta; + point->flags |= AH_FLAG_TOUCH_Y; + } + else + { + point->x += delta; + point->flags |= AH_FLAG_TOUCH_X; + } - if ( point == seg->last ) - break; + if ( point == seg->last ) + break; - point = point->next; + point = point->next; + } } seg = seg->edge_next; @@ -855,6 +1130,7 @@ edges = outline->vert_edges; edge_limit = edges + outline->num_vedges; + snapping = hinter->do_horz_snapping; } } @@ -871,6 +1147,7 @@ AH_Point points; AH_Point point_limit; AH_Flags touch_flag; + AH_Flags strong_flag; points = outline->points; @@ -879,6 +1156,7 @@ edges = outline->horz_edges; edge_limit = edges + outline->num_hedges; touch_flag = AH_FLAG_TOUCH_Y; + strong_flag = AH_FLAG_STRONG_Y; for ( dimension = 1; dimension >= 0; dimension-- ) { @@ -899,8 +1177,7 @@ #ifndef AH_OPTION_NO_WEAK_INTERPOLATION /* if this point is candidate to weak interpolation, we will */ /* interpolate it after all strong points have been processed */ - if ( ( point->flags & AH_FLAG_WEAK_INTERPOLATION ) && - !( point->flags & AH_FLAG_INFLECTION ) ) + if ( !( point->flags & strong_flag ) ) continue; #endif @@ -1034,6 +1311,7 @@ edges = outline->vert_edges; edge_limit = edges + outline->num_vedges; touch_flag = AH_FLAG_TOUCH_X; + strong_flag = AH_FLAG_STRONG_X; } } @@ -1234,10 +1512,8 @@ FT_LOCAL_DEF( void ) - ah_hinter_align_points( AH_Hinter hinter ) + ah_hinter_align_normal_points( AH_Hinter hinter ) { - ah_hinter_align_edge_points( hinter ); - #ifndef AH_OPTION_NO_STRONG_INTERPOLATION ah_hinter_align_strong_points( hinter ); #endif @@ -1263,17 +1539,69 @@ static void ah_hinter_scale_globals( AH_Hinter hinter, FT_Fixed x_scale, - FT_Fixed y_scale ) + FT_Fixed y_scale, + FT_Byte type ) { FT_Int n; AH_Face_Globals globals = hinter->globals; - AH_Globals design = &globals->design; + AH_Globals design = &globals->designs[type]; AH_Globals scaled = &globals->scaled; + FT_Pos baseline = design->baseline; + + globals->x_scale_linear = x_scale; + globals->y_scale_linear = y_scale; + globals->cur_type = type; /* copy content */ *scaled = *design; +#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 ( design->has_blues ) + { + FT_Pos shoot = design->blue_shoots[AH_BLUE_SMALL_TOP]; + FT_Pos ref = design->blue_refs[AH_BLUE_SMALL_TOP]; + + + baseline = FT_MulFix( baseline, y_scale ); + + /* the value of 'shoot' will be -1000 if the font doesn't have */ + /* small latin letters; we simply check the sign here... */ + if ( shoot > 0 ) + { + FT_Pos fitted; + + + shoot = FT_MulFix( shoot, y_scale ); + ref = FT_MulFix( ref, y_scale ); + + if ( shoot < 6*64 ) + fitted = ( shoot + 44 ) & -64; + else if ( shoot < 8*64 ) + fitted = ( shoot + 38 ) & -64; + else + fitted = ( shoot + 32 ) & -64; + + + if ( ref <= fitted && fitted < shoot ) + fitted = shoot; + else if ( fitted < ref ) + shoot = ref; + + if ( fitted > shoot ) + { + y_scale = FT_MulDiv( y_scale, fitted, shoot ); + baseline -= ( fitted - shoot )/2; + } + } + } + +#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ + /* scale the standard widths & heights */ for ( n = 0; n < design->num_widths; n++ ) scaled->widths[n] = FT_MulFix( design->widths[n], x_scale ); @@ -1284,10 +1612,20 @@ 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; + + if ( !design->has_blues ) + return; + + + scaled->baseline = ( baseline + 32 ) & -64; + /* scale the blue zones */ for ( n = 0; n < AH_BLUE_MAX; n++ ) { FT_Pos delta, delta2; + FT_Pos ref, shoot, delta3, delta4; delta = design->blue_shoots[n] - design->blue_refs[n]; @@ -1306,13 +1644,37 @@ 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; - } + if ( n == AH_BLUE_SMALL_BOTTOM ) + { + scaled->blue_shoots[n] = delta2; + scaled->blue_refs[n] = 0; + continue; + } - globals->x_scale = x_scale; - globals->y_scale = y_scale; + shoot = FT_MulFix( design->blue_shoots[n], y_scale ); + ref = FT_MulFix( design->blue_refs[n], y_scale ); + delta3 = ( ( shoot + 32 ) & -64 ) - shoot; + delta4 = ( ( ref + 32 ) & -64 ) - ref; + + if ( !hinter->do_stem_adjust ) + { + if ( delta3 > 16 ) delta3 = 16; + if ( delta3 < -16 ) delta3 = -16; + if ( delta4 > 16 ) delta4 = 16; + if ( delta4 < -16 ) delta4 = -16; + } + + shoot += delta3; + ref += delta4; + + if ( ABS( delta3 ) < ABS( delta4 ) ) + ref = shoot - delta2; + else + shoot = ref + delta2; + + scaled->blue_refs[n] = ref; + scaled->blue_shoots[n] = shoot; + } } @@ -1320,7 +1682,7 @@ ah_hinter_align( AH_Hinter hinter ) { ah_hinter_align_edge_points( hinter ); - ah_hinter_align_points( hinter ); + ah_hinter_align_normal_points( hinter ); } @@ -1401,7 +1763,7 @@ hinter->globals = face_globals; if ( globals ) - face_globals->design = *globals; + face_globals->designs[0] = *globals; else ah_hinter_compute_globals( hinter ); @@ -1410,6 +1772,27 @@ ah_hinter_done_face_globals; face_globals->face = face; + ah_hinter_compute_char_table( hinter ); + + { + TT_OS2* os2 = FT_Get_Sfnt_Table( face, ft_sfnt_os2 ); + + + if ( os2 && os2->version != 0xFFFFU ) + face_globals->is_fixedpitch = FT_BOOL( os2->panose[3] == 9 ); + else + face_globals->is_fixedpitch = FT_BOOL( FT_IS_FIXED_WIDTH( face ) != 0 ); + + + face_globals->has_tt_bytecode_interp = FALSE; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + if ( !strcmp( face->driver->root.clazz->module_name, "truetype" ) || + !strcmp( face->driver->root.clazz->module_name, "type42" ) ) + face_globals->has_tt_bytecode_interp = TRUE; +#endif + } + Exit: return error; } @@ -1423,6 +1806,8 @@ FT_Memory memory = face->memory; + FT_Done_Size( globals->size_EM ); + FT_FREE( globals->table ); FT_FREE( globals ); } @@ -1441,12 +1826,17 @@ FT_Error error; AH_Outline outline = hinter->glyph; AH_Loader gloader = hinter->loader; + FT_Pos baseline = 0; + FT_Byte type = hinter->globals->cur_type; /* load the glyph */ - error = FT_Load_Glyph( face, glyph_index, load_flags ); - if ( error ) - goto Exit; + if ( !hinter->globals->has_tt_bytecode_interp ) + { + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + goto Exit; + } /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */ hinter->transformed = internal->glyph_transformed; @@ -1463,6 +1853,11 @@ FT_Matrix_Invert( &imatrix ); FT_Vector_Transform( &hinter->trans_delta, &imatrix ); } + else + { + hinter->trans_delta.x = 0; + hinter->trans_delta.y = 0; + } /* set linear horizontal metrics */ slot->linearHoriAdvance = slot->metrics.horiAdvance; @@ -1472,17 +1867,22 @@ { case FT_GLYPH_FORMAT_OUTLINE: + if ( hinter->do_blue_hints ) + baseline = hinter->globals->designs[type].baseline; + /* translate glyph outline if we need to */ - if ( hinter->transformed ) + if ( hinter->transformed || baseline != 0 ) { FT_UInt n = slot->outline.n_points; FT_Vector* point = slot->outline.points; + FT_Pos x_off = hinter->trans_delta.x; + FT_Pos y_off = hinter->trans_delta.y - baseline; for ( ; n > 0; point++, n-- ) { - point->x += hinter->trans_delta.x; - point->y += hinter->trans_delta.y; + point->x += x_off; + point->y += y_off; } } @@ -1524,7 +1924,7 @@ /* perform feature detection */ ah_outline_detect_features( outline ); - if ( hinter->do_vert_hints ) + if ( hinter->do_blue_hints ) { ah_outline_compute_blue_edges( outline, hinter->globals ); ah_outline_scale_blue_edges( outline, hinter->globals ); @@ -1539,6 +1939,8 @@ /* we now need to hint the metrics according to the change in */ /* width/positioning that occured during the hinting process */ + if ( !hinter->globals->is_fixedpitch && !hinter->composite && + type <= AH_CHAR_TYPE_HORIZONTAL ) { FT_Pos old_advance, old_rsb, old_lsb, new_lsb; AH_Edge edge1 = outline->vert_edges; /* leftmost edge */ @@ -1551,8 +1953,8 @@ old_lsb = edge1->opos; new_lsb = edge1->pos; - hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64; - hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64; + hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64; + hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 40 ) & -64; #if 0 /* try to fix certain bad advance computations */ @@ -1705,6 +2107,13 @@ FT_BBox bbox; + if ( hinter->do_blue_hints ) + { + if ( hinter->globals->scaled.baseline != 0 ) + FT_Outline_Translate( &gloader->base.outline, + 0, hinter->globals->scaled.baseline ); + } + /* transform the hinted outline if needed */ if ( hinter->transformed ) FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix ); @@ -1725,14 +2134,7 @@ slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; - /* for mono-width fonts (like Andale, Courier, etc.) we need */ - /* to keep the original rounded advance width */ - if ( !FT_IS_FIXED_WIDTH( slot->face ) ) - slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; - else - slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, - x_scale ); - + slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + 32 ) & -64; /* now copy outline into glyph slot */ @@ -1754,6 +2156,236 @@ } +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + +#define AH_MAX_COMPOSITE_RECURSE 5 + + static FT_Error + ah_hinter_load_truetype( 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; + + + hinter->composite = TRUE; + + 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_load_truetype( 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_NO_RECURSE & + ~FT_LOAD_NO_SCALE; + 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, @@ -1768,6 +2400,7 @@ FT_Fixed y_scale = size->metrics.y_scale; AH_Face_Globals face_globals = FACE_GLOBALS( face ); FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE( load_flags ); + FT_Byte type; /* first of all, we need to check that we're using the correct face and */ @@ -1787,46 +2420,6 @@ } -#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 - */ - { - AH_Globals design = &face_globals->design; - FT_Pos shoot = 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 ( shoot > 0 ) - { - FT_Pos scaled = FT_MulFix( shoot, y_scale ); - FT_Pos fitted = ( scaled + 32 ) & -64; - - - if ( scaled != fitted ) - { - /* adjust y_scale - */ - y_scale = FT_MulDiv( y_scale, fitted, scaled ); - - /* adust x_scale - */ - if ( fitted < scaled ) - x_scale -= x_scale / 50; /* x_scale*0.98 with integers */ - } - } - } - -#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */ - - /* now, we must check the current character pixel size to see if we */ - /* need to rescale the global metrics */ - if ( face_globals->x_scale != x_scale || - face_globals->y_scale != y_scale ) - ah_hinter_scale_globals( hinter, x_scale, y_scale ); - ah_loader_rewind( hinter->loader ); /* reset hinting flags according to load flags and current render target */ @@ -1850,11 +2443,51 @@ hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); + type = ah_hinter_get_char_type( hinter, glyph_index ); + + hinter->do_blue_hints = face_globals->designs[type].has_blues; + hinter->composite = FALSE; + + /* now, we must check the current character pixel size to see if we */ + /* need to rescale the global metrics */ + if ( face_globals->x_scale_linear != x_scale || + face_globals->y_scale_linear != y_scale || + face_globals->cur_type != type ) + ah_hinter_scale_globals( hinter, x_scale, y_scale, type ); + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM ; - error = ah_hinter_load( hinter, glyph_index, load_flags, 0 ); +#ifndef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + + error = ah_hinter_load( hinter, glyph_index, load_flags, 0 ); + +#else + + if ( face_globals->has_tt_bytecode_interp ) + { + short* num_contours; + short* num_points; + int num_simple_glyphs; + int size_array; + + + load_flags |= FT_LOAD_NO_RECURSE; + + error = ah_hinter_load_truetype( hinter, + glyph_index, + load_flags, + 0, + &num_contours, + &num_points, + &num_simple_glyphs, + &size_array ); + } + else + error = ah_hinter_load( hinter, glyph_index, load_flags, 0 ); + +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ Exit: return error; @@ -1885,7 +2518,7 @@ goto Fail; } - *globals = FACE_GLOBALS( face )->design; + *globals = FACE_GLOBALS( face )->designs[0]; *global_hints = globals; *global_len = sizeof( *globals ); diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.5-orig/src/autohint/ahtypes.h freetype-2.1.5/src/autohint/ahtypes.h --- freetype-2.1.5-orig/src/autohint/ahtypes.h Wed May 28 14:52:05 2003 +++ freetype-2.1.5/src/autohint/ahtypes.h Wed Nov 5 16:00:17 2003 @@ -138,6 +138,8 @@ /* weak interpolation */ #define AH_FLAG_WEAK_INTERPOLATION 256 #define AH_FLAG_INFLECTION 512 +#define AH_FLAG_STRONG_X 1024 +#define AH_FLAG_STRONG_Y 2048 typedef FT_Int AH_Flags; @@ -264,7 +266,10 @@ AH_Segment link; /* link segment */ AH_Segment serif; /* primary segment for serifs */ FT_Pos num_linked; /* number of linked segments */ - FT_Pos score; + FT_Pos score1; + FT_Pos score2; + FT_Pos length; + FT_Int sign; AH_Point first; /* first point in edge segment */ AH_Point last; /* last point in edge segment */ @@ -402,6 +407,37 @@ 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 + + enum + { + AH_CHAR_TYPE_LATINATE = 0, + AH_CHAR_TYPE_LATIN_FULLWIDTH, + AH_CHAR_TYPE_HORIZONTAL, + AH_CHAR_TYPE_OTHER, + AH_CHAR_TYPE_COUNT + }; + + + typedef struct AH_CharType_ + { + FT_Byte type; + FT_ULong start; + FT_ULong last; + + } AH_CharType; + + + typedef struct AH_CharTypeTable_ + { + FT_ULong size; + AH_CharType* types; + + } AH_CharTypeTable; + + /*************************************************************************/ /* */ /* */ @@ -440,6 +476,10 @@ FT_Pos blue_refs [AH_BLUE_MAX]; FT_Pos blue_shoots[AH_BLUE_MAX]; + FT_Pos baseline; + + FT_Bool has_blues; + } AH_GlobalsRec, *AH_Globals; @@ -470,12 +510,21 @@ typedef struct AH_Face_GlobalsRec_ { FT_Face face; - AH_GlobalsRec design; + AH_GlobalsRec designs[AH_CHAR_TYPE_COUNT]; AH_GlobalsRec scaled; FT_Fixed x_scale; FT_Fixed y_scale; FT_Bool control_overshoot; + FT_Fixed x_scale_linear; + FT_Fixed y_scale_linear; + + AH_CharTypeTable* table; + FT_Byte cur_type; + FT_Size size_EM; + FT_Bool is_fixedpitch; + FT_Bool has_tt_bytecode_interp; + } AH_Face_GlobalsRec, *AH_Face_Globals; @@ -494,6 +543,7 @@ AH_Loader loader; FT_Vector pp1; FT_Vector pp2; + FT_Bool composite; FT_Bool transformed; FT_Vector trans_delta; @@ -504,6 +554,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; /* disable blue hinting */ } AH_HinterRec, *AH_Hinter; diff -u -x Makefile -x ahmodule.h -x ahmodule.c freetype-2.1.5-orig/src/autohint/autohint.c freetype-2.1.5/src/autohint/autohint.c --- freetype-2.1.5-orig/src/autohint/autohint.c Fri Jun 29 02:48:46 2001 +++ freetype-2.1.5/src/autohint/autohint.c Sat Sep 20 09:58:12 2003 @@ -22,7 +22,6 @@ #define FT_MAKE_OPTION_SINGLE_OBJECT #include -#include "ahangles.c" #include "ahglyph.c" #include "ahglobal.c" #include "ahhint.c" Only in freetype-2.1.5/src/autohint: autohint.o