📄 pshalgo.c
字号:
{
point->org_u = vec->x;
point->org_v = vec->y;
}
else
{
point->org_u = vec->y;
point->org_v = vec->x;
}
#ifdef DEBUG_HINTER
point->org_x = vec->x;
point->org_y = vec->y;
#endif
}
}
/* save hinted point coordinates back to outline */
static void
psh_glyph_save_points( PSH_Glyph glyph,
FT_Int dimension )
{
FT_UInt n;
PSH_Point point = glyph->points;
FT_Vector* vec = glyph->outline->points;
char* tags = glyph->outline->tags;
for ( n = 0; n < glyph->num_points; n++ )
{
if ( dimension == 0 )
vec[n].x = point->cur_u;
else
vec[n].y = point->cur_u;
if ( psh_point_is_strong( point ) )
tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
#ifdef DEBUG_HINTER
if ( dimension == 0 )
{
point->cur_x = point->cur_u;
point->flags_x = point->flags2 | point->flags;
}
else
{
point->cur_y = point->cur_u;
point->flags_y = point->flags2 | point->flags;
}
#endif
point++;
}
}
static FT_Error
psh_glyph_init( PSH_Glyph glyph,
FT_Outline* outline,
PS_Hints ps_hints,
PSH_Globals globals )
{
FT_Error error;
FT_Memory memory;
/* clear all fields */
FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
memory = glyph->memory = globals->memory;
/* allocate and setup points + contours arrays */
if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
goto Exit;
glyph->num_points = outline->n_points;
glyph->num_contours = outline->n_contours;
{
FT_UInt first = 0, next, n;
PSH_Point points = glyph->points;
PSH_Contour contour = glyph->contours;
for ( n = 0; n < glyph->num_contours; n++ )
{
FT_Int count;
PSH_Point point;
next = outline->contours[n] + 1;
count = next - first;
contour->start = points + first;
contour->count = (FT_UInt)count;
if ( count > 0 )
{
point = points + first;
point->prev = points + next - 1;
point->contour = contour;
for ( ; count > 1; count-- )
{
point[0].next = point + 1;
point[1].prev = point;
point++;
point->contour = contour;
}
point->next = points + first;
}
contour++;
first = next;
}
}
{
PSH_Point points = glyph->points;
PSH_Point point = points;
FT_Vector* vec = outline->points;
FT_UInt n;
for ( n = 0; n < glyph->num_points; n++, point++ )
{
FT_Int n_prev = (FT_Int)( point->prev - points );
FT_Int n_next = (FT_Int)( point->next - points );
FT_Pos dxi, dyi, dxo, dyo;
if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
point->flags = PSH_POINT_OFF;
dxi = vec[n].x - vec[n_prev].x;
dyi = vec[n].y - vec[n_prev].y;
point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi );
dxo = vec[n_next].x - vec[n].x;
dyo = vec[n_next].y - vec[n].y;
point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo );
/* detect smooth points */
if ( point->flags & PSH_POINT_OFF )
point->flags |= PSH_POINT_SMOOTH;
else if ( point->dir_in != PSH_DIR_NONE ||
point->dir_out != PSH_DIR_NONE )
{
if ( point->dir_in == point->dir_out )
point->flags |= PSH_POINT_SMOOTH;
}
else
{
FT_Angle angle_in, angle_out, diff;
angle_in = FT_Atan2( dxi, dyi );
angle_out = FT_Atan2( dxo, dyo );
diff = angle_in - angle_out;
if ( diff < 0 )
diff = -diff;
if ( diff > FT_ANGLE_PI )
diff = FT_ANGLE_2PI - diff;
if ( diff < FT_ANGLE_PI / 16 )
point->flags |= PSH_POINT_SMOOTH;
}
}
}
glyph->outline = outline;
glyph->globals = globals;
#ifdef COMPUTE_INFLEXS
psh_glyph_load_points( glyph, 0 );
psh_glyph_compute_inflections( glyph );
#endif /* COMPUTE_INFLEXS */
/* now deal with hints tables */
error = psh_hint_table_init( &glyph->hint_tables [0],
&ps_hints->dimension[0].hints,
&ps_hints->dimension[0].masks,
&ps_hints->dimension[0].counters,
memory );
if ( error )
goto Exit;
error = psh_hint_table_init( &glyph->hint_tables [1],
&ps_hints->dimension[1].hints,
&ps_hints->dimension[1].masks,
&ps_hints->dimension[1].counters,
memory );
if ( error )
goto Exit;
Exit:
return error;
}
/* compute all extrema in a glyph for a given dimension */
static void
psh_glyph_compute_extrema( PSH_Glyph glyph )
{
FT_UInt n;
/* first of all, compute all local extrema */
for ( n = 0; n < glyph->num_contours; n++ )
{
PSH_Point first = glyph->contours[n].start;
PSH_Point point, before, after;
if ( glyph->contours[n].count == 0 )
continue;
point = first;
before = point;
after = point;
do
{
before = before->prev;
if ( before == first )
goto Skip;
} while ( before->org_u == point->org_u );
first = point = before->next;
for (;;)
{
after = point;
do
{
after = after->next;
if ( after == first )
goto Next;
} while ( after->org_u == point->org_u );
if ( before->org_u < point->org_u )
{
if ( after->org_u < point->org_u )
{
/* local maximum */
goto Extremum;
}
}
else /* before->org_u > point->org_u */
{
if ( after->org_u > point->org_u )
{
/* local minimum */
Extremum:
do
{
psh_point_set_extremum( point );
point = point->next;
} while ( point != after );
}
}
before = after->prev;
point = after;
} /* for */
Next:
;
}
/* for each extremum, determine its direction along the */
/* orthogonal axis */
for ( n = 0; n < glyph->num_points; n++ )
{
PSH_Point point, before, after;
point = &glyph->points[n];
before = point;
after = point;
if ( psh_point_is_extremum( point ) )
{
do
{
before = before->prev;
if ( before == point )
goto Skip;
} while ( before->org_v == point->org_v );
do
{
after = after->next;
if ( after == point )
goto Skip;
} while ( after->org_v == point->org_v );
}
if ( before->org_v < point->org_v &&
after->org_v > point->org_v )
{
psh_point_set_positive( point );
}
else if ( before->org_v > point->org_v &&
after->org_v < point->org_v )
{
psh_point_set_negative( point );
}
Skip:
;
}
}
/* major_dir is the direction for points on the bottom/left of the stem; */
/* Points on the top/right of the stem will have a direction of */
/* -major_dir. */
static void
psh_hint_table_find_strong_point( PSH_Hint_Table table,
PSH_Point point,
FT_Int threshold,
FT_Int major_dir )
{
PSH_Hint* sort = table->sort;
FT_UInt num_hints = table->num_hints;
FT_Int point_dir = 0;
if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) )
point_dir = point->dir_in;
else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) )
point_dir = point->dir_out;
if ( point_dir )
{
FT_UInt flag;
for ( ; num_hints > 0; num_hints--, sort++ )
{
PSH_Hint hint = sort[0];
FT_Pos d;
if ( point_dir == major_dir )
{
flag = PSH_POINT_EDGE_MIN;
d = point->org_u - hint->org_pos;
if ( FT_ABS( d ) < threshold )
{
Is_Strong:
psh_point_set_strong( point );
point->flags2 |= flag;
point->hint = hint;
break;
}
}
else if ( point_dir == -major_dir )
{
flag = PSH_POINT_EDGE_MAX;
d = point->org_u - hint->org_pos - hint->org_len;
if ( FT_ABS( d ) < threshold )
goto Is_Strong;
}
}
}
#if 1
else if ( psh_point_is_extremum( point ) )
{
/* treat extrema as special cases for stem edge alignment */
FT_UInt min_flag, max_flag;
if ( major_dir == PSH_DIR_HORIZONTAL )
{
min_flag = PSH_POINT_POSITIVE;
max_flag = PSH_POINT_NEGATIVE;
}
else
{
min_flag = PSH_POINT_NEGATIVE;
max_flag = PSH_POINT_POSITIVE;
}
for ( ; num_hints > 0; num_hints--, sort++ )
{
PSH_Hint hint = sort[0];
FT_Pos d;
FT_Int flag;
if ( point->flags2 & min_flag )
{
flag = PSH_POINT_EDGE_MIN;
d = point->org_u - hint->org_pos;
if ( FT_ABS( d ) < threshold )
{
Is_Strong2:
point->flags2 |= flag;
point->hint = hint;
psh_point_set_strong( point );
break;
}
}
else if ( point->flags2 & max_flag )
{
flag = PSH_POINT_EDGE_MAX;
d = point->org_u - hint->org_pos - hint->org_len;
if ( FT_ABS( d ) < threshold )
goto Is_Strong2;
}
if ( point->org_u >= hint->org_pos &&
point->org_u <= hint->org_pos + hint->org_len )
{
point->hint = hint;
}
}
}
#endif /* 1 */
}
/* the accepted shift for strong points in fractional pixels */
#define PSH_STRONG_THRESHOLD 32
/* the maximum shift value in font units */
#define PSH_STRONG_THRESHOLD_MAXIMUM 30
/* find strong points in a glyph */
static void
psh_glyph_find_strong_points( PSH_Glyph glyph,
FT_Int dimension )
{
/* a point is `strong' if it is located on a stem edge and */
/* has an `in' or `out' tangent parallel to the hint's direction */
PSH_Hint_Table table = &glyph->hint_tables[dimension];
PS_Mask mask = table->hint_masks->masks;
FT_UInt num_masks = table->hint_masks->num_masks;
FT_UInt first = 0;
FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL
: PSH_DIR_HORIZONTAL;
PSH_Dimension dim = &glyph->globals->dimension[dimension];
FT_Fixed scale = dim->scale_mult;
FT_Int threshold;
threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale );
if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM )
threshold = PSH_STRONG_THRESHOLD_MAXIMUM;
/* process secondary hints to `selected' points */
if ( num_masks > 1 && glyph->num_points > 0 )
{
first = mask->end_point;
mask++;
for ( ; num_masks > 1; num_masks--, mask++ )
{
FT_UInt next;
FT_Int count;
next = mask->end_point;
count = next - first;
if ( count > 0 )
{
PSH_Point point = glyph->points + first;
psh_hint_table_activate_mask( table, mask );
for ( ; count > 0; count--, point++ )
psh_hint_table_find_strong_point( table, point,
threshold, major_dir );
}
first = next;
}
}
/* process primary hints for all points */
if ( num_masks == 1 )
{
FT_UInt count = glyph->num_points;
PSH_Point point = glyph->points;
psh_hint_table_activate_mask( table, table->hint_masks->masks );
for ( ; count > 0; count--, point++ )
{
if ( !psh_point_is_strong( point ) )
psh_hint_table_find_strong_point( table, point,
threshold, major_dir );
}
}
/* now, certain points may have been attached to a hint and */
/* not marked as strong; update their flags then */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -