* 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
This commit is contained in:
parent
d393ca3738
commit
d25ad56d78
17
ChangeLog
17
ChangeLog
@ -1,3 +1,16 @@
|
||||
2003-10-01 David Turner <david@freetype.org>
|
||||
|
||||
* 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 <wl@gnu.org>
|
||||
|
||||
* src/cid/cidload.c (cid_parse_dict): Skip token if no keyword is
|
||||
@ -21,9 +34,9 @@
|
||||
2003-09-29 David Turner <david@freetype.org>
|
||||
|
||||
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
|
||||
|
@ -389,6 +389,69 @@ FT_BEGIN_HEADER
|
||||
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 );
|
||||
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
|
@ -216,8 +216,8 @@ FT_BEGIN_HEADER
|
||||
FT_FACE(face)->internal->services. service_ ## id = \
|
||||
(FT_Pointer)( svc != NULL ? svc \
|
||||
: FT_SERVICE_UNAVAILABLE ); \
|
||||
*pptr = svc; \
|
||||
} \
|
||||
*pptr = svc; \
|
||||
FT_END_STMNT
|
||||
|
||||
|
||||
|
164
src/autofit/afangles.c
Normal file
164
src/autofit/afangles.c
Normal file
@ -0,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;
|
||||
}
|
||||
|
626
src/autofit/afhints.c
Normal file
626
src/autofit/afhints.c
Normal file
@ -0,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
233
src/autofit/afhints.h
Normal file
233
src/autofit/afhints.h
Normal file
@ -0,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__ */
|
755
src/autofit/aflatin.c
Normal file
755
src/autofit/aflatin.c
Normal file
@ -0,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;
|
||||
}
|
||||
}
|
||||
|
89
src/autofit/aflatin.h
Normal file
89
src/autofit/aflatin.h
Normal file
@ -0,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__ */
|
289
src/autofit/aftypes.h
Normal file
289
src/autofit/aftypes.h
Normal file
@ -0,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__ */
|
@ -26,6 +26,7 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_OUTLINE_H
|
||||
#include FT_INTERNAL_OBJECTS_H
|
||||
#include FT_TRIGONOMETRY_H
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
@ -655,4 +656,140 @@
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user