From d8e3f99cdf46297afeb26fe15ad30f7c6de8ee7c Mon Sep 17 00:00:00 2001 From: marha Date: Mon, 18 Jul 2011 08:30:47 +0200 Subject: Switched to freetype 2.4.5 --- freetype/src/autofit/afangles.c | 4 +- freetype/src/autofit/afcjk.c | 835 ++++++++++++++++++++++++++++++++++++++-- freetype/src/autofit/afcjk.h | 104 ++++- freetype/src/autofit/afdummy.c | 9 +- freetype/src/autofit/afdummy.h | 4 +- freetype/src/autofit/afglobal.c | 14 +- freetype/src/autofit/afglobal.h | 8 +- freetype/src/autofit/afhints.c | 241 ++++++++++-- freetype/src/autofit/afhints.h | 217 +++++++++-- freetype/src/autofit/afindic.c | 55 ++- freetype/src/autofit/aflatin.c | 479 ++++++++++++++--------- freetype/src/autofit/aflatin.h | 25 +- freetype/src/autofit/aflatin2.c | 227 ++++++----- freetype/src/autofit/afloader.c | 32 +- freetype/src/autofit/afloader.h | 8 +- freetype/src/autofit/afmodule.c | 17 +- freetype/src/autofit/afpic.c | 46 ++- freetype/src/autofit/afpic.h | 27 +- freetype/src/autofit/aftypes.h | 129 +++---- freetype/src/autofit/afwarp.c | 62 ++- freetype/src/autofit/autofit.c | 4 +- freetype/src/autofit/rules.mk | 7 +- 22 files changed, 1949 insertions(+), 605 deletions(-) (limited to 'freetype/src/autofit') diff --git a/freetype/src/autofit/afangles.c b/freetype/src/autofit/afangles.c index e2360d157..790af1779 100644 --- a/freetype/src/autofit/afangles.c +++ b/freetype/src/autofit/afangles.c @@ -5,7 +5,7 @@ /* Routines used to compute vector angles with limited accuracy */ /* and very high speed. It also contains sorting routines (body). */ /* */ -/* Copyright 2003, 2004, 2005, 2006 by */ +/* Copyright 2003-2006, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -77,7 +77,7 @@ return 1 - 2 * ( delta < 0 ); } -#endif +#endif /* 0 */ /* diff --git a/freetype/src/autofit/afcjk.c b/freetype/src/autofit/afcjk.c index f3b1067ed..0acef9c85 100644 --- a/freetype/src/autofit/afcjk.c +++ b/freetype/src/autofit/afcjk.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for CJK script (body). */ /* */ -/* Copyright 2006, 2007, 2008, 2009, 2010 by */ +/* Copyright 2006-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -22,21 +22,37 @@ * */ +#include +#include FT_ADVANCES_H +#include FT_INTERNAL_DEBUG_H + #include "aftypes.h" #include "aflatin.h" #ifdef AF_CONFIG_OPTION_CJK +#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + #include "afcjk.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_afcjk + + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -45,24 +61,504 @@ /*************************************************************************/ /*************************************************************************/ + + /* Basically the Latin version with AF_CJKMetrics */ + /* to replace AF_LatinMetrics. */ + + FT_LOCAL_DEF( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face, + FT_ULong charcode ) + { + /* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + + + af_glyph_hints_init( hints, face->memory ); + + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + + { + FT_Error error; + FT_UInt glyph_index; + int dim; + AF_CJKMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + + + glyph_index = FT_Get_Char_Index( face, charcode ); + if ( glyph_index == 0 ) + goto Exit; + + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + + FT_ZERO( dummy ); + + dummy->units_per_em = metrics->units_per_em; + + 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; + + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); + + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + + + error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim ); + if ( error ) + goto Exit; + + af_latin_hints_link_segments( hints, (AF_Dimension)dim ); + + seg = axhints->segments; + limit = seg + axhints->num_segments; + + for ( ; seg < limit; seg++ ) + { + link = seg->link; + + /* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + + + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + + if ( num_widths < AF_CJK_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } + + af_sort_widths( num_widths, axis->widths ); + axis->width_count = num_widths; + } + + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + + + 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; + axis->standard_width = stdw; + axis->extra_light = 0; + } + } + + af_glyph_hints_done( hints ); + } + + +#define AF_CJK_MAX_TEST_CHARACTERS 32 + + + /* 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 + }; + + + /* 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 */ + } + } +#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ + }; + + + /* 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] ) + { + 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 bb; + AF_CJKBlue blue; + FT_Error error; + AF_CJKAxis axis; + FT_GlyphSlot glyph = face->glyph; + +#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_type_name[AF_CJK_BLUE_TYPE_MAX] = { + (FT_String*)"filled", + (FT_String*)"unfilled" + }; +#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.). */ + + FT_TRACE5(( "cjk blue zones computation\n" )); + FT_TRACE5(( "------------------------------------------------\n" )); + + for ( bb = 0; bb < AF_CJK_BLUE_MAX; bb++ ) + { + FT_Int fill_type; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + + + num_fills = 0; + num_flats = 0; + + 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* limit = p + AF_CJK_MAX_TEST_CHARACTERS; + FT_Bool fill = FT_BOOL( + fill_type == AF_CJK_BLUE_TYPE_FILL ); + + + 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; + FT_Pos best_pos; /* same as points.y */ + FT_Int best_point; + FT_Vector* points; + + + FT_TRACE5(( " U+%lX...", *p )); + + /* 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 ) + { + FT_TRACE5(( "no outline\n" )); + continue; + } + + /* 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; + + + for ( nn = 0; + nn < glyph->outline.n_contours; + first = last + 1, nn++ ) + { + 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 ) + { + case AF_CJK_BLUE_TOP: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y > best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + break; + + case AF_CJK_BLUE_BOTTOM: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y < best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + break; + + case AF_CJK_BLUE_LEFT: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x < best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + break; + + case AF_CJK_BLUE_RIGHT: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x > best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + break; + + default: + ; + } + } + FT_TRACE5(( "best_pos=%5ld\n", best_pos )); + } + + if ( fill ) + fills[num_fills++] = best_pos; + else + flats[num_flats++] = best_pos; + } + } + + if ( num_flats == 0 && num_fills == 0 ) + { + /* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( "empty\n" )); + continue; + } + + /* we have computed the contents of the `fill' and `flats' tables, */ + /* now determine the reference position of the blue -- */ + /* 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; + + axis->blue_count++; + if ( num_flats == 0 ) + { + *blue_ref = fills[num_fills / 2]; + *blue_shoot = fills[num_fills / 2]; + } + else if ( num_fills == 0 ) + { + *blue_ref = flats[num_flats / 2]; + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = fills[num_fills / 2]; + *blue_shoot = flats[num_flats / 2]; + } + + /* make sure blue_ref >= blue_shoot for top/right or */ + /* vice versa for bottom/left */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + 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; + } + + 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; + + FT_TRACE5(( "-- cjk %s bluezone ref = %ld shoot = %ld\n", + cjk_blue_name[bb], *blue_ref, *blue_shoot )); + } + + 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 ) + { + FT_UInt i; + FT_Bool started = 0, same_width = 1; + FT_Fixed advance, old_advance = 0; + + + /* check whether all ASCII digits have the same advance width; */ + /* digit `0' is 0x30 in all supported charmaps */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt glyph_index; + + + glyph_index = FT_Get_Char_Index( face, i ); + if ( glyph_index == 0 ) + continue; + + if ( FT_Get_Advance( face, glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + &advance ) ) + continue; + + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + + metrics->root.digits_have_same_width = same_width; + } + + FT_LOCAL_DEF( FT_Error ) - af_cjk_metrics_init( AF_LatinMetrics metrics, - FT_Face face ) + af_cjk_metrics_init( AF_CJKMetrics metrics, + FT_Face face ) { FT_CharMap oldmap = face->charmap; metrics->units_per_em = face->units_per_EM; - /* TODO are there blues? */ - if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) face->charmap = NULL; else { - /* latin's version would suffice */ - af_latin_metrics_init_widths( metrics, face, 0x7530 ); - af_latin_metrics_check_digits( metrics, face ); + af_cjk_metrics_init_widths( metrics, face, 0x7530 ); + af_cjk_metrics_init_blues( metrics, face, af_cjk_hani_blue_chars ); + af_cjk_metrics_check_digits( metrics, face ); } FT_Set_Charmap( face, oldmap ); @@ -72,31 +568,100 @@ static void - af_cjk_metrics_scale_dim( AF_LatinMetrics metrics, - AF_Scaler scaler, - AF_Dimension dim ) + af_cjk_metrics_scale_dim( AF_CJKMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) { - AF_LatinAxis axis; + FT_Fixed scale; + FT_Pos delta; + AF_CJKAxis axis; + FT_UInt nn; axis = &metrics->axis[dim]; if ( dim == AF_DIMENSION_HORZ ) { - axis->scale = scaler->x_scale; - axis->delta = scaler->x_delta; + scale = scaler->x_scale; + delta = scaler->x_delta; } else { - axis->scale = scaler->y_scale; - axis->delta = scaler->y_delta; + scale = scaler->y_scale; + delta = scaler->y_delta; + } + + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + + axis->org_scale = scale; + axis->org_delta = delta; + + axis->scale = scale; + axis->delta = delta; + + /* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_CJKBlue blue = &axis->blues[nn]; + FT_Pos dist; + + + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_CJK_BLUE_ACTIVE; + + /* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { + FT_Pos delta1, delta2; + + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + + /* shoot is under shoot for cjk */ + delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + + delta2 = FT_MulFix( delta2, scale ); + + FT_TRACE5(( "delta: %d", delta1 )); + if ( delta2 < 32 ) + delta2 = 0; +#if 0 + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); +#endif + else + delta2 = FT_PIX_ROUND( delta2 ); + FT_TRACE5(( "/%d\n", delta2 )); + + if ( delta1 < 0 ) + delta2 = -delta2; + + 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 )); + + blue->flags |= AF_CJK_BLUE_ACTIVE; + } } } FT_LOCAL_DEF( void ) - af_cjk_metrics_scale( AF_LatinMetrics metrics, - AF_Scaler scaler ) + af_cjk_metrics_scale( AF_CJKMetrics metrics, + AF_Scaler scaler ) { metrics->root.scaler = *scaler; @@ -329,7 +894,7 @@ AF_AxisHints axis = &hints->axis[dim]; FT_Error error = AF_Err_Ok; FT_Memory memory = hints->memory; - AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; + AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; @@ -601,9 +1166,96 @@ } + FT_LOCAL_DEF( void ) + af_cjk_hints_compute_blue_edges( AF_GlyphHints hints, + AF_CJKMetrics metrics, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = edge + axis->num_edges; + AF_CJKAxis cjk = &metrics->axis[dim]; + FT_Fixed scale = cjk->scale; + FT_Pos best_dist0; /* initial threshold */ + + + /* compute the initial threshold as a fraction of the EM size */ + best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); + + if ( best_dist0 > 64 / 2 ) /* maximum 1/2 pixel */ + best_dist0 = 64 / 2; + + /* compute which blue zones are active, i.e. have their scaled */ + /* size < 3/4 pixels */ + + /* If the distant between an edge and a blue zone is shorter than */ + /* best_dist0, set the blue zone for the edge. Then search for */ + /* the blue zone with the smallest best_dist to the edge. */ + + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; + FT_Pos best_dist = best_dist0; + + + for ( bb = 0; bb < cjk->blue_count; bb++ ) + { + AF_CJKBlue blue = cjk->blues + bb; + FT_Bool is_top_right_blue, is_major_dir; + + + /* skip inactive blue zones (i.e., those that are too small) */ + if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) ) + continue; + + /* if it is a top zone, check for right edges -- if it is a bottom */ + /* 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 ); + + /* 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 */ + /* direction */ + if ( is_top_right_blue ^ is_major_dir ) + { + FT_Pos dist; + AF_Width compare; + + + /* Compare the edge to the closest blue zone type */ + if ( FT_ABS( edge->fpos - blue->ref.org ) > + FT_ABS( edge->fpos - blue->shoot.org ) ) + compare = &blue->shoot; + else + compare = &blue->ref; + + dist = edge->fpos - compare->org; + if ( dist < 0 ) + dist = -dist; + + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = compare; + } + } + } + + if ( best_blue ) + edge->blue_edge = best_blue; + } + } + + FT_LOCAL_DEF( FT_Error ) - af_cjk_hints_init( AF_GlyphHints hints, - AF_LatinMetrics metrics ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_CJKMetrics metrics ) { FT_Render_Mode mode; FT_UInt32 scaler_flags, other_flags; @@ -623,7 +1275,7 @@ /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; -#ifdef AF_USE_WARPER +#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; #endif @@ -728,11 +1380,11 @@ AF_Edge_Flags base_flags, AF_Edge_Flags stem_flags ) { - 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 ); + 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 ); FT_UNUSED( base_flags ); FT_UNUSED( stem_flags ); @@ -1025,7 +1677,61 @@ AF_Edge anchor = 0; FT_Pos delta = 0; FT_Int skipped = 0; + FT_Bool has_last_stem = FALSE; + FT_Pos last_stem_pos = 0; + + /* 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 ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; + + + if ( edge->flags & AF_EDGE_DONE ) + continue; + + blue = edge->blue_edge; + edge1 = NULL; + edge2 = edge->link; + + if ( blue ) + { + edge1 = edge; + } + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + + 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 )); + + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + + if ( edge2 && !edge2->blue_edge ) + { + af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + } + + if ( !anchor ) + anchor = edge; + } + } /* now we align all stem edges. */ for ( edge = edges; edge < edge_limit; edge++ ) @@ -1044,12 +1750,43 @@ continue; } + /* Some CJK characters have so many stems that + * the hinter is likely to merge two adjacent ones. + * To solve this problem, if either edge of a stem + * is too close to the previous one, we avoid + * aligning the two edges, but rather interpolate + * their locations at the end of this function in + * order to preserve the space between the stems. + */ + if ( has_last_stem && + ( edge->pos < last_stem_pos + 64 || + edge2->pos < last_stem_pos + 64 ) ) + { + skipped++; + continue; + } + /* now align the stem */ + /* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges )); + + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + continue; + } if ( edge2 < edge ) { af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; + /* We rarely reaches here it seems; + * usually the two edges belonging + * to one stem are marked as DONE together + */ + has_last_stem = TRUE; + last_stem_pos = edge->pos; continue; } @@ -1142,6 +1879,8 @@ anchor = edge; edge->flags |= AF_EDGE_DONE; edge2->flags |= AF_EDGE_DONE; + has_last_stem = TRUE; + last_stem_pos = edge2->pos; } /* make sure that lowercase m's maintain their symmetry */ @@ -1361,9 +2100,9 @@ FT_LOCAL_DEF( FT_Error ) - af_cjk_hints_apply( AF_GlyphHints hints, - FT_Outline* outline, - AF_LatinMetrics metrics ) + af_cjk_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_CJKMetrics metrics ) { FT_Error error; int dim; @@ -1381,6 +2120,8 @@ error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ ); if ( error ) goto Exit; + + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ ); } if ( AF_HINTS_DO_VERTICAL( hints ) ) @@ -1388,6 +2129,8 @@ error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT ); if ( error ) goto Exit; + + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT ); } /* grid-fit the outline */ @@ -1397,7 +2140,7 @@ ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER if ( dim == AF_DIMENSION_HORZ && metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL ) { @@ -1406,11 +2149,13 @@ 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 /* AF_USE_WARPER */ +#endif /* AF_CONFIG_OPTION_USE_WARPER */ af_cjk_hint_edges( hints, (AF_Dimension)dim ); af_cjk_align_edge_points( hints, (AF_Dimension)dim ); @@ -1441,18 +2186,19 @@ /*************************************************************************/ + /* this corresponds to Unicode 6.0 */ + static const AF_Script_UniRangeRec af_cjk_uniranges[] = { -#if 0 - AF_UNIRANGE_REC( 0x0100UL, 0xFFFFUL ), /* why this? */ -#endif 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 */ @@ -1461,10 +2207,19 @@ 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 ) }; @@ -1474,7 +2229,7 @@ AF_SCRIPT_CJK, af_cjk_uniranges, - sizeof( AF_LatinMetricsRec ), + sizeof( AF_CJKMetricsRec ), (AF_Script_InitMetricsFunc) af_cjk_metrics_init, (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale, @@ -1496,7 +2251,7 @@ AF_SCRIPT_CJK, af_cjk_uniranges, - sizeof( AF_LatinMetricsRec ), + sizeof( AF_CJKMetricsRec ), (AF_Script_InitMetricsFunc) NULL, (AF_Script_ScaleMetricsFunc)NULL, diff --git a/freetype/src/autofit/afcjk.h b/freetype/src/autofit/afcjk.h index 0b20d4ae3..8416c0d02 100644 --- a/freetype/src/autofit/afcjk.h +++ b/freetype/src/autofit/afcjk.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for CJK script (specification). */ /* */ -/* Copyright 2006, 2007 by */ +/* Copyright 2006, 2007, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -20,6 +20,7 @@ #define __AFCJK_H__ #include "afhints.h" +#include "aflatin.h" FT_BEGIN_HEADER @@ -29,23 +30,106 @@ FT_BEGIN_HEADER AF_DECLARE_SCRIPT_CLASS(af_cjk_script_class) + /* CJK (global) metrics management */ + + /* + * CJK glyphs tend to fill the square. So we have both vertical and + * horizontal blue zones. But some glyphs have flat bounding strokes that + * leave some space between neighbour glyphs. + */ + enum + { + AF_CJK_BLUE_TOP, + AF_CJK_BLUE_BOTTOM, + AF_CJK_BLUE_LEFT, + AF_CJK_BLUE_RIGHT, + + AF_CJK_BLUE_MAX + }; + + +#define AF_CJK_MAX_WIDTHS 16 +#define AF_CJK_MAX_BLUES AF_CJK_BLUE_MAX + + + enum + { + AF_CJK_BLUE_ACTIVE = 1 << 0, + AF_CJK_BLUE_IS_TOP = 1 << 1, + AF_CJK_BLUE_IS_RIGHT = 1 << 2, + AF_CJK_BLUE_ADJUSTMENT = 1 << 3, /* used for scale adjustment */ + /* optimization */ + AF_CJK_BLUE_FLAG_MAX + }; + + + typedef struct AF_CJKBlueRec_ + { + AF_WidthRec ref; + AF_WidthRec shoot; /* undershoot */ + FT_UInt flags; + + } AF_CJKBlueRec, *AF_CJKBlue; + + + typedef struct AF_CJKAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; + + FT_UInt width_count; + AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; + FT_Pos edge_distance_threshold; + FT_Pos standard_width; + FT_Bool extra_light; + + /* used for horizontal metrics too for CJK */ + FT_Bool control_overshoot; + FT_UInt blue_count; + AF_CJKBlueRec blues[AF_CJK_BLUE_MAX]; + + FT_Fixed org_scale; + FT_Pos org_delta; + + } AF_CJKAxisRec, *AF_CJKAxis; + + + typedef struct AF_CJKMetricsRec_ + { + AF_ScriptMetricsRec root; + FT_UInt units_per_em; + AF_CJKAxisRec axis[AF_DIMENSION_MAX]; + + } AF_CJKMetricsRec, *AF_CJKMetrics; + FT_LOCAL( FT_Error ) - af_cjk_metrics_init( AF_LatinMetrics metrics, - FT_Face face ); + af_cjk_metrics_init( AF_CJKMetrics metrics, + FT_Face face ); FT_LOCAL( void ) - af_cjk_metrics_scale( AF_LatinMetrics metrics, - AF_Scaler scaler ); + af_cjk_metrics_scale( AF_CJKMetrics metrics, + AF_Scaler scaler ); FT_LOCAL( FT_Error ) - af_cjk_hints_init( AF_GlyphHints hints, - AF_LatinMetrics metrics ); + af_cjk_hints_init( AF_GlyphHints hints, + AF_CJKMetrics metrics ); FT_LOCAL( FT_Error ) - af_cjk_hints_apply( AF_GlyphHints hints, - FT_Outline* outline, - AF_LatinMetrics metrics ); + af_cjk_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_CJKMetrics metrics ); + + /* Shared. called from afindic.c */ + FT_LOCAL( void ) + af_cjk_metrics_check_digits( AF_CJKMetrics metrics, + FT_Face face ); + + FT_LOCAL( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face, + FT_ULong charcode ); + /* */ diff --git a/freetype/src/autofit/afdummy.c b/freetype/src/autofit/afdummy.c index 42b2fcb21..c71265131 100644 --- a/freetype/src/autofit/afdummy.c +++ b/freetype/src/autofit/afdummy.c @@ -5,7 +5,7 @@ /* Auto-fitter dummy routines to be used if no hinting should be */ /* performed (body). */ /* */ -/* Copyright 2003, 2004, 2005 by */ +/* Copyright 2003-2005, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -19,6 +19,7 @@ #include "afdummy.h" #include "afhints.h" +#include "aferrors.h" static FT_Error @@ -27,7 +28,7 @@ { af_glyph_hints_rescale( hints, metrics ); - return 0; + return AF_Err_Ok; } @@ -38,11 +39,11 @@ FT_UNUSED( hints ); FT_UNUSED( outline ); - return 0; + return AF_Err_Ok; } - AF_DEFINE_SCRIPT_CLASS(af_dummy_script_class, + AF_DEFINE_SCRIPT_CLASS( af_dummy_script_class, AF_SCRIPT_NONE, NULL, diff --git a/freetype/src/autofit/afdummy.h b/freetype/src/autofit/afdummy.h index b69ef437f..95d8f8cf1 100644 --- a/freetype/src/autofit/afdummy.h +++ b/freetype/src/autofit/afdummy.h @@ -5,7 +5,7 @@ /* Auto-fitter dummy routines to be used if no hinting should be */ /* performed (specification). */ /* */ -/* Copyright 2003, 2004, 2005 by */ +/* Copyright 2003-2005, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -29,7 +29,7 @@ FT_BEGIN_HEADER * be performed. This is the default for non-latin glyphs! */ - AF_DECLARE_SCRIPT_CLASS(af_dummy_script_class) + AF_DECLARE_SCRIPT_CLASS( af_dummy_script_class ) /* */ diff --git a/freetype/src/autofit/afglobal.c b/freetype/src/autofit/afglobal.c index 178c884cd..3c5f02ec6 100644 --- a/freetype/src/autofit/afglobal.c +++ b/freetype/src/autofit/afglobal.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter routines to compute global hinting values (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, */ @@ -31,8 +31,8 @@ #ifndef FT_CONFIG_OPTION_PIC -/* when updating this table, don't forget to update - AF_SCRIPT_CLASSES_COUNT and autofit_module_class_pic_init */ + /* when updating this table, don't forget to update */ + /* AF_SCRIPT_CLASSES_COUNT and autofit_module_class_pic_init */ /* populate this list when you add new scripts */ static AF_ScriptClass const af_script_classes[] = @@ -47,7 +47,7 @@ NULL /* do not remove */ }; -#endif /* FT_CONFIG_OPTION_PIC */ +#endif /* !FT_CONFIG_OPTION_PIC */ /* index of default script in `af_script_classes' */ #define AF_SCRIPT_LIST_DEFAULT 2 @@ -85,7 +85,7 @@ FT_UInt ss, i; - /* the value 255 means `uncovered glyph' */ + /* the value AF_SCRIPT_LIST_NONE means `uncovered glyph' */ FT_MEM_SET( globals->glyph_scripts, AF_SCRIPT_LIST_NONE, globals->glyph_count ); @@ -126,9 +126,7 @@ if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count && gscripts[gindex] == AF_SCRIPT_LIST_NONE ) - { gscripts[gindex] = (FT_Byte)ss; - } for (;;) { @@ -139,9 +137,7 @@ if ( gindex < (FT_ULong)globals->glyph_count && gscripts[gindex] == AF_SCRIPT_LIST_NONE ) - { gscripts[gindex] = (FT_Byte)ss; - } } } } diff --git a/freetype/src/autofit/afglobal.h b/freetype/src/autofit/afglobal.h index 2a68e1960..cc6860b26 100644 --- a/freetype/src/autofit/afglobal.h +++ b/freetype/src/autofit/afglobal.h @@ -5,7 +5,7 @@ /* Auto-fitter routines to compute global hinting values */ /* (specification). */ /* */ -/* Copyright 2003, 2004, 2005, 2007, 2009 by */ +/* Copyright 2003-2005, 2007, 2009, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -17,8 +17,8 @@ /***************************************************************************/ -#ifndef __AF_GLOBAL_H__ -#define __AF_GLOBAL_H__ +#ifndef __AFGLOBAL_H__ +#define __AFGLOBAL_H__ #include "aftypes.h" @@ -65,7 +65,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __AF_GLOBALS_H__ */ +#endif /* __AFGLOBAL_H__ */ /* END */ diff --git a/freetype/src/autofit/afhints.c b/freetype/src/autofit/afhints.c index c3497091d..f51066f02 100644 --- a/freetype/src/autofit/afhints.c +++ b/freetype/src/autofit/afhints.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines (body). */ /* */ -/* Copyright 2003, 2004, 2005, 2006, 2007, 2009, 2010 by */ +/* Copyright 2003-2007, 2009-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -21,6 +21,8 @@ #include FT_INTERNAL_CALC_H + /* Get new segment for given axis. */ + FT_LOCAL_DEF( FT_Error ) af_axis_hints_new_segment( AF_AxisHints axis, FT_Memory memory, @@ -61,6 +63,8 @@ } + /* Get new edge for given axis, direction, and position. */ + FT_LOCAL( FT_Error ) af_axis_hints_new_edge( AF_AxisHints axis, FT_Int fpos, @@ -125,7 +129,7 @@ } -#ifdef AF_DEBUG +#ifdef FT_DEBUG_AUTOFIT #include FT_CONFIG_STANDARD_LIBRARY_H @@ -160,6 +164,9 @@ #define AF_INDEX_NUM( ptr, base ) ( (ptr) ? ( (ptr) - (base) ) : -1 ) +#ifdef __cplusplus + extern "C" { +#endif void af_glyph_hints_dump_points( AF_GlyphHints hints ) { @@ -169,20 +176,20 @@ printf( "Table of points:\n" ); - printf( " [ index | xorg | yorg | xscale | yscale " - "| xfit | yfit | flags ]\n" ); + printf( " [ index | xorg | yorg | xscale | yscale" + " | xfit | yfit | flags ]\n" ); for ( point = points; point < limit; point++ ) { - printf( " [ %5d | %5d | %5d | %-5.2f | %-5.2f " - "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n", + printf( " [ %5d | %5d | %5d | %6.2f | %6.2f" + " | %5.2f | %5.2f | %c%c%c%c%c%c ]\n", point - points, point->fx, point->fy, - point->ox/64.0, - point->oy/64.0, - point->x/64.0, - point->y/64.0, + point->ox / 64.0, + point->oy / 64.0, + point->x / 64.0, + point->y / 64.0, ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ', ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ', ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ', @@ -192,6 +199,9 @@ } printf( "\n" ); } +#ifdef __cplusplus + } +#endif static const char* @@ -222,7 +232,11 @@ } - /* A function to dump the array of linked segments. */ + /* Dump the array of linked segments. */ + +#ifdef __cplusplus + extern "C" { +#endif void af_glyph_hints_dump_segments( AF_GlyphHints hints ) { @@ -240,11 +254,11 @@ printf ( "Table of %s segments:\n", dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ); printf ( " [ index | pos | dir | link | serif |" - " height | extra | flags ]\n" ); + " height | extra | flags ]\n" ); for ( seg = segments; seg < limit; seg++ ) { - printf ( " [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n", + printf ( " [ %5d | %5.2g | %5s | %4d | %5d | %6d | %5d | %11s ]\n", seg - segments, dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0 : (int)seg->first->oy / 64.0, @@ -253,13 +267,84 @@ AF_INDEX_NUM( seg->serif, segments ), seg->height, seg->height - ( seg->max_coord - seg->min_coord ), - af_edge_flags_to_string( seg->flags ) ); + af_edge_flags_to_string( (AF_Edge_Flags)seg->flags ) ); } printf( "\n" ); } } +#ifdef __cplusplus + } +#endif + + + /* Fetch number of segments. */ + +#ifdef __cplusplus + extern "C" { +#endif + FT_Error + af_glyph_hints_get_num_segments( AF_GlyphHints hints, + FT_Int dimension, + FT_Int* num_segments ) + { + AF_Dimension dim; + AF_AxisHints axis; + + + dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; + + axis = &hints->axis[dim]; + *num_segments = axis->num_segments; + + return AF_Err_Ok; + } +#ifdef __cplusplus + } +#endif + + + /* Fetch offset of segments into user supplied offset array. */ + +#ifdef __cplusplus + extern "C" { +#endif + FT_Error + af_glyph_hints_get_segment_offset( AF_GlyphHints hints, + FT_Int dimension, + FT_Int idx, + FT_Pos* offset ) + { + AF_Dimension dim; + AF_AxisHints axis; + AF_Segment seg; + + + if ( !offset ) + return AF_Err_Invalid_Argument; + + dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT; + + axis = &hints->axis[dim]; + + if ( idx < 0 || idx >= axis->num_segments ) + return AF_Err_Invalid_Argument; + + seg = &axis->segments[idx]; + *offset = (dim == AF_DIMENSION_HORZ) ? seg->first->ox + : seg->first->oy; + + return AF_Err_Ok; + } +#ifdef __cplusplus + } +#endif + + /* Dump the array of linked edges. */ +#ifdef __cplusplus + extern "C" { +#endif void af_glyph_hints_dump_edges( AF_GlyphHints hints ) { @@ -276,17 +361,17 @@ /* * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges - * since they have constant a X coordinate. + * since they have a constant X coordinate. */ printf ( "Table of %s edges:\n", dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ); printf ( " [ index | pos | dir | link |" - " serif | blue | opos | pos | flags ]\n" ); + " serif | blue | opos | pos | flags ]\n" ); for ( edge = edges; edge < limit; edge++ ) { printf ( " [ %5d | %5.2g | %5s | %4d |" - " %5d | %c | %5.2f | %5.2f | %s ]\n", + " %5d | %c | %5.2f | %5.2f | %11s ]\n", edge - edges, (int)edge->opos / 64.0, af_dir_str( (AF_Direction)edge->dir ), @@ -295,16 +380,23 @@ edge->blue_edge ? 'y' : 'n', edge->opos / 64.0, edge->pos / 64.0, - af_edge_flags_to_string( edge->flags ) ); + af_edge_flags_to_string( (AF_Edge_Flags)edge->flags ) ); } printf( "\n" ); } } +#ifdef __cplusplus + } +#endif -#else /* !AF_DEBUG */ +#else /* !FT_DEBUG_AUTOFIT */ /* these empty stubs are only used to link the `ftgrid' test program */ - /* when debugging is disabled */ + /* if debugging is disabled */ + +#ifdef __cplusplus + extern "C" { +#endif void af_glyph_hints_dump_points( AF_GlyphHints hints ) @@ -320,16 +412,49 @@ } + FT_Error + af_glyph_hints_get_num_segments( AF_GlyphHints hints, + FT_Int dimension, + FT_Int* num_segments ) + { + FT_UNUSED( hints ); + FT_UNUSED( dimension ); + FT_UNUSED( num_segments ); + + return 0; + } + + + FT_Error + af_glyph_hints_get_segment_offset( AF_GlyphHints hints, + FT_Int dimension, + FT_Int idx, + FT_Pos* offset ) + { + FT_UNUSED( hints ); + FT_UNUSED( dimension ); + FT_UNUSED( idx ); + FT_UNUSED( offset ); + + return 0; + } + + void af_glyph_hints_dump_edges( AF_GlyphHints hints ) { FT_UNUSED( hints ); } -#endif /* !AF_DEBUG */ +#ifdef __cplusplus + } +#endif +#endif /* !FT_DEBUG_AUTOFIT */ + + + /* Compute the direction value of a given vector. */ - /* compute the direction value of a given vector */ FT_LOCAL_DEF( AF_Direction ) af_direction_compute( FT_Pos dx, FT_Pos dy ) @@ -369,6 +494,8 @@ } } + /* return no direction if arm lengths differ too much */ + /* (value 14 is heuristic) */ ss *= 14; if ( FT_ABS( ll ) <= FT_ABS( ss ) ) dir = AF_DIR_NONE; @@ -397,7 +524,7 @@ /* * note that we don't need to free the segment and edge - * buffers, since they are really within the hints->points array + * buffers since they are really within the hints->points array */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { @@ -408,8 +535,8 @@ axis->max_segments = 0; FT_FREE( axis->segments ); - axis->num_edges = 0; - axis->max_edges = 0; + axis->num_edges = 0; + axis->max_edges = 0; FT_FREE( axis->edges ); } @@ -426,6 +553,8 @@ } + /* Reset metrics. */ + FT_LOCAL_DEF( void ) af_glyph_hints_rescale( AF_GlyphHints hints, AF_ScriptMetrics metrics ) @@ -435,6 +564,9 @@ } + /* Recompute all AF_Point in AF_GlyphHints from the definitions */ + /* in a source outline. */ + FT_LOCAL_DEF( FT_Error ) af_glyph_hints_reload( AF_GlyphHints hints, FT_Outline* outline ) @@ -457,12 +589,12 @@ hints->axis[1].num_segments = 0; hints->axis[1].num_edges = 0; - /* first of all, reallocate the contours array when necessary */ + /* first of all, reallocate the contours array if necessary */ new_max = (FT_UInt)outline->n_contours; old_max = hints->max_contours; if ( new_max > old_max ) { - new_max = ( new_max + 3 ) & ~3; + new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) goto Exit; @@ -479,7 +611,7 @@ old_max = hints->max_points; if ( new_max > old_max ) { - new_max = ( new_max + 2 + 7 ) & ~7; + new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */ if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) goto Exit; @@ -545,7 +677,7 @@ point->flags = AF_FLAG_CUBIC; break; default: - point->flags = 0; + point->flags = AF_FLAG_NONE; } point->prev = prev; @@ -563,7 +695,7 @@ } } - /* set-up the contours array */ + /* set up the contours array */ { AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; @@ -611,6 +743,8 @@ in_dir = af_direction_compute( out_x, out_y ); point->out_dir = (FT_Char)in_dir; + /* check for weak points */ + if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) { Is_Weak_Point: @@ -639,6 +773,8 @@ } + /* Store the hinted outline in an FT_Outline structure. */ + FT_LOCAL_DEF( void ) af_glyph_hints_save( AF_GlyphHints hints, FT_Outline* outline ) @@ -671,6 +807,9 @@ ****************************************************************/ + /* Align all points of an edge to the same coordinate value, */ + /* either horizontally or vertically. */ + FT_LOCAL_DEF( void ) af_glyph_hints_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) @@ -704,7 +843,6 @@ break; point = point->next; - } } } @@ -744,8 +882,8 @@ ****************************************************************/ - /* hint the strong points -- this is equivalent to the TrueType `IP' */ - /* hinting instruction */ + /* Hint the strong points -- this is equivalent to the TrueType `IP' */ + /* hinting instruction. */ FT_LOCAL_DEF( void ) af_glyph_hints_align_strong_points( AF_GlyphHints hints, @@ -827,11 +965,12 @@ max = edge_limit - edges; #if 1 - /* for small edge counts, a linear search is better */ + /* for a small number of edges, a linear search is better */ if ( max <= 8 ) { FT_PtrDist nn; + for ( nn = 0; nn < max; nn++ ) if ( edges[nn].fpos >= u ) break; @@ -863,6 +1002,7 @@ } } + /* point is not on an edge */ { AF_Edge before = edges + min - 1; AF_Edge after = edges + min + 0; @@ -898,6 +1038,10 @@ ****************************************************************/ + /* Shift the original coordinates of all points between `p1' and */ + /* `p2' to get hinted coordinates, using the same difference as */ + /* given by `ref'. */ + static void af_iup_shift( AF_Point p1, AF_Point p2, @@ -906,6 +1050,7 @@ AF_Point p; FT_Pos delta = ref->u - ref->v; + if ( delta == 0 ) return; @@ -917,6 +1062,13 @@ } + /* Interpolate the original coordinates of all points between `p1' and */ + /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */ + /* reference points. The `u' and `v' members are the current and */ + /* original coordinate values, respectively. */ + /* */ + /* Details can be found in the TrueType bytecode specification. */ + static void af_iup_interp( AF_Point p1, AF_Point p2, @@ -985,6 +1137,9 @@ } + /* Hint the weak points -- this is equivalent to the TrueType `IUP' */ + /* hinting instruction. */ + FT_LOCAL_DEF( void ) af_glyph_hints_align_weak_points( AF_GlyphHints hints, AF_Dimension dim ) @@ -1050,17 +1205,18 @@ for (;;) { - FT_ASSERT( point <= end_point && + FT_ASSERT( point <= end_point && ( point->flags & touch_flag ) != 0 ); - /* skip any touched neighbhours */ - while ( point < end_point && ( point[1].flags & touch_flag ) != 0 ) + /* skip any touched neighbours */ + while ( point < end_point && + ( point[1].flags & touch_flag ) != 0 ) point++; last_touched = point; /* find the next touched point, if any */ - point ++; + point++; for (;;) { if ( point > end_point ) @@ -1080,9 +1236,8 @@ EndContour: /* special case: only one point was touched */ if ( last_touched == first_touched ) - { af_iup_shift( first_point, end_point, first_touched ); - } + else /* interpolate the last part */ { if ( last_touched < end_point ) @@ -1112,7 +1267,9 @@ } -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER + + /* Apply (small) warp scale and warp delta for given dimension. */ FT_LOCAL_DEF( void ) af_glyph_hints_scale_dim( AF_GlyphHints hints, @@ -1137,6 +1294,6 @@ } } -#endif /* AF_USE_WARPER */ +#endif /* AF_CONFIG_OPTION_USE_WARPER */ /* END */ diff --git a/freetype/src/autofit/afhints.h b/freetype/src/autofit/afhints.h index 10e673b3f..1c52e0de7 100644 --- a/freetype/src/autofit/afhints.h +++ b/freetype/src/autofit/afhints.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines (specification). */ /* */ -/* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2010 by */ +/* Copyright 2003-2008, 2010-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -25,10 +25,10 @@ FT_BEGIN_HEADER - /* - * The definition of outline glyph hints. These are shared by all - * script analysis routines (until now). - */ + /* + * The definition of outline glyph hints. These are shared by all + * script analysis routines (until now). + */ typedef enum AF_Dimension_ { @@ -55,6 +55,151 @@ FT_BEGIN_HEADER } AF_Direction; + /* + * The following explanations are mostly taken from the article + * + * Real-Time Grid Fitting of Typographic Outlines + * + * by David Turner and Werner Lemberg + * + * http://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf + * + * + * Segments + * + * `af_{cjk,latin,...}_hints_compute_segments' are the functions to + * find segments in an outline. A segment is a series of consecutive + * points that are approximately aligned along a coordinate axis. The + * analysis to do so is specific to a script. + * + * A segment must have at least two points, except in the case of + * `fake' segments that are generated to hint metrics appropriately, + * and which consist of a single point. + * + * + * Edges + * + * As soon as segments are defined, the auto-hinter groups them into + * edges. An edge corresponds to a single position on the main + * dimension that collects one or more segments (allowing for a small + * threshold). + * + * The auto-hinter first tries to grid fit edges, then to align + * segments on the edges unless it detects that they form a serif. + * + * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find + * edges; they are specific to a script. + * + * + * A H + * | | + * | | + * | | + * | | + * C | | F + * +------<-----+ +-----<------+ + * | B G | + * | | + * | | + * +--------------->------------------+ + * D E + * + * + * Stems + * + * Segments need to be `linked' to other ones in order to detect stems. + * A stem is made of two segments that face each other in opposite + * directions and that are sufficiently close to each other. Using + * vocabulary from the TrueType specification, stem segments form a + * `black distance'. + * + * In the above ASCII drawing, the horizontal segments are BC, DE, and + * FG; the vertical segments are AB, CD, EF, and GH. + * + * Each segment has at most one `best' candidate to form a black + * distance, or no candidate at all. Notice that two distinct segments + * can have the same candidate, which frequently means a serif. + * + * A stem is recognized by the following condition: + * + * best segment_1 = segment_2 && best segment_2 = segment_1 + * + * The best candidate is stored in field `link' in structure + * `AF_Segment'. + * + * Stems are detected by `af_{cjk,latin,...}_hint_edges'. + * + * In the above ASCII drawing, the best candidate for both AB and CD is + * GH, while the best candidate for GH is AB. Similarly, the best + * candidate for EF and GH is AB, while the best candidate for AB is + * GH. + * + * + * Serifs + * + * On the opposite, a serif has + * + * best segment_1 = segment_2 && best segment_2 != segment_1 + * + * where segment_1 corresponds to the serif segment (CD and EF in the + * above ASCII drawing). + * + * The best candidate is stored in field `serif' in structure + * `AF_Segment' (and `link' is set to NULL). + * + * Serifs are detected by `af_{cjk,latin,...}_hint_edges'. + * + * + * Touched points + * + * A point is called `touched' if it has been processed somehow by the + * auto-hinter. It basically means that it shouldn't be moved again + * (or moved only under certain constraints to preserve the already + * applied processing). + * + * + * Flat and round segments + * + * Segments are `round' or `flat', depending on the series of points + * that define them. A segment is round if the next and previous point + * of an extremum (which can be either a single point or sequence of + * points) are both conic or cubic control points. Otherwise, a + * segment with an extremum is flat. + * + * + * Strong Points + * + * Experience has shown that points which are not part of an edge need + * to be interpolated linearly between their two closest edges, even if + * these are not part of the contour of those particular points. + * Typical candidates for this are + * + * - angle points (i.e., points where the `in' and `out' direction + * differ greatly) + * + * - inflection points (i.e., where the `in' and `out' angles are the + * same, but the curvature changes sign) + * + * `af_glyph_hints_align_strong_points' is the function which takes + * care of such situations; it is equivalent to the TrueType `IP' + * hinting instruction. + * + * + * Weak Points + * + * Other points in the outline must be interpolated using the + * coordinates of their previous and next unfitted contour neighbours. + * These are called `weak points' and are touched by the function + * `af_glyph_hints_align_weak_points', equivalent to the TrueType `IUP' + * hinting instruction. Typical candidates are control points and + * points on the contour without a major direction. + * + * The major effect is to reduce possible distortion caused by + * alignment of edges and strong points, thus weak points are processed + * after strong points. + */ + + /* point hint flags */ typedef enum AF_Flags_ { @@ -137,9 +282,8 @@ FT_BEGIN_HEADER FT_Pos score; /* used during stem matching */ FT_Pos len; /* used during stem matching */ - AF_Point first; /* first point in edge segment */ - AF_Point last; /* last point in edge segment */ - AF_Point* contour; /* ptr to first point of segment's contour */ + AF_Point first; /* first point in edge segment */ + AF_Point last; /* last point in edge segment */ } AF_SegmentRec; @@ -155,32 +299,31 @@ FT_BEGIN_HEADER FT_Fixed scale; /* used to speed up interpolation between edges */ AF_Width blue_edge; /* non-NULL if this is a blue edge */ - AF_Edge link; - AF_Edge serif; - FT_Short num_linked; - - FT_Int score; + AF_Edge link; /* link edge */ + AF_Edge serif; /* primary edge for serifs */ + FT_Short num_linked; /* number of linked edges */ + FT_Int score; /* used during stem matching */ - AF_Segment first; - AF_Segment last; + AF_Segment first; /* first segment in edge */ + AF_Segment last; /* last segment in edge */ } AF_EdgeRec; typedef struct AF_AxisHintsRec_ { - FT_Int num_segments; - FT_Int max_segments; - AF_Segment segments; + FT_Int num_segments; /* number of used segments */ + FT_Int max_segments; /* number of allocated segments */ + AF_Segment segments; /* segments array */ #ifdef AF_SORT_SEGMENTS FT_Int mid_segments; #endif - FT_Int num_edges; - FT_Int max_edges; - AF_Edge edges; + FT_Int num_edges; /* number of used edges */ + FT_Int max_edges; /* number of allocated edges */ + AF_Edge edges; /* edges array */ - AF_Direction major_dir; + AF_Direction major_dir; /* either vertical or horizontal */ } AF_AxisHintsRec, *AF_AxisHints; @@ -195,15 +338,13 @@ FT_BEGIN_HEADER FT_Fixed y_scale; FT_Pos y_delta; - FT_Pos edge_distance_threshold; + FT_Int max_points; /* number of allocated points */ + FT_Int num_points; /* number of used points */ + AF_Point points; /* points array */ - FT_Int max_points; - FT_Int num_points; - AF_Point points; - - FT_Int max_contours; - FT_Int num_contours; - AF_Point* contours; + FT_Int max_contours; /* number of allocated contours */ + FT_Int num_contours; /* number of used contours */ + AF_Point* contours; /* contours array */ AF_AxisHintsRec axis[AF_DIMENSION_MAX]; @@ -214,7 +355,7 @@ FT_BEGIN_HEADER FT_Pos xmin_delta; /* used for warping */ FT_Pos xmax_delta; - + } AF_GlyphHintsRec; @@ -222,7 +363,7 @@ FT_BEGIN_HEADER #define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) ) -#ifdef AF_DEBUG +#ifdef FT_DEBUG_AUTOFIT #define AF_HINTS_DO_HORIZONTAL( h ) \ ( !_af_debug_disable_horz_hints && \ @@ -237,7 +378,7 @@ FT_BEGIN_HEADER #define AF_HINTS_DO_BLUES( h ) ( !_af_debug_disable_blue_hints ) -#else /* !AF_DEBUG */ +#else /* !FT_DEBUG_AUTOFIT */ #define AF_HINTS_DO_HORIZONTAL( h ) \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) @@ -250,7 +391,7 @@ FT_BEGIN_HEADER #define AF_HINTS_DO_BLUES( h ) 1 -#endif /* !AF_DEBUG */ +#endif /* !FT_DEBUG_AUTOFIT */ FT_LOCAL( AF_Direction ) @@ -274,12 +415,6 @@ FT_BEGIN_HEADER af_glyph_hints_init( AF_GlyphHints hints, FT_Memory memory ); - - - /* - * recompute all AF_Point in a AF_GlyphHints from the definitions - * in a source outline - */ FT_LOCAL( void ) af_glyph_hints_rescale( AF_GlyphHints hints, AF_ScriptMetrics metrics ); @@ -304,7 +439,7 @@ FT_BEGIN_HEADER af_glyph_hints_align_weak_points( AF_GlyphHints hints, AF_Dimension dim ); -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER FT_LOCAL( void ) af_glyph_hints_scale_dim( AF_GlyphHints hints, AF_Dimension dim, diff --git a/freetype/src/autofit/afindic.c b/freetype/src/autofit/afindic.c index 1d9e9eafb..c232cff78 100644 --- a/freetype/src/autofit/afindic.c +++ b/freetype/src/autofit/afindic.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for Indic scripts (body). */ /* */ -/* Copyright 2007 by */ +/* Copyright 2007, 2011 by */ /* Rahul Bhalerao , . */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -27,23 +27,42 @@ #include "afcjk.h" -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER #include "afwarp.h" #endif static FT_Error - af_indic_metrics_init( AF_LatinMetrics metrics, - FT_Face face ) + af_indic_metrics_init( AF_CJKMetrics metrics, + FT_Face face ) { - /* use CJK routines */ - return af_cjk_metrics_init( metrics, face ); + /* skip blue zone init in CJK routines */ + FT_CharMap oldmap = face->charmap; + + + metrics->units_per_em = face->units_per_EM; + + if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + face->charmap = NULL; + else + { + af_cjk_metrics_init_widths( metrics, face, 0x7530 ); +#if 0 + /* either need indic specific blue_chars[] or just skip blue zones */ + af_cjk_metrics_init_blues( metrics, face, af_cjk_blue_chars ); +#endif + af_cjk_metrics_check_digits( metrics, face ); + } + + FT_Set_Charmap( face, oldmap ); + + return AF_Err_Ok; } static void - af_indic_metrics_scale( AF_LatinMetrics metrics, - AF_Scaler scaler ) + af_indic_metrics_scale( AF_CJKMetrics metrics, + AF_Scaler scaler ) { /* use CJK routines */ af_cjk_metrics_scale( metrics, scaler ); @@ -51,8 +70,8 @@ static FT_Error - af_indic_hints_init( AF_GlyphHints hints, - AF_LatinMetrics metrics ) + af_indic_hints_init( AF_GlyphHints hints, + AF_CJKMetrics metrics ) { /* use CJK routines */ return af_cjk_hints_init( hints, metrics ); @@ -60,9 +79,9 @@ static FT_Error - af_indic_hints_apply( AF_GlyphHints hints, - FT_Outline* outline, - AF_LatinMetrics metrics) + af_indic_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_CJKMetrics metrics ) { /* use CJK routines */ return af_cjk_hints_apply( hints, outline, metrics ); @@ -84,6 +103,12 @@ AF_UNIRANGE_REC( 0x0100UL, 0xFFFFUL ), /* why this? */ #endif AF_UNIRANGE_REC( 0x0900UL, 0x0DFFUL), /* Indic Range */ + AF_UNIRANGE_REC( 0x0F00UL, 0x0FFFUL), /* Tibetan */ + AF_UNIRANGE_REC( 0x1900UL, 0x194FUL), /* Limbu */ + AF_UNIRANGE_REC( 0x1B80UL, 0x1BBFUL), /* Sundanese */ + AF_UNIRANGE_REC( 0x1C80UL, 0x1CDFUL), /* Meetei Mayak */ + AF_UNIRANGE_REC( 0xA800UL, 0xA82FUL), /* Syloti Nagri */ + AF_UNIRANGE_REC( 0x11800UL, 0x118DFUL), /* Sharada */ AF_UNIRANGE_REC( 0UL, 0UL) }; @@ -92,7 +117,7 @@ AF_SCRIPT_INDIC, af_indic_uniranges, - sizeof( AF_LatinMetricsRec ), + sizeof( AF_CJKMetricsRec ), (AF_Script_InitMetricsFunc) af_indic_metrics_init, (AF_Script_ScaleMetricsFunc)af_indic_metrics_scale, @@ -114,7 +139,7 @@ AF_SCRIPT_INDIC, af_indic_uniranges, - sizeof( AF_LatinMetricsRec ), + sizeof( AF_CJKMetricsRec ), (AF_Script_InitMetricsFunc) NULL, (AF_Script_ScaleMetricsFunc)NULL, diff --git a/freetype/src/autofit/aflatin.c b/freetype/src/autofit/aflatin.c index 63491e310..54fcf7f0a 100644 --- a/freetype/src/autofit/aflatin.c +++ b/freetype/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,16 +18,27 @@ #include #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 + + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -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; @@ -1572,6 +1669,7 @@ else { /* strong hinting process: snap the stem width to integer pixels */ + FT_Pos org_dist = dist; @@ -1646,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, @@ -1664,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, @@ -1678,7 +1779,7 @@ { FT_UNUSED( hints ); - serif->pos = base->pos + (serif->opos - base->opos); + serif->pos = base->pos + ( serif->opos - base->opos ); } @@ -1693,6 +1794,8 @@ /*************************************************************************/ + /* The main grid-fitting routine. */ + FT_LOCAL_DEF( void ) af_latin_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) @@ -1702,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 */ @@ -1714,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 ) @@ -1725,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; @@ -1738,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; @@ -1757,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; @@ -1780,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; @@ -1789,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; @@ -1798,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; } @@ -1809,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 ); @@ -1831,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; @@ -1853,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 ) { @@ -1868,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; @@ -1891,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 { @@ -1908,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; @@ -1933,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; } } @@ -2028,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 { @@ -2064,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 )); } } @@ -2090,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, @@ -2107,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 @@ -2131,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 @@ -2206,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, diff --git a/freetype/src/autofit/aflatin.h b/freetype/src/autofit/aflatin.h index 660b10c83..c5c2d13f8 100644 --- a/freetype/src/autofit/aflatin.h +++ b/freetype/src/autofit/aflatin.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter hinting routines for latin script (specification). */ /* */ -/* Copyright 2003, 2004, 2005, 2006, 2007, 2009 by */ +/* Copyright 2003-2007, 2009, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -30,8 +30,8 @@ FT_BEGIN_HEADER AF_DECLARE_SCRIPT_CLASS(af_latin_script_class) -/* constants are given with units_per_em == 2048 in mind */ -#define AF_LATIN_CONSTANT( metrics, c ) \ + /* constants are given with units_per_em == 2048 in mind */ +#define AF_LATIN_CONSTANT( metrics, c ) \ ( ( (c) * (FT_Long)( (AF_LatinMetrics)(metrics) )->units_per_em ) / 2048 ) @@ -76,10 +76,10 @@ FT_BEGIN_HEADER enum { - AF_LATIN_BLUE_ACTIVE = 1 << 0, - AF_LATIN_BLUE_TOP = 1 << 1, - AF_LATIN_BLUE_ADJUSTMENT = 1 << 2, /* used for scale adjustment */ - /* optimization */ + AF_LATIN_BLUE_ACTIVE = 1 << 0, /* set if zone height is <= 3/4px */ + AF_LATIN_BLUE_TOP = 1 << 1, /* result of AF_LATIN_IS_TOP_BLUE */ + AF_LATIN_BLUE_ADJUSTMENT = 1 << 2, /* used for scale adjustment */ + /* optimization */ AF_LATIN_BLUE_FLAG_MAX }; @@ -98,14 +98,13 @@ FT_BEGIN_HEADER FT_Fixed scale; FT_Pos delta; - FT_UInt width_count; - AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; - FT_Pos edge_distance_threshold; - FT_Pos standard_width; - FT_Bool extra_light; + FT_UInt width_count; /* number of used widths */ + AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; /* widths array */ + FT_Pos edge_distance_threshold; /* used for creating edges */ + FT_Pos standard_width; /* the default stem thickness */ + FT_Bool extra_light; /* is standard width very light? */ /* ignored for horizontal metrics */ - FT_Bool control_overshoot; FT_UInt blue_count; AF_LatinBlueRec blues[AF_LATIN_BLUE_MAX]; diff --git a/freetype/src/autofit/aflatin2.c b/freetype/src/autofit/aflatin2.c index 6546475a1..23558b879 100644 --- a/freetype/src/autofit/aflatin2.c +++ b/freetype/src/autofit/aflatin2.c @@ -1,10 +1,10 @@ /***************************************************************************/ /* */ -/* aflatin.c */ +/* aflatin2.c */ /* */ /* 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, */ @@ -23,13 +23,24 @@ #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_aflatin2 + + FT_LOCAL_DEF( FT_Error ) af_latin2_hints_compute_segments( AF_GlyphHints hints, - AF_Dimension dim ); + AF_Dimension dim ); FT_LOCAL_DEF( void ) af_latin2_hints_link_segments( AF_GlyphHints hints, @@ -45,8 +56,8 @@ FT_LOCAL_DEF( void ) af_latin2_metrics_init_widths( AF_LatinMetrics metrics, - FT_Face face, - FT_ULong charcode ) + FT_Face face, + FT_ULong charcode ) { /* scan the array of segments in each direction */ AF_GlyphHintsRec hints[1]; @@ -156,7 +167,8 @@ #define AF_LATIN_MAX_TEST_CHARACTERS 12 - static const char af_latin2_blue_chars[AF_LATIN_MAX_BLUES][AF_LATIN_MAX_TEST_CHARACTERS+1] = + static const char af_latin2_blue_chars[AF_LATIN_MAX_BLUES] + [AF_LATIN_MAX_TEST_CHARACTERS+1] = { "THEZOCQS", "HEZLOCUS", @@ -169,7 +181,7 @@ static void af_latin2_metrics_init_blues( AF_LatinMetrics metrics, - FT_Face face ) + FT_Face face ) { FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS]; FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS]; @@ -182,12 +194,12 @@ FT_GlyphSlot glyph = face->glyph; - /* we compute the blues simply by loading each character from the */ + /* we compute the blues simply by loading each character from the */ /* 'af_latin2_blue_chars[blues]' string, then compute its top-most or */ - /* bottom-most points (depending on `AF_IS_TOP_BLUE') */ + /* 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++ ) { @@ -197,7 +209,7 @@ FT_Pos* blue_shoot; - AF_LOG(( "blue %3d: ", bb )); + FT_TRACE5(( "blue %3d: ", bb )); num_flats = 0; num_rounds = 0; @@ -210,7 +222,7 @@ FT_Bool round; - 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 ); @@ -273,7 +285,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 */ @@ -321,7 +333,7 @@ FT_CURVE_TAG( glyph->outline.tags[start] ) != FT_CURVE_TAG_ON || FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON ); - AF_LOG(( "%c ", round ? 'r' : 'f' )); + FT_TRACE5(( "%c ", round ? 'r' : 'f' )); } if ( round ) @@ -330,7 +342,7 @@ flats[num_flats++] = best_y; } - AF_LOG(( "\n" )); + FT_TRACE5(( "\n" )); if ( num_flats == 0 && num_rounds == 0 ) { @@ -338,7 +350,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; } @@ -396,7 +408,7 @@ 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 )); } return; @@ -451,7 +463,7 @@ FT_LOCAL_DEF( FT_Error ) af_latin2_metrics_init( AF_LatinMetrics metrics, - FT_Face face ) + FT_Face face ) { FT_Error error = AF_Err_Ok; FT_CharMap oldmap = face->charmap; @@ -492,8 +504,8 @@ static void af_latin2_metrics_scale_dim( AF_LatinMetrics metrics, - AF_Scaler scaler, - AF_Dimension dim ) + AF_Scaler scaler, + AF_Dimension dim ) { FT_Fixed scale; FT_Pos delta; @@ -548,7 +560,10 @@ if ( scaled != fitted ) { scale = FT_MulDiv( scale, fitted, scaled ); - AF_LOG(( "== scaled x-top = %.2g fitted = %.2g, scaling = %.4g\n", scaled/64.0, fitted/64.0, (fitted*1.0)/scaled )); + FT_TRACE5(( "== scaled x-top = %.2g" + " fitted = %.2g, scaling = %.4g\n", + scaled / 64.0, fitted / 64.0, + ( fitted * 1.0 ) / scaled )); } #endif } @@ -579,7 +594,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 ); @@ -624,9 +639,11 @@ blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); blue->shoot.fit = blue->ref.fit + delta2; - AF_LOG(( ">> activating blue zone %d: ref.cur=%.2g ref.fit=%.2g shoot.cur=%.2g shoot.fit=%.2g\n", - nn, blue->ref.cur/64.0, blue->ref.fit/64.0, - blue->shoot.cur/64.0, blue->shoot.fit/64.0 )); + FT_TRACE5(( ">> activating blue zone %d:" + " ref.cur=%.2g ref.fit=%.2g" + " shoot.cur=%.2g shoot.fit=%.2g\n", + nn, blue->ref.cur / 64.0, blue->ref.fit / 64.0, + blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); blue->flags |= AF_LATIN_BLUE_ACTIVE; } @@ -637,7 +654,7 @@ FT_LOCAL_DEF( void ) af_latin2_metrics_scale( AF_LatinMetrics metrics, - AF_Scaler scaler ) + AF_Scaler scaler ) { metrics->root.scaler.render_mode = scaler->render_mode; metrics->root.scaler.face = scaler->face; @@ -659,7 +676,7 @@ FT_LOCAL_DEF( FT_Error ) af_latin2_hints_compute_segments( AF_GlyphHints hints, - AF_Dimension dim ) + AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Memory memory = hints->memory; @@ -779,7 +796,6 @@ segment->dir = first->out_dir; segment->first = first; segment->last = point; - segment->contour = contour; segment->pos = (FT_Short)(( min_u + max_u ) >> 1); segment->min_coord = (FT_Short) min_v; segment->max_coord = (FT_Short) max_v; @@ -917,7 +933,7 @@ FT_LOCAL_DEF( void ) af_latin2_hints_link_segments( AF_GlyphHints hints, - AF_Dimension dim ) + AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; @@ -1017,7 +1033,7 @@ FT_LOCAL_DEF( FT_Error ) af_latin2_hints_compute_edges( AF_GlyphHints hints, - AF_Dimension dim ) + AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Error error = AF_Err_Ok; @@ -1137,7 +1153,8 @@ /* insert a new edge in the list and */ /* sort according to the position */ - error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, memory, &edge ); + error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, + memory, &edge ); if ( error ) goto Exit; @@ -1205,8 +1222,10 @@ { 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; @@ -1222,11 +1241,13 @@ else is_straight++; +#if 0 /* check for segment direction */ if ( seg->dir == up_dir ) ups += seg->max_coord-seg->min_coord; else downs += seg->max_coord-seg->min_coord; +#endif /* check for links -- if seg->serif is set, then seg->link must */ /* be ignored */ @@ -1318,7 +1339,7 @@ FT_LOCAL_DEF( FT_Error ) af_latin2_hints_detect_features( AF_GlyphHints hints, - AF_Dimension dim ) + AF_Dimension dim ) { FT_Error error; @@ -1336,7 +1357,7 @@ FT_LOCAL_DEF( void ) af_latin2_hints_compute_blue_edges( AF_GlyphHints hints, - AF_LatinMetrics metrics ) + AF_LatinMetrics metrics ) { AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ]; AF_Edge edge = axis->edges; @@ -1442,7 +1463,7 @@ static FT_Error af_latin2_hints_init( AF_GlyphHints hints, - AF_LatinMetrics metrics ) + AF_LatinMetrics metrics ) { FT_Render_Mode mode; FT_UInt32 scaler_flags, other_flags; @@ -1463,7 +1484,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; @@ -1524,8 +1545,8 @@ static FT_Pos af_latin2_snap_width( AF_Width widths, - FT_Int count, - FT_Pos width ) + FT_Int count, + FT_Pos width ) { int n; FT_Pos best = 64 + 32 + 2; @@ -1571,10 +1592,10 @@ static FT_Pos af_latin2_compute_stem_width( AF_GlyphHints hints, - AF_Dimension dim, - FT_Pos width, - AF_Edge_Flags base_flags, - AF_Edge_Flags stem_flags ) + AF_Dimension dim, + FT_Pos width, + AF_Edge_Flags base_flags, + AF_Edge_Flags stem_flags ) { AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics; AF_LatinAxis axis = & metrics->axis[dim]; @@ -1739,9 +1760,9 @@ static void af_latin2_align_linked_edge( AF_GlyphHints hints, - AF_Dimension dim, - AF_Edge base_edge, - AF_Edge stem_edge ) + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) { FT_Pos dist = stem_edge->opos - base_edge->opos; @@ -1753,17 +1774,17 @@ 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 )); } static void af_latin2_align_serif_edge( AF_GlyphHints hints, - AF_Edge base, - AF_Edge serif ) + AF_Edge base, + AF_Edge serif ) { FT_UNUSED( hints ); @@ -1784,7 +1805,7 @@ FT_LOCAL_DEF( void ) af_latin2_hint_edges( AF_GlyphHints hints, - AF_Dimension dim ) + AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; @@ -1796,7 +1817,8 @@ - AF_LOG(( "==== hinting %s edges =====\n", dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); + FT_TRACE5(( "==== hinting %s edges =====\n", + dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ @@ -1830,10 +1852,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; @@ -1878,7 +1900,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_latin2_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; @@ -1929,11 +1951,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; @@ -1945,7 +1967,7 @@ anchor_drift = ( (anchor->pos - anchor->opos) + (edge2->pos - edge2->opos)) >> 1; - AF_LOG(( "DRIFT: %.2f\n", anchor_drift/64.0 )); + FT_TRACE5(( "DRIFT: %.2f\n", anchor_drift/64.0 )); } else { @@ -1965,12 +1987,13 @@ org_left = org_pos + ((org_len - cur_len) >> 1); org_right = org_pos + ((org_len + cur_len) >> 1); - AF_LOG(( "ALIGN: left=%.2f right=%.2f ", org_left/64.0, org_right/64.0 )); + FT_TRACE5(( "ALIGN: left=%.2f right=%.2f ", + org_left / 64.0, org_right / 64.0 )); cur_center = org_center; if ( edge2->flags & AF_EDGE_DONE ) { - AF_LOG(( "\n" )); + FT_TRACE5(( "\n" )); edge->pos = edge2->pos - cur_len; } else @@ -1985,14 +2008,14 @@ /* note: don't even try to fit tiny stems */ if ( cur_len < 32 ) { - AF_LOG(( "tiny stem\n" )); + FT_TRACE5(( "tiny stem\n" )); goto AlignStem; } /* if the span is within a single pixel, don't touch it */ if ( FT_PIX_FLOOR(org_left) == FT_PIX_CEIL(org_right) ) { - AF_LOG(( "single pixel stem\n" )); + FT_TRACE5(( "single pixel stem\n" )); goto AlignStem; } @@ -2015,14 +2038,14 @@ delta = FT_ABS(fit - org); displacements[count] = fit - org; scores[count++] = delta; - AF_LOG(( "dispA=%.2f (%d) ", (fit - org)/64.0, delta )); + FT_TRACE5(( "dispA=%.2f (%d) ", (fit - org) / 64.0, delta )); org = frac_right; fit = (org <= 32) ? 16 : 48; delta = FT_ABS(fit - org); displacements[count] = fit - org; scores[count++] = delta; - AF_LOG(( "dispB=%.2f (%d) ", (fit - org)/64.0, delta )); + FT_TRACE5(( "dispB=%.2f (%d) ", (fit - org) / 64.0, delta )); } } @@ -2032,7 +2055,7 @@ delta = FT_ABS(fit - org); displacements[count] = fit - org; scores[count++] = delta; - AF_LOG(( "dispC=%.2f (%d) ", (fit - org)/64.0, delta )); + FT_TRACE5(( "dispC=%.2f (%d) ", (fit - org) / 64.0, delta )); /* snapping the right edge to the grid */ org = org_right; @@ -2040,7 +2063,7 @@ delta = FT_ABS(fit - org); displacements[count] = fit - org; scores[count++] = delta; - AF_LOG(( "dispD=%.2f (%d) ", (fit - org)/64.0, delta )); + FT_TRACE5(( "dispD=%.2f (%d) ", (fit - org) / 64.0, delta )); /* now find the best displacement */ { @@ -2059,27 +2082,28 @@ cur_center = org_center + best_disp; } - AF_LOG(( "\n" )); + FT_TRACE5(( "\n" )); } AlignStem: edge->pos = cur_center - (cur_len >> 1); edge2->pos = edge->pos + cur_len; - AF_LOG(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f) " - "snapped to (%.2f) and (%.2f), org_len = %.2f cur_len=%.2f\n", - edge-edges, edge->opos / 64.0, - edge2-edges, edge2->opos / 64.0, - edge->pos / 64.0, edge2->pos / 64.0, - org_len / 64.0, cur_len / 64.0 )); + FT_TRACE5(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f)" + " snapped to (%.2f) and (%.2f)," + " org_len=%.2f cur_len=%.2f\n", + edge-edges, edge->opos / 64.0, + edge2-edges, edge2->opos / 64.0, + edge->pos / 64.0, edge2->pos / 64.0, + org_len / 64.0, cur_len / 64.0 )); edge->flags |= AF_EDGE_DONE; edge2->flags |= AF_EDGE_DONE; 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; } } @@ -2179,16 +2203,17 @@ if ( delta < 64 + 16 ) { af_latin2_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 )); + FT_TRACE5(( "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; } @@ -2215,15 +2240,19 @@ 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); + 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 )); } } @@ -2243,8 +2272,8 @@ static FT_Error af_latin2_hints_apply( AF_GlyphHints hints, - FT_Outline* outline, - AF_LatinMetrics metrics ) + FT_Outline* outline, + AF_LatinMetrics metrics ) { FT_Error error; int dim; @@ -2255,7 +2284,7 @@ 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 ) ) #else @@ -2279,7 +2308,7 @@ /* grid-fit the outline */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER if ( ( dim == AF_DIMENSION_HORZ && metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) ) { @@ -2321,7 +2350,7 @@ static const AF_Script_UniRangeRec af_latin2_uniranges[] = { - AF_UNIRANGE_REC( 32UL, 127UL ), /* XXX: TODO: Add new Unicode ranges here! */ + AF_UNIRANGE_REC( 32UL, 127UL ), /* TODO: Add new Unicode ranges here! */ AF_UNIRANGE_REC( 160UL, 255UL ), AF_UNIRANGE_REC( 0UL, 0UL ) }; diff --git a/freetype/src/autofit/afloader.c b/freetype/src/autofit/afloader.c index 6dd9f2a31..966a0df73 100644 --- a/freetype/src/autofit/afloader.c +++ b/freetype/src/autofit/afloader.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter glyph loading routines (body). */ /* */ -/* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */ +/* Copyright 2003-2009, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -22,6 +22,8 @@ #include "aferrors.h" + /* Initialize glyph loader. */ + FT_LOCAL_DEF( FT_Error ) af_loader_init( AF_Loader loader, FT_Memory memory ) @@ -29,13 +31,15 @@ FT_ZERO( loader ); af_glyph_hints_init( &loader->hints, memory ); -#ifdef AF_DEBUG +#ifdef FT_DEBUG_AUTOFIT _af_debug_hints = &loader->hints; #endif return FT_GlyphLoader_New( memory, &loader->gloader ); } + /* Reset glyph loader and compute globals if necessary. */ + FT_LOCAL_DEF( FT_Error ) af_loader_reset( AF_Loader loader, FT_Face face ) @@ -64,6 +68,8 @@ } + /* Finalize glyph loader. */ + FT_LOCAL_DEF( void ) af_loader_done( AF_Loader loader ) { @@ -72,7 +78,7 @@ loader->face = NULL; loader->globals = NULL; -#ifdef AF_DEBUG +#ifdef FT_DEBUG_AUTOFIT _af_debug_hints = NULL; #endif FT_GlyphLoader_Done( loader->gloader ); @@ -80,6 +86,10 @@ } + /* Load a single glyph component. This routine calls itself */ + /* recursively, if necessary, and does the main work of */ + /* `af_loader_load_glyph.' */ + static FT_Error af_loader_load_g( AF_Loader loader, AF_Scaler scaler, @@ -169,8 +179,8 @@ &gloader->current.outline, metrics ); - /* we now need to hint the metrics according to the change in */ - /* width/positioning that occurred during the hinting process */ + /* we now need to adjust the metrics according to the change in */ + /* width/positioning that occurred during the hinting process */ if ( scaler->render_mode != FT_RENDER_MODE_LIGHT ) { FT_Pos old_rsb, old_lsb, new_lsb; @@ -265,7 +275,7 @@ gloader->current.num_subglyphs = num_subglyphs; num_base_subgs = gloader->base.num_subglyphs; - /* now, read each subglyph independently */ + /* now read each subglyph independently */ for ( nn = 0; nn < num_subglyphs; nn++ ) { FT_Vector pp1, pp2; @@ -305,7 +315,7 @@ num_points = gloader->base.outline.n_points; num_new_points = num_points - num_base_points; - /* now perform the transform required for this subglyph */ + /* now perform the transformation required for this subglyph */ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | FT_SUBGLYPH_FLAG_XY_SCALE | @@ -444,7 +454,7 @@ #endif slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, - metrics->scaler.y_scale ); + metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); @@ -459,15 +469,13 @@ slot->format = FT_GLYPH_FORMAT_OUTLINE; } -#ifdef DEBUG_HINTER - af_debug_hinter = hinter; -#endif - Exit: return error; } + /* Load a glyph. */ + FT_LOCAL_DEF( FT_Error ) af_loader_load_glyph( AF_Loader loader, FT_Face face, diff --git a/freetype/src/autofit/afloader.h b/freetype/src/autofit/afloader.h index fa67c10ff..3f91e1a22 100644 --- a/freetype/src/autofit/afloader.h +++ b/freetype/src/autofit/afloader.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter glyph loading routines (specification). */ /* */ -/* Copyright 2003, 2004, 2005 by */ +/* Copyright 2003-2005, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,8 +16,8 @@ /***************************************************************************/ -#ifndef __AF_LOADER_H__ -#define __AF_LOADER_H__ +#ifndef __AFLOADER_H__ +#define __AFLOADER_H__ #include "afhints.h" #include "afglobal.h" @@ -67,7 +67,7 @@ FT_BEGIN_HEADER FT_END_HEADER -#endif /* __AF_LOADER_H__ */ +#endif /* __AFLOADER_H__ */ /* END */ diff --git a/freetype/src/autofit/afmodule.c b/freetype/src/autofit/afmodule.c index ec2d707c9..20b621838 100644 --- a/freetype/src/autofit/afmodule.c +++ b/freetype/src/autofit/afmodule.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter module implementation (body). */ /* */ -/* Copyright 2003, 2004, 2005, 2006 by */ +/* Copyright 2003-2006, 2009, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -20,8 +20,7 @@ #include "afloader.h" #include "afpic.h" -#ifdef AF_DEBUG - int _af_debug; +#ifdef FT_DEBUG_AUTOFIT int _af_debug_disable_horz_hints; int _af_debug_disable_vert_hints; int _af_debug_disable_blue_hints; @@ -67,14 +66,15 @@ } - FT_DEFINE_AUTOHINTER_SERVICE(af_autofitter_service, + FT_DEFINE_AUTOHINTER_SERVICE( + af_autofitter_service, NULL, NULL, NULL, - (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph - ) + (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph ) - FT_DEFINE_MODULE(autofit_module_class, + FT_DEFINE_MODULE( + autofit_module_class, FT_MODULE_HINTER, sizeof ( FT_AutofitterRec ), @@ -87,8 +87,7 @@ (FT_Module_Constructor)af_autofitter_init, (FT_Module_Destructor) af_autofitter_done, - (FT_Module_Requester) NULL - ) + (FT_Module_Requester) NULL ) /* END */ diff --git a/freetype/src/autofit/afpic.c b/freetype/src/autofit/afpic.c index 5b9aba691..3aefbc51c 100644 --- a/freetype/src/autofit/afpic.c +++ b/freetype/src/autofit/afpic.c @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for autofit module. */ /* */ -/* Copyright 2009, 2010 by */ +/* Copyright 2009, 2010, 2011 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -24,7 +24,8 @@ #ifdef FT_CONFIG_OPTION_PIC /* forward declaration of PIC init functions from afmodule.c */ - void FT_Init_Class_af_autofitter_service( FT_Library, FT_AutoHinter_ServiceRec*); + void FT_Init_Class_af_autofitter_service( FT_Library, + FT_AutoHinter_ServiceRec* ); /* forward declaration of PIC init functions from script classes */ #include "aflatin.h" @@ -34,10 +35,12 @@ #include "afindic.h" void - autofit_module_class_pic_free( FT_Library library ) + autofit_module_class_pic_free( FT_Library library ) { - FT_PIC_Container* pic_container = &library->pic_container; - FT_Memory memory = library->memory; + FT_PIC_Container* pic_container = &library->pic_container; + FT_Memory memory = library->memory; + + if ( pic_container->autofit ) { FT_FREE( pic_container->autofit ); @@ -62,28 +65,37 @@ FT_MEM_SET( container, 0, sizeof ( *container ) ); pic_container->autofit = container; - /* initialize pointer table - this is how the module usually expects this data */ + /* initialize pointer table - */ + /* this is how the module usually expects this data */ for ( ss = 0 ; ss < AF_SCRIPT_CLASSES_REC_COUNT ; ss++ ) { - container->af_script_classes[ss] = &container->af_script_classes_rec[ss]; + container->af_script_classes[ss] = + &container->af_script_classes_rec[ss]; } - container->af_script_classes[AF_SCRIPT_CLASSES_COUNT-1] = NULL; + container->af_script_classes[AF_SCRIPT_CLASSES_COUNT - 1] = NULL; /* add call to initialization function when you add new scripts */ ss = 0; - FT_Init_Class_af_dummy_script_class(&container->af_script_classes_rec[ss++]); + FT_Init_Class_af_dummy_script_class( + &container->af_script_classes_rec[ss++] ); #ifdef FT_OPTION_AUTOFIT2 - FT_Init_Class_af_latin2_script_class(&container->af_script_classes_rec[ss++]); + FT_Init_Class_af_latin2_script_class( + &container->af_script_classes_rec[ss++] ); #endif - FT_Init_Class_af_latin_script_class(&container->af_script_classes_rec[ss++]); - FT_Init_Class_af_cjk_script_class(&container->af_script_classes_rec[ss++]); - FT_Init_Class_af_indic_script_class(&container->af_script_classes_rec[ss++]); + FT_Init_Class_af_latin_script_class( + &container->af_script_classes_rec[ss++] ); + FT_Init_Class_af_cjk_script_class( + &container->af_script_classes_rec[ss++] ); + FT_Init_Class_af_indic_script_class( + &container->af_script_classes_rec[ss++] ); + + FT_Init_Class_af_autofitter_service( + library, &container->af_autofitter_service ); - FT_Init_Class_af_autofitter_service(library, &container->af_autofitter_service); +/* Exit: */ -/*Exit:*/ - if(error) - autofit_module_class_pic_free(library); + if ( error ) + autofit_module_class_pic_free( library ); return error; } diff --git a/freetype/src/autofit/afpic.h b/freetype/src/autofit/afpic.h index 80e62d39a..c1632e76e 100644 --- a/freetype/src/autofit/afpic.h +++ b/freetype/src/autofit/afpic.h @@ -4,7 +4,7 @@ /* */ /* The FreeType position independent code services for autofit module. */ /* */ -/* Copyright 2009 by */ +/* Copyright 2009, 2011 by */ /* Oran Agra and Mickey Gabel. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -33,24 +33,29 @@ FT_BEGIN_HEADER #include "aftypes.h" -/* increase these when you add new scripts, and update autofit_module_class_pic_init */ + /* increase these when you add new scripts, */ + /* and update autofit_module_class_pic_init */ #ifdef FT_OPTION_AUTOFIT2 - #define AF_SCRIPT_CLASSES_COUNT 6 +#define AF_SCRIPT_CLASSES_COUNT 6 #else - #define AF_SCRIPT_CLASSES_COUNT 5 +#define AF_SCRIPT_CLASSES_COUNT 5 #endif -#define AF_SCRIPT_CLASSES_REC_COUNT (AF_SCRIPT_CLASSES_COUNT-1) +#define AF_SCRIPT_CLASSES_REC_COUNT ( AF_SCRIPT_CLASSES_COUNT - 1 ) typedef struct AFModulePIC_ { - AF_ScriptClass af_script_classes[AF_SCRIPT_CLASSES_COUNT]; - AF_ScriptClassRec af_script_classes_rec[AF_SCRIPT_CLASSES_REC_COUNT]; - FT_AutoHinter_ServiceRec af_autofitter_service; + AF_ScriptClass af_script_classes[AF_SCRIPT_CLASSES_COUNT]; + AF_ScriptClassRec af_script_classes_rec[AF_SCRIPT_CLASSES_REC_COUNT]; + FT_AutoHinter_ServiceRec af_autofitter_service; + } AFModulePIC; -#define GET_PIC(lib) ((AFModulePIC*)((lib)->pic_container.autofit)) -#define AF_SCRIPT_CLASSES_GET (GET_PIC(FT_FACE_LIBRARY(globals->face))->af_script_classes) -#define AF_AF_AUTOFITTER_SERVICE_GET (GET_PIC(library)->af_autofitter_service) +#define GET_PIC( lib ) \ + ( (AFModulePIC*)((lib)->pic_container.autofit) ) +#define AF_SCRIPT_CLASSES_GET \ + ( GET_PIC( FT_FACE_LIBRARY(globals->face) )->af_script_classes ) +#define AF_AF_AUTOFITTER_SERVICE_GET \ + ( GET_PIC( library )->af_autofitter_service ) #endif /* FT_CONFIG_OPTION_PIC */ diff --git a/freetype/src/autofit/aftypes.h b/freetype/src/autofit/aftypes.h index 5574f0c30..44997d1e2 100644 --- a/freetype/src/autofit/aftypes.h +++ b/freetype/src/autofit/aftypes.h @@ -4,7 +4,7 @@ /* */ /* Auto-fitter types (specification only). */ /* */ -/* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */ +/* Copyright 2003-2009, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -53,26 +53,16 @@ FT_BEGIN_HEADER /*************************************************************************/ /*************************************************************************/ -#define xxAF_USE_WARPER /* only define to use warp hinting */ -#define xxAF_DEBUG - -#ifdef AF_DEBUG +#ifdef FT_DEBUG_AUTOFIT #include FT_CONFIG_STANDARD_LIBRARY_H -#define AF_LOG( x ) do { if ( _af_debug ) printf x; } while ( 0 ) - -extern int _af_debug; extern int _af_debug_disable_horz_hints; extern int _af_debug_disable_vert_hints; extern int _af_debug_disable_blue_hints; extern void* _af_debug_hints; -#else /* !AF_DEBUG */ - -#define AF_LOG( x ) do { } while ( 0 ) /* nothing */ - -#endif /* !AF_DEBUG */ +#endif /* FT_DEBUG_AUTOFIT */ /*************************************************************************/ @@ -159,36 +149,11 @@ extern void* _af_debug_hints; FT_END_STMNT - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** O U T L I N E S *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - /* opaque handle to glyph-specific hints -- see `afhints.h' for more * details */ typedef struct AF_GlyphHintsRec_* AF_GlyphHints; - /* This structure is used to model an input glyph outline to - * the auto-hinter. The latter will set the `hints' field - * depending on the glyph's script. - */ - typedef struct AF_OutlineRec_ - { - FT_Face face; - FT_Outline outline; - FT_UInt outline_resolution; - - FT_Int advance; - FT_UInt metrics_resolution; - - AF_GlyphHints hints; - - } AF_OutlineRec; - /*************************************************************************/ /*************************************************************************/ @@ -241,7 +206,7 @@ extern void* _af_debug_hints; /*************************************************************************/ /* - * The list of know scripts. Each different script corresponds to the + * The list of known scripts. Each different script corresponds to the * following information: * * - A set of Unicode ranges to test whether the face supports the @@ -342,55 +307,57 @@ extern void* _af_debug_hints; } AF_ScriptClassRec; -/* Declare and define vtables for classes */ + + /* Declare and define vtables for classes */ #ifndef FT_CONFIG_OPTION_PIC -#define AF_DECLARE_SCRIPT_CLASS(script_class) \ - FT_CALLBACK_TABLE const AF_ScriptClassRec \ +#define AF_DECLARE_SCRIPT_CLASS( script_class ) \ + FT_CALLBACK_TABLE const AF_ScriptClassRec \ script_class; -#define AF_DEFINE_SCRIPT_CLASS(script_class, script_, ranges, m_size, \ - m_init, m_scale, m_done, h_init, h_apply) \ - FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec \ - script_class = \ - { \ - script_, \ - ranges, \ - \ - m_size, \ - \ - m_init, \ - m_scale, \ - m_done, \ - \ - h_init, \ - h_apply \ +#define AF_DEFINE_SCRIPT_CLASS( script_class, script_, ranges, m_size, \ + m_init, m_scale, m_done, h_init, h_apply ) \ + FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec \ + script_class = \ + { \ + script_, \ + ranges, \ + \ + m_size, \ + \ + m_init, \ + m_scale, \ + m_done, \ + \ + h_init, \ + h_apply \ }; -#else - -#define AF_DECLARE_SCRIPT_CLASS(script_class) \ - FT_LOCAL(void) \ - FT_Init_Class_##script_class(AF_ScriptClassRec* ac); - -#define AF_DEFINE_SCRIPT_CLASS(script_class, script_, ranges, m_size, \ - m_init, m_scale, m_done, h_init, h_apply) \ - FT_LOCAL_DEF(void) \ - FT_Init_Class_##script_class(AF_ScriptClassRec* ac) \ - { \ - ac->script = script_; \ - ac->script_uni_ranges = ranges; \ - \ - ac->script_metrics_size = m_size; \ - \ - ac->script_metrics_init = m_init; \ - ac->script_metrics_scale = m_scale; \ - ac->script_metrics_done = m_done; \ - \ - ac->script_hints_init = h_init; \ - ac->script_hints_apply = h_apply; \ +#else /* FT_CONFIG_OPTION_PIC */ + +#define AF_DECLARE_SCRIPT_CLASS( script_class ) \ + FT_LOCAL( void ) \ + FT_Init_Class_##script_class( AF_ScriptClassRec* ac ); + +#define AF_DEFINE_SCRIPT_CLASS( script_class, script_, ranges, m_size, \ + m_init, m_scale, m_done, h_init, h_apply ) \ + FT_LOCAL_DEF( void ) \ + FT_Init_Class_##script_class( AF_ScriptClassRec* ac ) \ + { \ + ac->script = script_; \ + ac->script_uni_ranges = ranges; \ + \ + ac->script_metrics_size = m_size; \ + \ + ac->script_metrics_init = m_init; \ + ac->script_metrics_scale = m_scale; \ + ac->script_metrics_done = m_done; \ + \ + ac->script_hints_init = h_init; \ + ac->script_hints_apply = h_apply; \ } -#endif + +#endif /* FT_CONFIG_OPTION_PIC */ /* */ diff --git a/freetype/src/autofit/afwarp.c b/freetype/src/autofit/afwarp.c index f5bb9b18a..d0d4850bd 100644 --- a/freetype/src/autofit/afwarp.c +++ b/freetype/src/autofit/afwarp.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter warping algorithm (body). */ /* */ -/* Copyright 2006, 2007 by */ +/* Copyright 2006, 2007, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -16,10 +16,30 @@ /***************************************************************************/ + /* + * The idea of the warping code is to slightly scale and shift a glyph + * within a single dimension so that as much of its segments are aligned + * (more or less) on the grid. To find out the optimal scaling and + * shifting value, various parameter combinations are tried and scored. + */ + #include "afwarp.h" -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER + + /*************************************************************************/ + /* */ + /* 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_afwarp + + /* The weights cover the range 0/64 - 63/64 of a pixel. Obviously, */ + /* values around a half pixel (which means exactly between two grid */ + /* lines) gets the worst weight. */ #if 1 static const AF_WarpScore af_warper_weights[64] = @@ -43,6 +63,11 @@ #endif + /* Score segments for a given `scale' and `delta' in the range */ + /* `xx1' to `xx2', and store the best result in `warper'. If */ + /* the new best score is equal to the old one, prefer the */ + /* value with a smaller distortion (around `base_distort'). */ + static void af_warper_compute_line_best( AF_Warper warper, FT_Fixed scale, @@ -82,12 +107,12 @@ if ( idx_min < 0 || idx_min > idx_max || idx_max > 64 ) { - AF_LOG(( "invalid indices:\n" - " min=%d max=%d, xx1=%ld xx2=%ld,\n" - " x1min=%ld x1max=%ld, x2min=%ld x2max=%ld\n", - idx_min, idx_max, xx1, xx2, - warper->x1min, warper->x1max, - warper->x2min, warper->x2max )); + FT_TRACE5(( "invalid indices:\n" + " min=%d max=%d, xx1=%ld xx2=%ld,\n" + " x1min=%ld x1max=%ld, x2min=%ld x2max=%ld\n", + idx_min, idx_max, xx1, xx2, + warper->x1min, warper->x1max, + warper->x2min, warper->x2max )); return; } } @@ -100,6 +125,7 @@ FT_Int idx; + /* score the length of the segments for the given range */ for ( idx = idx_min; idx <= idx_max; idx++, y++ ) scores[idx] += af_warper_weights[y & 63] * len; } @@ -115,9 +141,9 @@ AF_WarpScore distort = base_distort + ( idx - idx0 ); - if ( score > warper->best_score || + if ( score > warper->best_score || ( score == warper->best_score && - distort < warper->best_distort ) ) + distort < warper->best_distort ) ) { warper->best_score = score; warper->best_distort = distort; @@ -129,6 +155,9 @@ } + /* Compute optimal scaling and delta values for a given glyph and */ + /* dimension. */ + FT_LOCAL_DEF( void ) af_warper_compute( AF_Warper warper, AF_GlyphHints hints, @@ -215,6 +244,7 @@ warper->t1 = AF_WARPER_FLOOR( warper->x1 ); warper->t2 = AF_WARPER_CEIL( warper->x2 ); + /* examine a half pixel wide range around the maximum coordinates */ warper->x1min = warper->x1 & ~31; warper->x1max = warper->x1min + 32; warper->x2min = warper->x2 & ~31; @@ -234,10 +264,12 @@ warper->x2min = warper->x2; } + /* examine (at most) a pixel wide range around the natural width */ warper->wmin = warper->x2min - warper->x1max; warper->wmax = warper->x2max - warper->x1min; #if 1 + /* some heuristics to reduce the number of widths to be examined */ { int margin = 16; @@ -273,6 +305,8 @@ FT_Pos xx1, xx2; + /* compute min and max positions for given width, */ + /* assuring that they stay within the coordinate ranges */ xx1 = warper->x1; xx2 = warper->x2; if ( w >= warper->w0 ) @@ -304,6 +338,7 @@ else base_distort += xx2 - warper->x2; + /* give base distortion a greater weight while scoring */ base_distort *= 10; new_scale = org_scale + FT_DivFix( w - warper->w0, X2 - X1 ); @@ -329,10 +364,11 @@ } } -#else /* !AF_USE_WARPER */ +#else /* !AF_CONFIG_OPTION_USE_WARPER */ -char af_warper_dummy = 0; /* make compiler happy */ + /* ANSI C doesn't like empty source files */ + typedef int _af_warp_dummy; -#endif /* !AF_USE_WARPER */ +#endif /* !AF_CONFIG_OPTION_USE_WARPER */ /* END */ diff --git a/freetype/src/autofit/autofit.c b/freetype/src/autofit/autofit.c index 83b613e79..3883a0a70 100644 --- a/freetype/src/autofit/autofit.c +++ b/freetype/src/autofit/autofit.c @@ -4,7 +4,7 @@ /* */ /* Auto-fitter module (body). */ /* */ -/* Copyright 2003, 2004, 2005, 2006, 2007 by */ +/* Copyright 2003-2007, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -34,7 +34,7 @@ #include "afloader.c" #include "afmodule.c" -#ifdef AF_USE_WARPER +#ifdef AF_CONFIG_OPTION_USE_WARPER #include "afwarp.c" #endif diff --git a/freetype/src/autofit/rules.mk b/freetype/src/autofit/rules.mk index 017489d9e..b76bb79ab 100644 --- a/freetype/src/autofit/rules.mk +++ b/freetype/src/autofit/rules.mk @@ -3,7 +3,7 @@ # -# Copyright 2003, 2004, 2005, 2006, 2007 by +# Copyright 2003, 2004, 2005, 2006, 2007, 2011 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, @@ -34,13 +34,14 @@ AUTOF_DRV_SRC := $(AUTOF_DIR)/afangles.c \ $(AUTOF_DIR)/aflatin.c \ $(AUTOF_DIR)/afloader.c \ $(AUTOF_DIR)/afmodule.c \ + $(AUTOF_DIR)/afpic.c \ $(AUTOF_DIR)/afwarp.c # AUTOF driver headers # AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \ - $(AUTOF_DIR)/aftypes.h \ - $(AUTOF_DIR)/aferrors.h + $(AUTOF_DIR)/aferrors.h \ + $(AUTOF_DIR)/aftypes.h # AUTOF driver object(s) -- cgit v1.2.3