From b9c22aff61a90a17d8ace2dfda5094df31ac860c Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 1 Mar 2005 15:48:29 +0000 Subject: [PATCH] * src/autofit/{afhints.h,afhints.c,aflatin.h,aflatin.c,afloader.c}: various bug-fixes and drastic heap usage reduction improvements. * include/freetype/config/ftmodule.h: the auto-fitter is now the only supported auto-hinting module * include/freetype/config/ftstdlib.h: adding FT_INT_MAX definition --- ChangeLog | 10 + include/freetype/config/ftmodule.h | 2 +- include/freetype/config/ftstdlib.h | 1 + src/autofit/afhints.c | 146 +++++++++----- src/autofit/afhints.h | 23 ++- src/autofit/aflatin.c | 300 ++++++++++++++++------------- src/autofit/aflatin.h | 6 +- src/autofit/afloader.c | 4 +- 8 files changed, 297 insertions(+), 195 deletions(-) diff --git a/ChangeLog b/ChangeLog index dc0b1e091..82d7a8b2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2005-03-01 David Turner + + * src/autofit/{afhints.h,afhints.c,aflatin.h,aflatin.c,afloader.c}: + various bug-fixes and drastic heap usage reduction improvements. + + * include/freetype/config/ftmodule.h: the auto-fitter is now the + only supported auto-hinting module + + * include/freetype/config/ftstdlib.h: adding FT_INT_MAX definition + 2005-02-28 Werner Lemberg * src/truetype/ttpload.c (tt_face_load_loca): Fix typo. diff --git a/include/freetype/config/ftmodule.h b/include/freetype/config/ftmodule.h index 762d4af30..74782f0ad 100644 --- a/include/freetype/config/ftmodule.h +++ b/include/freetype/config/ftmodule.h @@ -1,4 +1,4 @@ -FT_USE_MODULE(autohint_module_class) +FT_USE_MODULE(autofit_module_class) FT_USE_MODULE(tt_driver_class) FT_USE_MODULE(t1_driver_class) FT_USE_MODULE(cff_driver_class) diff --git a/include/freetype/config/ftstdlib.h b/include/freetype/config/ftstdlib.h index 448ae4bf5..4b9b398b2 100644 --- a/include/freetype/config/ftstdlib.h +++ b/include/freetype/config/ftstdlib.h @@ -66,6 +66,7 @@ #include #define FT_UINT_MAX UINT_MAX +#define FT_INT_MAX INT_MAX #define FT_ULONG_MAX ULONG_MAX diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index a1a50dce3..9e85ae13e 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -1,5 +1,96 @@ #include "afhints.h" + + FT_LOCAL_DEF( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ) + { + FT_Error error = 0; + AF_Segment segment = NULL; + + if ( axis->num_segments >= axis->max_segments ) + { + FT_Int old_max = axis->max_segments; + FT_Int new_max = old_max; + FT_Int big_max = FT_INT_MAX / sizeof(*segment); + + if ( old_max >= big_max ) + { + error = FT_Err_Out_Of_Memory; + goto Exit; + } + + new_max += (new_max >> 1) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + + if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) + goto Exit; + + axis->max_segments = new_max; + } + + segment = axis->segments + axis->num_segments++; + FT_ZERO( segment ); + + Exit: + *asegment = segment; + return error; + } + + FT_LOCAL( FT_Error) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + FT_Memory memory, + AF_Edge *aedge ) + { + FT_Error error = 0; + AF_Edge edge = NULL; + AF_Edge edges; + + if ( axis->num_edges >= axis->max_edges ) + { + FT_Int old_max = axis->max_edges; + FT_Int new_max = old_max; + FT_Int big_max = FT_INT_MAX / sizeof(*edge); + + if ( old_max >= big_max ) + { + error = FT_Err_Out_Of_Memory; + goto Exit; + } + + new_max += (new_max >> 1) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + + if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) + goto Exit; + + axis->max_edges = new_max; + } + + edges = axis->edges; + edge = edges + axis->num_edges; + + while ( edge > edges && edge[-1].fpos > fpos ) + { + edge[0] = edge[-1]; + edge--; + } + + axis->num_edges++; + + FT_ZERO(edge); + edge->fpos = (FT_Short) fpos; + + Exit: + *aedge = edge; + return error; + } + + #ifdef AF_DEBUG #include @@ -295,9 +386,12 @@ AF_AxisHints axis = &hints->axis[ dim ]; axis->num_segments = 0; + axis->max_segments = 0; + FT_FREE( axis->segments ); + axis->num_edges = 0; - axis->segments = NULL; - axis->edges = NULL; + axis->max_edges = 0; + FT_FREE( axis->edges ); } FT_FREE( hints->contours ); @@ -359,7 +453,7 @@ hints->max_contours = new_max; } - /* then, reallocate the points, segments & edges arrays if needed -- + /* then, reallocate the points arrays if needed -- * note that we reserved two additional point positions, used to * hint metrics appropriately */ @@ -367,59 +461,17 @@ old_max = hints->max_points; if ( new_max > old_max ) { - FT_Byte* items; - FT_ULong off1, off2, off3; - - /* we store in a single buffer the following arrays: - * - * - an array of N AF_PointRec items - * - an array of 2*N AF_SegmentRec items - * - an array of 2*N AF_EdgeRec items - * - */ - new_max = ( new_max + 2 + 7 ) & ~7; -#define OFF_PAD2(x,y) (((x)+(y)-1) & ~((y)-1)) -#define OFF_PADX(x,y) ((((x)+(y)-1)/(y))*(y)) -#define OFF_PAD(x,y) ( ((y) & ((y)-1)) ? OFF_PADX(x,y) : OFF_PAD2(x,y) ) - -#undef OFF_INCREMENT -#define OFF_INCREMENT( _off, _type, _count ) \ - ( OFF_PAD( _off, sizeof(_type) ) + (_count)*sizeof(_type)) - - off1 = OFF_INCREMENT( 0, AF_PointRec, new_max ); - off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max*2 ); - off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 ); - - FT_FREE( hints->points ); - - if ( FT_ALLOC( items, off3 ) ) - { - hints->max_points = 0; - hints->axis[0].segments = NULL; - hints->axis[0].edges = NULL; - hints->axis[1].segments = NULL; - hints->axis[1].edges = NULL; + if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) goto Exit; - } - /* readjust some pointers - */ - hints->max_points = new_max; - hints->points = (AF_Point) items; - - hints->axis[0].segments = (AF_Segment)( items + off1 ); - hints->axis[1].segments = hints->axis[0].segments + new_max; - - hints->axis[0].edges = (AF_Edge) ( items + off2 ); - hints->axis[1].edges = hints->axis[0].edges + new_max; + hints->max_points = new_max; } hints->num_points = outline->n_points; hints->num_contours = outline->n_contours; - /* We can't rely on the value of `FT_Outline.flags' to know the fill */ /* direction used for a glyph, given that some fonts are broken (e.g. */ /* the Arphic ones). We thus recompute it each time we need to. */ diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h index a570cc807..9b71c8c1f 100644 --- a/src/autofit/afhints.h +++ b/src/autofit/afhints.h @@ -84,15 +84,15 @@ FT_BEGIN_HEADER typedef struct AF_PointRec_ { - AF_Flags flags; /* point flags used by hinter */ + FT_UShort flags; /* point flags used by hinter */ + FT_Char in_dir; /* direction of inwards vector */ + FT_Char out_dir; /* direction of outwards vector */ + FT_Pos ox, oy; /* original, scaled position */ FT_Short fx, fy; /* original, unscaled position (font units) */ FT_Pos x, y; /* current position */ FT_Pos u, v; /* current (x,y) or (y,x) depending on context */ - FT_Char in_dir; /* direction of inwards vector */ - FT_Char out_dir; /* direction of outwards vector */ - AF_Point next; /* next point in contour */ AF_Point prev; /* previous point in contour */ @@ -101,7 +101,7 @@ FT_BEGIN_HEADER typedef struct AF_SegmentRec_ { - AF_Edge_Flags flags; /* edge/segment flags for this segment */ + FT_Byte flags; /* edge/segment flags for this segment */ FT_Char dir; /* segment direction */ FT_Short pos; /* position of segment */ FT_Short min_coord; /* minimum coordinate of segment */ @@ -148,9 +148,11 @@ FT_BEGIN_HEADER typedef struct AF_AxisHintsRec_ { FT_Int num_segments; + FT_Int max_segments; AF_Segment segments; FT_Int num_edges; + FT_Int max_edges; AF_Edge edges; AF_Direction major_dir; @@ -205,6 +207,17 @@ FT_BEGIN_HEADER FT_Pos dy ); + FT_LOCAL( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ); + + FT_LOCAL( FT_Error) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + FT_Memory memory, + AF_Edge *edge ); + FT_LOCAL( void ) af_glyph_hints_init( AF_GlyphHints hints, FT_Memory memory ); diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index ce0f8c961..fa5d56574 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -58,7 +58,10 @@ FT_UInt num_widths = 0; FT_Pos edge_distance_threshold = 32000; - af_latin_hints_compute_segments( hints, dim ); + error = af_latin_hints_compute_segments( hints, dim ); + if ( error ) + goto Exit; + af_latin_hints_link_segments ( hints, dim ); seg = axhints->segments; @@ -506,9 +509,6 @@ af_latin_metrics_scale( AF_LatinMetrics metrics, AF_Scaler scaler ) { - if ( AF_SCALER_EQUAL_SCALES( scaler, &metrics->root.scaler ) ) - return; - af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); } @@ -522,14 +522,14 @@ /***************************************************************************/ /***************************************************************************/ - FT_LOCAL_DEF( void ) + FT_LOCAL_DEF( FT_Error ) af_latin_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = &hints->axis[dim]; - AF_Segment segments = axis->segments; - AF_Segment segment = segments; - FT_Int num_segments = 0; + AF_AxisHints axis = &hints->axis[dim]; + FT_Memory memory = hints->memory; + FT_Error error = 0; + AF_Segment segment = NULL; AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; AF_Direction major_dir, segment_dir; @@ -544,6 +544,8 @@ major_dir = FT_ABS( axis->major_dir ); segment_dir = major_dir; + axis->num_segments = 0; + /* set up (u,v) in each point */ if ( dim == AF_DIMENSION_HORZ ) { @@ -656,8 +658,7 @@ segment->max_coord = max_pos; on_edge = 0; - num_segments++; - segment++; + segment = NULL; /* fallthrough */ } } @@ -676,7 +677,9 @@ segment_dir = point->out_dir; /* clear all segment fields */ - FT_ZERO( segment ); + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error ) + goto Exit; segment->dir = segment_dir; segment->flags = AF_EDGE_NORMAL; @@ -740,7 +743,9 @@ if ( min_point ) { /* clear all segment fields */ - FT_ZERO( segment ); + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error ) + goto Exit; segment->dir = segment_dir; segment->flags = AF_EDGE_NORMAL; @@ -750,15 +755,16 @@ segment->score = 32000; segment->link = NULL; - num_segments++; - segment++; + segment = NULL; } /* insert maximum segment */ if ( max_point ) { /* clear all segment fields */ - FT_ZERO( segment ); + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error) + goto Exit; segment->dir = segment_dir; segment->flags = AF_EDGE_NORMAL; @@ -768,13 +774,13 @@ segment->score = 32000; segment->link = NULL; - num_segments++; - segment++; + segment = NULL; } } #endif /* AF_HINT_METRICS */ - axis->num_segments = num_segments; + Exit: + return error; } @@ -858,14 +864,14 @@ } - FT_LOCAL_DEF( void ) + FT_LOCAL_DEF( FT_Error ) af_latin_hints_compute_edges( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = &hints->axis[dim]; + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = 0; + FT_Memory memory = hints->memory; AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; - AF_Edge edges = axis->edges; - AF_Edge edge, edge_limit; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; @@ -875,6 +881,7 @@ FT_Fixed scale; FT_Pos edge_distance_threshold; + axis->num_edges = 0; scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale : hints->y_scale; @@ -906,16 +913,16 @@ edge_distance_threshold = FT_DivFix( edge_distance_threshold, scale ); - edge_limit = edges; for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge found = 0; - + FT_Int ee; /* look for an edge corresponding to the segment */ - for ( edge = edges; edge < edge_limit; edge++ ) + for ( ee = 0; ee < axis->num_edges; ee++ ) { - FT_Pos dist; + AF_Edge edge = axis->edges + ee; + FT_Pos dist; dist = seg->pos - edge->fpos; @@ -931,19 +938,17 @@ if ( !found ) { + AF_Edge edge; + /* insert a new edge in the list and */ /* sort according to the position */ - while ( edge > edges && edge[-1].fpos > seg->pos ) - { - edge[0] = edge[-1]; - edge--; - } - edge_limit++; - - /* clear all edge fields */ - FT_ZERO( edge ); + error = af_axis_hints_new_edge( axis, seg->pos, memory, &edge ); + if ( error ) + goto Exit; /* add the segment to the new edge's list */ + FT_ZERO(edge); + edge->first = seg; edge->last = seg; edge->fpos = seg->pos; @@ -954,12 +959,11 @@ { /* if an edge was found, simply add the segment to the edge's */ /* list */ - seg->edge_next = edge->first; - edge->last->edge_next = seg; - edge->last = seg; + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; } } - axis->num_edges = (FT_Int)( edge_limit - edges ); /*********************************************************************/ @@ -982,133 +986,148 @@ * code above. For some reason, it slows down execution * speed -- on a Sun. */ - for ( edge = edges; edge < edge_limit; edge++ ) { - seg = edge->first; - if ( seg ) + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + } + while ( seg != edge->first ); + } + + /* now, compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + 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; + do { - seg->edge = edge; - seg = seg->edge_next; - } - while ( seg != edge->first ); - } - - /* now, compute each edge properties */ - for ( edge = edges; edge < edge_limit; edge++ ) - { - 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 */ + FT_Bool is_serif; - seg = edge->first; + /* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; - do - { - FT_Bool is_serif; + /* 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 ); - /* check for roundness of segment */ - if ( seg->flags & AF_EDGE_ROUND ) - is_round++; - 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 ); - - if ( seg->link || is_serif ) - { - AF_Edge edge2; - AF_Segment seg2; - - - edge2 = edge->link; - seg2 = seg->link; - - if ( is_serif ) + if ( seg->link || is_serif ) { - seg2 = seg->serif; - edge2 = edge->serif; - } - - if ( edge2 ) - { - FT_Pos edge_delta; - FT_Pos seg_delta; + AF_Edge edge2; + AF_Segment seg2; - edge_delta = edge->fpos - edge2->fpos; - if ( edge_delta < 0 ) - edge_delta = -edge_delta; + edge2 = edge->link; + seg2 = seg->link; - seg_delta = seg->pos - seg2->pos; - if ( seg_delta < 0 ) - seg_delta = -seg_delta; + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } - if ( seg_delta < edge_delta ) + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + + + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + + seg_delta = seg->pos - seg2->pos; + if ( seg_delta < 0 ) + seg_delta = -seg_delta; + + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else edge2 = seg2->edge; + + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; } - else - edge2 = seg2->edge; - if ( is_serif ) - { - edge->serif = edge2; - edge2->flags |= AF_EDGE_SERIF; - } - else - edge->link = edge2; - } + seg = seg->edge_next; - seg = seg->edge_next; + } while ( seg != edge->first ); - } while ( seg != edge->first ); + /* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; - /* set the round/straight flags */ - edge->flags = AF_EDGE_NORMAL; + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; - if ( is_round > 0 && is_round >= is_straight ) - edge->flags |= AF_EDGE_ROUND; + /* set the edge's main direction */ + edge->dir = AF_DIR_NONE; - /* set the edge's main direction */ - edge->dir = AF_DIR_NONE; + if ( ups > downs ) + edge->dir = up_dir; - if ( ups > downs ) - edge->dir = up_dir; + else 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! */ - 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 */ - /* 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 */ - - if ( edge->serif && edge->link ) - edge->serif = 0; + if ( edge->serif && edge->link ) + edge->serif = 0; + } } + + Exit: + return error; } - FT_LOCAL_DEF( void ) + FT_LOCAL_DEF( FT_Error ) af_latin_hints_detect_features( AF_GlyphHints hints, AF_Dimension dim ) { - af_latin_hints_compute_segments( hints, dim ); - af_latin_hints_link_segments ( hints, dim ); - af_latin_hints_compute_edges ( hints, dim ); + FT_Error error; + + error = af_latin_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_latin_hints_link_segments ( hints, dim ); + error = af_latin_hints_compute_edges ( hints, dim ); + } + return error; } @@ -1812,11 +1831,18 @@ /* analyze glyph outline */ if ( AF_HINTS_DO_HORIZONTAL(hints) ) - af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ ); + { + error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + } if ( AF_HINTS_DO_VERTICAL(hints) ) { - af_latin_hints_detect_features( hints, AF_DIMENSION_VERT ); + error = af_latin_hints_detect_features( hints, AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + af_latin_hints_compute_blue_edges( hints, metrics ); } diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h index e7e8e4842..9b7f8fee1 100644 --- a/src/autofit/aflatin.h +++ b/src/autofit/aflatin.h @@ -140,7 +140,7 @@ FT_BEGIN_HEADER /* this shouldn't normally be exported. However, other scripts might * like to use this function as-is */ - FT_LOCAL( void ) + FT_LOCAL( FT_Error ) af_latin_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ); @@ -154,11 +154,11 @@ FT_BEGIN_HEADER /* this shouldn't normally be exported. However, other scripts might * want to use this function as-is */ - FT_LOCAL( void ) + FT_LOCAL( FT_Error ) af_latin_hints_compute_edges( AF_GlyphHints hints, AF_Dimension dim ); - FT_LOCAL( void ) + FT_LOCAL( FT_Error ) af_latin_hints_detect_features( AF_GlyphHints hints, AF_Dimension dim ); diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c index acd11c1d3..c03a9f36e 100644 --- a/src/autofit/afloader.c +++ b/src/autofit/afloader.c @@ -449,10 +449,10 @@ { loader->metrics = metrics; - metrics->scaler = scaler; - if ( metrics->clazz->script_metrics_scale ) metrics->clazz->script_metrics_scale( metrics, &scaler ); + else + metrics->scaler = scaler; load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; load_flags &= ~FT_LOAD_RENDER;