summaryrefslogtreecommitdiffstats
path: root/src/autofit/aflatin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/autofit/aflatin.c')
-rw-r--r--src/autofit/aflatin.c500
1 files changed, 316 insertions, 184 deletions
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 8c6c430..54fcf7f 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -4,7 +4,7 @@
/* */
/* Auto-fitter hinting routines for latin script (body). */
/* */
-/* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */
+/* Copyright 2003-2011 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -18,17 +18,28 @@
#include <ft2build.h>
#include FT_ADVANCES_H
+#include FT_INTERNAL_DEBUG_H
#include "aflatin.h"
#include "aferrors.h"
-#ifdef AF_USE_WARPER
+#ifdef AF_CONFIG_OPTION_USE_WARPER
#include "afwarp.h"
#endif
/*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_aflatin
+
+
+ /*************************************************************************/
/*************************************************************************/
/***** *****/
/***** L A T I N G L O B A L M E T R I C S *****/
@@ -36,6 +47,10 @@
/*************************************************************************/
/*************************************************************************/
+
+ /* Find segments and links, compute all stem widths, and initialize */
+ /* standard width and height for the glyph with given charcode. */
+
FT_LOCAL_DEF( void )
af_latin_metrics_init_widths( AF_LatinMetrics metrics,
FT_Face face,
@@ -69,8 +84,12 @@
FT_ZERO( dummy );
dummy->units_per_em = metrics->units_per_em;
- scaler->x_scale = scaler->y_scale = 0x10000L;
- scaler->x_delta = scaler->y_delta = 0;
+
+ scaler->x_scale = 0x10000L;
+ scaler->y_scale = 0x10000L;
+ scaler->x_delta = 0;
+ scaler->y_delta = 0;
+
scaler->face = face;
scaler->render_mode = FT_RENDER_MODE_NORMAL;
scaler->flags = 0;
@@ -115,7 +134,7 @@
dist = -dist;
if ( num_widths < AF_LATIN_MAX_WIDTHS )
- axis->widths[ num_widths++ ].org = dist;
+ axis->widths[num_widths++].org = dist;
}
}
@@ -161,6 +180,9 @@
};
+ /* Find all blue zones. Flat segments give the reference points, */
+ /* round segments the overshoot positions. */
+
static void
af_latin_metrics_init_blues( AF_LatinMetrics metrics,
FT_Face face )
@@ -177,11 +199,11 @@
/* we compute the blues simply by loading each character from the */
- /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */
+ /* `af_latin_blue_chars[blues]' string, then finding its top-most or */
/* bottom-most points (depending on `AF_IS_TOP_BLUE') */
- AF_LOG(( "blue zones computation\n" ));
- AF_LOG(( "------------------------------------------------\n" ));
+ FT_TRACE5(( "blue zones computation\n" ));
+ FT_TRACE5(( "------------------------------------------------\n" ));
for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
{
@@ -191,7 +213,7 @@
FT_Pos* blue_shoot;
- AF_LOG(( "blue %3d: ", bb ));
+ FT_TRACE5(( "blue %3d: ", bb ));
num_flats = 0;
num_rounds = 0;
@@ -199,13 +221,13 @@
for ( ; p < limit && *p; p++ )
{
FT_UInt glyph_index;
- FT_Pos best_y; /* same as points.y */
+ FT_Pos best_y; /* same as points.y */
FT_Int best_point, best_first, best_last;
FT_Vector* points;
FT_Bool round = 0;
- AF_LOG(( "'%c'", *p ));
+ FT_TRACE5(( "'%c'", *p ));
/* load the character in the face -- skip unknown or empty ones */
glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
@@ -229,7 +251,9 @@
FT_Int last = -1;
- for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
+ for ( nn = 0;
+ nn < glyph->outline.n_contours;
+ first = last + 1, nn++ )
{
FT_Int old_best_point = best_point;
FT_Int pp;
@@ -241,7 +265,7 @@
/* In some fonts, they correspond to mark attachment points */
/* which are way outside of the glyph's real outline. */
if ( last <= first )
- continue;
+ continue;
if ( AF_LATIN_IS_TOP_BLUE( bb ) )
{
@@ -268,7 +292,7 @@
best_last = last;
}
}
- AF_LOG(( "%5d", best_y ));
+ FT_TRACE5(( "%5d", best_y ));
}
/* now check whether the point belongs to a straight or round */
@@ -311,12 +335,12 @@
} while ( next != best_point );
- /* now, set the `round' flag depending on the segment's kind */
+ /* now set the `round' flag depending on the segment's kind */
round = FT_BOOL(
FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
- AF_LOG(( "%c ", round ? 'r' : 'f' ));
+ FT_TRACE5(( "%c ", round ? 'r' : 'f' ));
}
if ( round )
@@ -325,7 +349,7 @@
flats[num_flats++] = best_y;
}
- AF_LOG(( "\n" ));
+ FT_TRACE5(( "\n" ));
if ( num_flats == 0 && num_rounds == 0 )
{
@@ -333,7 +357,7 @@
* we couldn't find a single glyph to compute this blue zone,
* we will simply ignore it then
*/
- AF_LOG(( "empty\n" ));
+ FT_TRACE5(( "empty\n" ));
continue;
}
@@ -343,9 +367,9 @@
af_sort_pos( num_rounds, rounds );
af_sort_pos( num_flats, flats );
- blue = & axis->blues[axis->blue_count];
- blue_ref = & blue->ref.org;
- blue_shoot = & blue->shoot.org;
+ blue = &axis->blues[axis->blue_count];
+ blue_ref = &blue->ref.org;
+ blue_shoot = &blue->shoot.org;
axis->blue_count++;
@@ -376,7 +400,8 @@
if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
- *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+ *blue_ref =
+ *blue_shoot = ( shoot + ref ) / 2;
}
blue->flags = 0;
@@ -391,13 +416,17 @@
if ( bb == AF_LATIN_BLUE_SMALL_TOP )
blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
- AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ FT_TRACE5(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
}
+ FT_TRACE5(( "\n" ));
+
return;
}
+ /* Check whether all ASCII digits have the same advance width. */
+
FT_LOCAL_DEF( void )
af_latin_metrics_check_digits( AF_LatinMetrics metrics,
FT_Face face )
@@ -407,8 +436,7 @@
FT_Fixed advance, old_advance = 0;
- /* check whether all ASCII digits have the same advance width; */
- /* digit `0' is 0x30 in all supported charmaps */
+ /* digit `0' is 0x30 in all supported charmaps */
for ( i = 0x30; i <= 0x39; i++ )
{
FT_UInt glyph_index;
@@ -444,6 +472,8 @@
}
+ /* Initialize global metrics. */
+
FT_LOCAL_DEF( FT_Error )
af_latin_metrics_init( AF_LatinMetrics metrics,
FT_Face face )
@@ -458,6 +488,7 @@
FT_ENCODING_APPLE_ROMAN,
FT_ENCODING_ADOBE_STANDARD,
FT_ENCODING_ADOBE_LATIN_1,
+
FT_ENCODING_NONE /* end of list */
};
@@ -485,6 +516,9 @@
}
+ /* Adjust scaling value, then scale and shift widths */
+ /* and blue zones (if applicable) for given dimension. */
+
static void
af_latin_metrics_scale_dim( AF_LatinMetrics metrics,
AF_Scaler scaler,
@@ -550,9 +584,7 @@
else
#endif
if ( dim == AF_DIMENSION_VERT )
- {
scale = FT_MulDiv( scale, fitted, scaled );
- }
}
}
}
@@ -571,7 +603,7 @@
metrics->root.scaler.y_delta = delta;
}
- /* scale the standard widths */
+ /* scale the widths */
for ( nn = 0; nn < axis->width_count; nn++ )
{
AF_Width width = axis->widths + nn;
@@ -582,7 +614,7 @@
}
/* an extra-light axis corresponds to a standard width that is */
- /* smaller than 0.75 pixels */
+ /* smaller than 5/8 pixels */
axis->extra_light =
(FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
@@ -605,9 +637,17 @@
dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
if ( dist <= 48 && dist >= -48 )
{
- FT_Pos delta1, delta2;
+#if 0
+ FT_Pos delta1;
+#endif
+ FT_Pos delta2;
+
+ /* use discrete values for blue zone widths */
+#if 0
+
+ /* generic, original code */
delta1 = blue->shoot.org - blue->ref.org;
delta2 = delta1;
if ( delta1 < 0 )
@@ -628,6 +668,28 @@
blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
blue->shoot.fit = blue->ref.fit + delta2;
+#else
+
+ /* simplified version due to abs(dist) <= 48 */
+ delta2 = dist;
+ if ( dist < 0 )
+ delta2 = -delta2;
+
+ if ( delta2 < 32 )
+ delta2 = 0;
+ else if ( delta < 48 )
+ delta2 = 32;
+ else
+ delta2 = 64;
+
+ if ( dist < 0 )
+ delta2 = -delta2;
+
+ blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
+ blue->shoot.fit = blue->ref.fit - delta2;
+
+#endif
+
blue->flags |= AF_LATIN_BLUE_ACTIVE;
}
}
@@ -635,6 +697,8 @@
}
+ /* Scale global values in both directions. */
+
FT_LOCAL_DEF( void )
af_latin_metrics_scale( AF_LatinMetrics metrics,
AF_Scaler scaler )
@@ -655,18 +719,21 @@
/*************************************************************************/
/*************************************************************************/
+
+ /* Walk over all contours and compute its segments. */
+
FT_LOCAL_DEF( FT_Error )
af_latin_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;
+ 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 );
@@ -762,7 +829,7 @@
/* a segment is round if either its first or last point */
/* is a control point */
if ( ( segment->first->flags | point->flags ) &
- AF_FLAG_CONTROL )
+ AF_FLAG_CONTROL )
segment->flags |= AF_EDGE_ROUND;
/* compute segment size */
@@ -808,7 +875,6 @@
min_pos = max_pos = point->u;
segment->first = point;
segment->last = point;
- segment->contour = contour;
on_edge = 1;
}
@@ -874,6 +940,8 @@
}
+ /* Link segments to form stems and serifs. */
+
FT_LOCAL_DEF( void )
af_latin_hints_link_segments( AF_GlyphHints hints,
AF_Dimension dim )
@@ -899,51 +967,56 @@
if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
continue;
+ /* search for stems having opposite directions, */
+ /* with seg1 to the `left' of seg2 */
for ( seg2 = segments; seg2 < segment_limit; seg2++ )
- if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos )
- {
- FT_Pos pos1 = seg1->pos;
- FT_Pos pos2 = seg2->pos;
- FT_Pos dist = pos2 - pos1;
+ {
+ FT_Pos pos1 = seg1->pos;
+ FT_Pos pos2 = seg2->pos;
- if ( dist < 0 )
- dist = -dist;
+ if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
+ {
+ /* compute distance between the two segments */
+ FT_Pos dist = pos2 - pos1;
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len, score;
- {
- FT_Pos min = seg1->min_coord;
- FT_Pos max = seg1->max_coord;
- FT_Pos len, score;
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
- if ( min < seg2->min_coord )
- min = seg2->min_coord;
+ if ( max > seg2->max_coord )
+ max = seg2->max_coord;
- if ( max > seg2->max_coord )
- max = seg2->max_coord;
+ /* compute maximum coordinate difference of the two segments */
+ len = max - min;
+ if ( len >= len_threshold )
+ {
+ /* small coordinate differences cause a higher score, and */
+ /* segments with a greater distance cause a higher score also */
+ score = dist + len_score / len;
- len = max - min;
- if ( len >= len_threshold )
+ /* and we search for the smallest score */
+ /* of the sum of the two values */
+ if ( score < seg1->score )
{
- score = dist + len_score / len;
-
- if ( score < seg1->score )
- {
- seg1->score = score;
- seg1->link = seg2;
- }
+ seg1->score = score;
+ seg1->link = seg2;
+ }
- if ( score < seg2->score )
- {
- seg2->score = score;
- seg2->link = seg1;
- }
+ if ( score < seg2->score )
+ {
+ seg2->score = score;
+ seg2->link = seg1;
}
}
}
+ }
}
- /* now, compute the `serif' segments */
+ /* now compute the `serif' segments, cf. explanations in `afhints.h' */
for ( seg1 = segments; seg1 < segment_limit; seg1++ )
{
seg2 = seg1->link;
@@ -960,6 +1033,8 @@
}
+ /* Link segments to edges, using feature analysis for selection. */
+
FT_LOCAL_DEF( FT_Error )
af_latin_hints_compute_edges( AF_GlyphHints hints,
AF_Dimension dim )
@@ -973,7 +1048,9 @@
AF_Segment segment_limit = segments + axis->num_segments;
AF_Segment seg;
+#if 0
AF_Direction up_dir;
+#endif
FT_Fixed scale;
FT_Pos edge_distance_threshold;
FT_Pos segment_length_threshold;
@@ -984,11 +1061,13 @@
scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
: hints->y_scale;
+#if 0
up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
: AF_DIR_RIGHT;
+#endif
/*
- * We ignore all segments that are less than 1 pixels in length,
+ * We ignore all segments that are less than 1 pixel in length
* to avoid many problems with serif fonts. We compute the
* corresponding threshold in font units.
*/
@@ -999,20 +1078,21 @@
/*********************************************************************/
/* */
- /* We will begin by generating a sorted table of edges for the */
- /* current direction. To do so, we simply scan each segment and try */
- /* to find an edge in our table that corresponds to its position. */
+ /* We begin by generating a sorted table of edges for the current */
+ /* direction. To do so, we simply scan each segment and try to find */
+ /* an edge in our table that corresponds to its position. */
/* */
/* If no edge is found, we create and insert a new edge in the */
/* sorted table. Otherwise, we simply add the segment to the edge's */
- /* list which will be processed in the second step to compute the */
+ /* list which gets processed in the second step to compute the */
/* edge's properties. */
/* */
- /* Note that the edges table is sorted along the segment/edge */
+ /* Note that the table of edges is sorted along the segment/edge */
/* position. */
/* */
/*********************************************************************/
+ /* assure that edge distance threshold is at most 0.25px */
edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
scale );
if ( edge_distance_threshold > 64 / 4 )
@@ -1023,7 +1103,7 @@
for ( seg = segments; seg < segment_limit; seg++ )
{
- AF_Edge found = 0;
+ AF_Edge found = NULL;
FT_Int ee;
@@ -1072,9 +1152,10 @@
edge->first = seg;
edge->last = seg;
- edge->fpos = seg->pos;
edge->dir = seg->dir;
- edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ edge->fpos = seg->pos;
+ edge->opos = FT_MulFix( seg->pos, scale );
+ edge->pos = edge->opos;
seg->edge_next = seg;
}
else
@@ -1091,9 +1172,9 @@
/*********************************************************************/
/* */
/* Good, we will now compute each edge's properties according to */
- /* segments found on its position. Basically, these are: */
+ /* the segments found on its position. Basically, these are */
/* */
- /* - edge's main direction */
+ /* - the 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 */
@@ -1126,13 +1207,15 @@
} while ( seg != edge->first );
}
- /* now, compute each edge properties */
+ /* 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? */
+#if 0
FT_Pos ups = 0; /* number of upwards segments */
FT_Pos downs = 0; /* number of downwards segments */
+#endif
seg = edge->first;
@@ -1148,11 +1231,13 @@
else
is_straight++;
+#if 0
/* check for segment direction */
if ( seg->dir == up_dir )
- ups += seg->max_coord-seg->min_coord;
+ ups += seg->max_coord - seg->min_coord;
else
- downs += seg->max_coord-seg->min_coord;
+ downs += seg->max_coord - seg->min_coord;
+#endif
/* check for links -- if seg->serif is set, then seg->link must */
/* be ignored */
@@ -1228,7 +1313,7 @@
edge->dir = 0; /* both up and down! */
#endif
- /* gets rid of serifs if link is set */
+ /* 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 */
@@ -1242,6 +1327,8 @@
}
+ /* Detect segments and edges for given dimension. */
+
FT_LOCAL_DEF( FT_Error )
af_latin_hints_detect_features( AF_GlyphHints hints,
AF_Dimension dim )
@@ -1256,18 +1343,21 @@
error = af_latin_hints_compute_edges( hints, dim );
}
+
return error;
}
+ /* Compute all edges which lie within blue zones. */
+
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_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 ];
+ AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
FT_Fixed scale = latin->scale;
@@ -1283,8 +1373,10 @@
/* compute the initial threshold as a fraction of the EM size */
+ /* (the value 40 is heuristic) */
best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
+ /* assure a minimum distance of 0.5px */
if ( best_dist > 64 / 2 )
best_dist = 64 / 2;
@@ -1294,7 +1386,7 @@
FT_Bool is_top_blue, is_major_dir;
- /* skip inactive blue zones (i.e., those that are too small) */
+ /* skip inactive blue zones (i.e., those that are too large) */
if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
continue;
@@ -1322,12 +1414,13 @@
if ( dist < best_dist )
{
best_dist = dist;
- best_blue = & blue->ref;
+ 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 */
+ /* now compare it to the overshoot position and check whether */
+ /* the edge is rounded, and whether 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 );
@@ -1335,7 +1428,6 @@
if ( is_top_blue ^ is_under_ref )
{
- blue = latin->blues + bb;
dist = edge->fpos - blue->shoot.org;
if ( dist < 0 )
dist = -dist;
@@ -1344,7 +1436,7 @@
if ( dist < best_dist )
{
best_dist = dist;
- best_blue = & blue->shoot;
+ best_blue = &blue->shoot;
}
}
}
@@ -1357,6 +1449,8 @@
}
+ /* Initalize hinting engine. */
+
static FT_Error
af_latin_hints_init( AF_GlyphHints hints,
AF_LatinMetrics metrics )
@@ -1370,7 +1464,7 @@
/*
* correct x_scale and y_scale if needed, since they may have
- * been modified `af_latin_metrics_scale_dim' above
+ * been modified by `af_latin_metrics_scale_dim' above
*/
hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
@@ -1380,7 +1474,7 @@
/* compute flags depending on render mode, etc. */
mode = metrics->root.scaler.render_mode;
-#if 0 /* #ifdef AF_USE_WARPER */
+#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
{
metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
@@ -1417,14 +1511,14 @@
* 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 )
+ 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;
+ return AF_Err_Ok;
}
@@ -1436,8 +1530,8 @@
/*************************************************************************/
/*************************************************************************/
- /* snap a given width in scaled coordinates to one of the */
- /* current standard widths */
+ /* Snap a given width in scaled coordinates to one of the */
+ /* current standard widths. */
static FT_Pos
af_latin_snap_width( AF_Width widths,
@@ -1484,7 +1578,9 @@
}
- /* compute the snapped width of a given stem */
+ /* Compute the snapped width of a given stem, ignoring very thin ones. */
+ /* There is a lot of voodoo in this function; changing the hard-coded */
+ /* parameters influence the whole hinting process. */
static FT_Pos
af_latin_compute_stem_width( AF_GlyphHints hints,
@@ -1501,7 +1597,7 @@
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
- axis->extra_light )
+ axis->extra_light )
return width;
if ( dist < 0 )
@@ -1516,11 +1612,12 @@
/* 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 ) )
+ if ( ( stem_flags & AF_EDGE_SERIF ) &&
+ vertical &&
+ ( dist < 3 * 64 ) )
goto Done_Width;
- else if ( ( base_flags & AF_EDGE_ROUND ) )
+ else if ( base_flags & AF_EDGE_ROUND )
{
if ( dist < 80 )
dist = 64;
@@ -1534,21 +1631,18 @@
/* compare to standard width */
- if ( axis->width_count > 0 )
- {
- delta = dist - axis->widths[0].cur;
+ delta = dist - axis->widths[0].cur;
- if ( delta < 0 )
- delta = -delta;
+ if ( delta < 0 )
+ delta = -delta;
- if ( delta < 40 )
- {
- dist = axis->widths[0].cur;
- if ( dist < 48 )
- dist = 48;
+ if ( delta < 40 )
+ {
+ dist = axis->widths[0].cur;
+ if ( dist < 48 )
+ dist = 48;
- goto Done_Width;
- }
+ goto Done_Width;
}
if ( dist < 3 * 64 )
@@ -1575,6 +1669,7 @@
else
{
/* strong hinting process: snap the stem width to integer pixels */
+
FT_Pos org_dist = dist;
@@ -1649,7 +1744,7 @@
}
- /* align one stem edge relative to the previous stem edge */
+ /* Align one stem edge relative to the previous stem edge. */
static void
af_latin_align_linked_edge( AF_GlyphHints hints,
@@ -1667,13 +1762,16 @@
stem_edge->pos = base_edge->pos + fitted_width;
- AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), "
- "dist was %.2f, now %.2f\n",
- stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
- stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
+ FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to (%.2f),"
+ " dist was %.2f, now %.2f\n",
+ stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
+ stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
}
+ /* Shift the coordinates of the `serif' edge by the same amount */
+ /* as the corresponding `base' edge has been moved already. */
+
static void
af_latin_align_serif_edge( AF_GlyphHints hints,
AF_Edge base,
@@ -1681,7 +1779,7 @@
{
FT_UNUSED( hints );
- serif->pos = base->pos + (serif->opos - base->opos);
+ serif->pos = base->pos + ( serif->opos - base->opos );
}
@@ -1696,6 +1794,8 @@
/*************************************************************************/
+ /* The main grid-fitting routine. */
+
FT_LOCAL_DEF( void )
af_latin_hint_edges( AF_GlyphHints hints,
AF_Dimension dim )
@@ -1705,10 +1805,13 @@
AF_Edge edge_limit = edges + axis->num_edges;
FT_PtrDist n_edges;
AF_Edge edge;
- AF_Edge anchor = 0;
+ AF_Edge anchor = NULL;
FT_Int has_serifs = 0;
+ FT_TRACE5(("%s edge hinting\n", dim == AF_DIMENSION_VERT ? "horizontal"
+ : "vertical"));
+
/* we begin by aligning all stems relative to the blue zone */
/* if needed -- that's only for horizontal edges */
@@ -1717,7 +1820,7 @@
for ( edge = edges; edge < edge_limit; edge++ )
{
AF_Width blue;
- AF_Edge edge1, edge2;
+ AF_Edge edge1, edge2; /* these edges form the stem to check */
if ( edge->flags & AF_EDGE_DONE )
@@ -1728,9 +1831,9 @@
edge2 = edge->link;
if ( blue )
- {
edge1 = edge;
- }
+
+ /* flip edges if the other stem is aligned to a blue zone */
else if ( edge2 && edge2->blue_edge )
{
blue = edge2->blue_edge;
@@ -1741,10 +1844,10 @@
if ( !edge1 )
continue;
- AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), "
- "was (%.2f)\n",
- edge1-edges, edge1->opos / 64.0, blue->fit / 64.0,
- edge1->pos / 64.0 ));
+ FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to (%.2f),"
+ " was (%.2f)\n",
+ edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
+ edge1->pos / 64.0 ));
edge1->pos = blue->fit;
edge1->flags |= AF_EDGE_DONE;
@@ -1760,8 +1863,8 @@
}
}
- /* now we will align all stem edges, trying to maintain the */
- /* relative order of stems in the glyph */
+ /* now we align all other stem edges, trying to maintain the */
+ /* relative order of stems in the glyph */
for ( edge = edges; edge < edge_limit; edge++ )
{
AF_Edge edge2;
@@ -1783,7 +1886,7 @@
/* this should not happen, but it's better to be safe */
if ( edge2->blue_edge )
{
- AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
+ FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2-edges ));
af_latin_align_linked_edge( hints, dim, edge2, edge );
edge->flags |= AF_EDGE_DONE;
@@ -1792,6 +1895,8 @@
if ( !anchor )
{
+ /* if we reach this if clause, no stem has been aligned yet */
+
FT_Pos org_len, org_center, cur_len;
FT_Pos cur_pos1, error1, error2, u_off, d_off;
@@ -1801,10 +1906,19 @@
hints, dim, org_len,
(AF_Edge_Flags)edge->flags,
(AF_Edge_Flags)edge2->flags );
+
+ /* some voodoo to specially round edges for small stem widths; */
+ /* the idea is to align the center of a stem, then shifting */
+ /* the stem edges to suitable positions */
if ( cur_len <= 64 )
- u_off = d_off = 32;
+ {
+ /* width <= 1px */
+ u_off = 32;
+ d_off = 32;
+ }
else
{
+ /* 1px < width < 1.5px */
u_off = 38;
d_off = 26;
}
@@ -1812,7 +1926,6 @@
if ( cur_len < 96 )
{
org_center = edge->opos + ( org_len >> 1 );
-
cur_pos1 = FT_PIX_ROUND( org_center );
error1 = org_center - ( cur_pos1 - u_off );
@@ -1834,11 +1947,11 @@
else
edge->pos = FT_PIX_ROUND( edge->opos );
- AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) "
- "snapped to (%.2f) (%.2f)\n",
- edge-edges, edge->opos / 64.0,
- edge2-edges, edge2->opos / 64.0,
- edge->pos / 64.0, edge2->pos / 64.0 ));
+ FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
+ " snapped to (%.2f) (%.2f)\n",
+ edge - edges, edge->opos / 64.0,
+ edge2 - edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
anchor = edge;
edge->flags |= AF_EDGE_DONE;
@@ -1856,12 +1969,18 @@
org_center = org_pos + ( org_len >> 1 );
cur_len = af_latin_compute_stem_width(
- hints, dim, org_len,
- (AF_Edge_Flags)edge->flags,
- (AF_Edge_Flags)edge2->flags );
+ hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
if ( edge2->flags & AF_EDGE_DONE )
+ {
+ FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n",
+ edge - edges, edge->pos / 64.0,
+ ( edge2->pos - cur_len ) / 64.0 ));
+
edge->pos = edge2->pos - cur_len;
+ }
else if ( cur_len < 96 )
{
@@ -1871,7 +1990,10 @@
cur_pos1 = FT_PIX_ROUND( org_center );
if (cur_len <= 64 )
- u_off = d_off = 32;
+ {
+ u_off = 32;
+ d_off = 32;
+ }
else
{
u_off = 38;
@@ -1894,11 +2016,11 @@
edge->pos = cur_pos1 - cur_len / 2;
edge2->pos = cur_pos1 + cur_len / 2;
- AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) "
- "snapped to (%.2f) and (%.2f)\n",
- edge-edges, edge->opos / 64.0,
- edge2-edges, edge2->opos / 64.0,
- edge->pos / 64.0, edge2->pos / 64.0 ));
+ FT_TRACE5(( " STEM: %d (opos=%.2f) to %d (opos=%.2f)"
+ " snapped to (%.2f) and (%.2f)\n",
+ edge - edges, edge->opos / 64.0,
+ edge2 - edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
}
else
{
@@ -1911,24 +2033,24 @@
(AF_Edge_Flags)edge->flags,
(AF_Edge_Flags)edge2->flags );
- cur_pos1 = FT_PIX_ROUND( org_pos );
- delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
+ cur_pos1 = FT_PIX_ROUND( org_pos );
+ delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
if ( delta1 < 0 )
delta1 = -delta1;
- cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
- delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
+ cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
+ delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
if ( delta2 < 0 )
delta2 = -delta2;
edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
edge2->pos = edge->pos + cur_len;
- AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) "
- "snapped to (%.2f) and (%.2f)\n",
- edge-edges, edge->opos / 64.0,
- edge2-edges, edge2->opos / 64.0,
- edge->pos / 64.0, edge2->pos / 64.0 ));
+ FT_TRACE5(( " STEM: %d (opos=%.2f) to %d (opos=%.2f)"
+ " snapped to (%.2f) and (%.2f)\n",
+ edge - edges, edge->opos / 64.0,
+ edge2 - edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
}
edge->flags |= AF_EDGE_DONE;
@@ -1936,8 +2058,8 @@
if ( edge > edges && edge->pos < edge[-1].pos )
{
- AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n",
- edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
+ FT_TRACE5(( " BOUND: %d (pos=%.2f) to (%.2f)\n",
+ edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
edge->pos = edge[-1].pos;
}
}
@@ -2031,18 +2153,19 @@
if ( delta < 64 + 16 )
{
af_latin_align_serif_edge( hints, edge->serif, edge );
- AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) "
- "aligned to (%.2f)\n",
- edge-edges, edge->opos / 64.0,
- edge->serif - edges, edge->serif->opos / 64.0,
- edge->pos / 64.0 ));
+ FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
+ " aligned to (%.2f)\n",
+ edge - edges, edge->opos / 64.0,
+ edge->serif - edges, edge->serif->opos / 64.0,
+ edge->pos / 64.0 ));
}
else if ( !anchor )
{
- AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
- edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
edge->pos = FT_PIX_ROUND( edge->opos );
anchor = edge;
+ FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)"
+ " snapped to (%.2f)\n",
+ edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
}
else
{
@@ -2067,18 +2190,21 @@
FT_MulDiv( edge->opos - before->opos,
after->pos - before->pos,
after->opos - before->opos );
- AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) "
- "from %d (opos=%.2f)\n",
- edge-edges, edge->opos / 64.0,
- edge->pos / 64.0, before - edges,
- before->opos / 64.0 ));
+
+ FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f)"
+ " from %d (opos=%.2f)\n",
+ edge - edges, edge->opos / 64.0,
+ edge->pos / 64.0,
+ before - edges, before->opos / 64.0 ));
}
else
{
edge->pos = anchor->pos +
( ( edge->opos - anchor->opos + 16 ) & ~31 );
- AF_LOG(( "SERIF_LINK2: edge %d (opos=%.2f) snapped to (%.2f)\n",
- edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
+
+ FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)"
+ " snapped to (%.2f)\n",
+ edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
}
}
@@ -2093,9 +2219,13 @@
edge->pos = edge[1].pos;
}
}
+
+ FT_TRACE5(( "\n" ));
}
+ /* Apply the complete hinting algorithm to a latin glyph. */
+
static FT_Error
af_latin_hints_apply( AF_GlyphHints hints,
FT_Outline* outline,
@@ -2110,9 +2240,9 @@
goto Exit;
/* analyze glyph outline */
-#ifdef AF_USE_WARPER
+#ifdef AF_CONFIG_OPTION_USE_WARPER
if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ||
- AF_HINTS_DO_HORIZONTAL( hints ) )
+ AF_HINTS_DO_HORIZONTAL( hints ) )
#else
if ( AF_HINTS_DO_HORIZONTAL( hints ) )
#endif
@@ -2134,17 +2264,19 @@
/* grid-fit the outline */
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
{
-#ifdef AF_USE_WARPER
- if ( ( dim == AF_DIMENSION_HORZ &&
- metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) )
+#ifdef AF_CONFIG_OPTION_USE_WARPER
+ if ( dim == AF_DIMENSION_HORZ &&
+ metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT )
{
AF_WarperRec warper;
FT_Fixed scale;
FT_Pos delta;
- af_warper_compute( &warper, hints, dim, &scale, &delta );
- af_glyph_hints_scale_dim( hints, dim, scale, delta );
+ af_warper_compute( &warper, hints, (AF_Dimension)dim,
+ &scale, &delta );
+ af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
+ scale, delta );
continue;
}
#endif
@@ -2209,7 +2341,7 @@
};
- AF_DEFINE_SCRIPT_CLASS(af_latin_script_class,
+ AF_DEFINE_SCRIPT_CLASS(af_latin_script_class,
AF_SCRIPT_LATIN,
af_latin_uniranges,