* 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
This commit is contained in:
David Turner 2005-03-01 15:48:29 +00:00
parent e793092d0a
commit b9c22aff61
8 changed files with 297 additions and 195 deletions

View File

@ -1,3 +1,13 @@
2005-03-01 David Turner <david@freetype.org>
* 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 <wl@gnu.org> 2005-02-28 Werner Lemberg <wl@gnu.org>
* src/truetype/ttpload.c (tt_face_load_loca): Fix typo. * src/truetype/ttpload.c (tt_face_load_loca): Fix typo.

View File

@ -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(tt_driver_class)
FT_USE_MODULE(t1_driver_class) FT_USE_MODULE(t1_driver_class)
FT_USE_MODULE(cff_driver_class) FT_USE_MODULE(cff_driver_class)

View File

@ -66,6 +66,7 @@
#include <limits.h> #include <limits.h>
#define FT_UINT_MAX UINT_MAX #define FT_UINT_MAX UINT_MAX
#define FT_INT_MAX INT_MAX
#define FT_ULONG_MAX ULONG_MAX #define FT_ULONG_MAX ULONG_MAX

View File

@ -1,5 +1,96 @@
#include "afhints.h" #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 #ifdef AF_DEBUG
#include <stdio.h> #include <stdio.h>
@ -295,9 +386,12 @@
AF_AxisHints axis = &hints->axis[ dim ]; AF_AxisHints axis = &hints->axis[ dim ];
axis->num_segments = 0; axis->num_segments = 0;
axis->max_segments = 0;
FT_FREE( axis->segments );
axis->num_edges = 0; axis->num_edges = 0;
axis->segments = NULL; axis->max_edges = 0;
axis->edges = NULL; FT_FREE( axis->edges );
} }
FT_FREE( hints->contours ); FT_FREE( hints->contours );
@ -359,7 +453,7 @@
hints->max_contours = new_max; 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 * note that we reserved two additional point positions, used to
* hint metrics appropriately * hint metrics appropriately
*/ */
@ -367,59 +461,17 @@
old_max = hints->max_points; old_max = hints->max_points;
if ( new_max > old_max ) 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; new_max = ( new_max + 2 + 7 ) & ~7;
#define OFF_PAD2(x,y) (((x)+(y)-1) & ~((y)-1)) if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
#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;
goto Exit; goto Exit;
}
/* readjust some pointers
*/
hints->max_points = new_max; 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->num_points = outline->n_points; hints->num_points = outline->n_points;
hints->num_contours = outline->n_contours; hints->num_contours = outline->n_contours;
/* We can't rely on the value of `FT_Outline.flags' to know the fill */ /* 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. */ /* 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. */ /* the Arphic ones). We thus recompute it each time we need to. */

View File

@ -84,15 +84,15 @@ FT_BEGIN_HEADER
typedef struct AF_PointRec_ 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_Pos ox, oy; /* original, scaled position */
FT_Short fx, fy; /* original, unscaled position (font units) */ FT_Short fx, fy; /* original, unscaled position (font units) */
FT_Pos x, y; /* current position */ FT_Pos x, y; /* current position */
FT_Pos u, v; /* current (x,y) or (y,x) depending on context */ 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 next; /* next point in contour */
AF_Point prev; /* previous point in contour */ AF_Point prev; /* previous point in contour */
@ -101,7 +101,7 @@ FT_BEGIN_HEADER
typedef struct AF_SegmentRec_ 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_Char dir; /* segment direction */
FT_Short pos; /* position of segment */ FT_Short pos; /* position of segment */
FT_Short min_coord; /* minimum coordinate of segment */ FT_Short min_coord; /* minimum coordinate of segment */
@ -148,9 +148,11 @@ FT_BEGIN_HEADER
typedef struct AF_AxisHintsRec_ typedef struct AF_AxisHintsRec_
{ {
FT_Int num_segments; FT_Int num_segments;
FT_Int max_segments;
AF_Segment segments; AF_Segment segments;
FT_Int num_edges; FT_Int num_edges;
FT_Int max_edges;
AF_Edge edges; AF_Edge edges;
AF_Direction major_dir; AF_Direction major_dir;
@ -205,6 +207,17 @@ FT_BEGIN_HEADER
FT_Pos dy ); 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 ) FT_LOCAL( void )
af_glyph_hints_init( AF_GlyphHints hints, af_glyph_hints_init( AF_GlyphHints hints,
FT_Memory memory ); FT_Memory memory );

View File

@ -58,7 +58,10 @@
FT_UInt num_widths = 0; FT_UInt num_widths = 0;
FT_Pos edge_distance_threshold = 32000; 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 ); af_latin_hints_link_segments ( hints, dim );
seg = axhints->segments; seg = axhints->segments;
@ -506,9 +509,6 @@
af_latin_metrics_scale( AF_LatinMetrics metrics, af_latin_metrics_scale( AF_LatinMetrics metrics,
AF_Scaler scaler ) 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_HORZ );
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); 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_latin_hints_compute_segments( AF_GlyphHints hints,
AF_Dimension dim ) AF_Dimension dim )
{ {
AF_AxisHints axis = &hints->axis[dim]; AF_AxisHints axis = &hints->axis[dim];
AF_Segment segments = axis->segments; FT_Memory memory = hints->memory;
AF_Segment segment = segments; FT_Error error = 0;
FT_Int num_segments = 0; AF_Segment segment = NULL;
AF_Point* contour = hints->contours; AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours; AF_Point* contour_limit = contour + hints->num_contours;
AF_Direction major_dir, segment_dir; AF_Direction major_dir, segment_dir;
@ -544,6 +544,8 @@
major_dir = FT_ABS( axis->major_dir ); major_dir = FT_ABS( axis->major_dir );
segment_dir = major_dir; segment_dir = major_dir;
axis->num_segments = 0;
/* set up (u,v) in each point */ /* set up (u,v) in each point */
if ( dim == AF_DIMENSION_HORZ ) if ( dim == AF_DIMENSION_HORZ )
{ {
@ -656,8 +658,7 @@
segment->max_coord = max_pos; segment->max_coord = max_pos;
on_edge = 0; on_edge = 0;
num_segments++; segment = NULL;
segment++;
/* fallthrough */ /* fallthrough */
} }
} }
@ -676,7 +677,9 @@
segment_dir = point->out_dir; segment_dir = point->out_dir;
/* clear all segment fields */ /* 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->dir = segment_dir;
segment->flags = AF_EDGE_NORMAL; segment->flags = AF_EDGE_NORMAL;
@ -740,7 +743,9 @@
if ( min_point ) if ( min_point )
{ {
/* clear all segment fields */ /* 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->dir = segment_dir;
segment->flags = AF_EDGE_NORMAL; segment->flags = AF_EDGE_NORMAL;
@ -750,15 +755,16 @@
segment->score = 32000; segment->score = 32000;
segment->link = NULL; segment->link = NULL;
num_segments++; segment = NULL;
segment++;
} }
/* insert maximum segment */ /* insert maximum segment */
if ( max_point ) if ( max_point )
{ {
/* clear all segment fields */ /* 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->dir = segment_dir;
segment->flags = AF_EDGE_NORMAL; segment->flags = AF_EDGE_NORMAL;
@ -768,13 +774,13 @@
segment->score = 32000; segment->score = 32000;
segment->link = NULL; segment->link = NULL;
num_segments++; segment = NULL;
segment++;
} }
} }
#endif /* AF_HINT_METRICS */ #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_latin_hints_compute_edges( AF_GlyphHints hints,
AF_Dimension dim ) 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_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 segments = axis->segments;
AF_Segment segment_limit = segments + axis->num_segments; AF_Segment segment_limit = segments + axis->num_segments;
@ -875,6 +881,7 @@
FT_Fixed scale; FT_Fixed scale;
FT_Pos edge_distance_threshold; FT_Pos edge_distance_threshold;
axis->num_edges = 0;
scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
: hints->y_scale; : hints->y_scale;
@ -906,15 +913,15 @@
edge_distance_threshold = FT_DivFix( edge_distance_threshold, edge_distance_threshold = FT_DivFix( edge_distance_threshold,
scale ); scale );
edge_limit = edges;
for ( seg = segments; seg < segment_limit; seg++ ) for ( seg = segments; seg < segment_limit; seg++ )
{ {
AF_Edge found = 0; AF_Edge found = 0;
FT_Int ee;
/* look for an edge corresponding to the segment */ /* look for an edge corresponding to the segment */
for ( edge = edges; edge < edge_limit; edge++ ) for ( ee = 0; ee < axis->num_edges; ee++ )
{ {
AF_Edge edge = axis->edges + ee;
FT_Pos dist; FT_Pos dist;
@ -931,19 +938,17 @@
if ( !found ) if ( !found )
{ {
AF_Edge edge;
/* insert a new edge in the list and */ /* insert a new edge in the list and */
/* sort according to the position */ /* sort according to the position */
while ( edge > edges && edge[-1].fpos > seg->pos ) error = af_axis_hints_new_edge( axis, seg->pos, memory, &edge );
{ if ( error )
edge[0] = edge[-1]; goto Exit;
edge--;
}
edge_limit++;
/* clear all edge fields */
FT_ZERO( edge );
/* add the segment to the new edge's list */ /* add the segment to the new edge's list */
FT_ZERO(edge);
edge->first = seg; edge->first = seg;
edge->last = seg; edge->last = seg;
edge->fpos = seg->pos; edge->fpos = seg->pos;
@ -954,12 +959,11 @@
{ {
/* if an edge was found, simply add the segment to the edge's */ /* if an edge was found, simply add the segment to the edge's */
/* list */ /* list */
seg->edge_next = edge->first; seg->edge_next = found->first;
edge->last->edge_next = seg; found->last->edge_next = seg;
edge->last = seg; found->last = seg;
} }
} }
axis->num_edges = (FT_Int)( edge_limit - edges );
/*********************************************************************/ /*********************************************************************/
@ -982,6 +986,11 @@
* code above. For some reason, it slows down execution * code above. For some reason, it slows down execution
* speed -- on a Sun. * speed -- on a Sun.
*/ */
{
AF_Edge edges = axis->edges;
AF_Edge edge_limit = edges + axis->num_edges;
AF_Edge edge;
for ( edge = edges; edge < edge_limit; edge++ ) for ( edge = edges; edge < edge_limit; edge++ )
{ {
seg = edge->first; seg = edge->first;
@ -1101,14 +1110,24 @@
} }
} }
Exit:
return error;
}
FT_LOCAL_DEF( void )
FT_LOCAL_DEF( FT_Error )
af_latin_hints_detect_features( AF_GlyphHints hints, af_latin_hints_detect_features( AF_GlyphHints hints,
AF_Dimension dim ) AF_Dimension dim )
{ {
af_latin_hints_compute_segments( hints, dim ); FT_Error error;
error = af_latin_hints_compute_segments( hints, dim );
if ( !error )
{
af_latin_hints_link_segments ( hints, dim ); af_latin_hints_link_segments ( hints, dim );
af_latin_hints_compute_edges ( hints, dim ); error = af_latin_hints_compute_edges ( hints, dim );
}
return error;
} }
@ -1812,11 +1831,18 @@
/* analyze glyph outline /* analyze glyph outline
*/ */
if ( AF_HINTS_DO_HORIZONTAL(hints) ) 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) ) 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 ); af_latin_hints_compute_blue_edges( hints, metrics );
} }

View File

@ -140,7 +140,7 @@ FT_BEGIN_HEADER
/* this shouldn't normally be exported. However, other scripts might /* this shouldn't normally be exported. However, other scripts might
* like to use this function as-is * like to use this function as-is
*/ */
FT_LOCAL( void ) FT_LOCAL( FT_Error )
af_latin_hints_compute_segments( AF_GlyphHints hints, af_latin_hints_compute_segments( AF_GlyphHints hints,
AF_Dimension dim ); AF_Dimension dim );
@ -154,11 +154,11 @@ FT_BEGIN_HEADER
/* this shouldn't normally be exported. However, other scripts might /* this shouldn't normally be exported. However, other scripts might
* want to use this function as-is * want to use this function as-is
*/ */
FT_LOCAL( void ) FT_LOCAL( FT_Error )
af_latin_hints_compute_edges( AF_GlyphHints hints, af_latin_hints_compute_edges( AF_GlyphHints hints,
AF_Dimension dim ); AF_Dimension dim );
FT_LOCAL( void ) FT_LOCAL( FT_Error )
af_latin_hints_detect_features( AF_GlyphHints hints, af_latin_hints_detect_features( AF_GlyphHints hints,
AF_Dimension dim ); AF_Dimension dim );

View File

@ -449,10 +449,10 @@
{ {
loader->metrics = metrics; loader->metrics = metrics;
metrics->scaler = scaler;
if ( metrics->clazz->script_metrics_scale ) if ( metrics->clazz->script_metrics_scale )
metrics->clazz->script_metrics_scale( metrics, &scaler ); 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_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
load_flags &= ~FT_LOAD_RENDER; load_flags &= ~FT_LOAD_RENDER;