diff options
author | marha <marha@users.sourceforge.net> | 2014-06-26 09:53:21 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2014-06-26 09:53:21 +0200 |
commit | 90137f4c5e30b1c6f9a262e8c853494540dad2d7 (patch) | |
tree | 7da9d06a291a853f0d17b2ee49a2d31d86a5d757 /freetype/src/autofit/afcjk.c | |
parent | d47db8d4713de42ccca071c9e8401fc7a213ed49 (diff) | |
parent | fba3b6d1979c1d1ad0d56d46fc2d787f111c07fb (diff) | |
download | vcxsrv-90137f4c5e30b1c6f9a262e8c853494540dad2d7.tar.gz vcxsrv-90137f4c5e30b1c6f9a262e8c853494540dad2d7.tar.bz2 vcxsrv-90137f4c5e30b1c6f9a262e8c853494540dad2d7.zip |
Merge remote-tracking branch 'origin/released'
* origin/released:
Updated to freetype 2.5.3
Diffstat (limited to 'freetype/src/autofit/afcjk.c')
-rw-r--r-- | freetype/src/autofit/afcjk.c | 691 |
1 files changed, 352 insertions, 339 deletions
diff --git a/freetype/src/autofit/afcjk.c b/freetype/src/autofit/afcjk.c index c94727b1b..7402b9b08 100644 --- a/freetype/src/autofit/afcjk.c +++ b/freetype/src/autofit/afcjk.c @@ -2,7 +2,7 @@ /* */ /* afcjk.c */ /* */ -/* Auto-fitter hinting routines for CJK script (body). */ +/* Auto-fitter hinting routines for CJK writing system (body). */ /* */ /* Copyright 2006-2013 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ @@ -26,7 +26,8 @@ #include <freetype/ftadvanc.h> #include <freetype/internal/ftdebug.h> -#include "aftypes.h" +#include "afglobal.h" +#include "afpic.h" #include "aflatin.h" @@ -73,6 +74,12 @@ AF_GlyphHintsRec hints[1]; + FT_TRACE5(( "\n" + "cjk standard widths computation (style `%s')\n" + "===================================================\n" + "\n", + af_style_names[metrics->root.style_class->style] )); + af_glyph_hints_init( hints, face->memory ); metrics->axis[AF_DIMENSION_HORZ].width_count = 0; @@ -80,16 +87,59 @@ { FT_Error error; - FT_UInt glyph_index; + FT_ULong glyph_index; + FT_Long y_offset; int dim; AF_CJKMetricsRec dummy[1]; AF_Scaler scaler = &dummy->root.scaler; +#ifdef FT_CONFIG_OPTION_PIC + AF_FaceGlobals globals = metrics->root.globals; +#endif - glyph_index = FT_Get_Char_Index( face, - metrics->root.clazz->standard_char ); - if ( glyph_index == 0 ) - goto Exit; + AF_StyleClass style_class = metrics->root.style_class; + AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET + [style_class->script]; + + FT_UInt32 standard_char; + + + standard_char = script_class->standard_char1; + af_get_char_index( &metrics->root, + standard_char, + &glyph_index, + &y_offset ); + if ( !glyph_index ) + { + if ( script_class->standard_char2 ) + { + standard_char = script_class->standard_char2; + af_get_char_index( &metrics->root, + standard_char, + &glyph_index, + &y_offset ); + if ( !glyph_index ) + { + if ( script_class->standard_char3 ) + { + standard_char = script_class->standard_char3; + af_get_char_index( &metrics->root, + standard_char, + &glyph_index, + &y_offset ); + if ( !glyph_index ) + goto Exit; + } + else + goto Exit; + } + } + else + goto Exit; + } + + FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", + standard_char, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || face->glyph->outline.n_points <= 0 ) @@ -108,7 +158,7 @@ scaler->render_mode = FT_RENDER_MODE_NORMAL; scaler->flags = 0; - af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); + af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy ); error = af_glyph_hints_reload( hints, &face->glyph->outline ); if ( error ) @@ -122,11 +172,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; @@ -151,7 +203,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; @@ -171,263 +223,204 @@ axis->edge_distance_threshold = stdw / 5; axis->standard_width = stdw; axis->extra_light = 0; - } - } - - af_glyph_hints_done( hints ); - } - - -#define AF_CJK_MAX_TEST_CHARACTERS 32 +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_UInt i; - /* Each blue zone has two types of fill and unfill, this is, */ - /* filling the entire glyph square or not. */ - enum - { - AF_CJK_BLUE_TYPE_FILL, - AF_CJK_BLUE_TYPE_UNFILL, - AF_CJK_BLUE_TYPE_MAX - }; + 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 )); - /* Put some common and representative Han Ideographs characters here. */ - static const FT_ULong af_cjk_hani_blue_chars[AF_CJK_BLUE_MAX] - [AF_CJK_BLUE_TYPE_MAX] - [AF_CJK_MAX_TEST_CHARACTERS] = - { - { - { - 0x4ED6, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730, - 0x5BF9, 0x5C0D, 0x5C31, 0x5E2D, 0x6211, 0x65F6, 0x6642, 0x6703, - 0x6765, 0x70BA, 0x80FD, 0x8230, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019, - 0x9F4A /* top fill */ - }, - { - 0x519B, 0x540C, 0x5DF2, 0x613F, 0x65E2, 0x661F, 0x662F, 0x666F, - 0x6C11, 0x7167, 0x73B0, 0x73FE, 0x7406, 0x7528, 0x7F6E, 0x8981, - 0x8ECD, 0x90A3, 0x914D, 0x91CC, 0x958B, 0x96F7, 0x9732, 0x9762, - 0x987E /* top unfill */ - } - }, - { - { - 0x4E2A, 0x4E3A, 0x4EBA, 0x4ED6, 0x4EE5, 0x4EEC, 0x4F60, 0x4F86, - 0x500B, 0x5011, 0x5230, 0x548C, 0x5927, 0x5BF9, 0x5C0D, 0x5C31, - 0x6211, 0x65F6, 0x6642, 0x6709, 0x6765, 0x70BA, 0x8981, 0x8AAA, - 0x8BF4 /* bottom fill */ - }, - { - 0x4E3B, 0x4E9B, 0x56E0, 0x5B83, 0x60F3, 0x610F, 0x7406, 0x751F, - 0x7576, 0x770B, 0x7740, 0x7F6E, 0x8005, 0x81EA, 0x8457, 0x88E1, - 0x8FC7, 0x8FD8, 0x8FDB, 0x9032, 0x904E, 0x9053, 0x9084, 0x91CC, - 0x9762 /* bottom unfill */ - } - }, -#ifndef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT - { {0x0000}, {0x0000} }, - { {0x0000}, {0x0000} } -#else - { - { - 0x4E9B, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730, - 0x5979, 0x5C06, 0x5C07, 0x5C31, 0x5E74, 0x5F97, 0x60C5, 0x6700, - 0x6837, 0x6A23, 0x7406, 0x80FD, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019, - 0x901A /* left fill */ - }, - { - 0x5373, 0x5417, 0x5427, 0x542C, 0x5462, 0x54C1, 0x54CD, 0x55CE, - 0x5E08, 0x5E2B, 0x6536, 0x65AD, 0x65B7, 0x660E, 0x773C, 0x9593, - 0x95F4, 0x9645, 0x9648, 0x9650, 0x9664, 0x9673, 0x968F, 0x969B, - 0x96A8 /* left unfill */ - } - }, - { - { - 0x4E8B, 0x524D, 0x5B78, 0x5C06, 0x5C07, 0x60C5, 0x60F3, 0x6216, - 0x653F, 0x65AF, 0x65B0, 0x6837, 0x6A23, 0x6C11, 0x6C92, 0x6CA1, - 0x7136, 0x7279, 0x73B0, 0x73FE, 0x7403, 0x7B2C, 0x7D93, 0x8C01, - 0x8D77 /* right fill */ - }, - { - 0x4F8B, 0x5225, 0x522B, 0x5236, 0x52A8, 0x52D5, 0x5417, 0x55CE, - 0x589E, 0x6307, 0x660E, 0x671D, 0x671F, 0x6784, 0x7269, 0x786E, - 0x79CD, 0x8ABF, 0x8C03, 0x8CBB, 0x8D39, 0x90A3, 0x90FD, 0x9593, - 0x95F4 /* right unfill */ + FT_TRACE5(( "\n" )); + } +#endif } } -#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ - }; + FT_TRACE5(( "\n" )); + + af_glyph_hints_done( hints ); + } - /* Calculate blue zones for all the CJK_BLUE_XXX's. */ + + /* Find all blue zones. */ 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_BLUE_STRING_MAX_LEN]; + FT_Pos flats[AF_BLUE_STRING_MAX_LEN]; - 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; + AF_CJKBlue blue; + FT_Error error; + AF_CJKAxis axis; + FT_Outline outline; + + AF_StyleClass sc = metrics->root.style_class; + + AF_Blue_Stringset bss = sc->blue_stringset; + const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; #ifdef FT_DEBUG_LEVEL_TRACE - FT_String* cjk_blue_name[AF_CJK_BLUE_MAX] = { - (FT_String*)"top", - (FT_String*)"bottom", - (FT_String*)"left", - (FT_String*)"right" + FT_String* cjk_blue_name[4] = + { + (FT_String*)"bottom", /* -- , -- */ + (FT_String*)"top", /* -- , TOP */ + (FT_String*)"left", /* HORIZ, -- */ + (FT_String*)"right" /* HORIZ, TOP */ }; - FT_String* cjk_blue_type_name[AF_CJK_BLUE_TYPE_MAX] = { - (FT_String*)"filled", - (FT_String*)"unfilled" + + FT_String* cjk_blue_type_name[2] = + { + (FT_String*)"unfilled", /* -- */ + (FT_String*)"filled" /* FILL */ }; #endif - /* We compute the blues simply by loading each character from the */ - /* `blue_chars[blues]' string, then computing its extreme points */ - /* (depending blue zone type etc.). */ + /* we walk over the blue character strings as specified in the */ + /* style's entry in the `af_blue_stringset' array, computing its */ + /* extremum points (depending on the string properties) */ - 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++ ) + for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { - FT_Int fill_type; - FT_Pos* blue_ref; - FT_Pos* blue_shoot; + const char* p = &af_blue_strings[bs->string]; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) + axis = &metrics->axis[AF_DIMENSION_HORZ]; + else + axis = &metrics->axis[AF_DIMENSION_VERT]; + + FT_TRACE5(( "blue zone %d:\n", axis->blue_count )); + num_fills = 0; num_flats = 0; - for ( fill_type = 0; fill_type < AF_CJK_BLUE_TYPE_MAX; fill_type++ ) + FT_TRACE5(( " cjk blue %s/%s\n", + cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | + AF_CJK_IS_TOP_BLUE( bs ) ], + cjk_blue_type_name[!!AF_CJK_IS_FILLED_BLUE( bs )] )); + + while ( *p ) { - const FT_ULong* p = 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 ); + FT_ULong ch; + FT_ULong glyph_index; + FT_Long y_offset; + FT_Pos best_pos; /* same as points.y or points.x, resp. */ + FT_Int best_point; + FT_Vector* points; - FT_TRACE5(( "cjk blue %s/%s\n", cjk_blue_name[bb], - cjk_blue_type_name[fill_type] )); + GET_UTF8_CHAR( ch, p ); + /* load the character in the face -- skip unknown or empty ones */ + af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( " U+%04lX unavailable\n", ch )); + continue; + } - for ( ; p < limit && *p; p++ ) + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + if ( error || outline.n_points <= 0 ) { - FT_UInt glyph_index; - FT_Pos best_pos; /* same as points.y */ - FT_Int best_point; - FT_Vector* points; + FT_TRACE5(( " U+%04lX contains no outlines\n", ch )); + continue; + } + /* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; + best_pos = 0; /* make compiler happy */ - FT_TRACE5(( " U+%lX...", *p )); + { + FT_Int nn; + FT_Int first = 0; + FT_Int last = -1; - /* load the character in the face -- skip unknown or empty ones */ - glyph_index = FT_Get_Char_Index( face, *p ); - if ( glyph_index == 0 ) - { - FT_TRACE5(( "unavailable\n" )); - continue; - } - error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); - if ( error || glyph->outline.n_points <= 0 ) + for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) { - FT_TRACE5(( "no outline\n" )); - continue; - } + FT_Int pp; - /* now compute min or max point indices and coordinates */ - points = glyph->outline.points; - best_point = -1; - best_pos = 0; /* make compiler happy */ - { - FT_Int nn; - FT_Int first = 0; - FT_Int last = -1; + last = outline.contours[nn]; + /* Avoid single-point contours since they are never rasterized. */ + /* In some fonts, they correspond to mark attachment points */ + /* which are way outside of the glyph's real outline. */ + if ( last <= first ) + continue; - for ( nn = 0; - nn < glyph->outline.n_contours; - first = last + 1, nn++ ) + if ( AF_CJK_IS_HORIZ_BLUE( bs ) ) { - FT_Int pp; - - - last = glyph->outline.contours[nn]; - - /* Avoid single-point contours since they are never */ - /* rasterized. In some fonts, they correspond to mark */ - /* attachment points which are way outside of the glyph's */ - /* real outline. */ - if ( last <= first ) - continue; - - switch ( bb ) + if ( AF_CJK_IS_RIGHT_BLUE( bs ) ) { - case AF_CJK_BLUE_TOP: for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].y > best_pos ) + if ( best_point < 0 || points[pp].x > best_pos ) { best_point = pp; - best_pos = points[pp].y; + best_pos = points[pp].x; } - break; - - case AF_CJK_BLUE_BOTTOM: + } + else + { for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].y < best_pos ) + if ( best_point < 0 || points[pp].x < best_pos ) { best_point = pp; - best_pos = points[pp].y; + best_pos = points[pp].x; } - break; - - case AF_CJK_BLUE_LEFT: + } + } + else + { + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + { for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].x < best_pos ) + if ( best_point < 0 || points[pp].y > best_pos ) { best_point = pp; - best_pos = points[pp].x; + best_pos = points[pp].y; } - break; - - case AF_CJK_BLUE_RIGHT: + } + else + { for ( pp = first; pp <= last; pp++ ) - if ( best_point < 0 || points[pp].x > best_pos ) + if ( best_point < 0 || points[pp].y < best_pos ) { best_point = pp; - best_pos = points[pp].x; + best_pos = points[pp].y; } - break; - - default: - ; } } - FT_TRACE5(( "best_pos=%5ld\n", best_pos )); } - if ( fill ) - fills[num_fills++] = best_pos; - else - flats[num_flats++] = best_pos; + FT_TRACE5(( " U+%04lX: best_pos = %5ld\n", ch, best_pos )); } + + if ( AF_CJK_IS_FILLED_BLUE( bs ) ) + fills[num_fills++] = best_pos; + else + flats[num_flats++] = best_pos; } if ( num_flats == 0 && num_fills == 0 ) @@ -436,34 +429,30 @@ * 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 ); - if ( AF_CJK_BLUE_TOP == bb || AF_CJK_BLUE_BOTTOM == bb ) - axis = &metrics->axis[AF_DIMENSION_VERT]; - 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 @@ -481,26 +470,34 @@ FT_Bool under_ref = FT_BOOL( shoot < ref ); - if ( ( AF_CJK_BLUE_TOP == bb || - AF_CJK_BLUE_RIGHT == bb ) ^ under_ref ) - *blue_shoot = *blue_ref = ( shoot + ref ) / 2; + /* AF_CJK_IS_TOP_BLUE covers `right' and `top' */ + if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + + FT_TRACE5(( " [overshoot smaller than reference," + " taking mean value]\n" )); + } } blue->flags = 0; - if ( AF_CJK_BLUE_TOP == bb ) - blue->flags |= AF_CJK_BLUE_IS_TOP; - else if ( AF_CJK_BLUE_RIGHT == bb ) - blue->flags |= AF_CJK_BLUE_IS_RIGHT; + if ( AF_CJK_IS_TOP_BLUE( bs ) ) + blue->flags |= AF_CJK_BLUE_TOP; - FT_TRACE5(( "-- cjk %s bluezone ref = %ld shoot = %ld\n", - cjk_blue_name[bb], *blue_ref, *blue_shoot )); + FT_TRACE5(( " -> reference = %ld\n" + " overshoot = %ld\n", + *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 ) @@ -510,14 +507,14 @@ 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; + FT_ULong glyph_index; + FT_Long y_offset; - glyph_index = FT_Get_Char_Index( face, i ); + af_get_char_index( &metrics->root, i, &glyph_index, &y_offset ); if ( glyph_index == 0 ) continue; @@ -547,6 +544,8 @@ } + /* Initialize global metrics. */ + FT_LOCAL_DEF( FT_Error ) af_cjk_metrics_init( AF_CJKMetrics metrics, FT_Face face ) @@ -556,21 +555,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, @@ -582,8 +581,6 @@ FT_UInt nn; - axis = &metrics->axis[dim]; - if ( dim == AF_DIMENSION_HORZ ) { scale = scaler->x_scale; @@ -595,6 +592,8 @@ delta = scaler->y_delta; } + axis = &metrics->axis[dim]; + if ( axis->org_scale == scale && axis->org_delta == delta ) return; @@ -650,12 +649,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; } @@ -663,10 +663,14 @@ } + /* Scale global values in both directions. */ + FT_LOCAL_DEF( void ) af_cjk_metrics_scale( AF_CJKMetrics metrics, AF_Scaler scaler ) { + /* we copy the whole structure since the x and y scaling values */ + /* are not modified, contrary to e.g. the `latin' auto-hinter */ metrics->root.scaler = *scaler; af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); @@ -682,6 +686,9 @@ /*************************************************************************/ /*************************************************************************/ + + /* Walk over all contours and compute its segments. */ + static FT_Error af_cjk_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) @@ -938,7 +945,7 @@ for ( seg = segments; seg < segment_limit; seg++ ) { - AF_Edge found = 0; + AF_Edge found = NULL; FT_Pos best = 0xFFFFU; FT_Int ee; @@ -1026,25 +1033,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 */ - /* */ - /*********************************************************************/ - - /* 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. */ + /******************************************************************/ + /* */ + /* 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. + */ { AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; @@ -1153,6 +1161,8 @@ } + /* Detect segments and edges for given dimension. */ + static FT_Error af_cjk_hints_detect_features( AF_GlyphHints hints, AF_Dimension dim ) @@ -1171,6 +1181,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, @@ -1218,10 +1230,8 @@ /* zone, check for left edges */ /* */ /* of course, that's for TrueType */ - is_top_right_blue = - FT_BOOL( ( ( blue->flags & AF_CJK_BLUE_IS_TOP ) != 0 ) || - ( ( blue->flags & AF_CJK_BLUE_IS_RIGHT ) != 0 ) ); - is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); + is_top_right_blue = FT_BOOL( blue->flags & AF_CJK_BLUE_TOP ); + 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 */ @@ -1258,6 +1268,8 @@ } + /* Initalize hinting engine. */ + FT_LOCAL_DEF( FT_Error ) af_cjk_hints_init( AF_GlyphHints hints, AF_CJKMetrics metrics ) @@ -1266,7 +1278,7 @@ FT_UInt32 scaler_flags, other_flags; - af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics ); + af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); /* * correct x_scale and y_scale when needed, since they may have @@ -1316,7 +1328,7 @@ hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; - return 0; + return FT_Err_Ok; } @@ -1328,8 +1340,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, @@ -1376,7 +1388,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, @@ -1385,8 +1399,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 ); @@ -1497,7 +1511,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, @@ -1517,6 +1531,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, @@ -1670,6 +1687,8 @@ } + /* The main grid-fitting routine. */ + static void af_cjk_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) @@ -1685,10 +1704,16 @@ FT_Bool has_last_stem = FALSE; FT_Pos last_stem_pos = 0; +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt num_actions = 0; +#endif + + + FT_TRACE5(( "cjk %s edge hinting (style `%s')\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical", + af_style_names[hints->metrics->style_class->style] )); /* we begin by aligning all stems relative to the blue zone */ - FT_TRACE5(( "==== cjk hinting %s edges =====\n", - dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); if ( AF_HINTS_DO_BLUES( hints ) ) { @@ -1719,10 +1744,14 @@ if ( !edge1 ) continue; - FT_TRACE5(( "CJKBLUE: edge %d @%d (opos=%.2f) snapped to (%.2f), " - "was (%.2f)\n", - edge1-edges, edge1->fpos, edge1->opos / 64.0, blue->fit / 64.0, - edge1->pos / 64.0 )); +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE5(( " CJKBLUE: edge %d @%d (opos=%.2f) snapped to %.2f," + " was %.2f\n", + edge1 - edges, edge1->fpos, edge1->opos / 64.0, + blue->fit / 64.0, edge1->pos / 64.0 )); + + num_actions++; +#endif edge1->pos = blue->fit; edge1->flags |= AF_EDGE_DONE; @@ -1731,6 +1760,10 @@ { af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); edge2->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif } if ( !anchor ) @@ -1772,6 +1805,7 @@ } /* now align the stem */ + /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { @@ -1779,6 +1813,11 @@ af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + continue; } @@ -1786,6 +1825,11 @@ { af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; + +#ifdef FT_DEBUG_LEVEL_TRACE + num_actions++; +#endif + /* We rarely reaches here it seems; * usually the two edges belonging * to one stem are marked as DONE together @@ -1953,7 +1997,7 @@ } if ( !skipped ) - return; + goto Exit; /* * now hint the remaining edges (serifs and single) in order @@ -1973,7 +2017,7 @@ } if ( !skipped ) - return; + goto Exit; for ( edge = edges; edge < edge_limit; edge++ ) { @@ -2011,6 +2055,16 @@ } } } + + Exit: + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !num_actions ) + FT_TRACE5(( " (none)\n" )); + FT_TRACE5(( "\n" )); +#endif + + return; } @@ -2104,6 +2158,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, @@ -2191,84 +2247,41 @@ /*************************************************************************/ - /* this corresponds to Unicode 6.0 */ + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, - static const AF_Script_UniRangeRec af_cjk_uniranges[] = - { - AF_UNIRANGE_REC( 0x1100UL, 0x11FFUL ), /* Hangul Jamo */ - AF_UNIRANGE_REC( 0x2E80UL, 0x2EFFUL ), /* CJK Radicals Supplement */ - AF_UNIRANGE_REC( 0x2F00UL, 0x2FDFUL ), /* Kangxi Radicals */ - AF_UNIRANGE_REC( 0x2FF0UL, 0x2FFFUL ), /* Ideographic Description Characters */ - AF_UNIRANGE_REC( 0x3000UL, 0x303FUL ), /* CJK Symbols and Punctuation */ - AF_UNIRANGE_REC( 0x3040UL, 0x309FUL ), /* Hiragana */ - AF_UNIRANGE_REC( 0x30A0UL, 0x30FFUL ), /* Katakana */ - AF_UNIRANGE_REC( 0x3100UL, 0x312FUL ), /* Bopomofo */ - AF_UNIRANGE_REC( 0x3130UL, 0x318FUL ), /* Hangul Compatibility Jamo */ - AF_UNIRANGE_REC( 0x3190UL, 0x319FUL ), /* Kanbun */ - AF_UNIRANGE_REC( 0x31A0UL, 0x31BFUL ), /* Bopomofo Extended */ - AF_UNIRANGE_REC( 0x31C0UL, 0x31EFUL ), /* CJK Strokes */ - AF_UNIRANGE_REC( 0x31F0UL, 0x31FFUL ), /* Katakana Phonetic Extensions */ - AF_UNIRANGE_REC( 0x3200UL, 0x32FFUL ), /* Enclosed CJK Letters and Months */ - AF_UNIRANGE_REC( 0x3300UL, 0x33FFUL ), /* CJK Compatibility */ - AF_UNIRANGE_REC( 0x3400UL, 0x4DBFUL ), /* CJK Unified Ideographs Extension A */ - AF_UNIRANGE_REC( 0x4DC0UL, 0x4DFFUL ), /* Yijing Hexagram Symbols */ - AF_UNIRANGE_REC( 0x4E00UL, 0x9FFFUL ), /* CJK Unified Ideographs */ - AF_UNIRANGE_REC( 0xA960UL, 0xA97FUL ), /* Hangul Jamo Extended-A */ - AF_UNIRANGE_REC( 0xAC00UL, 0xD7AFUL ), /* Hangul Syllables */ - AF_UNIRANGE_REC( 0xD7B0UL, 0xD7FFUL ), /* Hangul Jamo Extended-B */ - AF_UNIRANGE_REC( 0xF900UL, 0xFAFFUL ), /* CJK Compatibility Ideographs */ - AF_UNIRANGE_REC( 0xFE10UL, 0xFE1FUL ), /* Vertical forms */ - AF_UNIRANGE_REC( 0xFE30UL, 0xFE4FUL ), /* CJK Compatibility Forms */ - AF_UNIRANGE_REC( 0xFF00UL, 0xFFEFUL ), /* Halfwidth and Fullwidth Forms */ - AF_UNIRANGE_REC( 0x1B000UL, 0x1B0FFUL ), /* Kana Supplement */ - AF_UNIRANGE_REC( 0x1D300UL, 0x1D35FUL ), /* Tai Xuan Hing Symbols */ - AF_UNIRANGE_REC( 0x1F200UL, 0x1F2FFUL ), /* Enclosed Ideographic Supplement */ - AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ), /* CJK Unified Ideographs Extension B */ - AF_UNIRANGE_REC( 0x2A700UL, 0x2B73FUL ), /* CJK Unified Ideographs Extension C */ - AF_UNIRANGE_REC( 0x2B740UL, 0x2B81FUL ), /* CJK Unified Ideographs Extension D */ - AF_UNIRANGE_REC( 0x2F800UL, 0x2FA1FUL ), /* CJK Compatibility Ideographs Supplement */ - AF_UNIRANGE_REC( 0UL, 0UL ) - }; - - - AF_DEFINE_SCRIPT_CLASS( af_cjk_script_class, - AF_SCRIPT_CJK, - af_cjk_uniranges, - 0x7530, /* 田 */ + AF_WRITING_SYSTEM_CJK, sizeof ( AF_CJKMetricsRec ), - (AF_Script_InitMetricsFunc) af_cjk_metrics_init, - (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale, - (AF_Script_DoneMetricsFunc) NULL, + (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init, + (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale, + (AF_WritingSystem_DoneMetricsFunc) NULL, - (AF_Script_InitHintsFunc) af_cjk_hints_init, - (AF_Script_ApplyHintsFunc) af_cjk_hints_apply + (AF_WritingSystem_InitHintsFunc) af_cjk_hints_init, + (AF_WritingSystem_ApplyHintsFunc) af_cjk_hints_apply ) + #else /* !AF_CONFIG_OPTION_CJK */ - static const AF_Script_UniRangeRec af_cjk_uniranges[] = - { - AF_UNIRANGE_REC( 0UL, 0UL ) - }; + AF_DEFINE_WRITING_SYSTEM_CLASS( + af_cjk_writing_system_class, - AF_DEFINE_SCRIPT_CLASS( af_cjk_script_class, - AF_SCRIPT_CJK, - af_cjk_uniranges, - 0, + AF_WRITING_SYSTEM_CJK, sizeof ( AF_CJKMetricsRec ), - (AF_Script_InitMetricsFunc) NULL, - (AF_Script_ScaleMetricsFunc)NULL, - (AF_Script_DoneMetricsFunc) NULL, + (AF_WritingSystem_InitMetricsFunc) NULL, + (AF_WritingSystem_ScaleMetricsFunc)NULL, + (AF_WritingSystem_DoneMetricsFunc) NULL, - (AF_Script_InitHintsFunc) NULL, - (AF_Script_ApplyHintsFunc) NULL + (AF_WritingSystem_InitHintsFunc) NULL, + (AF_WritingSystem_ApplyHintsFunc) NULL ) + #endif /* !AF_CONFIG_OPTION_CJK */ |