ref: d25ad56d787cd4ecb37a69c64bfb2714458df7fc
parent: d393ca373812bd597651fc6f57dc5f6d58f8e7e1
author: David Turner <[email protected]>
date: Thu Oct 2 17:07:10 EDT 2003
* src/autofit/*: adding first sources of the new multi-script "auto-fitter" * include/freetype/ftoutln.h, src/base/ftoutln.c: adding the definition of FT_Outline_Get_Orientation, used to compute the fill orientation of a given glyph outline. * include/freetype/internal/ftserv.h: fixed trivial bug which could crashed the font engine when a cached service pointer was retrieved with FT_FACE_LOOKUP_SERVICE
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2003-10-01 David Turner <[email protected]>
+
+ * src/autofit/*: adding first sources of the new multi-script
+ "auto-fitter"
+
+ * include/freetype/ftoutln.h, src/base/ftoutln.c: adding the
+ definition of FT_Outline_Get_Orientation, used to compute the
+ fill orientation of a given glyph outline.
+
+ * include/freetype/internal/ftserv.h: fixed trivial bug which
+ could crashed the font engine when a cached service pointer was
+ retrieved with FT_FACE_LOOKUP_SERVICE
+
2003-09-30 Werner Lemberg <[email protected]>
* src/cid/cidload.c (cid_parse_dict): Skip token if no keyword is
@@ -21,9 +34,9 @@
2003-09-29 David Turner <[email protected]>
Added new service to handle glyph name dictionaries, replacing the
- old internal header named `psnames.h' by `services/svpsname.h'.
+ old internal header named `psnames.h' by `services/svpsname.h'.
Note that this is different from `services/svpostnm.h' which only
- handles the retrieval of PostScript font names for a given face.
+ handles the retrieval of PostScript font names for a given face.
(Should we merge these two services into a single header?)
* include/freetype/internal/psnames.h: Removed. Most of its
--- a/include/freetype/ftoutln.h
+++ b/include/freetype/ftoutln.h
@@ -389,6 +389,69 @@
FT_Raster_Params* params );
+ /**************************************************************************
+ *
+ * @enum: FT_Orientation
+ *
+ * @description:
+ * a list of values used to describe an outline's contour orientation
+ *
+ * The TrueType and Postscript specifications used different conventions
+ * to determine wether outline contours should be filled or unfilled.
+ *
+ * @values:
+ * FT_ORIENTATION_TRUETYPE ::
+ * according to the TrueType specification, clockwise contours must
+ * be filled, and counter-clockwise ones must be unfilled
+ *
+ * FT_ORIENTATION_POSTSCRIPT ::
+ * according to the Postscript specification, counter-clockwise contours
+ * must be filled, and clockwise ones must be unfilled
+ *
+ * FT_ORIENTATION_FILL_RIGHT ::
+ * this is identical to @FT_ORIENTATION_TRUETYPE, but is used to
+ * remember that in TrueType, everything that is to the right of
+ * the drawing direction of a contour must be filled.
+ *
+ * FT_ORIENTATION_FILL_LEFT ::
+ * this is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to
+ * remember that in Postscript, everything that is to the left of
+ * the drawing direction of a contour must be filled
+ */
+ typedef enum
+ {
+ FT_ORIENTATION_TRUETYPE = 0,
+ FT_ORIENTATION_POSTSCRIPT = 1,
+ FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE,
+ FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT
+
+ } FT_Orientation;
+
+
+ /**************************************************************************
+ *
+ * @function: FT_Outline_Get_Orientation
+ *
+ * @description:
+ * this function analyzes a glyph outline and tries to compute its
+ * fill orientation (see @FT_Orientation). This is done by computing
+ * the direction of each global horizontal and/or vertical extrema
+ * within the outline.
+ *
+ * note that this will return @FT_ORIENTATION_TRUETYPE for empty
+ * outlines.
+ *
+ * @input:
+ * outline :: handle to source outline
+ *
+ * @return:
+ * orientation
+ *
+ */
+ FT_EXPORT( FT_Orientation )
+ FT_Outline_Get_Orientation( FT_Outline* outline );
+
+
/* */
--- a/include/freetype/internal/ftserv.h
+++ b/include/freetype/internal/ftserv.h
@@ -216,8 +216,8 @@
FT_FACE(face)->internal->services. service_ ## id = \
(FT_Pointer)( svc != NULL ? svc \
: FT_SERVICE_UNAVAILABLE ); \
- *pptr = svc; \
} \
+ *pptr = svc; \
FT_END_STMNT
--- /dev/null
+++ b/src/autofit/afangles.c
@@ -1,0 +1,164 @@
+#include "aftypes.h"
+
+ /* this table was generated for AF_ANGLE_PI = 256 */
+#define AF_ANGLE_MAX_ITERS 8
+
+ static const FT_Fixed
+ af_angle_arctan_table[9] =
+ {
+ 90, 64, 38, 20, 10, 5, 3, 1, 1
+ };
+
+ static FT_Int
+ af_angle_prenorm( FT_Vector* vec )
+ {
+ FT_Fixed x, y, z;
+ FT_Int shift;
+
+
+ x = vec->x;
+ y = vec->y;
+
+ z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y );
+ shift = 0;
+
+ if ( z < ( 1L << 27 ) )
+ {
+ do
+ {
+ shift++;
+ z <<= 1;
+ } while ( z < ( 1L << 27 ) );
+
+ vec->x = x << shift;
+ vec->y = y << shift;
+ }
+ else if ( z > ( 1L << 28 ) )
+ {
+ do
+ {
+ shift++;
+ z >>= 1;
+ } while ( z > ( 1L << 28 ) );
+
+ vec->x = x >> shift;
+ vec->y = y >> shift;
+ shift = -shift;
+ }
+ return shift;
+ }
+
+
+ static void
+ af_angle_pseudo_polarize( FT_Vector* vec )
+ {
+ FT_Fixed theta;
+ FT_Fixed yi, i;
+ FT_Fixed x, y;
+ const FT_Fixed *arctanptr;
+
+
+ x = vec->x;
+ y = vec->y;
+
+ /* Get the vector into the right half plane */
+ theta = 0;
+ if ( x < 0 )
+ {
+ x = -x;
+ y = -y;
+ theta = 2 * AF_ANGLE_PI2;
+ }
+
+ if ( y > 0 )
+ theta = - theta;
+
+ arctanptr = af_angle_arctan_table;
+
+ if ( y < 0 )
+ {
+ /* Rotate positive */
+ yi = y + ( x << 1 );
+ x = x - ( y << 1 );
+ y = yi;
+ theta -= *arctanptr++; /* Subtract angle */
+ }
+ else
+ {
+ /* Rotate negative */
+ yi = y - ( x << 1 );
+ x = x + ( y << 1 );
+ y = yi;
+ theta += *arctanptr++; /* Add angle */
+ }
+
+ i = 0;
+ do
+ {
+ if ( y < 0 )
+ {
+ /* Rotate positive */
+ yi = y + ( x >> i );
+ x = x - ( y >> i );
+ y = yi;
+ theta -= *arctanptr++;
+ }
+ else
+ {
+ /* Rotate negative */
+ yi = y - ( x >> i );
+ x = x + ( y >> i );
+ y = yi;
+ theta += *arctanptr++;
+ }
+ } while ( ++i < AF_TRIG_MAX_ITERS );
+
+ /* round theta */
+ if ( theta >= 0 )
+ theta = ( theta + 2 ) & -4;
+ else
+ theta = - (( -theta + 2 ) & -4);
+
+ vec->x = x;
+ vec->y = theta;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_LOCAL_DEF( AF_Angle )
+ af_angle_atan( FT_Fixed dx,
+ FT_Fixed dy )
+ {
+ FT_Vector v;
+
+
+ if ( dx == 0 && dy == 0 )
+ return 0;
+
+ v.x = dx;
+ v.y = dy;
+ af_angle_prenorm( &v );
+ af_angle_pseudo_polarize( &v );
+
+ return v.y;
+ }
+
+
+
+ FT_LOCAL_DEF( AF_Angle )
+ af_angle_diff( AF_Angle angle1,
+ AF_Angle angle2 )
+ {
+ AF_Angle delta = angle2 - angle1;
+
+ delta %= AF_ANGLE_2PI;
+ if ( delta < 0 )
+ delta += AF_ANGLE_2PI;
+
+ if ( delta > AF_ANGLE_PI )
+ delta -= AF_ANGLE_2PI;
+
+ return delta;
+ }
+
--- /dev/null
+++ b/src/autofit/afhints.c
@@ -1,0 +1,626 @@
+#include "afhints.h"
+
+#ifdef AF_DEBUG
+
+#include <stdio.h>
+
+ void
+ af_outline_hints_dump_edges( AF_OutlineHints hints )
+ {
+ AF_Edge edges;
+ AF_Edge edge_limit;
+ AF_Segment segments;
+ FT_Int dimension;
+
+
+ edges = hints->horz_edges;
+ edge_limit = edges + hints->num_hedges;
+ segments = hints->horz_segments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AF_Edge edge;
+
+
+ printf ( "Table of %s edges:\n",
+ !dimension ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link |"
+ " serif | blue | opos | pos ]\n" );
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n",
+ edge - edges,
+ (int)edge->fpos,
+ edge->dir == AF_DIR_UP
+ ? "up"
+ : ( edge->dir == AF_DIR_DOWN
+ ? "down"
+ : ( edge->dir == AF_DIR_LEFT
+ ? "left"
+ : ( edge->dir == AF_DIR_RIGHT
+ ? "right"
+ : "none" ) ) ),
+ edge->link ? ( edge->link - edges ) : -1,
+ edge->serif ? ( edge->serif - edges ) : -1,
+ edge->blue_edge ? 'y' : 'n',
+ edge->opos / 64.0,
+ edge->pos / 64.0 );
+ }
+
+ edges = hints->vert_edges;
+ edge_limit = edges + hints->num_vedges;
+ segments = hints->vert_segments;
+ }
+ }
+
+
+ /* A function used to dump the array of linked segments */
+ void
+ af_outline_hints_dump_segments( AF_OutlineHints hints )
+ {
+ AF_Segment segments;
+ AF_Segment segment_limit;
+ AF_Point points;
+ FT_Int dimension;
+
+
+ points = hints->points;
+ segments = hints->horz_segments;
+ segment_limit = segments + hints->num_hsegments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AF_Segment seg;
+
+
+ printf ( "Table of %s segments:\n",
+ !dimension ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link | serif |"
+ " numl | first | start ]\n" );
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
+ seg - segments,
+ (int)seg->pos,
+ seg->dir == AF_DIR_UP
+ ? "up"
+ : ( seg->dir == AF_DIR_DOWN
+ ? "down"
+ : ( seg->dir == AF_DIR_LEFT
+ ? "left"
+ : ( seg->dir == AF_DIR_RIGHT
+ ? "right"
+ : "none" ) ) ),
+ seg->link ? ( seg->link - segments ) : -1,
+ seg->serif ? ( seg->serif - segments ) : -1,
+ (int)seg->num_linked,
+ seg->first - points,
+ seg->last - points );
+ }
+
+ segments = hints->vert_segments;
+ segment_limit = segments + hints->num_vsegments;
+ }
+ }
+
+#endif /* AF_DEBUG */
+
+
+ /* compute the direction value of a given vector */
+ FT_LOCAL_DEF( AF_Direction )
+ af_direction_compute( FT_Pos dx,
+ FT_Pos dy )
+ {
+ AF_Direction dir;
+ FT_Pos ax = ABS( dx );
+ FT_Pos ay = ABS( dy );
+
+
+ dir = AF_DIR_NONE;
+
+ /* atan(1/12) == 4.7 degrees */
+
+ /* test for vertical direction */
+ if ( ax * 12 < ay )
+ {
+ dir = dy > 0 ? AF_DIR_UP : AF_DIR_DOWN;
+ }
+ /* test for horizontal direction */
+ else if ( ay * 12 < ax )
+ {
+ dir = dx > 0 ? AF_DIR_RIGHT : AF_DIR_LEFT;
+ }
+
+ return dir;
+ }
+
+
+ /* compute all inflex points in a given glyph */
+ static void
+ af_outline_hints_compute_inflections( AF_OutlineHints hints )
+ {
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+
+
+ /* load original coordinates in (u,v) */
+ af_outline_hints_setup_uv( hints, outline, AF_UV_FXY );
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point point = contour[0];
+ AF_Point first = point;
+ AF_Point start = point;
+ AF_Point end = point;
+ AF_Point before;
+ AF_Point after;
+ AF_Angle angle_in, angle_seg, angle_out;
+ AF_Angle diff_in, diff_out;
+ FT_Int finished = 0;
+
+
+ /* compute first segment in contour */
+ first = point;
+
+ start = end = first;
+ do
+ {
+ end = end->next;
+ if ( end == first )
+ goto Skip;
+
+ } while ( end->u == first->u && end->v == first->v );
+
+ angle_seg = af_angle( end->u - start->u,
+ end->v - start->v );
+
+ /* extend the segment start whenever possible */
+ before = start;
+ do
+ {
+ do
+ {
+ start = before;
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ } while ( before->u == start->u && before->v == start->v );
+
+ angle_in = af_angle( start->u - before->u,
+ start->v - before->v );
+
+ } while ( angle_in == angle_seg );
+
+ first = start;
+ diff_in = af_angle_diff( angle_in, angle_seg );
+
+ /* now, process all segments in the contour */
+ do
+ {
+ /* first, extend current segment's end whenever possible */
+ after = end;
+ do
+ {
+ do
+ {
+ end = after;
+ after = after->next;
+ if ( after == first )
+ finished = 1;
+
+ } while ( end->u == after->u && end->v == after->v );
+
+ vec.x = after->u - end->u;
+ vec.y = after->v - end->v;
+ angle_out = af_angle( after->u - end->u,
+ after->v - end->v );
+
+ } while ( angle_out == angle_seg );
+
+ diff_out = af_angle_diff( angle_seg, angle_out );
+
+ if ( ( diff_in ^ diff_out ) < 0 )
+ {
+ /* diff_in and diff_out have different signs, we have */
+ /* inflection points here... */
+ do
+ {
+ start->flags |= AF_FLAG_INFLECTION;
+ start = start->next;
+
+ } while ( start != end );
+
+ start->flags |= AF_FLAG_INFLECTION;
+ }
+
+ start = end;
+ end = after;
+ angle_seg = angle_out;
+ diff_in = diff_out;
+
+ } while ( !finished );
+
+ Skip:
+ ;
+ }
+ }
+
+
+
+ FT_LOCAL_DEF( void )
+ af_outline_hints_init( AF_OutlineHints hints,
+ FT_Memory memory )
+ {
+ FT_ZERO( hints );
+ hints->memory = memory;
+ }
+
+
+
+ FT_LOCAL_DEF( void )
+ af_outline_hints_done( AF_OutlineHints hints )
+ {
+ if ( hints && hints->memory )
+ {
+ FT_Memory memory = hints->memory;
+ AF_Dimension dim;
+
+ /* note that we don't need to free the segment and edge
+ * buffers, since they're really within the hints->points array
+ */
+ for ( dim = 0; dim < 2; dim++ )
+ {
+ AF_AxisHints axis = &hints->axis[ dim ];
+
+ axis->num_segments = 0;
+ axis->num_edges = 0;
+ axis->segments = NULL;
+ axis->edges = NULL;
+ }
+
+ FT_FREE( hints->contours );
+ hints->max_contours = 0;
+ hints->num_contours = 0;
+
+ FT_FREE( hints->points );
+ hints->num_points = 0;
+ hints->max_points = 0;
+
+ hints->memory = NULL;
+ }
+ }
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_outline_hints_reset( AF_OutlineHints hints,
+ FT_Outline* outline,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale )
+ {
+ FT_Error error = AF_Err_Ok;
+
+ FT_UInt old_max, new_max;
+
+ hints->num_points = 0;
+ hints->num_contours = 0;
+
+ hints->axis[0].num_segments = 0;
+ hints->axis[0].num_edges = 0;
+ hints->axis[1].num_segments = 0;
+ hints->axis[1].num_edges = 0;
+
+ /* first of all, reallocate the contours array when necessary
+ */
+ new_max = (FT_UInt) outline->n_contours;
+ old_max = hints->max_contours;
+ if ( new_max > old_max )
+ {
+ new_max = (new_max + 3) & ~3;
+
+ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
+ goto Exit;
+
+ hints->max_contours = new_max;
+ }
+
+ /* then, reallocate the points, segments & edges arrays if needed --
+ * note that we reserved two additional point positions, used to
+ * hint metrics appropriately
+ */
+ new_max = (FT_UInt)( outline->n_points + 2 );
+ 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;
+
+#undef OFF_INCREMENT
+#define OFF_INCREMENT( _off, _type, _count ) \
+ ((((_off) + sizeof(_type)) & ~(sizeof(_type)) + ((_count)*sizeof(_type)))
+
+ off1 = OFF_INCREMENT( 0, AF_PointRec, new_max );
+ off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max );
+ 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;
+ }
+
+ /* 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->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. */
+ /* */
+ hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_UP;
+ hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_LEFT;
+
+ if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
+ {
+ hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_DOWN;
+ hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_RIGHT;
+ }
+
+ hints->x_scale = x_scale;
+ hints->y_scale = y_scale;
+
+ points = hints->points;
+ if ( hints->num_points == 0 )
+ goto Exit;
+
+ {
+ /* do one thing at a time -- it is easier to understand, and */
+ /* the code is clearer */
+ AF_Point point;
+ AF_Point point_limit = points + hints->num_points;
+
+
+ /* compute coordinates & bezier flags */
+ {
+ FT_Vector* vec = outline->points;
+ char* tag = outline->tags;
+
+
+ for ( point = points; point < point_limit; point++, vec++, tag++ )
+ {
+ point->fx = vec->x;
+ point->fy = vec->y;
+ point->ox = point->x = FT_MulFix( vec->x, x_scale );
+ point->oy = point->y = FT_MulFix( vec->y, y_scale );
+
+ switch ( FT_CURVE_TAG( *tag ) )
+ {
+ case FT_CURVE_TAG_CONIC:
+ point->flags = AF_FLAG_CONIC;
+ break;
+ case FT_CURVE_TAG_CUBIC:
+ point->flags = AF_FLAG_CUBIC;
+ break;
+ default:
+ point->flags = 0;
+ ;
+ }
+ }
+ }
+
+ /* compute `next' and `prev' */
+ {
+ FT_Int contour_index;
+ AF_Point prev;
+ AF_Point first;
+ AF_Point end;
+
+
+ contour_index = 0;
+
+ first = points;
+ end = points + outline->contours[0];
+ prev = end;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->prev = prev;
+ if ( point < end )
+ {
+ point->next = point + 1;
+ prev = point;
+ }
+ else
+ {
+ point->next = first;
+ contour_index++;
+ if ( point + 1 < point_limit )
+ {
+ end = points + source->contours[contour_index];
+ first = point + 1;
+ prev = end;
+ }
+ }
+ }
+ }
+
+ /* set-up the contours array */
+ {
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ short* end = outline->contours;
+ short idx = 0;
+
+
+ for ( ; contour < contour_limit; contour++, end++ )
+ {
+ contour[0] = points + idx;
+ idx = (short)( end[0] + 1 );
+ }
+ }
+
+ /* compute directions of in & out vectors */
+ {
+ for ( point = points; point < point_limit; point++ )
+ {
+ AF_Point prev;
+ AF_Point next;
+ FT_Pos in_x, in_y, out_x, out_y;
+
+
+ prev = point->prev;
+ in_x = point->fx - prev->fx;
+ in_y = point->fy - prev->fy;
+
+ point->in_dir = af_compute_direction( in_x, in_y );
+
+ next = point->next;
+ out_x = next->fx - point->fx;
+ out_y = next->fy - point->fy;
+
+ point->out_dir = af_compute_direction( out_x, out_y );
+
+ if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
+ {
+ Is_Weak_Point:
+ point->flags |= AF_FLAG_WEAK_INTERPOLATION;
+ }
+ else if ( point->out_dir == point->in_dir )
+ {
+ AF_Angle angle_in, angle_out, delta;
+
+
+ if ( point->out_dir != AF_DIR_NONE )
+ goto Is_Weak_Point;
+
+ angle_in = af_angle( in_x, in_y );
+ angle_out = af_angle( out_x, out_y );
+ delta = af_angle_diff( angle_in, angle_out );
+
+ if ( delta < 2 && delta > -2 )
+ goto Is_Weak_Point;
+ }
+ else if ( point->in_dir == -point->out_dir )
+ goto Is_Weak_Point;
+ }
+ }
+ }
+
+ /* compute inflection points
+ */
+ af_outline_hints_compute_inflections( hints );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_outline_hints_setup_uv( AF_OutlineHints hints,
+ AF_UV source )
+ {
+ AF_Point point = hints->points;
+ AF_Point point_limit = point + hints->num_points;
+
+
+ switch ( source )
+ {
+ case AF_UV_FXY:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->fx;
+ point->v = point->fy;
+ }
+ break;
+
+ case AF_UV_FYX:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->fy;
+ point->v = point->fx;
+ }
+ break;
+
+ case AF_UV_OXY:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->ox;
+ point->v = point->oy;
+ }
+ break;
+
+ case AF_UV_OYX:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->oy;
+ point->v = point->ox;
+ }
+ break;
+
+ case AF_UV_YX:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->y;
+ point->v = point->x;
+ }
+ break;
+
+ case AF_UV_OX:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->x;
+ point->v = point->ox;
+ }
+ break;
+
+ case AF_UV_OY:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->y;
+ point->v = point->oy;
+ }
+ break;
+
+ default:
+ for ( ; point < point_limit; point++ )
+ {
+ point->u = point->x;
+ point->v = point->y;
+ }
+ }
+ }
+
+
+
--- /dev/null
+++ b/src/autofit/afhints.h
@@ -1,0 +1,233 @@
+#ifndef __AFHINTS_H__
+#define __AFHINTS_H__
+
+#include "aftypes.h"
+
+FT_BEGIN_HEADER
+
+ /*
+ * The definition of outline hints. These are shared by all
+ * script analysis routines
+ *
+ */
+
+ typedef enum
+ {
+ AF_DIMENSION_HORZ = 0, /* x coordinates, i.e. vertical segments & edges */
+ AF_DIMENSION_VERT = 1, /* y coordinates, i.e. horizontal segments & edges */
+
+ AF_DIMENSION_MAX /* do not remove */
+
+ } AF_Dimension;
+
+
+ /* hint directions -- the values are computed so that two vectors are */
+ /* in opposite directions iff `dir1+dir2 == 0' */
+ typedef enum
+ {
+ AF_DIR_NONE = 4,
+ AF_DIR_RIGHT = 1,
+ AF_DIR_LEFT = -1,
+ AF_DIR_UP = 2,
+ AF_DIR_DOWN = -2
+
+ } AF_Direction;
+
+
+ /* point hint flags */
+ typedef enum
+ {
+ AF_FLAG_NONE = 0,
+
+ /* point type flags */
+ AF_FLAG_CONIC = (1 << 0),
+ AF_FLAG_CUBIC = (1 << 1),
+ AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC,
+
+ /* point extremum flags */
+ AF_FLAG_EXTREMA_X = (1 << 2),
+ AF_FLAG_EXTREMA_Y = (1 << 3),
+
+ /* point roundness flags */
+ AF_FLAG_ROUND_X = (1 << 4),
+ AF_FLAG_ROUND_Y = (1 << 5),
+
+ /* point touch flags */
+ AF_FLAG_TOUCH_X = (1 << 6),
+ AF_FLAG_TOUCH_Y = (1 << 7),
+
+ /* candidates for weak interpolation have this flag set */
+ AF_FLAG_WEAK_INTERPOLATION = (1 << 8),
+
+ /* all inflection points in the outline have this flag set */
+ AF_FLAG_INFLECTION = (1 << 9)
+
+ } AF_Flags;
+
+
+ /* edge hint flags */
+ typedef enum
+ {
+ AF_EDGE_NORMAL = 0,
+ AF_EDGE_ROUND = (1 << 0),
+ AF_EDGE_SERIF = (1 << 1),
+ AF_EDGE_DONE = (1 << 2)
+
+ } AF_Edge_Flags;
+
+
+
+ typedef struct AF_PointRec_* AF_Point;
+ typedef struct AF_SegmentRec_* AF_Segment;
+ typedef struct AF_EdgeRec_* AF_Edge;
+
+
+ typedef struct AF_PointRec_
+ {
+ AF_Flags flags; /* point flags used by hinter */
+ FT_Pos ox, oy; /* original, scaled position */
+ FT_Pos 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 */
+
+ AF_Direction in_dir; /* direction of inwards vector */
+ AF_Direction out_dir; /* direction of outwards vector */
+
+ AF_Point next; /* next point in contour */
+ AF_Point prev; /* previous point in contour */
+
+ } AF_PointRec;
+
+
+ typedef struct AF_SegmentRec_
+ {
+ AF_Edge_Flags flags; /* edge/segment flags for this segment */
+ AF_Direction dir; /* segment direction */
+ FT_Pos pos; /* position of segment */
+ FT_Pos min_coord; /* minimum coordinate of segment */
+ FT_Pos max_coord; /* maximum coordinate of segment */
+
+ AF_Edge edge; /* the segment's parent edge */
+ AF_Segment edge_next; /* link to next segment in parent edge */
+
+ AF_Segment link; /* link segment */
+ AF_Segment serif; /* primary segment for serifs */
+ FT_Pos num_linked; /* number of linked segments */
+ FT_Pos score;
+
+ AF_Point first; /* first point in edge segment */
+ AF_Point last; /* last point in edge segment */
+ AF_Point* contour; /* ptr to first point of segment's contour */
+
+ } AF_SegmentRec;
+
+
+ typedef struct AF_EdgeRec_
+ {
+ FT_Pos fpos; /* original, unscaled position (font units) */
+ FT_Pos opos; /* original, scaled position */
+ FT_Pos pos; /* current position */
+
+ AF_Edge_Flags flags; /* edge flags */
+ AF_Direction dir; /* edge direction */
+ FT_Fixed scale; /* used to speed up interpolation between edges */
+ FT_Pos* blue_edge; /* non-NULL if this is a blue edge */
+
+ AF_Edge link;
+ AF_Edge serif;
+ FT_Int num_linked;
+
+ FT_Int score;
+
+ AF_Segment first;
+ AF_Segment last;
+
+
+ } AF_EdgeRec;
+
+
+ typedef struct AF_AxisHintsRec_
+ {
+ FT_Int num_segments;
+ AF_Segment segments;
+
+ FT_Int num_edges;
+ AF_Edge edges;
+
+ AF_Direction major_dir;
+
+ } AF_AxisHintsRec, *AF_AxisHints;
+
+
+ typedef struct AF_OutlineHintsRec_
+ {
+ FT_Memory memory;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+ FT_Pos edge_distance_threshold;
+
+ FT_Int max_points;
+ FT_Int num_points;
+ AF_Point points;
+
+ FT_Int max_contours;
+ FT_Int num_contours;
+ AF_Point* contours;
+
+ AF_AxisHintsRec axis[ AF_DIMENSION_MAX ];
+
+ } AF_OutlineHintsRec;
+
+
+
+
+ FT_LOCAL( AF_Direction )
+ af_direction_compute( FT_Pos dx,
+ FT_Pos dy );
+
+
+ FT_LOCAL( void )
+ af_outline_hints_init( AF_OutlineHints hints );
+
+
+ /* used to set the (u,v) fields of each AF_Point in a AF_OutlineHints
+ * object.
+ */
+ typedef enum AH_UV_
+ {
+ AH_UV_FXY, /* (u,v) = (fx,fy) */
+ AH_UV_FYX, /* (u,v) = (fy,fx) */
+ AH_UV_OXY, /* (u,v) = (ox,oy) */
+ AH_UV_OYX, /* (u,v) = (oy,ox) */
+ AH_UV_OX, /* (u,v) = (ox,x) */
+ AH_UV_OY, /* (u,v) = (oy,y) */
+ AH_UV_YX, /* (u,v) = (y,x) */
+ AH_UV_XY /* (u,v) = (x,y) * should always be last! */
+
+ } AH_UV;
+
+ FT_LOCAL_DEF( void )
+ af_outline_hints_setup_uv( AF_OutlineHints hints,
+ AF_UV source );
+
+
+ /* recomputes all AF_Point in a AF_OutlineHints from the definitions
+ * in a source outline
+ */
+ FT_LOCAL( FT_Error )
+ af_outline_hints_reset( AF_OutlineHints hints,
+ FT_Outline* outline,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale );
+
+ FT_LOCAL( void )
+ af_outline_hints_done( AF_OutlineHints hints );
+
+
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFHINTS_H__ */
--- /dev/null
+++ b/src/autofit/aflatin.c
@@ -1,0 +1,755 @@
+#include "aflatin.h"
+
+ FT_LOCAL_DEF( void )
+ af_latin_hints_compute_segments( AF_OutlineHints 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_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ AF_Direction major_dir;
+
+#ifdef AF_HINT_METRICS
+ AF_Point min_point = 0;
+ AF_Point max_point = 0;
+ FT_Pos min_coord = 32000;
+ FT_Pos max_coord = -32000;
+#endif
+
+ major_dir = ABS( axis->major_dir );
+ segment_dir = major_dir;
+
+ /* set up (u,v) in each point */
+ af_setup_uv( outline, (dim == AF_DIMENSION_HORZ)
+ ? AF_UV_FXY,
+ : AF_UV_FYX );
+
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point point = contour[0];
+ AF_Point last = point->prev;
+ int on_edge = 0;
+ FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */
+ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
+ FT_Bool passed;
+
+
+#ifdef AF_HINT_METRICS
+ if ( point->u < min_coord )
+ {
+ min_coord = point->u;
+ min_point = point;
+ }
+ if ( point->u > max_coord )
+ {
+ max_coord = point->u;
+ max_point = point;
+ }
+#endif
+
+ if ( point == last ) /* skip singletons -- just in case */
+ continue;
+
+ if ( ABS( last->out_dir ) == major_dir &&
+ ABS( point->out_dir ) == major_dir )
+ {
+ /* we are already on an edge, try to locate its start */
+ last = point;
+
+ for (;;)
+ {
+ point = point->prev;
+ if ( ABS( point->out_dir ) != major_dir )
+ {
+ point = point->next;
+ break;
+ }
+ if ( point == last )
+ break;
+ }
+ }
+
+ last = point;
+ passed = 0;
+
+ for (;;)
+ {
+ FT_Pos u, v;
+
+
+ if ( on_edge )
+ {
+ u = point->u;
+ if ( u < min_pos )
+ min_pos = u;
+ if ( u > max_pos )
+ max_pos = u;
+
+ if ( point->out_dir != segment_dir || point == last )
+ {
+ /* we are just leaving an edge; record a new segment! */
+ segment->last = point;
+ segment->pos = ( min_pos + max_pos ) >> 1;
+
+ /* a segment is round if either its first or last point */
+ /* is a control point */
+ if ( ( segment->first->flags | point->flags ) &
+ AF_FLAG_CONTROL )
+ segment->flags |= AF_EDGE_ROUND;
+
+ /* compute segment size */
+ min_pos = max_pos = point->v;
+
+ v = segment->first->v;
+ if ( v < min_pos )
+ min_pos = v;
+ if ( v > max_pos )
+ max_pos = v;
+
+ segment->min_coord = min_pos;
+ segment->max_coord = max_pos;
+
+ on_edge = 0;
+ num_segments++;
+ segment++;
+ /* fallthrough */
+ }
+ }
+
+ /* now exit if we are at the start/end point */
+ if ( point == last )
+ {
+ if ( passed )
+ break;
+ passed = 1;
+ }
+
+ if ( !on_edge && ABS( point->out_dir ) == major_dir )
+ {
+ /* this is the start of a new segment! */
+ segment_dir = point->out_dir;
+
+ /* clear all segment fields */
+ FT_ZERO( segment );
+
+ segment->dir = segment_dir;
+ segment->flags = AF_EDGE_NORMAL;
+ min_pos = max_pos = point->u;
+ segment->first = point;
+ segment->last = point;
+ segment->contour = contour;
+ segment->score = 32000;
+ segment->link = NULL;
+ on_edge = 1;
+
+#ifdef AF_HINT_METRICS
+ if ( point == max_point )
+ max_point = 0;
+
+ if ( point == min_point )
+ min_point = 0;
+#endif
+ }
+
+ point = point->next;
+ }
+
+ } /* contours */
+
+#ifdef AF_HINT_METRICS
+ /* we need to ensure that there are edges on the left-most and */
+ /* right-most points of the glyph in order to hint the metrics; */
+ /* we do this by inserting fake segments when needed */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ AF_Point point = hints->points;
+ AF_Point point_limit = point + hints->num_points;
+
+ FT_Pos min_pos = 32000;
+ FT_Pos max_pos = -32000;
+
+
+ min_point = 0;
+ max_point = 0;
+
+ /* compute minimum and maximum points */
+ for ( ; point < point_limit; point++ )
+ {
+ FT_Pos x = point->fx;
+
+
+ if ( x < min_pos )
+ {
+ min_pos = x;
+ min_point = point;
+ }
+ if ( x > max_pos )
+ {
+ max_pos = x;
+ max_point = point;
+ }
+ }
+
+ /* insert minimum segment */
+ if ( min_point )
+ {
+ /* clear all segment fields */
+ FT_ZERO( segment );
+
+ segment->dir = segment_dir;
+ segment->flags = AF_EDGE_NORMAL;
+ segment->first = min_point;
+ segment->last = min_point;
+ segment->pos = min_pos;
+ segment->score = 32000;
+ segment->link = NULL;
+
+ num_segments++;
+ segment++;
+ }
+
+ /* insert maximum segment */
+ if ( max_point )
+ {
+ /* clear all segment fields */
+ FT_ZERO( segment );
+
+ segment->dir = segment_dir;
+ segment->flags = AF_EDGE_NORMAL;
+ segment->first = max_point;
+ segment->last = max_point;
+ segment->pos = max_pos;
+ segment->score = 32000;
+ segment->link = NULL;
+
+ num_segments++;
+ segment++;
+ }
+ }
+#endif /* AF_HINT_METRICS */
+
+ axis->num_segments = num_segments;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin_hints_link_segments( AF_OutlineHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Direction major_dir = axis->major_dir;
+ AF_Segment seg1, seg2;
+
+ /* now compare each segment to the others */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ /* the fake segments are introduced to hint the metrics -- */
+ /* we must never link them to anything */
+ if ( seg1->first == seg1->last || seg1->dir != major_dir )
+ continue;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 )
+ {
+ FT_Pos pos1 = seg1->pos;
+ FT_Pos pos2 = seg2->pos;
+ FT_Pos dist = pos2 - pos1;
+
+
+ if ( dist < 0 )
+ continue;
+
+ {
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len, score;
+
+
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
+
+ if ( max > seg2->max_coord )
+ max = seg2->max_coord;
+
+ len = max - min;
+ if ( len >= 8 )
+ {
+ score = dist + 3000 / len;
+
+ if ( score < seg1->score )
+ {
+ seg1->score = score;
+ seg1->link = seg2;
+ }
+
+ if ( score < seg2->score )
+ {
+ seg2->score = score;
+ seg2->link = seg1;
+ }
+ }
+ }
+ }
+ }
+
+ /* now, compute the `serif' segments */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ seg2 = seg1->link;
+
+ if ( seg2 )
+ {
+ seg2->num_linked++;
+ if ( seg2->link != seg1 )
+ {
+ seg1->link = 0;
+ seg1->serif = seg2->link;
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin_hints_compute_edges( AF_OutlineHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->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;
+ AF_Segment seg;
+
+ AF_Direction up_dir;
+ FT_Fixed scale;
+ FT_Pos edge_distance_threshold;
+
+
+ scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
+ : hints->y_scale;
+
+ up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
+ : AF_DIR_RIGHT;
+
+ /*********************************************************************/
+ /* */
+ /* We will begin by generating a sorted table of edges for the */
+ /* current direction. To do so, we simply scan each segment and try */
+ /* to find an edge in our table that corresponds to its position. */
+ /* */
+ /* If no edge is found, we create and insert a new edge in the */
+ /* sorted table. Otherwise, we simply add the segment to the edge's */
+ /* list which will be processed in the second step to compute the */
+ /* edge's properties. */
+ /* */
+ /* Note that the edges table is sorted along the segment/edge */
+ /* position. */
+ /* */
+ /*********************************************************************/
+
+ edge_distance_threshold = FT_MulFix( outline->edge_distance_threshold,
+ scale );
+ if ( edge_distance_threshold > 64 / 4 )
+ edge_distance_threshold = 64 / 4;
+
+ edge_distance_threshold = FT_DivFix( edge_distance_threshold,
+ scale );
+
+ edge_limit = edges;
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge found = 0;
+
+
+ /* look for an edge corresponding to the segment */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - edge->fpos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( dist < edge_distance_threshold )
+ {
+ found = edge;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ /* 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_MEM_ZERO( edge, sizeof ( *edge ) );
+
+ /* add the segment to the new edge's list */
+ edge->first = seg;
+ edge->last = seg;
+ edge->fpos = seg->pos;
+ edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ seg->edge_next = seg;
+ }
+ else
+ {
+ /* 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;
+ }
+ }
+ *p_num_edges = (FT_Int)( edge_limit - edges );
+
+
+ /*********************************************************************/
+ /* */
+ /* Good, we will now compute each edge's properties according to */
+ /* segments found on its position. Basically, these are: */
+ /* */
+ /* - edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straight or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /*********************************************************************/
+
+ /* first of all, set the `edge' field in each segment -- this is */
+ /* required in order to compute edge links */
+
+ /* Note that I've tried to remove this loop, setting
+ * the "edge" field of each segment directly in the
+ * 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 );
+ }
+
+ /* 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
+ {
+ FT_Bool is_serif;
+
+
+ /* 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 )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
+
+ 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;
+
+#ifdef FT_CONFIG_CHESTER_SERIF
+ if ( is_serif )
+ {
+ edge->serif = edge2;
+ edge2->flags |= AF_EDGE_SERIF;
+ }
+ else
+ edge->link = edge2;
+#else /* !FT_CONFIG_CHESTER_SERIF */
+ if ( is_serif )
+ edge->serif = edge2;
+ else
+ edge->link = edge2;
+#endif /* !FT_CONFIG_CHESTER_SERIF */
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+
+ /* set the round/straight flags */
+ edge->flags = AF_EDGE_NORMAL;
+
+ if ( is_round > 0 && is_round >= is_straight )
+ edge->flags |= AF_EDGE_ROUND;
+
+ /* set the edge's main direction */
+ edge->dir = AF_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 */
+
+ if ( edge->serif && edge->link )
+ edge->serif = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* af_outline_detect_features */
+ /* */
+ /* <Description> */
+ /* Performs feature detection on a given AF_OutlineRec object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ af_latin_hints_detect_features( AF_OutlineHints 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 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* af_outline_compute_blue_edges */
+ /* */
+ /* <Description> */
+ /* Computes the `blue edges' in a given outline (i.e. those that must */
+ /* be snapped to a blue zone edge (top or bottom). */
+ /* */
+ FT_LOCAL_DEF( void )
+ af_latin_hints_compute_blue_edges( AF_OutlineHints outline,
+ AF_Face_Globals face_globals )
+ {
+ AF_Edge edge = outline->horz_edges;
+ AF_Edge edge_limit = edge + outline->num_hedges;
+ AF_Globals globals = &face_globals->design;
+ FT_Fixed y_scale = outline->y_scale;
+
+ FT_Bool blue_active[AF_BLUE_MAX];
+
+
+ /* compute which blue zones are active, i.e. have their scaled */
+ /* size < 3/4 pixels */
+ {
+ AF_Blue blue;
+ FT_Bool check = 0;
+
+
+ for ( blue = AF_BLUE_CAPITAL_TOP; blue < AF_BLUE_MAX; blue++ )
+ {
+ FT_Pos ref, shoot, dist;
+
+
+ ref = globals->blue_refs[blue];
+ shoot = globals->blue_shoots[blue];
+ dist = ref - shoot;
+ if ( dist < 0 )
+ dist = -dist;
+
+ blue_active[blue] = 0;
+
+ if ( FT_MulFix( dist, y_scale ) < 48 )
+ {
+ blue_active[blue] = 1;
+ check = 1;
+ }
+ }
+
+ /* return immediately if no blue zone is active */
+ if ( !check )
+ return;
+ }
+
+ /* for each horizontal edge search the blue zone which is closest */
+ for ( ; edge < edge_limit; edge++ )
+ {
+ AF_Blue blue;
+ FT_Pos* best_blue = 0;
+ FT_Pos best_dist; /* initial threshold */
+
+
+ /* compute the initial threshold as a fraction of the EM size */
+ best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale );
+
+#ifdef FT_CONFIG_CHESTER_SMALL_F
+ if ( best_dist > 64 / 2 )
+ best_dist = 64 / 2;
+#else
+ if ( best_dist > 64 / 4 )
+ best_dist = 64 / 4;
+#endif
+
+ for ( blue = AF_BLUE_CAPITAL_TOP; blue < AF_BLUE_MAX; blue++ )
+ {
+ /* if it is a top zone, check for right edges -- if it is a bottom */
+ /* zone, check for left edges */
+ /* */
+ /* of course, that's for TrueType XXX */
+ FT_Bool is_top_blue =
+ FT_BOOL( AF_IS_TOP_BLUE( blue ) );
+ FT_Bool is_major_dir =
+ FT_BOOL( edge->dir == outline->horz_major_dir );
+
+
+ if ( !blue_active[blue] )
+ continue;
+
+ /* if it is a top zone, the edge must be against the major */
+ /* direction; if it is a bottom zone, it must be in the major */
+ /* direction */
+ if ( is_top_blue ^ is_major_dir )
+ {
+ FT_Pos dist;
+ FT_Pos* blue_pos = globals->blue_refs + blue;
+
+
+ /* first of all, compare it to the reference position */
+ dist = edge->fpos - *blue_pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, y_scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = blue_pos;
+ }
+
+ /* now, compare it to the overshoot position if the edge is */
+ /* rounded, and if the edge is over the reference position of a */
+ /* top zone, or under the reference position of a bottom zone */
+ if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
+ {
+ FT_Bool is_under_ref = FT_BOOL( edge->fpos < *blue_pos );
+
+
+ if ( is_top_blue ^ is_under_ref )
+ {
+ blue_pos = globals->blue_shoots + blue;
+ dist = edge->fpos - *blue_pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, y_scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = blue_pos;
+ }
+ }
+ }
+ }
+ }
+
+ if ( best_blue )
+ edge->blue_edge = best_blue;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* af_outline_scale_blue_edges */
+ /* */
+ /* <Description> */
+ /* This function must be called before hinting in order to re-adjust */
+ /* the contents of the detected edges (basically change the `blue */
+ /* edge' pointer from `design units' to `scaled ones'). */
+ /* */
+ FT_LOCAL_DEF( void )
+ af_outline_hints_scale_blue_edges( AF_OutlineHints hints ) outline,
+ {
+ AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
+ AF_Edge edge = axis->edges;
+ AF_Edge edge_limit = edge + axis->num_edges;
+ FT_Pos delta;
+
+
+ delta = globals->scaled.blue_refs - globals->design.blue_refs;
+
+ for ( ; edge < edge_limit; edge++ )
+ {
+ if ( edge->blue_edge )
+ edge->blue_edge += delta;
+ }
+ }
+
--- /dev/null
+++ b/src/autofit/aflatin.h
@@ -1,0 +1,89 @@
+#ifndef __AFLATIN_H__
+#define __AFLATIN_H__
+
+#include "afhints.h"
+
+FT_BEGIN_HEADER
+
+ /*
+ * the latin-specific script class
+ *
+ */
+ FT_LOCAL( const FT_ScriptClassRec ) af_latin_script_class;
+
+ /*
+ * the following declarations could be embedded in the file "aflatin.c"
+ * they've been made semi-public to allow alternate script hinters to
+ * re-use some of them
+ */
+
+ /*
+ * Latin (global) metrics management
+ *
+ */
+
+#define AF_LATIN_MAX_WIDTHS 16
+#define AF_LATIN_MAX_BLUES 32
+
+ typedef struct AF_LatinAxisRec_
+ {
+ FT_Fixed scale;
+ FT_Pos delta;
+
+ FT_UInt width_count;
+ AF_WidthRec widths[ AF_LATIN_MAX_WIDTHS ];
+
+ /* ignored for horizontal metrics */
+ FT_Bool control_overshoot;
+ FT_UInt blue_count;
+ AF_WidthRec blue_refs [ AF_MAX_BLUES ];
+ AF_WidthRec blue_shoots[ AF_MAX_BLUES ];
+
+ } AF_LatinAxisRec, *AF_LatinAxis;
+
+ typedef struct AF_LatinMetricsRec_
+ {
+ AF_OutlineMetricsRec root;
+ AF_LatinAxisRec axis[ AF_DIMENSION_MAX ];
+
+ } AF_LatinMetricsRec, *AF_LatinMetrics;
+
+
+ FT_LOCAL( FT_Error )
+ af_latin_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face );
+
+ FT_LOCAL( void )
+ af_latin_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler );
+
+
+ /*
+ * Latin (glyph) hints management
+ *
+ */
+
+ FT_LOCAL(
+
+ FT_LOCAL( void )
+ af_latin_hints_compute_segments( AF_OutlineHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( void )
+ af_latin_hints_link_segments( AF_OutlineHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( void )
+ af_latin_hints_compute_edges( AF_OutlineHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( void )
+ af_latin_hints_init( AF_OutlineHints hints,
+ AF_Dimension dim );
+
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFLATIN_H__ */
--- /dev/null
+++ b/src/autofit/aftypes.h
@@ -1,0 +1,289 @@
+#ifndef __AFTYPES_H__
+#define __AFTYPES_H__
+
+FT_BEGIN_HEADER
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** D E B U G G I N G *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+#define xxAF_DEBUG
+
+#ifdef AF_DEBUG
+
+# include <stdio.h>
+# define AF_LOG( x ) printf ## x
+
+#else
+
+# define AF_LOG( x ) do ; while ( 0 ) /* nothing */
+
+#endif /* AF_DEBUG */
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** A N G L E T Y P E S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ /*
+ * Angle type. The auto-fitter doesn't need a very high angular accuracy,
+ * and this allows us to speed up some computations considerably with a
+ * light Cordic algorithm (see afangle.c)
+ *
+ */
+
+ typedef FT_Int AF_Angle;
+
+#define AF_ANGLE_PI 128
+#define AF_ANGLE_2PI (AF_ANGLE_PI*2)
+#define AF_ANGLE_PI2 (AF_ANGLE_PI/2)
+#define AF_ANGLE_PI4 (AF_ANGLE_PI/4)
+
+ /*
+ * compute the angle of a given 2-D vector
+ *
+ */
+ FT_LOCAL( AF_Angle )
+ af_angle( FT_Pos dx,
+ FT_Pos dy );
+
+
+ /*
+ * computes "angle2 - angle1", the result is always within
+ * the range [ -AF_ANGLE_PI .. AF_ANGLE_PI-1 ]
+ *
+ */
+ FT_LOCAL( AF_Angle )
+ af_angle_diff( AF_Angle angle1,
+ AF_Angle angle2 );
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** O U T L I N E S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ typedef struct AF_OutlineHintsRec_* AF_OutlineHints;
+
+ typedef struct AF_GlobalHintsRec_* AF_GlobalHints;
+
+ typedef struct AF_OutlineRec_
+ {
+ FT_Memory memory;
+ FT_Face face;
+ FT_OutlineRec outline;
+ FT_UInt outline_resolution;
+
+ FT_Int advance;
+ FT_UInt metrics_resolution;
+
+ AF_OutlineHints hints;
+
+ } AF_OutlineRec;
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** G L O B A L M E T R I C S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ /*
+ * the following define global metrics in a _single_ dimension
+ *
+ * the "blue_refs" and "blue_shoots" arrays are ignored in
+ * the horizontal dimension
+ */
+
+ typedef struct AF_WidthRec_
+ {
+ FT_Pos org; /* original position/width in font units */
+ FT_Pos cur; /* current/scaled position/width in device sub-pixels */
+ FT_Pos fit; /* current/fitted position/width in device sub-pixels */
+
+ } AF_WidthRec, *AF_Width;
+
+
+#define AF_MAX_WIDTHS 16
+#define AF_MAX_BLUES 32
+
+ typedef struct AF_GlobalMetricsRec_
+ {
+ FT_Int num_widths;
+ AF_WidthRec widths[ AF_MAX_WIDTHS ];
+
+ FT_Fixed scale; /* used to scale from org to cur with: */
+ FT_Pos delta; /* x_cur = x_org * scale + delta */
+
+ /* ignored for horizontal metrics */
+ AF_WidthRec blue_refs [ AF_MAX_BLUES ];
+ AF_WidthRec blue_shoots[ AF_MAX_BLUES ];
+
+ FT_Bool control_overshoot;
+
+ } AF_GlobalMetricsRec, *AF_GlobalMetrics;
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** S C A L E R S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ /*
+ * A scaler models the target pixel device that will receive the
+ * auto-hinted glyph image
+ *
+ */
+
+ typedef enum
+ {
+ AF_SCALER_FLAG_NO_HORIZONTAL = 1, /* disable horizontal hinting */
+ AF_SCALER_FLAG_NO_VERTICAL = 2, /* disable vertical hinting */
+ AF_SCALER_FLAG_NO_ADVANCE = 4 /* disable advance hinting */
+
+ } AF_ScalerFlags;
+
+
+ typedef struct AF_ScalerRec_
+ {
+ FT_Face face; /* source font face */
+ FT_Fixed x_scale; /* from font units to 1/64th device pixels */
+ FT_Fixed y_scale; /* from font units to 1/64th device pixels */
+ FT_Pos x_delta; /* in 1/64th device pixels */
+ FT_Pos y_delta; /* in 1/64th device pixels */
+ FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc.. */
+ FT_UInt32 flags; /* additionnal control flags, see above */
+
+ } AF_ScalerRec, *AF_Scaler;
+
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** S C R I P T S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ /*
+ * the list of know scripts. Each different script correspond to the
+ * following information:
+ *
+ * - a set of Unicode ranges to test wether the face supports the
+ * script
+ *
+ * - a specific global analyzer that will compute global metrics
+ * specific to the script.
+ *
+ * - a specific hinting routine
+ *
+ * all scripts should share the same analysis routine though
+ */
+ typedef enum
+ {
+ AF_SCRIPT_LATIN = 0,
+ /* add new scripts here */
+
+ AF_SCRIPT_MAX /* do not remove */
+
+ } AF_Script;
+
+
+ typedef struct AF_ScriptClassRec_ const* AF_ScriptClass;
+
+ /*
+ * root class for script-specific metrics
+ */
+ typedef struct AF_ScriptMetricsRec_
+ {
+ AF_ScriptClass script_class;
+ AF_GlobalMetricsRec horz_metrics;
+ AF_GlobalMetricsRec vert_metrics;
+
+ } AF_ScriptMetricsRec, *AF_ScriptMetrics;
+
+
+ /* this function parses a FT_Face to compute global metrics for
+ * a specific script
+ */
+ typedef FT_Error (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics metrics,
+ FT_Face face );
+
+ typedef void (*AF_Script_ScaleMetricsFunc)( AF_ScriptMetrics metrics,
+ AF_Scaler scaler );
+
+ typedef void (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics metrics );
+
+
+ typedef FT_Error (*AF_Script_InitHintsFunc)( AF_OutlineHints hints,
+ AF_Scaler scaler,
+ AF_ScriptMetrics metrics );
+
+ typedef void (*AF_Script_ApplyHintsFunc)( AF_OutlineHints hints );
+
+
+ typedef struct AF_Script_UniRangeRec_
+ {
+ FT_UInt32 first;
+ FT_UInt32 last;
+
+ } AF_Script_UniRangeRec, *AF_Script_UniRange;
+
+
+ typedef struct AF_ScriptClassRec_
+ {
+ AF_Script script;
+ AF_Scipt_UniRange script_uni_ranges; /* last must be { 0, 0 } */
+
+ FT_UInt script_metrics_size;
+ AF_Script_InitMetricsFunc script_metrics_init;
+ AF_Script_ScaleMetricsFunc script_metrics_scale;
+ AF_Script_DoneMetricsFunc script_metrics_done;
+
+ } AF_ScriptClassRec;
+
+
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** F A C E G L O B A L S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ /*
+ * models the global hints data for a given face, decomposed into
+ * script-specific items..
+ *
+ */
+ typedef struct AF_FaceGlobalsRec_
+ {
+ FT_Face face;
+ FT_UInt glyph_count; /* same as face->num_glyphs */
+ FT_Byte* glyph_scripts; /* maps each gindex to a script */
+
+ FT_ScriptMetrics metrics[ AF_SCRIPT_MAX ];
+
+ } AF_FaceGlobalsRec, *AF_FaceGlobals;
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFTYPES_H__ */
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -26,6 +26,7 @@
#include <ft2build.h>
#include FT_OUTLINE_H
#include FT_INTERNAL_OBJECTS_H
+#include FT_TRIGONOMETRY_H
/*************************************************************************/
@@ -654,5 +655,141 @@
FT_Vector_Transform( vec, matrix );
}
+
+
+ typedef FT_OrientationExtremumRec_
+ {
+ FT_Int index;
+ FT_Int pos;
+ FT_Int first;
+ FT_Int last;
+
+ } FT_OrientationExtremumRec;
+
+
+ static FT_Orientation
+ ft_orientation_extremum_compute( FT_OrientationExtremumRec* extremum,
+ FT_Outline* outline )
+ {
+ FT_Vector *point, *first, *last, *prev, *next;
+ FT_Vector* points = outline->points;
+ FT_Angle angle_in, angle_out;
+
+ /* compute the previous and next points in the same contour
+ */
+ point = points + extremum->index;
+ first = points + extremum->first;
+ last = points + extremum->last;
+
+ do
+ {
+ prev = ( point == first ) ? last : point-1;
+
+ if ( prev == point )
+ return FT_ORIENTATION_TRUETYPE; /* degenerate case */
+
+ } while ( prev->x != point->x || prev->y != point->y );
+
+ do
+ {
+ next = ( point == last ) ? first : point+1;
+
+ if ( next == point )
+ return FT_ORIENTATION_TRUETYPE; /* shouldn't happen */
+
+ } while ( next->x != point->x || next->y != point->y );
+
+ /* now, compute the orientation of the "out" vector relative
+ * to the "in" vector.
+ */
+ angle_in = FT_Atan2( point->x - prev->x, point->y - prev->y );
+ angle_out = FT_Atan2( next->x - point->x, next->y - point->y );
+
+ return ( FT_Angle_Diff( angle_in, angle_out ) >= 0 )
+ ? FT_ORIENTATION_TRUETYPE
+ : FT_ORIENTATION_POSTSCRIPT;
+ }
+
+
+ FT_EXPORT_DEF( FT_Orientation )
+ FT_Outline_Get_Orientation( FT_Outline* outline )
+ {
+ FT_Orientation result = FT_ORIENTATION_TRUETYPE;
+
+ if ( outline && outline->n_points > 0 )
+ {
+ FT_OrientationExtremumRec xmin, ymin, xmax, ymax;
+ FT_Int n;
+ FT_Int first, last;
+ FT_Vector* points = outline->points;
+
+ xmin.pos = ymin.pos = +32768L;
+ xmax.pos = ymax.pos = -32768L;
+
+ xmin.index = ymin.index = xmax.index = ymax.index = -1;
+
+ first = 0;
+ for ( n = 0; n < outline->n_contours; n++, first = last+1 )
+ {
+ last = outline->contours[n];
+
+ /* skip single-point contours, these are degenerated cases
+ */
+ if ( last > first+1 )
+ {
+ FT_Int i;
+
+ for ( i = first; i < last; i++ )
+ {
+ x = points[i].x;
+ y = points[i].y;
+
+ if ( x < xmin.pos )
+ {
+ xmin.pos = x;
+ xmin.index = i;
+ xmin.first = first;
+ xmin.last = last;
+ }
+ if ( x > xmax.pos )
+ {
+ xmax.pos = x;
+ xmax.index = i;
+ xmax.first = first;
+ xmax.last = last;
+ }
+ if ( y < ymin.pos )
+ {
+ ymin.pos = y;
+ ymin.index = i;
+ ymin.first = first;
+ ymin.last = last;
+ }
+ if ( y > ymax.pos )
+ {
+ ymax.pos = y;
+ ymax.index = i;
+ ymax.first = first;
+ ymax.last = last;
+ }
+ }
+ }
+
+ if ( xmin.index >= 0 )
+ result = ft_orientation_extremum_compute( &xmin, outline );
+
+ else if ( xmax.index >= 0 )
+ result = ft_orientation_extremum_compute( &xmax, outline );
+
+ else if ( ymin.index >= 0 )
+ result = ft_orientation_extremum_compute( &ymin, outline );
+
+ else if ( ymax.index >= 0 )
+ result = ft_orientation_extremum_compute( &ymax, outline );
+ }
+ }
+
+ return result;
+ }
/* END */