📄 pshalgo.c
字号:
if ( ax < 0 )
ax = -ax;
if ( ay < 0 )
ay = -ay;
d_in = ax + ay;
ax = x_out;
if ( ax < 0 )
ax = -ax;
ay = y_out;
if ( ay < 0 )
ay = -ay;
d_out = ax + ay;
ax = x_out + x_in;
if ( ax < 0 )
ax = -ax;
ay = y_out + y_in;
if ( ay < 0 )
ay = -ay;
d_corner = ax + ay;
return ( d_in + d_out - d_corner ) < ( d_corner >> 4 );
}
static FT_Int
psh_corner_orientation( FT_Pos in_x,
FT_Pos in_y,
FT_Pos out_x,
FT_Pos out_y )
{
FT_Int result;
/* deal with the trivial cases quickly */
if ( in_y == 0 )
{
if ( in_x >= 0 )
result = out_y;
else
result = -out_y;
}
else if ( in_x == 0 )
{
if ( in_y >= 0 )
result = -out_x;
else
result = out_x;
}
else if ( out_y == 0 )
{
if ( out_x >= 0 )
result = in_y;
else
result = -in_y;
}
else if ( out_x == 0 )
{
if ( out_y >= 0 )
result = -in_x;
else
result = in_x;
}
else /* general case */
{
long long delta = (long long)in_x * out_y - (long long)in_y * out_x;
if ( delta == 0 )
result = 0;
else
result = 1 - 2 * ( delta < 0 );
}
return result;
}
#endif /* !1 */
#ifdef COMPUTE_INFLEXS
/* compute all inflex points in a given glyph */
static void
psh_glyph_compute_inflections( PSH_Glyph glyph )
{
FT_UInt n;
for ( n = 0; n < glyph->num_contours; n++ )
{
PSH_Point first, start, end, before, after;
FT_Pos in_x, in_y, out_x, out_y;
FT_Int orient_prev, orient_cur;
FT_Int finished = 0;
/* we need at least 4 points to create an inflection point */
if ( glyph->contours[n].count < 4 )
continue;
/* compute first segment in contour */
first = glyph->contours[n].start;
start = end = first;
do
{
end = end->next;
if ( end == first )
goto Skip;
in_x = end->org_u - start->org_u;
in_y = end->org_v - start->org_v;
} while ( in_x == 0 && in_y == 0 );
/* extend the segment start whenever possible */
before = start;
do
{
do
{
start = before;
before = before->prev;
if ( before == first )
goto Skip;
out_x = start->org_u - before->org_u;
out_y = start->org_v - before->org_v;
} while ( out_x == 0 && out_y == 0 );
orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y );
} while ( orient_prev == 0 );
first = start;
in_x = out_x;
in_y = out_y;
/* 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;
out_x = after->org_u - end->org_u;
out_y = after->org_v - end->org_v;
} while ( out_x == 0 && out_y == 0 );
orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y );
} while ( orient_cur == 0 );
if ( ( orient_cur ^ orient_prev ) < 0 )
{
do
{
psh_point_set_inflex( start );
start = start->next;
}
while ( start != end );
psh_point_set_inflex( start );
}
start = end;
end = after;
orient_prev = orient_cur;
in_x = out_x;
in_y = out_y;
} while ( !finished );
Skip:
;
}
}
#endif /* COMPUTE_INFLEXS */
static void
psh_glyph_done( PSH_Glyph glyph )
{
FT_Memory memory = glyph->memory;
psh_hint_table_done( &glyph->hint_tables[1], memory );
psh_hint_table_done( &glyph->hint_tables[0], memory );
FT_FREE( glyph->points );
FT_FREE( glyph->contours );
glyph->num_points = 0;
glyph->num_contours = 0;
glyph->memory = 0;
}
static int
psh_compute_dir( FT_Pos dx,
FT_Pos dy )
{
FT_Pos ax, ay;
int result = PSH_DIR_NONE;
ax = ( dx >= 0 ) ? dx : -dx;
ay = ( dy >= 0 ) ? dy : -dy;
if ( ay * 12 < ax )
{
/* |dy| <<< |dx| means a near-horizontal segment */
result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT;
}
else if ( ax * 12 < ay )
{
/* |dx| <<< |dy| means a near-vertical segment */
result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN;
}
return result;
}
/* load outline point coordinates into hinter glyph */
static void
psh_glyph_load_points( PSH_Glyph glyph,
FT_Int dimension )
{
FT_Vector* vec = glyph->outline->points;
PSH_Point point = glyph->points;
FT_UInt count = glyph->num_points;
for ( ; count > 0; count--, point++, vec++ )
{
point->flags2 = 0;
point->hint = NULL;
if ( dimension == 0 )
{
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 == point->dir_out )
{
if ( point->dir_out != PSH_DIR_NONE ||
psh_corner_is_flat( dxi, dyi, dxo, dyo ) )
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -