|
|
|
@ -27,11 +27,12 @@ |
|
|
|
|
#include FT_OUTLINE_H |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define FACE_GLOBALS( face ) ((AH_Face_Globals)(face)->autohint.data) |
|
|
|
|
#define FACE_GLOBALS( face ) ( (AH_Face_Globals)(face)->autohint.data ) |
|
|
|
|
|
|
|
|
|
#define AH_USE_IUP |
|
|
|
|
#define OPTIM_STEM_SNAP |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
/**** ****/ |
|
|
|
@ -70,7 +71,7 @@ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
scaled = (reference+32) & -64; |
|
|
|
|
scaled = ( reference + 32 ) & -64; |
|
|
|
|
|
|
|
|
|
if ( width >= reference ) |
|
|
|
|
{ |
|
|
|
@ -116,7 +117,7 @@ |
|
|
|
|
else if ( ( vertical && !hinter->do_vert_snapping ) || |
|
|
|
|
( !vertical && !hinter->do_horz_snapping ) ) |
|
|
|
|
{ |
|
|
|
|
/* smooth hinting process, very lightly quantize the stem width */ |
|
|
|
|
/* smooth hinting process: very lightly quantize the stem width */ |
|
|
|
|
/* */ |
|
|
|
|
|
|
|
|
|
/* leave the widths of serifs alone */ |
|
|
|
@ -150,8 +151,8 @@ |
|
|
|
|
|
|
|
|
|
if ( dist < 3 * 64 ) |
|
|
|
|
{ |
|
|
|
|
delta = ( dist & 63 ); |
|
|
|
|
dist &= -64; |
|
|
|
|
delta = dist & 63; |
|
|
|
|
dist &= -64; |
|
|
|
|
|
|
|
|
|
if ( delta < 10 ) |
|
|
|
|
dist += delta; |
|
|
|
@ -171,7 +172,7 @@ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* strong hinting process, snap the stem width to integer pixels */ |
|
|
|
|
/* strong hinting process: snap the stem width to integer pixels */ |
|
|
|
|
/* */ |
|
|
|
|
if ( vertical ) |
|
|
|
|
{ |
|
|
|
@ -186,7 +187,7 @@ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
dist = ah_snap_width( globals->widths, globals->num_widths, dist ); |
|
|
|
|
dist = ah_snap_width( globals->widths, globals->num_widths, dist ); |
|
|
|
|
|
|
|
|
|
if ( hinter->flags & AH_HINTER_MONOCHROME ) |
|
|
|
|
{ |
|
|
|
@ -208,7 +209,7 @@ |
|
|
|
|
else if ( dist < 128 ) |
|
|
|
|
dist = ( dist + 22 ) & -64; |
|
|
|
|
else |
|
|
|
|
/* XXX: round otherwise, prevent color fringes in LCD mode */ |
|
|
|
|
/* XXX: round otherwise to prevent color fringes in LCD mode */ |
|
|
|
|
dist = ( dist + 32 ) & -64; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -246,7 +247,7 @@ |
|
|
|
|
else if ( ( vertical && !hinter->do_vert_snapping ) || |
|
|
|
|
( !vertical && !hinter->do_horz_snapping ) ) |
|
|
|
|
{ |
|
|
|
|
/* smooth hinting process, very lightly quantize the stem width */ |
|
|
|
|
/* smooth hinting process: very lightly quantize the stem width */ |
|
|
|
|
/* */ |
|
|
|
|
if ( dist < 64 ) |
|
|
|
|
dist = 64; |
|
|
|
@ -267,8 +268,8 @@ |
|
|
|
|
|
|
|
|
|
if ( dist < 3 * 64 ) |
|
|
|
|
{ |
|
|
|
|
delta = ( dist & 63 ); |
|
|
|
|
dist &= -64; |
|
|
|
|
delta = dist & 63; |
|
|
|
|
dist &= -64; |
|
|
|
|
|
|
|
|
|
if ( delta < 10 ) |
|
|
|
|
dist += delta; |
|
|
|
@ -288,7 +289,7 @@ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* strong hinting process, snap the stem width to integer pixels */ |
|
|
|
|
/* strong hinting process: snap the stem width to integer pixels */ |
|
|
|
|
/* */ |
|
|
|
|
if ( vertical ) |
|
|
|
|
{ |
|
|
|
@ -303,7 +304,7 @@ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
dist = ah_snap_width( globals->widths, globals->num_widths, dist ); |
|
|
|
|
dist = ah_snap_width( globals->widths, globals->num_widths, dist ); |
|
|
|
|
|
|
|
|
|
if ( hinter->flags & AH_HINTER_MONOCHROME ) |
|
|
|
|
{ |
|
|
|
@ -325,7 +326,7 @@ |
|
|
|
|
else if ( dist < 128 ) |
|
|
|
|
dist = ( dist + 22 ) & -64; |
|
|
|
|
else |
|
|
|
|
/* XXX: round otherwise, prevent color fringes in LCD mode */ |
|
|
|
|
/* XXX: round otherwise to prevent color fringes in LCD mode */ |
|
|
|
|
dist = ( dist + 32 ) & -64; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -357,6 +358,7 @@ |
|
|
|
|
base_edge->flags, |
|
|
|
|
stem_edge->flags ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stem_edge->pos = base_edge->pos + fitted_width; |
|
|
|
|
|
|
|
|
|
#else |
|
|
|
@ -381,6 +383,7 @@ |
|
|
|
|
FT_UNUSED( hinter ); |
|
|
|
|
FT_UNUSED( vertical ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dist = serif->opos - base->opos; |
|
|
|
|
if ( dist < 0 ) |
|
|
|
|
{ |
|
|
|
@ -388,15 +391,16 @@ |
|
|
|
|
sign = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* do not touch serifs widths !! */ |
|
|
|
|
#if 0 |
|
|
|
|
/* do not touch serifs widths! */ |
|
|
|
|
if ( base->flags & AH_EDGE_DONE ) |
|
|
|
|
{ |
|
|
|
|
if ( dist >= 64 ) |
|
|
|
|
dist = (dist+8) & -64; |
|
|
|
|
dist = ( dist + 8 ) & -64; |
|
|
|
|
|
|
|
|
|
else if ( dist <= 32 && !vertical ) |
|
|
|
|
dist = ( dist + 33 ) >> 1; |
|
|
|
|
|
|
|
|
|
else |
|
|
|
|
dist = 0; |
|
|
|
|
} |
|
|
|
@ -417,9 +421,8 @@ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Another alternative edge hinting algorithm */ |
|
|
|
|
static void |
|
|
|
|
ah_hint_edges_3( AH_Hinter hinter ) |
|
|
|
|
ah_hint_edges( AH_Hinter hinter ) |
|
|
|
|
{ |
|
|
|
|
AH_Edge edges; |
|
|
|
|
AH_Edge edge_limit; |
|
|
|
@ -464,7 +467,7 @@ |
|
|
|
|
{ |
|
|
|
|
edge1 = edge; |
|
|
|
|
} |
|
|
|
|
else if (edge2 && edge2->blue_edge) |
|
|
|
|
else if ( edge2 && edge2->blue_edge ) |
|
|
|
|
{ |
|
|
|
|
blue = edge2->blue_edge; |
|
|
|
|
edge1 = edge2; |
|
|
|
@ -488,8 +491,8 @@ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* now, we will align all stem edges, trying to maintain the */ |
|
|
|
|
/* relative order of stems in the glyph.. */ |
|
|
|
|
/* now we will align all stem edges, trying to maintain the */ |
|
|
|
|
/* relative order of stems in the glyph */ |
|
|
|
|
for ( edge = edges; edge < edge_limit; edge++ ) |
|
|
|
|
{ |
|
|
|
|
AH_EdgeRec* edge2; |
|
|
|
@ -506,12 +509,11 @@ |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* now, align the stem */ |
|
|
|
|
/* now align the stem */ |
|
|
|
|
|
|
|
|
|
/* this should not happen, but it's better to be safe. */ |
|
|
|
|
/* this should not happen, but it's better to be safe */ |
|
|
|
|
if ( edge2->blue_edge || edge2 < edge ) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
ah_align_linked_edge( hinter, edge2, edge, dimension ); |
|
|
|
|
edge->flags |= AH_EDGE_DONE; |
|
|
|
|
continue; |
|
|
|
@ -522,14 +524,15 @@ |
|
|
|
|
|
|
|
|
|
#ifdef FT_CONFIG_CHESTER_STEM |
|
|
|
|
|
|
|
|
|
FT_Pos org_len, org_center, cur_len; |
|
|
|
|
FT_Pos cur_pos1, error1, error2, u_off, d_off; |
|
|
|
|
FT_Pos org_len, org_center, cur_len; |
|
|
|
|
FT_Pos cur_pos1, error1, error2, u_off, d_off; |
|
|
|
|
|
|
|
|
|
org_len = edge2->opos - edge->opos; |
|
|
|
|
cur_len = ah_compute_stem_width( hinter, dimension, org_len, |
|
|
|
|
edge->flags, edge2->flags ); |
|
|
|
|
|
|
|
|
|
if (cur_len <= 64 ) |
|
|
|
|
org_len = edge2->opos - edge->opos; |
|
|
|
|
cur_len = ah_compute_stem_width( hinter, dimension, org_len, |
|
|
|
|
edge->flags, edge2->flags ); |
|
|
|
|
|
|
|
|
|
if ( cur_len <= 64 ) |
|
|
|
|
u_off = d_off = 32; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
@ -563,7 +566,7 @@ |
|
|
|
|
else |
|
|
|
|
edge->pos = ( edge->opos + 32 ) & -64; |
|
|
|
|
|
|
|
|
|
anchor = edge; |
|
|
|
|
anchor = edge; |
|
|
|
|
|
|
|
|
|
edge->flags |= AH_EDGE_DONE; |
|
|
|
|
|
|
|
|
@ -583,23 +586,23 @@ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
FT_Pos org_pos, org_len, org_center, cur_len; |
|
|
|
|
FT_Pos cur_pos1, cur_pos2, delta1, delta2; |
|
|
|
|
FT_Pos org_pos, org_len, org_center, cur_len; |
|
|
|
|
FT_Pos cur_pos1, cur_pos2, delta1, delta2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
org_pos = anchor->pos + (edge->opos - anchor->opos); |
|
|
|
|
org_pos = anchor->pos + ( edge->opos - anchor->opos ); |
|
|
|
|
org_len = edge2->opos - edge->opos; |
|
|
|
|
org_center = org_pos + ( org_len >> 1 ); |
|
|
|
|
|
|
|
|
|
#ifdef FT_CONFIG_CHESTER_SERIF |
|
|
|
|
|
|
|
|
|
cur_len = ah_compute_stem_width( hinter, dimension, org_len, |
|
|
|
|
edge->flags, edge2->flags ); |
|
|
|
|
cur_len = ah_compute_stem_width( hinter, dimension, org_len, |
|
|
|
|
edge->flags, edge2->flags ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else /* !FT_CONFIG_CHESTER_SERIF */ |
|
|
|
|
|
|
|
|
|
cur_len = ah_compute_stem_width( hinter, dimension, org_len ); |
|
|
|
|
cur_len = ah_compute_stem_width( hinter, dimension, org_len ); |
|
|
|
|
|
|
|
|
|
#endif /* !FT_CONFIG_CHESTER_SERIF */ |
|
|
|
|
|
|
|
|
@ -610,7 +613,7 @@ |
|
|
|
|
FT_Pos u_off, d_off; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cur_pos1 = ( org_center + 32 ) & -64; |
|
|
|
|
cur_pos1 = ( org_center + 32 ) & -64; |
|
|
|
|
|
|
|
|
|
if (cur_len <= 64 ) |
|
|
|
|
u_off = d_off = 32; |
|
|
|
@ -620,11 +623,11 @@ |
|
|
|
|
d_off = 26; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
delta1 = org_center - (cur_pos1 - u_off); |
|
|
|
|
delta1 = org_center - ( cur_pos1 - u_off ); |
|
|
|
|
if ( delta1 < 0 ) |
|
|
|
|
delta1 = -delta1; |
|
|
|
|
|
|
|
|
|
delta2 = org_center - (cur_pos1 + d_off); |
|
|
|
|
delta2 = org_center - ( cur_pos1 + d_off ); |
|
|
|
|
if ( delta2 < 0 ) |
|
|
|
|
delta2 = -delta2; |
|
|
|
|
|
|
|
|
@ -638,8 +641,7 @@ |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
org_pos = anchor->pos + (edge->opos - anchor->opos); |
|
|
|
|
org_pos = anchor->pos + ( edge->opos - anchor->opos ); |
|
|
|
|
org_len = edge2->opos - edge->opos; |
|
|
|
|
org_center = org_pos + ( org_len >> 1 ); |
|
|
|
|
|
|
|
|
@ -688,8 +690,8 @@ |
|
|
|
|
if ( !has_serifs ) |
|
|
|
|
goto Next_Dimension; |
|
|
|
|
|
|
|
|
|
/* now, hint the remaining edges (serifs and single) in order */ |
|
|
|
|
/* to complete our processing */ |
|
|
|
|
/* now hint the remaining edges (serifs and single) in order */ |
|
|
|
|
/* to complete our processing */ |
|
|
|
|
for ( edge = edges; edge < edge_limit; edge++ ) |
|
|
|
|
{ |
|
|
|
|
if ( edge->flags & AH_EDGE_DONE ) |
|
|
|
@ -731,7 +733,7 @@ |
|
|
|
|
/* reduce the problem of the disappearing eye in the `e' of Times... */ |
|
|
|
|
/* also, creates some artifacts near the blue zones? */ |
|
|
|
|
{ |
|
|
|
|
ah_hint_edges_3( hinter ); |
|
|
|
|
ah_hint_edges( hinter ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -807,6 +809,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* hint the strong points -- this is equivalent to the TrueType `IP' */ |
|
|
|
|
/* hinting instruction */ |
|
|
|
|
static void |
|
|
|
|
ah_hinter_align_strong_points( AH_Hinter hinter ) |
|
|
|
|
{ |
|
|
|
@ -872,7 +875,7 @@ |
|
|
|
|
goto Store_Point; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* is the point after the last edge ? */ |
|
|
|
|
/* is the point after the last edge? */ |
|
|
|
|
edge = edge_limit - 1; |
|
|
|
|
delta = u - edge->fpos; |
|
|
|
|
if ( delta >= 0 ) |
|
|
|
@ -1023,6 +1026,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* interpolate weak points -- this is equivalent to the TrueType `IUP' */ |
|
|
|
|
/* hinting instruction */ |
|
|
|
|
static void |
|
|
|
|
ah_hinter_align_weak_points( AH_Hinter hinter ) |
|
|
|
|
{ |
|
|
|
@ -1163,8 +1167,8 @@ |
|
|
|
|
{ |
|
|
|
|
FT_Int n; |
|
|
|
|
AH_Face_Globals globals = hinter->globals; |
|
|
|
|
AH_Globals design = &globals->design; |
|
|
|
|
AH_Globals scaled = &globals->scaled; |
|
|
|
|
AH_Globals design = &globals->design; |
|
|
|
|
AH_Globals scaled = &globals->scaled; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* copy content */ |
|
|
|
@ -1233,7 +1237,7 @@ |
|
|
|
|
ah_outline_done( hinter->glyph ); |
|
|
|
|
|
|
|
|
|
/* note: the `globals' pointer is _not_ owned by the hinter */ |
|
|
|
|
/* but by the current face object, we don't need to */ |
|
|
|
|
/* but by the current face object; we don't need to */ |
|
|
|
|
/* release it */ |
|
|
|
|
hinter->globals = 0; |
|
|
|
|
hinter->face = 0; |
|
|
|
@ -1382,8 +1386,8 @@ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* copy the outline points in the loader's current */ |
|
|
|
|
/* extra points, which is used to keep original glyph coordinates */ |
|
|
|
|
/* copy the outline points in the loader's current */ |
|
|
|
|
/* extra points which is used to keep original glyph coordinates */ |
|
|
|
|
error = ah_loader_check_points( gloader, slot->outline.n_points + 2, |
|
|
|
|
slot->outline.n_contours ); |
|
|
|
|
if ( error ) |
|
|
|
@ -1411,8 +1415,8 @@ |
|
|
|
|
if ( slot->outline.n_points == 0 ) |
|
|
|
|
goto Hint_Metrics; |
|
|
|
|
|
|
|
|
|
/* now, load the slot image into the auto-outline, and run the */ |
|
|
|
|
/* automatic hinting process */ |
|
|
|
|
/* now load the slot image into the auto-outline and run the */ |
|
|
|
|
/* automatic hinting process */ |
|
|
|
|
error = ah_outline_load( outline, x_scale, y_scale, face ); |
|
|
|
|
if ( error ) |
|
|
|
|
goto Exit; |
|
|
|
@ -1560,7 +1564,7 @@ |
|
|
|
|
|
|
|
|
|
l += num_base_points; |
|
|
|
|
|
|
|
|
|
/* for now, only use the current point coordinates */ |
|
|
|
|
/* for now, only use the current point coordinates; */ |
|
|
|
|
/* we may consider another approach in the near future */ |
|
|
|
|
p1 = gloader->base.outline.points + start_point + k; |
|
|
|
|
p2 = gloader->base.outline.points + start_point + l; |
|
|
|
@ -1605,8 +1609,8 @@ |
|
|
|
|
if ( hinter->transformed ) |
|
|
|
|
FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix ); |
|
|
|
|
|
|
|
|
|
/* we must translate our final outline by -pp1.x, and compute */ |
|
|
|
|
/* the new metrics */ |
|
|
|
|
/* we must translate our final outline by -pp1.x and compute */ |
|
|
|
|
/* the new metrics */ |
|
|
|
|
if ( hinter->pp1.x ) |
|
|
|
|
FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 ); |
|
|
|
|
|
|
|
|
@ -1621,8 +1625,8 @@ |
|
|
|
|
slot->metrics.horiBearingX = bbox.xMin; |
|
|
|
|
slot->metrics.horiBearingY = bbox.yMax; |
|
|
|
|
|
|
|
|
|
/* for mono-width fonts (like Andale, Courier, etc.), we need */ |
|
|
|
|
/* to keep the original rounded advance width */ |
|
|
|
|
/* for mono-width fonts (like Andale, Courier, etc.) we need */ |
|
|
|
|
/* to keep the original rounded advance width */ |
|
|
|
|
if ( !FT_IS_FIXED_WIDTH( slot->face ) ) |
|
|
|
|
slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; |
|
|
|
|
else |
|
|
|
@ -1663,7 +1667,7 @@ |
|
|
|
|
FT_Fixed x_scale = size->metrics.x_scale; |
|
|
|
|
FT_Fixed y_scale = size->metrics.y_scale; |
|
|
|
|
AH_Face_Globals face_globals = FACE_GLOBALS( face ); |
|
|
|
|
FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE(load_flags); |
|
|
|
|
FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE( load_flags ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* first of all, we need to check that we're using the correct face and */ |
|
|
|
|