diff --git a/ChangeLog b/ChangeLog index a828b4a49..b8bf2e412 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2013-08-25 Werner Lemberg + + [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 [autofit] Make `latin' module use blue stringsets. diff --git a/src/autofit/afcjk.c b/src/autofit/afcjk.c index dfb880031..c71b755f4 100644 --- a/src/autofit/afcjk.c +++ b/src/autofit/afcjk.c @@ -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, diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 5290650c9..9cc1d1822 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -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: