--- freetype-2.1.1/src/pshinter/pshalgo2.c.primaryhints Sat Jun 29 14:24:34 2002 +++ freetype-2.1.1/src/pshinter/pshalgo2.c Sun Jun 30 17:22:30 2002 @@ -351,6 +351,23 @@ } #endif + static FT_Fixed + psh2_hint_snap_stem_side_delta ( FT_Fixed pos, + FT_Fixed len ) + { + FT_Fixed delta1 = ( ( pos + 32 ) & -64 ) - pos; + FT_Fixed delta2 = ( ( pos + len + 32 ) & -64 ) - pos - len; + + if ( ABS( delta1 ) <= ABS( delta2 ) ) + { + return delta1; + } + else + { + return delta2; + } + } + static void psh2_hint_align( PSH2_Hint hint, @@ -367,12 +384,15 @@ FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; FT_Pos len = FT_MulFix( hint->org_len, scale ); +#undef SNAP_STEMS +#undef ONLY_ALIGN_Y + +#ifdef SNAP_STEMS FT_Pos fit_center; FT_Pos fit_len; PSH_AlignmentRec align; - /* compute fitted width/height */ fit_len = 0; if ( hint->org_len ) @@ -458,7 +478,151 @@ hint->cur_pos = fit_center - ( fit_len >> 1 ); } } +#else + PSH_AlignmentRec align; + + hint->cur_len = len; + + /* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + hint->org_pos + hint->org_len, + hint->org_pos, + &align ); +#ifdef ONLY_ALIGN_Y + else + { + hint->cur_pos = pos; + return; + } +#endif + + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + /* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - len; + break; + + case PSH_BLUE_ALIGN_BOT: + /* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: + /* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + default: + { + PSH2_Hint parent = hint->parent; + + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; + + + /* ensure that parent is already fitted */ + if ( !psh2_hint_is_fitted( parent ) ) + psh2_hint_align( parent, globals, dimension ); + + par_org_center = parent->org_pos + ( parent->org_len / 2); + par_cur_center = parent->cur_pos + ( parent->cur_len / 2); + cur_org_center = hint->org_pos + ( hint->org_len / 2); + + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + + { + /* Stems less than one pixel wide are easy - we want to + * make them as dark as possible, so they must fall within + * one pixel. If the stem is split between two pixels + * then snap the edge that is nearer to the pixel boundary + * to the pixel boundary + */ + if (len <= 64) + { + if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 ) + pos += psh2_hint_snap_stem_side_delta ( pos, len ); + } + /* Position stems other to minimize the amount of mid-grays. + * There are, in general, two positions that do this, + * illustrated as A) and B) below. + * + * + + + + + * + * A) |--------------------------------| + * B) |--------------------------------| + * C) |--------------------------------| + * + * Position A) (split the excess stem equally) should be better + * for stems of width N + f where f < 0.5 + * + * Position B) (split the deficiency equally) should be better + * for stems of width N + f where f > 0.5 + * + * It turns out though that minimizing the total number of lit + * pixels is also important, so position C), with one edge + * aligned with a pixel boundary is actually preferable + * to A). There are also more possibile positions for C) than + * for A) or B), so it involves less distortion of the overall + * character shape. + */ + else + { + FT_Fixed frac_len = len & 63; + FT_Fixed center = pos + ( len >> 1 ); + + FT_Fixed delta_a, delta_b; + + if ( ( len / 64 ) & 1 ) + { + delta_a = ( center & -64 ) + 32 - center; + delta_b = ( ( center + 32 ) & - 64 ) - center; + } + else + { + delta_a = ( ( center + 32 ) & - 64 ) - center; + delta_b = ( center & -64 ) + 32 - center; + } + + /* We choose between B) and C) above based on the amount + * of fractinal stem width; for small amounts, choose + * C) always, for large amounts, B) always, and inbetween, + * pick whichever one involves less stem movement. + */ + if (frac_len < 32) + { + pos += psh2_hint_snap_stem_side_delta ( pos, len ); + } + else if (frac_len < 48) + { + FT_Fixed side_delta = psh2_hint_snap_stem_side_delta ( pos, len ); + + if ( ABS( side_delta ) < ABS( delta_b ) ) + pos += side_delta; + else + pos += delta_b; + } + else + { + pos += delta_b; + } + } + } + + hint->cur_pos = pos; + } + } +#endif + psh2_hint_set_fitted( hint ); #ifdef DEBUG_HINTER