aflatin2.c.svn-base
来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 2,142 行 · 第 1/5 页
SVN-BASE
2,142 行
}
if ( !error )
{
/* For now, compute the standard width and height from the `o'. */
af_latin2_metrics_init_widths( metrics, face, 'o' );
af_latin2_metrics_init_blues( metrics, face );
}
FT_Set_Charmap( face, oldmap );
return AF_Err_Ok;
}
static void
af_latin2_metrics_scale_dim( AF_LatinMetrics metrics,
AF_Scaler scaler,
AF_Dimension dim )
{
FT_Fixed scale;
FT_Pos delta;
AF_LatinAxis axis;
FT_UInt nn;
if ( dim == AF_DIMENSION_HORZ )
{
scale = scaler->x_scale;
delta = scaler->x_delta;
}
else
{
scale = scaler->y_scale;
delta = scaler->y_delta;
}
axis = &metrics->axis[dim];
if ( axis->org_scale == scale && axis->org_delta == delta )
return;
axis->org_scale = scale;
axis->org_delta = delta;
/*
* correct Y scale to optimize the alignment of the top of small
* letters to the pixel grid
*/
if ( dim == AF_DIMENSION_VERT )
{
AF_LatinAxis vaxis = &metrics->axis[AF_DIMENSION_VERT];
AF_LatinBlue blue = NULL;
for ( nn = 0; nn < vaxis->blue_count; nn++ )
{
if ( vaxis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
{
blue = &vaxis->blues[nn];
break;
}
}
if ( blue )
{
FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
FT_Pos fitted = ( scaled + 40 ) & ~63;
#if 1
if ( scaled != fitted ) {
scale = FT_MulDiv( scale, fitted, scaled );
AF_LOG(( "== scaled x-top = %.2g fitted = %.2g, scaling = %.4g\n", scaled/64.0, fitted/64.0, (fitted*1.0)/scaled ));
}
#endif
}
}
axis->scale = scale;
axis->delta = delta;
if ( dim == AF_DIMENSION_HORZ )
{
metrics->root.scaler.x_scale = scale;
metrics->root.scaler.x_delta = delta;
}
else
{
metrics->root.scaler.y_scale = scale;
metrics->root.scaler.y_delta = delta;
}
/* scale the standard widths */
for ( nn = 0; nn < axis->width_count; nn++ )
{
AF_Width width = axis->widths + nn;
width->cur = FT_MulFix( width->org, scale );
width->fit = width->cur;
}
/* an extra-light axis corresponds to a standard width that is */
/* smaller than 0.75 pixels */
axis->extra_light =
(FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
if ( dim == AF_DIMENSION_VERT )
{
/* scale the blue zones */
for ( nn = 0; nn < axis->blue_count; nn++ )
{
AF_LatinBlue blue = &axis->blues[nn];
FT_Pos dist;
blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
blue->ref.fit = blue->ref.cur;
blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
blue->shoot.fit = blue->shoot.cur;
blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
/* a blue zone is only active if it is less than 3/4 pixels tall */
dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
if ( dist <= 48 && dist >= -48 )
{
FT_Pos delta1, delta2;
delta1 = blue->shoot.org - blue->ref.org;
delta2 = delta1;
if ( delta1 < 0 )
delta2 = -delta2;
delta2 = FT_MulFix( delta2, scale );
if ( delta2 < 32 )
delta2 = 0;
else if ( delta2 < 64 )
delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
else
delta2 = FT_PIX_ROUND( delta2 );
if ( delta1 < 0 )
delta2 = -delta2;
blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
blue->shoot.fit = blue->ref.fit + delta2;
AF_LOG(( ">> activating blue zone %d: ref.cur=%.2g ref.fit=%.2g shoot.cur=%.2g shoot.fit=%.2g\n",
nn, blue->ref.cur/64.0, blue->ref.fit/64.0,
blue->shoot.cur/64.0, blue->shoot.fit/64.0 ));
blue->flags |= AF_LATIN_BLUE_ACTIVE;
}
}
}
}
FT_LOCAL_DEF( void )
af_latin2_metrics_scale( AF_LatinMetrics metrics,
AF_Scaler scaler )
{
metrics->root.scaler.render_mode = scaler->render_mode;
metrics->root.scaler.face = scaler->face;
af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** L A T I N G L Y P H A N A L Y S I S *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
#define SORT_SEGMENTS
FT_LOCAL_DEF( FT_Error )
af_latin2_hints_compute_segments( AF_GlyphHints hints,
AF_Dimension dim )
{
AF_AxisHints axis = &hints->axis[dim];
FT_Memory memory = hints->memory;
FT_Error error = AF_Err_Ok;
AF_Segment segment = NULL;
AF_SegmentRec seg0;
AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours;
AF_Direction major_dir, segment_dir;
FT_ZERO( &seg0 );
seg0.score = 32000;
seg0.flags = AF_EDGE_NORMAL;
major_dir = (AF_Direction)FT_ABS( axis->major_dir );
segment_dir = major_dir;
axis->num_segments = 0;
/* set up (u,v) in each point */
if ( dim == AF_DIMENSION_HORZ )
{
AF_Point point = hints->points;
AF_Point limit = point + hints->num_points;
for ( ; point < limit; point++ )
{
point->u = point->fx;
point->v = point->fy;
}
}
else
{
AF_Point point = hints->points;
AF_Point limit = point + hints->num_points;
for ( ; point < limit; point++ )
{
point->u = point->fy;
point->v = point->fx;
}
}
/* do each contour separately */
for ( ; contour < contour_limit; contour++ )
{
AF_Point point = contour[0];
AF_Point start = point;
AF_Point last = point->prev;
if ( point == last ) /* skip singletons -- just in case */
continue;
/* already on an edge ?, backtrack to find its start */
if ( FT_ABS( point->in_dir ) == major_dir )
{
point = point->prev;
while ( point->in_dir == start->in_dir )
point = point->prev;
}
else /* otherwise, find first segment start, if any */
{
while ( FT_ABS( point->out_dir ) != major_dir )
{
point = point->next;
if ( point == start )
goto NextContour;
}
}
start = point;
for (;;)
{
AF_Point first;
FT_Pos min_u, min_v, max_u, max_v;
/* we're at the start of a new segment */
FT_ASSERT( FT_ABS( point->out_dir ) == major_dir &&
point->in_dir != point->out_dir );
first = point;
min_u = max_u = point->u;
min_v = max_v = point->v;
point = point->next;
while ( point->out_dir == first->out_dir )
{
point = point->next;
if ( point->u < min_u )
min_u = point->u;
if ( point->u > max_u )
max_u = point->u;
}
if ( point->v < min_v )
min_v = point->v;
if ( point->v > max_v )
max_v = point->v;
/* record new segment */
error = af_axis_hints_new_segment( axis, memory, &segment );
if ( error )
goto Exit;
segment[0] = seg0;
segment->dir = first->out_dir;
segment->first = first;
segment->last = point;
segment->contour = contour;
segment->pos = (FT_Short)(( min_u + max_u ) >> 1);
segment->min_coord = (FT_Short) min_v;
segment->max_coord = (FT_Short) max_v;
segment->height = (FT_Short)(max_v - min_v);
/* a segment is round if it doesn't have successive */
/* on-curve points. */
{
AF_Point pt = first;
AF_Point last = point;
AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
AF_Flags f1;
segment->flags &= ~AF_EDGE_ROUND;
for ( ; pt != last; f0 = f1 )
{
pt = pt->next;
f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
if ( !f0 && !f1 )
break;
if ( pt == last )
segment->flags |= AF_EDGE_ROUND;
}
}
/* this can happen in the case of a degenerate contour
* e.g. a 2-point vertical contour
*/
if ( point == start )
break;
/* jump to the start of the next segment, if any */
while ( FT_ABS(point->out_dir) != major_dir )
{
point = point->next;
if ( point == start )
goto NextContour;
}
}
NextContour:
;
} /* contours */
/* now slightly increase the height of segments when this makes */
/* sense -- this is used to better detect and ignore serifs */
{
AF_Segment segments = axis->segments;
AF_Segment segments_end = segments + axis->num_segments;
for ( segment = segments; segment < segments_end; segment++ )
{
AF_Point first = segment->first;
AF_Point last = segment->last;
AF_Point p;
FT_Pos first_v = first->v;
FT_Pos last_v = last->v;
if ( first == last )
continue;
if ( first_v < last_v )
{
p = first->prev;
if ( p->v < first_v )
segment->height = (FT_Short)( segment->height +
( ( first_v - p->v ) >> 1 ) );
p = last->next;
if ( p->v > last_v )
segment->height = (FT_Short)( segment->height +
( ( p->v - last_v ) >> 1 ) );
}
else
{
p = first->prev;
if ( p->v > first_v )
segment->height = (FT_Short)( segment->height +
( ( p->v - first_v ) >> 1 ) );
p = last->next;
if ( p->v < last_v )
segment->height = (FT_Short)( segment->height +
( ( last_v - p->v ) >> 1 ) );
}
}
}
#ifdef AF_SORT_SEGMENTS
/* place all segments with a negative direction to the start
* of the array, used to speed up segment linking later...
*/
{
AF_Segment segments = axis->segments;
FT_UInt count = axis->num_segments;
FT_UInt ii, jj;
for (ii = 0; ii < count; ii++)
{
if ( segments[ii].dir > 0 )
{
for (jj = ii+1; jj < count; jj++)
{
if ( segments[jj].dir < 0 )
{
AF_SegmentRec tmp;
tmp = segments[ii];
segments[ii] = segments[jj];
segments[jj] = tmp;
break;
}
}
if ( jj == count )
break;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?