📄 afcjk.c
字号:
{
FT_Bool is_serif;
/* check for roundness of segment */
if ( seg->flags & AF_EDGE_ROUND )
is_round++;
else
is_straight++;
/* 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 = AF_SEGMENT_DIST( seg, seg2 );
if ( seg_delta < edge_delta )
edge2 = seg2->edge;
}
else
edge2 = seg2->edge;
if ( is_serif )
{
edge->serif = edge2;
edge2->flags |= AF_EDGE_SERIF;
}
else
edge->link = edge2;
}
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;
/* get 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;
}
}
Exit:
return error;
}
static FT_Error
af_cjk_hints_detect_features( AF_GlyphHints hints,
AF_Dimension dim )
{
FT_Error error;
error = af_cjk_hints_compute_segments( hints, dim );
if ( !error )
{
af_cjk_hints_link_segments( hints, dim );
error = af_cjk_hints_compute_edges( hints, dim );
}
return error;
}
static FT_Error
af_cjk_hints_init( AF_GlyphHints hints,
AF_LatinMetrics metrics )
{
FT_Render_Mode mode;
FT_UInt32 scaler_flags, other_flags;
af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
/*
* correct x_scale and y_scale when needed, since they may have
* been modified af_cjk_scale_dim above
*/
hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
/* compute flags depending on render mode, etc. */
mode = metrics->root.scaler.render_mode;
#ifdef AF_USE_WARPER
if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
#endif
scaler_flags = hints->scaler_flags;
other_flags = 0;
/*
* We snap the width of vertical stems for the monochrome and
* horizontal LCD rendering targets only.
*/
if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
/*
* We snap the width of horizontal stems for the monochrome and
* vertical LCD rendering targets only.
*/
if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
other_flags |= AF_LATIN_HINTS_VERT_SNAP;
/*
* We adjust stems to full pixels only if we don't use the `light' mode.
*/
if ( mode != FT_RENDER_MODE_LIGHT )
other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
if ( mode == FT_RENDER_MODE_MONO )
other_flags |= AF_LATIN_HINTS_MONO;
scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE;
hints->scaler_flags = scaler_flags;
hints->other_flags = other_flags;
return 0;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** C J K G L Y P H G R I D - F I T T I N G *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/* snap a given width in scaled coordinates to one of the */
/* current standard widths */
static FT_Pos
af_cjk_snap_width( AF_Width widths,
FT_Int count,
FT_Pos width )
{
int n;
FT_Pos best = 64 + 32 + 2;
FT_Pos reference = width;
FT_Pos scaled;
for ( n = 0; n < count; n++ )
{
FT_Pos w;
FT_Pos dist;
w = widths[n].cur;
dist = width - w;
if ( dist < 0 )
dist = -dist;
if ( dist < best )
{
best = dist;
reference = w;
}
}
scaled = FT_PIX_ROUND( reference );
if ( width >= reference )
{
if ( width < scaled + 48 )
width = reference;
}
else
{
if ( width > scaled - 48 )
width = reference;
}
return width;
}
/* compute the snapped width of a given stem */
static FT_Pos
af_cjk_compute_stem_width( AF_GlyphHints hints,
AF_Dimension dim,
FT_Pos width,
AF_Edge_Flags base_flags,
AF_Edge_Flags stem_flags )
{
AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
AF_LatinAxis axis = & metrics->axis[dim];
FT_Pos dist = width;
FT_Int sign = 0;
FT_Int vertical = ( dim == AF_DIMENSION_VERT );
FT_UNUSED( base_flags );
FT_UNUSED( stem_flags );
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
return width;
if ( dist < 0 )
{
dist = -width;
sign = 1;
}
if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
{
/* smooth hinting process: very lightly quantize the stem width */
if ( axis->width_count > 0 )
{
if ( FT_ABS( dist - axis->widths[0].cur ) < 40 )
{
dist = axis->widths[0].cur;
if ( dist < 48 )
dist = 48;
goto Done_Width;
}
}
if ( dist < 54 )
dist += ( 54 - dist ) / 2 ;
else if ( dist < 3 * 64 )
{
FT_Pos delta;
delta = dist & 63;
dist &= -64;
if ( delta < 10 )
dist += delta;
else if ( delta < 22 )
dist += 10;
else if ( delta < 42 )
dist += delta;
else if ( delta < 54 )
dist += 54;
else
dist += delta;
}
}
else
{
/* strong hinting process: snap the stem width to integer pixels */
dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
if ( vertical )
{
/* in the case of vertical hinting, always round */
/* the stem heights to integer pixels */
if ( dist >= 64 )
dist = ( dist + 16 ) & ~63;
else
dist = 64;
}
else
{
if ( AF_LATIN_HINTS_DO_MONO( hints ) )
{
/* monochrome horizontal hinting: snap widths to integer pixels */
/* with a different threshold */
if ( dist < 64 )
dist = 64;
else
dist = ( dist + 32 ) & ~63;
}
else
{
/* for horizontal anti-aliased hinting, we adopt a more subtle */
/* approach: we strengthen small stems, round stems whose size */
/* is between 1 and 2 pixels to an integer, otherwise nothing */
if ( dist < 48 )
dist = ( dist + 64 ) >> 1;
else if ( dist < 128 )
dist = ( dist + 22 ) & ~63;
else
/* round otherwise to prevent color fringes in LCD mode */
dist = ( dist + 32 ) & ~63;
}
}
}
Done_Width:
if ( sign )
dist = -dist;
return dist;
}
/* align one stem edge relative to the previous stem edge */
static void
af_cjk_align_linked_edge( AF_GlyphHints hints,
AF_Dimension dim,
AF_Edge base_edge,
AF_Edge stem_edge )
{
FT_Pos dist = stem_edge->opos - base_edge->opos;
FT_Pos fitted_width = af_cjk_compute_stem_width(
hints, dim, dist,
(AF_Edge_Flags)base_edge->flags,
(AF_Edge_Flags)stem_edge->flags );
stem_edge->pos = base_edge->pos + fitted_width;
}
static void
af_cjk_align_serif_edge( AF_GlyphHints hints,
AF_Edge base,
AF_Edge serif )
{
FT_UNUSED( hints );
serif->pos = base->pos + ( serif->opos - base->opos );
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** E D G E H I N T I N G ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#define AF_LIGHT_MODE_MAX_HORZ_GAP 9
#define AF_LIGHT_MODE_MAX_VERT_GAP 15
#define AF_LIGHT_MODE_MAX_DELTA_ABS 14
static FT_Pos
af_hint_normal_stem( AF_GlyphHints hints,
AF_Edge edge,
AF_Edge edge2,
FT_Pos anchor,
AF_Dimension dim )
{
FT_Pos org_len, cur_len, org_center;
FT_Pos cur_pos1, cur_pos2;
FT_Pos d_off1, u_off1, d_off2, u_off2, delta;
FT_Pos offset;
FT_Pos threshold = 64;
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
{
if ( ( edge->flags & AF_EDGE_ROUND ) &&
( edge2->flags & AF_EDGE_ROUND ) )
{
if ( dim == AF_DIMENSION_VERT )
threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
else
threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
}
else
{
if ( dim == AF_DIMENSION_VERT )
threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
else
threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
}
}
org_len = edge2->opos - edge->opos;
cur_len = af_cjk_compute_stem_width( hints, dim, org_len,
(AF_Edge_Flags)edge->flags,
(AF_Edge_Flags)edge2->flags );
org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
cur_pos1 = org_center - cur_len / 2;
cur_pos2 = cur_pos1 + cur_len;
d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
u_off1 = 64 - d_off1;
u_off2 = 64 - d_off2;
delta = 0;
if ( d_off1 == 0 || d_off2 == 0 )
goto Exit;
if ( cur_len <= threshold )
{
if ( d_off2 < cur_len )
{
if ( u_off1 <= d_off2 )
delta = u_off1;
else
delta = -d_off2;
}
goto Exit;
}
if ( threshold < 64 )
{
if ( d_off1 >= threshold || u_off1 >= threshold ||
d_off2 >= threshold || u_off2 >= threshold )
goto Exit;
}
offset = cur_len % 64;
if ( offset < 32 )
{
if ( u_off1 <= offset || d_off2 <= offset )
goto Exit;
}
else
offset = 64 - threshold;
d_off1 = threshold - u_off1;
u_off1 = u_off1 - offset;
u_off2 = threshold - d_off2;
d_off2 = d_off2 - offset;
if ( d_off1 <= u_off1 )
u_off1 = -d_off1;
if ( d_off2 <= u_off2 )
u_off2 = -d_off2;
if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
delta = u_off1;
else
delta = u_off2;
Exit:
#if 1
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
{
if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
}
#endif
cur_pos1 += delta;
if ( edge->opos < edge2->opos )
{
edge->pos = cur_pos1;
edge2->pos = cur_pos1 + cur_len;
}
else
{
edge->pos = cur_pos1 + cur_len;
edge2->pos = cur_pos1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -