📄 aflatin.c
字号:
/* insert a new edge in the list and */
/* sort according to the position */
error = af_axis_hints_new_edge( axis, seg->pos, memory, &edge );
if ( error )
goto Exit;
/* add the segment to the new edge's list */
FT_ZERO( edge );
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 = found->first;
found->last->edge_next = seg;
found->last = seg;
}
}
/*********************************************************************/
/* */
/* 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 removing this loop and setting the `edge' field of each
* segment directly in the code above slows down execution speed for
* some reasons on platforms like the Sun.
*/
{
AF_Edge edges = axis->edges;
AF_Edge edge_limit = edges + axis->num_edges;
AF_Edge edge;
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;
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;
/* set the edge's main direction */
edge->dir = AF_DIR_NONE;
if ( ups > downs )
edge->dir = (FT_Char)up_dir;
else if ( ups < downs )
edge->dir = (FT_Char)-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;
}
}
Exit:
return error;
}
FT_LOCAL_DEF( FT_Error )
af_latin_hints_detect_features( AF_GlyphHints hints,
AF_Dimension dim )
{
FT_Error error;
error = af_latin_hints_compute_segments( hints, dim );
if ( !error )
{
af_latin_hints_link_segments( hints, dim );
error = af_latin_hints_compute_edges( hints, dim );
}
return error;
}
FT_LOCAL_DEF( void )
af_latin_hints_compute_blue_edges( AF_GlyphHints hints,
AF_LatinMetrics metrics )
{
AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
AF_Edge edge = axis->edges;
AF_Edge edge_limit = edge + axis->num_edges;
AF_LatinAxis latin = &metrics->axis[ AF_DIMENSION_VERT ];
FT_Fixed scale = latin->scale;
/* compute which blue zones are active, i.e. have their scaled */
/* size < 3/4 pixels */
/* for each horizontal edge search the blue zone which is closest */
for ( ; edge < edge_limit; edge++ )
{
FT_Int bb;
AF_Width best_blue = NULL;
FT_Pos best_dist; /* initial threshold */
/* compute the initial threshold as a fraction of the EM size */
best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
if ( best_dist > 64 / 2 )
best_dist = 64 / 2;
for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
{
AF_LatinBlue blue = latin->blues + bb;
FT_Bool is_top_blue, is_major_dir;
/* skip inactive blue zones (i.e., those that are too small) */
if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
continue;
/* 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 */
is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
/* 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;
/* first of all, compare it to the reference position */
dist = edge->fpos - blue->ref.org;
if ( dist < 0 )
dist = -dist;
dist = FT_MulFix( dist, scale );
if ( dist < best_dist )
{
best_dist = dist;
best_blue = & blue->ref;
}
/* 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->ref.org );
if ( is_top_blue ^ is_under_ref )
{
blue = latin->blues + bb;
dist = edge->fpos - blue->shoot.org;
if ( dist < 0 )
dist = -dist;
dist = FT_MulFix( dist, scale );
if ( dist < best_dist )
{
best_dist = dist;
best_blue = & blue->shoot;
}
}
}
}
}
if ( best_blue )
edge->blue_edge = best_blue;
}
}
static FT_Error
af_latin_hints_init( AF_GlyphHints hints,
AF_LatinMetrics metrics )
{
FT_Render_Mode mode;
FT_UInt32 scaler_flags, other_flags;
FT_Face face = metrics->root.scaler.face;
af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
/*
* correct x_scale and y_scale when needed, since they may have
* been modified af_latin_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;
/*
* In `light' hinting mode we disable horizontal hinting completely.
* We also do it if the face is italic.
*/
if ( mode == FT_RENDER_MODE_LIGHT ||
(face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 )
scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
hints->scaler_flags = scaler_flags;
hints->other_flags = other_flags;
return 0;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** L A T I N 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_latin_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_latin_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 );
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 */
/* leave the widths of serifs alone */
if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
goto Done_Width;
else if ( ( base_flags & AF_EDGE_ROUND ) )
{
if ( dist < 80 )
dist = 64;
}
else if ( dist < 56 )
dist = 56;
if ( axis->width_count > 0 )
{
FT_Pos delta;
/* compare to standard width */
if ( axis->width_count > 0 )
{
delta = dist - axis->widths[0].cur;
if ( delta < 0 )
delta = -delta;
if ( delta < 40 )
{
dist = axis->widths[0].cur;
if ( dist < 48 )
dist = 48;
goto Done_Width;
}
}
if ( dist < 3 * 64 )
{
delta = dist & 63;
dist &= -64;
if ( delta < 10 )
dist += delta;
else if ( delta < 32 )
dist += 10;
else if ( delta < 54 )
dist += 54;
else
dist += delta;
}
else
dist = ( dist + 32 ) & ~63;
}
}
else
{
/* strong hinting process: snap the stem width to integer pixels */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -