"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_SERVICELAYOUT
parent
6d1d122dbc
commit
ccdd3bebdc
10 changed files with 2372 additions and 3 deletions
@ -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; |
||||
}
|
||||
|
@ -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; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
@ -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__ */ |
@ -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; |
||||
} |
||||
} |
||||
|
@ -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__ */ |
@ -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__ */ |
Loading…
Reference in new issue