📄 pshalgo.c
字号:
FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
FT_Pos len = FT_MulFix( hint->org_len, scale );
FT_Int do_snapping;
FT_Pos fit_len;
PSH_AlignmentRec align;
/* ignore stem alignments when requested through the hint flags */
if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
( dimension == 1 && !glyph->do_vert_hints ) )
{
hint->cur_pos = pos;
hint->cur_len = len;
psh_hint_set_fitted( hint );
return;
}
/* perform stem snapping when requested - this is necessary
* for monochrome and LCD hinting modes only
*/
do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
( dimension == 1 && glyph->do_vert_snapping );
hint->cur_len = fit_len = len;
/* check blue zones for horizontal stems */
align.align = PSH_BLUE_ALIGN_NONE;
align.align_bot = align.align_top = 0;
if ( dimension == 1 )
psh_blues_snap_stem( &globals->blues,
hint->org_pos + hint->org_len,
hint->org_pos,
&align );
switch ( align.align )
{
case PSH_BLUE_ALIGN_TOP:
/* the top of the stem is aligned against a blue zone */
hint->cur_pos = align.align_top - fit_len;
break;
case PSH_BLUE_ALIGN_BOT:
/* the bottom of the stem is aligned against a blue zone */
hint->cur_pos = align.align_bot;
break;
case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
/* both edges of the stem are aligned against blue zones */
hint->cur_pos = align.align_bot;
hint->cur_len = align.align_top - align.align_bot;
break;
default:
{
PSH_Hint parent = hint->parent;
if ( parent )
{
FT_Pos par_org_center, par_cur_center;
FT_Pos cur_org_center, cur_delta;
/* ensure that parent is already fitted */
if ( !psh_hint_is_fitted( parent ) )
psh_hint_align( parent, globals, dimension, glyph );
/* keep original relation between hints, this is, use the */
/* scaled distance between the centers of the hints to */
/* compute the new position */
par_org_center = parent->org_pos + ( parent->org_len >> 1 );
par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
pos = par_cur_center + cur_delta - ( len >> 1 );
}
hint->cur_pos = pos;
hint->cur_len = fit_len;
/* Stem adjustment tries to snap stem widths to standard
* ones. This is important to prevent unpleasant rounding
* artefacts.
*/
if ( glyph->do_stem_adjust )
{
if ( len <= 64 )
{
/* the stem is less than one pixel; we will center it
* around the nearest pixel center
*/
#if 1
pos = FT_PIX_FLOOR( pos + ( len >> 1 ) );
#else
/* this seems to be a bug! */
pos = pos + FT_PIX_FLOOR( len >> 1 );
#endif
len = 64;
}
else
{
len = psh_dimension_quantize_len( dim, len, 0 );
}
}
/* now that we have a good hinted stem width, try to position */
/* the stem along a pixel grid integer coordinate */
hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len );
hint->cur_len = len;
}
}
if ( do_snapping )
{
pos = hint->cur_pos;
len = hint->cur_len;
if ( len < 64 )
len = 64;
else
len = FT_PIX_ROUND( len );
switch ( align.align )
{
case PSH_BLUE_ALIGN_TOP:
hint->cur_pos = align.align_top - len;
hint->cur_len = len;
break;
case PSH_BLUE_ALIGN_BOT:
hint->cur_len = len;
break;
case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
/* don't touch */
break;
default:
hint->cur_len = len;
if ( len & 64 )
pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32;
else
pos = FT_PIX_ROUND( pos + ( len >> 1 ) );
hint->cur_pos = pos - ( len >> 1 );
hint->cur_len = len;
}
}
psh_hint_set_fitted( hint );
#ifdef DEBUG_HINTER
if ( ps_debug_hint_func )
ps_debug_hint_func( hint, dimension );
#endif
}
}
#if 0 /* not used for now, experimental */
/*
* A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT)
* of stems
*/
static void
psh_hint_align_light( PSH_Hint hint,
PSH_Globals globals,
FT_Int dimension,
PSH_Glyph glyph )
{
PSH_Dimension dim = &globals->dimension[dimension];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
if ( !psh_hint_is_fitted( hint ) )
{
FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
FT_Pos len = FT_MulFix( hint->org_len, scale );
FT_Pos fit_len;
PSH_AlignmentRec align;
/* ignore stem alignments when requested through the hint flags */
if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
( dimension == 1 && !glyph->do_vert_hints ) )
{
hint->cur_pos = pos;
hint->cur_len = len;
psh_hint_set_fitted( hint );
return;
}
fit_len = len;
hint->cur_len = fit_len;
/* check blue zones for horizontal stems */
align.align = PSH_BLUE_ALIGN_NONE;
align.align_bot = align.align_top = 0;
if ( dimension == 1 )
psh_blues_snap_stem( &globals->blues,
hint->org_pos + hint->org_len,
hint->org_pos,
&align );
switch ( align.align )
{
case PSH_BLUE_ALIGN_TOP:
/* the top of the stem is aligned against a blue zone */
hint->cur_pos = align.align_top - fit_len;
break;
case PSH_BLUE_ALIGN_BOT:
/* the bottom of the stem is aligned against a blue zone */
hint->cur_pos = align.align_bot;
break;
case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
/* both edges of the stem are aligned against blue zones */
hint->cur_pos = align.align_bot;
hint->cur_len = align.align_top - align.align_bot;
break;
default:
{
PSH_Hint parent = hint->parent;
if ( parent )
{
FT_Pos par_org_center, par_cur_center;
FT_Pos cur_org_center, cur_delta;
/* ensure that parent is already fitted */
if ( !psh_hint_is_fitted( parent ) )
psh_hint_align_light( parent, globals, dimension, glyph );
par_org_center = parent->org_pos + ( parent->org_len / 2 );
par_cur_center = parent->cur_pos + ( parent->cur_len / 2 );
cur_org_center = hint->org_pos + ( hint->org_len / 2 );
cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
pos = par_cur_center + cur_delta - ( len >> 1 );
}
/* Stems less than one pixel wide are easy -- we want to
* make them as dark as possible, so they must fall within
* one pixel. If the stem is split between two pixels
* then snap the edge that is nearer to the pixel boundary
* to the pixel boundary.
*/
if ( len <= 64 )
{
if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
pos += psh_hint_snap_stem_side_delta ( pos, len );
}
/* Position stems other to minimize the amount of mid-grays.
* There are, in general, two positions that do this,
* illustrated as A) and B) below.
*
* + + + +
*
* A) |--------------------------------|
* B) |--------------------------------|
* C) |--------------------------------|
*
* Position A) (split the excess stem equally) should be better
* for stems of width N + f where f < 0.5.
*
* Position B) (split the deficiency equally) should be better
* for stems of width N + f where f > 0.5.
*
* It turns out though that minimizing the total number of lit
* pixels is also important, so position C), with one edge
* aligned with a pixel boundary is actually preferable
* to A). There are also more possibile positions for C) than
* for A) or B), so it involves less distortion of the overall
* character shape.
*/
else /* len > 64 */
{
FT_Fixed frac_len = len & 63;
FT_Fixed center = pos + ( len >> 1 );
FT_Fixed delta_a, delta_b;
if ( ( len / 64 ) & 1 )
{
delta_a = FT_PIX_FLOOR( center ) + 32 - center;
delta_b = FT_PIX_ROUND( center ) - center;
}
else
{
delta_a = FT_PIX_ROUND( center ) - center;
delta_b = FT_PIX_FLOOR( center ) + 32 - center;
}
/* We choose between B) and C) above based on the amount
* of fractinal stem width; for small amounts, choose
* C) always, for large amounts, B) always, and inbetween,
* pick whichever one involves less stem movement.
*/
if ( frac_len < 32 )
{
pos += psh_hint_snap_stem_side_delta ( pos, len );
}
else if ( frac_len < 48 )
{
FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos,
len );
if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) )
pos += side_delta;
else
pos += delta_b;
}
else
{
pos += delta_b;
}
}
hint->cur_pos = pos;
}
} /* switch */
psh_hint_set_fitted( hint );
#ifdef DEBUG_HINTER
if ( ps_debug_hint_func )
ps_debug_hint_func( hint, dimension );
#endif
}
}
#endif /* 0 */
static void
psh_hint_table_align_hints( PSH_Hint_Table table,
PSH_Globals globals,
FT_Int dimension,
PSH_Glyph glyph )
{
PSH_Hint hint;
FT_UInt count;
#ifdef DEBUG_HINTER
PSH_Dimension dim = &globals->dimension[dimension];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
if ( ps_debug_no_vert_hints && dimension == 0 )
{
ps_simple_scale( table, scale, delta, dimension );
return;
}
if ( ps_debug_no_horz_hints && dimension == 1 )
{
ps_simple_scale( table, scale, delta, dimension );
return;
}
#endif /* DEBUG_HINTER*/
hint = table->hints;
count = table->max_hints;
for ( ; count > 0; count--, hint++ )
psh_hint_align( hint, globals, dimension, glyph );
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** POINTS INTERPOLATION ROUTINES *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
#define PSH_ZONE_MIN -3200000L
#define PSH_ZONE_MAX +3200000L
#define xxDEBUG_ZONES
#ifdef DEBUG_ZONES
#include <stdio.h>
static void
psh_print_zone( PSH_Zone zone )
{
printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
zone->scale / 65536.0,
zone->delta / 64.0,
zone->min,
zone->max );
}
#else
#define psh_print_zone( x ) do { } while ( 0 )
#endif /* DEBUG_ZONES */
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** HINTER GLYPH MANAGEMENT *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
#if 1
#define psh_corner_is_flat ft_corner_is_flat
#define psh_corner_orientation ft_corner_orientation
#else
FT_LOCAL_DEF( FT_Int )
psh_corner_is_flat( FT_Pos x_in,
FT_Pos y_in,
FT_Pos x_out,
FT_Pos y_out )
{
FT_Pos ax = x_in;
FT_Pos ay = y_in;
FT_Pos d_in, d_out, d_corner;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -