[autofit] Synchronize `cjk' with `latin' module (and vice versa).

* src/autofit/afcjk.c (af_cjk_metrics_init_widths): Add tracing
messages.
(af_cjk_metrics_init_blues): Don't pass blue string array as
argument but use the global array directly.
Use `outline' directly.
Update and add tracing messages.
(af_cjk_metrics_init): Simplify code.
(af_cjk_metrics_scale_dim): Improve tracing message.
(af_cjk_metrics_scale): Synchronize.

* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues): Improve and add tracing messages.
This commit is contained in:
Werner Lemberg 2013-08-25 13:07:08 +02:00
parent 0975d685ed
commit 306f8c5d89
3 changed files with 186 additions and 96 deletions

View File

@ -1,3 +1,20 @@
2013-08-25 Werner Lemberg <wl@gnu.org>
[autofit] Synchronize `cjk' with `latin' module (and vice versa).
* src/autofit/afcjk.c (af_cjk_metrics_init_widths): Add tracing
messages.
(af_cjk_metrics_init_blues): Don't pass blue string array as
argument but use the global array directly.
Use `outline' directly.
Update and add tracing messages.
(af_cjk_metrics_init): Simplify code.
(af_cjk_metrics_scale_dim): Improve tracing message.
(af_cjk_metrics_scale): Synchronize.
* src/autofit/aflatin.c (af_latin_metrics_init_widths,
af_latin_metrics_init_blues): Improve and add tracing messages.
2013-08-25 Werner Lemberg <wl@gnu.org>
[autofit] Make `latin' module use blue stringsets.

View File

@ -73,6 +73,10 @@
AF_GlyphHintsRec hints[1];
FT_TRACE5(( "cjk standard widths computation\n"
"===============================\n"
"\n" ));
af_glyph_hints_init( hints, face->memory );
metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
@ -92,6 +96,9 @@
if ( glyph_index == 0 )
goto Exit;
FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
metrics->root.script_class->standard_char, glyph_index ));
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
if ( error || face->glyph->outline.n_points <= 0 )
goto Exit;
@ -123,11 +130,13 @@
FT_UInt num_widths = 0;
error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim );
error = af_latin_hints_compute_segments( hints,
(AF_Dimension)dim );
if ( error )
goto Exit;
af_latin_hints_link_segments( hints, (AF_Dimension)dim );
af_latin_hints_link_segments( hints,
(AF_Dimension)dim );
seg = axhints->segments;
limit = seg + axhints->num_segments;
@ -152,7 +161,7 @@
}
/* this also replaces multiple almost identical stem widths */
/* with a single one (the value 100 is heuristic) */
/* with a single one (the value 100 is heuristic) */
af_sort_and_quantize_widths( &num_widths, axis->widths,
dummy->units_per_em / 100 );
axis->width_count = num_widths;
@ -172,9 +181,28 @@
axis->edge_distance_threshold = stdw / 5;
axis->standard_width = stdw;
axis->extra_light = 0;
#ifdef FT_DEBUG_LEVEL_TRACE
{
FT_UInt i;
FT_TRACE5(( "%s widths:\n",
dim == AF_DIMENSION_VERT ? "horizontal"
: "vertical" ));
FT_TRACE5(( " %d (standard)", axis->standard_width ));
for ( i = 1; i < axis->width_count; i++ )
FT_TRACE5(( " %d", axis->widths[i].org ));
FT_TRACE5(( "\n" ));
}
#endif
}
}
FT_TRACE5(( "\n" ));
af_glyph_hints_done( hints );
}
@ -265,24 +293,20 @@
/* Calculate blue zones for all the CJK_BLUE_XXX's. */
static void
af_cjk_metrics_init_blues( AF_CJKMetrics metrics,
FT_Face face,
const FT_ULong blue_chars
[AF_CJK_BLUE_MAX]
[AF_CJK_BLUE_TYPE_MAX]
[AF_CJK_MAX_TEST_CHARACTERS] )
af_cjk_metrics_init_blues( AF_CJKMetrics metrics,
FT_Face face )
{
FT_Pos fills[AF_CJK_MAX_TEST_CHARACTERS];
FT_Pos flats[AF_CJK_MAX_TEST_CHARACTERS];
FT_Pos fills[AF_CJK_MAX_TEST_CHARACTERS];
FT_Pos flats[AF_CJK_MAX_TEST_CHARACTERS];
FT_Int num_fills;
FT_Int num_flats;
FT_Int num_fills;
FT_Int num_flats;
FT_Int bb;
AF_CJKBlue blue;
FT_Error error;
AF_CJKAxis axis;
FT_GlyphSlot glyph = face->glyph;
FT_Int bb;
AF_CJKBlue blue;
FT_Error error;
AF_CJKAxis axis;
FT_Outline outline;
#ifdef FT_DEBUG_LEVEL_TRACE
FT_String* cjk_blue_name[AF_CJK_BLUE_MAX] = {
@ -302,8 +326,9 @@
/* `blue_chars[blues]' string, then computing its extreme points */
/* (depending blue zone type etc.). */
FT_TRACE5(( "cjk blue zones computation\n" ));
FT_TRACE5(( "------------------------------------------------\n" ));
FT_TRACE5(( "cjk blue zones computation\n"
"==========================\n"
"\n" ));
for ( bb = 0; bb < AF_CJK_BLUE_MAX; bb++ )
{
@ -317,7 +342,7 @@
for ( fill_type = 0; fill_type < AF_CJK_BLUE_TYPE_MAX; fill_type++ )
{
const FT_ULong* p = blue_chars[bb][fill_type];
const FT_ULong* p = af_cjk_hani_blue_chars[bb][fill_type];
const FT_ULong* limit = p + AF_CJK_MAX_TEST_CHARACTERS;
FT_Bool fill = FT_BOOL(
fill_type == AF_CJK_BLUE_TYPE_FILL );
@ -326,7 +351,6 @@
FT_TRACE5(( "cjk blue %s/%s\n", cjk_blue_name[bb],
cjk_blue_type_name[fill_type] ));
for ( ; p < limit && *p; p++ )
{
FT_UInt glyph_index;
@ -335,7 +359,7 @@
FT_Vector* points;
FT_TRACE5(( " U+%lX...", *p ));
FT_TRACE5(( " U+%lX... ", *p ));
/* load the character in the face -- skip unknown or empty ones */
glyph_index = FT_Get_Char_Index( face, *p );
@ -345,15 +369,16 @@
continue;
}
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
if ( error || glyph->outline.n_points <= 0 )
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
outline = face->glyph->outline;
if ( error || outline.n_points <= 0 )
{
FT_TRACE5(( "no outline\n" ));
continue;
}
/* now compute min or max point indices and coordinates */
points = glyph->outline.points;
points = outline.points;
best_point = -1;
best_pos = 0; /* make compiler happy */
@ -363,14 +388,12 @@
FT_Int last = -1;
for ( nn = 0;
nn < glyph->outline.n_contours;
first = last + 1, nn++ )
for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
{
FT_Int pp;
last = glyph->outline.contours[nn];
last = outline.contours[nn];
/* Avoid single-point contours since they are never */
/* rasterized. In some fonts, they correspond to mark */
@ -421,7 +444,8 @@
;
}
}
FT_TRACE5(( "best_pos=%5ld\n", best_pos ));
FT_TRACE5(( "best_pos = %5ld\n", best_pos ));
}
if ( fill )
@ -437,12 +461,12 @@
* we couldn't find a single glyph to compute this blue zone,
* we will simply ignore it then
*/
FT_TRACE5(( "empty\n" ));
FT_TRACE5(( " empty\n" ));
continue;
}
/* we have computed the contents of the `fill' and `flats' tables, */
/* now determine the reference position of the blue -- */
/* now determine the reference position of the blue zone -- */
/* we simply take the median value after a simple sort */
af_sort_pos( num_flats, flats );
af_sort_pos( num_fills, fills );
@ -452,19 +476,20 @@
else
axis = &metrics->axis[AF_DIMENSION_HORZ];
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++;
if ( num_flats == 0 )
{
*blue_ref = fills[num_fills / 2];
*blue_ref =
*blue_shoot = fills[num_fills / 2];
}
else if ( num_fills == 0 )
{
*blue_ref = flats[num_flats / 2];
*blue_ref =
*blue_shoot = flats[num_flats / 2];
}
else
@ -484,7 +509,13 @@
if ( ( AF_CJK_BLUE_TOP == bb ||
AF_CJK_BLUE_RIGHT == bb ) ^ under_ref )
*blue_shoot = *blue_ref = ( shoot + ref ) / 2;
{
*blue_ref =
*blue_shoot = ( shoot + ref ) / 2;
FT_TRACE5(( " [overshoot smaller than reference,"
" taking mean value]\n" ));
}
}
blue->flags = 0;
@ -493,15 +524,20 @@
else if ( AF_CJK_BLUE_RIGHT == bb )
blue->flags |= AF_CJK_BLUE_IS_RIGHT;
FT_TRACE5(( "-- cjk %s bluezone ref = %ld shoot = %ld\n",
FT_TRACE5(( " cjk %s bluezone\n"
" -> reference = %ld\n"
" overshoot = %ld\n",
cjk_blue_name[bb], *blue_ref, *blue_shoot ));
}
FT_TRACE5(( "\n" ));
return;
}
/* Basically the Latin version with type AF_CJKMetrics for metrics. */
FT_LOCAL_DEF( void )
af_cjk_metrics_check_digits( AF_CJKMetrics metrics,
FT_Face face )
@ -511,8 +547,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;
@ -548,6 +583,8 @@
}
/* Initialize global metrics. */
FT_LOCAL_DEF( FT_Error )
af_cjk_metrics_init( AF_CJKMetrics metrics,
FT_Face face )
@ -557,21 +594,21 @@
metrics->units_per_em = face->units_per_EM;
if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
face->charmap = NULL;
else
if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
{
af_cjk_metrics_init_widths( metrics, face );
af_cjk_metrics_init_blues( metrics, face, af_cjk_hani_blue_chars );
af_cjk_metrics_init_blues( metrics, face );
af_cjk_metrics_check_digits( metrics, face );
}
FT_Set_Charmap( face, oldmap );
return FT_Err_Ok;
}
/* Adjust scaling value, then scale and shift widths */
/* and blue zones (if applicable) for given dimension. */
static void
af_cjk_metrics_scale_dim( AF_CJKMetrics metrics,
AF_Scaler scaler,
@ -583,8 +620,6 @@
FT_UInt nn;
axis = &metrics->axis[dim];
if ( dim == AF_DIMENSION_HORZ )
{
scale = scaler->x_scale;
@ -596,6 +631,8 @@
delta = scaler->y_delta;
}
axis = &metrics->axis[dim];
if ( axis->org_scale == scale && axis->org_delta == delta )
return;
@ -651,12 +688,13 @@
blue->shoot.fit = blue->ref.fit - delta2;
FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]: "
"ref: cur=%.2f fit=%.2f shoot: cur=%.2f fit=%.2f\n",
( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V',
nn, blue->ref.org, blue->shoot.org,
blue->ref.cur / 64.0, blue->ref.fit / 64.0,
blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 ));
FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n"
" ref: cur=%.2f fit=%.2f\n"
" shoot: cur=%.2f fit=%.2f\n",
( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V',
nn, blue->ref.org, blue->shoot.org,
blue->ref.cur / 64.0, blue->ref.fit / 64.0,
blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 ));
blue->flags |= AF_CJK_BLUE_ACTIVE;
}
@ -664,11 +702,15 @@
}
/* Scale global values in both directions. */
FT_LOCAL_DEF( void )
af_cjk_metrics_scale( AF_CJKMetrics metrics,
AF_Scaler scaler )
{
metrics->root.scaler = *scaler;
metrics->root.scaler.render_mode = scaler->render_mode;
metrics->root.scaler.face = scaler->face;
metrics->root.scaler.flags = scaler->flags;
af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
@ -683,6 +725,9 @@
/*************************************************************************/
/*************************************************************************/
/* Walk over all contours and compute its segments. */
static FT_Error
af_cjk_hints_compute_segments( AF_GlyphHints hints,
AF_Dimension dim )
@ -939,7 +984,7 @@
for ( seg = segments; seg < segment_limit; seg++ )
{
AF_Edge found = 0;
AF_Edge found = NULL;
FT_Pos best = 0xFFFFU;
FT_Int ee;
@ -1027,25 +1072,26 @@
}
}
/*********************************************************************/
/* */
/* Good, we now compute each edge's properties according to segments */
/* found on its position. Basically, these are as follows. */
/* */
/* - 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 */
/* */
/*********************************************************************/
/******************************************************************/
/* */
/* Good, we now compute each edge's properties according to the */
/* segments found on its position. Basically, these are */
/* */
/* - 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 */
/* */
/******************************************************************/
/* 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. */
/* 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;
@ -1154,6 +1200,8 @@
}
/* Detect segments and edges for given dimension. */
static FT_Error
af_cjk_hints_detect_features( AF_GlyphHints hints,
AF_Dimension dim )
@ -1172,6 +1220,8 @@
}
/* Compute all edges which lie within blue zones. */
FT_LOCAL_DEF( void )
af_cjk_hints_compute_blue_edges( AF_GlyphHints hints,
AF_CJKMetrics metrics,
@ -1259,6 +1309,8 @@
}
/* Initalize hinting engine. */
FT_LOCAL_DEF( FT_Error )
af_cjk_hints_init( AF_GlyphHints hints,
AF_CJKMetrics metrics )
@ -1317,7 +1369,7 @@
hints->scaler_flags = scaler_flags;
hints->other_flags = other_flags;
return 0;
return FT_Err_Ok;
}
@ -1329,8 +1381,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_cjk_snap_width( AF_Width widths,
@ -1377,7 +1429,9 @@
}
/* compute the snapped width of a given stem */
/* Compute the snapped width of a given stem. */
/* There is a lot of voodoo in this function; changing the hard-coded */
/* parameters influence the whole hinting process. */
static FT_Pos
af_cjk_compute_stem_width( AF_GlyphHints hints,
@ -1386,8 +1440,8 @@
AF_Edge_Flags base_flags,
AF_Edge_Flags stem_flags )
{
AF_CJKMetrics metrics = (AF_CJKMetrics) hints->metrics;
AF_CJKAxis axis = & metrics->axis[dim];
AF_CJKMetrics metrics = (AF_CJKMetrics)hints->metrics;
AF_CJKAxis axis = &metrics->axis[dim];
FT_Pos dist = width;
FT_Int sign = 0;
FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT );
@ -1498,7 +1552,7 @@
}
/* align one stem edge relative to the previous stem edge */
/* Align one stem edge relative to the previous stem edge. */
static void
af_cjk_align_linked_edge( AF_GlyphHints hints,
@ -1518,6 +1572,9 @@
}
/* Shift the coordinates of the `serif' edge by the same amount */
/* as the corresponding `base' edge has been moved already. */
static void
af_cjk_align_serif_edge( AF_GlyphHints hints,
AF_Edge base,
@ -1671,6 +1728,8 @@
}
/* The main grid-fitting routine. */
static void
af_cjk_hint_edges( AF_GlyphHints hints,
AF_Dimension dim )
@ -2105,6 +2164,8 @@
}
/* Apply the complete hinting algorithm to a CJK glyph. */
FT_LOCAL_DEF( FT_Error )
af_cjk_hints_apply( AF_GlyphHints hints,
FT_Outline* outline,

View File

@ -60,8 +60,9 @@
AF_GlyphHintsRec hints[1];
FT_TRACE5(( "standard widths computation\n"
"===========================\n\n" ));
FT_TRACE5(( "latin standard widths computation\n"
"=================================\n"
"\n" ));
af_glyph_hints_init( hints, face->memory );
@ -82,7 +83,7 @@
if ( glyph_index == 0 )
goto Exit;
FT_TRACE5(( "standard character: 0x%X (glyph index %d)\n",
FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
metrics->root.script_class->standard_char, glyph_index ));
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
@ -147,22 +148,21 @@
}
/* this also replaces multiple almost identical stem widths */
/* with a single one (the value 100 is heuristic) */
/* with a single one (the value 100 is heuristic) */
af_sort_and_quantize_widths( &num_widths, axis->widths,
dummy->units_per_em / 100 );
axis->width_count = num_widths;
}
Exit:
Exit:
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
{
AF_LatinAxis axis = &metrics->axis[dim];
FT_Pos stdw;
stdw = ( axis->width_count > 0 )
? axis->widths[0].org
: AF_LATIN_CONSTANT( metrics, 50 );
stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
: AF_LATIN_CONSTANT( metrics, 50 );
/* let's try 20% of the smallest width */
axis->edge_distance_threshold = stdw / 5;
@ -203,11 +203,13 @@
{
FT_Pos flats [AF_BLUE_STRING_MAX_LEN];
FT_Pos rounds[AF_BLUE_STRING_MAX_LEN];
FT_Int num_flats;
FT_Int num_rounds;
AF_LatinBlue blue;
FT_Error error;
AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
FT_Outline outline;
AF_Blue_Stringset bss = metrics->root.script_class->blue_stringset;
@ -219,8 +221,8 @@
/* top-most or bottom-most points (depending on the string */
/* properties) */
FT_TRACE5(( "blue zones computation\n"
"======================\n"
FT_TRACE5(( "latin blue zones computation\n"
"============================\n"
"\n" ));
for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
@ -247,15 +249,23 @@
GET_UTF8_CHAR( ch, p );
FT_TRACE5(( " U+%lX... ", ch ));
/* load the character in the face -- skip unknown or empty ones */
glyph_index = FT_Get_Char_Index( face, ch );
if ( glyph_index == 0 )
{
FT_TRACE5(( "unavailable\n" ));
continue;
}
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
outline = face->glyph->outline;
if ( error || outline.n_points <= 0 )
{
FT_TRACE5(( "no outline\n" ));
continue;
}
/* now compute min or max point indices and coordinates */
points = outline.points;
@ -309,7 +319,8 @@
best_contour_last = last;
}
}
FT_TRACE5(( " %c %ld", *p, best_y ));
FT_TRACE5(( "best_y = %5ld\n", best_y ));
}
/* now check whether the point belongs to a straight or round */
@ -456,7 +467,7 @@
}
else
{
*blue_ref = flats[num_flats / 2];
*blue_ref = flats [num_flats / 2];
*blue_shoot = rounds[num_rounds / 2];
}
@ -1662,8 +1673,8 @@
AF_Edge_Flags base_flags,
AF_Edge_Flags stem_flags )
{
AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
AF_LatinAxis axis = & metrics->axis[dim];
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 );
@ -2422,6 +2433,7 @@
af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
}
}
af_glyph_hints_save( hints, outline );
Exit: