ref: b9c22aff61a90a17d8ace2dfda5094df31ac860c
parent: e793092d0a9f4d4d383315bcefd485dcbe4804b3
author: David Turner <[email protected]>
date: Tue Mar 1 10:48:29 EST 2005
* 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
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2005-03-01 David Turner <[email protected]>
+
+ * 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 <[email protected]>
* src/truetype/ttpload.c (tt_face_load_loca): Fix typo.
--- 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)
--- a/include/freetype/config/ftstdlib.h
+++ b/include/freetype/config/ftstdlib.h
@@ -66,6 +66,7 @@
#include <limits.h>
#define FT_UINT_MAX UINT_MAX
+#define FT_INT_MAX INT_MAX
#define FT_ULONG_MAX ULONG_MAX
--- 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 <stdio.h>
@@ -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,58 +461,16 @@
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. */
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -84,15 +84,15 @@
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 @@
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 @@
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;
@@ -204,6 +206,17 @@
af_direction_compute( FT_Pos dx,
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,
--- 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,8 +755,7 @@
segment->score = 32000;
segment->link = NULL;
- num_segments++;
- segment++;
+ segment = NULL;
}
/* insert maximum segment */
@@ -758,7 +762,9 @@
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++;
+ error = af_axis_hints_new_edge( axis, seg->pos, memory, &edge );
+ if ( error )
+ goto Exit;
- /* clear all edge fields */
- FT_ZERO( edge );
-
/* 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 )
- do
- {
- seg->edge = edge;
- seg = seg->edge_next;
- }
- while ( seg != edge->first );
- }
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Edge edge;
- /* 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 */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ seg = edge->first;
+ if ( seg )
+ do
+ {
+ seg->edge = edge;
+ seg = seg->edge_next;
+ }
+ while ( seg != edge->first );
+ }
-
- seg = edge->first;
-
- do
+ /* now, compute each edge properties */
+ for ( edge = edges; edge < edge_limit; edge++ )
{
- FT_Bool is_serif;
+ 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 */
- /* check for roundness of segment */
- if ( seg->flags & AF_EDGE_ROUND )
- is_round++;
- else
- is_straight++;
+ seg = edge->first;
- /* check for segment direction */
- if ( seg->dir == up_dir )
- ups += seg->max_coord-seg->min_coord;
- else
- downs += seg->max_coord-seg->min_coord;
+ do
+ {
+ FT_Bool is_serif;
- /* 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;
+ /* 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;
- edge2 = edge->link;
- seg2 = seg->link;
+ /* 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 ( is_serif )
+ if ( seg->link || is_serif )
{
- seg2 = seg->serif;
- edge2 = edge->serif;
- }
+ AF_Edge edge2;
+ AF_Segment seg2;
- if ( edge2 )
- {
- FT_Pos edge_delta;
- FT_Pos seg_delta;
+ edge2 = edge->link;
+ seg2 = seg->link;
- edge_delta = edge->fpos - edge2->fpos;
- if ( edge_delta < 0 )
- edge_delta = -edge_delta;
+ if ( is_serif )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
- seg_delta = seg->pos - seg2->pos;
- if ( seg_delta < 0 )
- seg_delta = -seg_delta;
+ if ( edge2 )
+ {
+ FT_Pos edge_delta;
+ FT_Pos seg_delta;
- if ( seg_delta < edge_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;
- }
- else
- edge2 = seg2->edge;
- if ( is_serif )
- {
- edge->serif = edge2;
- edge2->flags |= AF_EDGE_SERIF;
+ if ( is_serif )
+ {
+ edge->serif = edge2;
+ edge2->flags |= AF_EDGE_SERIF;
+ }
+ else
+ edge->link = edge2;
}
- 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 );
}
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -140,7 +140,7 @@
/* 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 @@
/* 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 );
--- 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;