@ -22,12 +22,18 @@
*
*/
# include <ft2build.h>
# 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"
@ -37,6 +43,16 @@
# 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,481 @@
/*************************************************************************/
/*************************************************************************/
/* 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
/* Every blue zone has 2 types of fill and unfill,
* Which means fill the entire 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 ;
/* we compute the blues simply by loading each character from the */
/* 'blue_chars[blues]' string, then compute 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 %3d/%d: " , bb , fill_type ) ) ;
for ( ; p < limit & & * p ; p + + )
{
FT_UInt glyph_index ;
FT_Pos best_pos ; /* same as points.y */
FT_Int best_point , best_first , best_last ;
FT_Vector * points ;
FT_TRACE5 ( ( " 0x%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 )
continue ;
error = FT_Load_Glyph ( face , glyph_index , FT_LOAD_NO_SCALE ) ;
if ( error | | glyph - > outline . n_points < = 0 )
continue ;
/* now compute min or max point indices and coordinates */
points = glyph - > outline . points ;
best_point = - 1 ;
best_pos = 0 ; /* make compiler happy */
best_first = 0 ; /* ditto */
best_last = 0 ; /* ditto */
{
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 old_best_point = best_point ;
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 :
;
}
if ( best_point ! = old_best_point )
{
best_first = first ;
best_last = last ;
}
}
FT_TRACE5 ( ( " %5ld, " , best_pos ) ) ;
}
if ( fill )
fills [ num_fills + + ] = best_pos ;
else
flats [ num_flats + + ] = best_pos ;
}
FT_TRACE5 ( ( " \n " ) ) ;
}
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
* vis vesa 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 ref = %ld shoot = %ld \n " , * 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_CJK Metrics 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_blue s ( metrics , face , af_cjk_hani_blue_chars ) ;
af_cjk _metrics_check_digits ( metrics , face ) ;
}
FT_Set_Charmap ( face , oldmap ) ;
@ -72,31 +545,99 @@
static void
af_cjk_metrics_scale_dim ( AF_Latin Metrics metrics ,
AF_Scaler scaler ,
AF_Dimension dim )
af_cjk_metrics_scale_dim ( AF_CJK Metrics 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 ;
/*
else if ( delta2 < 64 )
delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~ 31 ) ;
*/
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_CJK Metrics metrics ,
AF_Scaler scaler )
{
metrics - > root . scaler = * scaler ;
@ -329,7 +870,7 @@
AF_AxisHints axis = & hints - > axis [ dim ] ;
FT_Error error = AF_Err_Ok ;
FT_Memory memory = hints - > memory ;
AF_LatinAxis laxis = & ( ( AF_Latin Metrics ) hints - > metrics ) - > axis [ dim ] ;
AF_CJKAxis laxis = & ( ( AF_CJK Metrics ) hints - > metrics ) - > axis [ dim ] ;
AF_Segment segments = axis - > segments ;
AF_Segment segment_limit = segments + axis - > num_segments ;
@ -601,9 +1142,93 @@
}
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_CJKMetrics metrics )
{
FT_Render_Mode mode ;
FT_UInt32 scaler_flags , other_flags ;
@ -728,11 +1353,11 @@
AF_Edge_Flags base_flags ,
AF_Edge_Flags stem_flags )
{
AF_LatinMetrics metrics = ( AF_Latin Metrics ) hints - > metrics ;
AF_LatinAxis axis = & metrics - > axis [ dim ] ;
AF_CJKMetrics metrics = ( AF_CJK Metrics ) hints - > metrics ;
AF_CJKAxis axis = & metrics - > axis [ dim ] ;
FT_Pos dist = width ;
FT_Int sign = 0 ;
FT_Int vertical = ( dim = = AF_DIMENSION_VERT ) ;
FT_Bool vertical = FT_BOOL ( dim = = AF_DIMENSION_VERT ) ;
FT_UNUSED ( base_flags ) ;
FT_UNUSED ( stem_flags ) ;
@ -1029,6 +1654,58 @@
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 + + )
{
@ -1063,6 +1740,15 @@
}
/* 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 )
{
@ -1389,7 +2075,7 @@
FT_LOCAL_DEF ( FT_Error )
af_cjk_hints_apply ( AF_GlyphHints hints ,
FT_Outline * outline ,
AF_LatinMetrics metrics )
AF_CJKMetrics metrics )
{
FT_Error error ;
int dim ;
@ -1407,6 +2093,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 ) )
@ -1414,6 +2102,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 */
@ -1512,7 +2202,7 @@
AF_SCRIPT_CJK ,
af_cjk_uniranges ,
sizeof ( AF_Latin MetricsRec ) ,
sizeof ( AF_CJK MetricsRec ) ,
( AF_Script_InitMetricsFunc ) af_cjk_metrics_init ,
( AF_Script_ScaleMetricsFunc ) af_cjk_metrics_scale ,
@ -1534,7 +2224,7 @@
AF_SCRIPT_CJK ,
af_cjk_uniranges ,
sizeof ( AF_Latin MetricsRec ) ,
sizeof ( AF_CJK MetricsRec ) ,
( AF_Script_InitMetricsFunc ) NULL ,
( AF_Script_ScaleMetricsFunc ) NULL ,