📄 pshalgo.c
字号:
* new_pos = left * else * new_pos = right */ FT_Pos left_nearest = FT_PIX_ROUND( pos ); FT_Pos right_nearest = FT_PIX_ROUND( pos + len ); FT_Pos left_disp = left_nearest - pos; FT_Pos right_disp = right_nearest - ( pos + len ); if ( left_disp < 0 ) left_disp = -left_disp; if ( right_disp < 0 ) right_disp = -right_disp; if ( left_disp <= right_disp ) pos = left_nearest; else pos = right_nearest; } else { /* this is a ghost stem; we simply round it */ pos = FT_PIX_ROUND( pos ); } } else { len = psh_dimension_quantize_len( dim, len, 0 ); } } /* now that we have a good hinted stem width, try to position */ /* the stem along a pixel grid integer coordinate */ hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len ); hint->cur_len = len; } } if ( do_snapping ) { pos = hint->cur_pos; len = hint->cur_len; if ( len < 64 ) len = 64; else len = FT_PIX_ROUND( len ); switch ( align.align ) { case PSH_BLUE_ALIGN_TOP: hint->cur_pos = align.align_top - len; hint->cur_len = len; break; case PSH_BLUE_ALIGN_BOT: hint->cur_len = len; break; case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP: /* don't touch */ break; default: hint->cur_len = len; if ( len & 64 ) pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32; else pos = FT_PIX_ROUND( pos + ( len >> 1 ) ); hint->cur_pos = pos - ( len >> 1 ); hint->cur_len = len; } } psh_hint_set_fitted( hint );#ifdef DEBUG_HINTER if ( ps_debug_hint_func ) ps_debug_hint_func( hint, dimension );#endif } }#if 0 /* not used for now, experimental */ /* * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT) * of stems */ static void psh_hint_align_light( PSH_Hint hint, PSH_Globals globals, FT_Int dimension, PSH_Glyph glyph ) { PSH_Dimension dim = &globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_Fixed delta = dim->scale_delta; if ( !psh_hint_is_fitted( hint ) ) { FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; FT_Pos len = FT_MulFix( hint->org_len, scale ); FT_Pos fit_len; PSH_AlignmentRec align; /* ignore stem alignments when requested through the hint flags */ if ( ( dimension == 0 && !glyph->do_horz_hints ) || ( dimension == 1 && !glyph->do_vert_hints ) ) { hint->cur_pos = pos; hint->cur_len = len; psh_hint_set_fitted( hint ); return; } fit_len = len; hint->cur_len = fit_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 ); 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 - fit_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: { PSH_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 ( !psh_hint_is_fitted( parent ) ) psh_hint_align_light( parent, globals, dimension, glyph ); 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 += psh_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 /* len > 64 */ { FT_Fixed frac_len = len & 63; FT_Fixed center = pos + ( len >> 1 ); FT_Fixed delta_a, delta_b; if ( ( len / 64 ) & 1 ) { delta_a = FT_PIX_FLOOR( center ) + 32 - center; delta_b = FT_PIX_ROUND( center ) - center; } else { delta_a = FT_PIX_ROUND( center ) - center; delta_b = FT_PIX_FLOOR( center ) + 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 += psh_hint_snap_stem_side_delta ( pos, len ); } else if ( frac_len < 48 ) { FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos, len ); if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) ) pos += side_delta; else pos += delta_b; } else { pos += delta_b; } } hint->cur_pos = pos; } } /* switch */ psh_hint_set_fitted( hint );#ifdef DEBUG_HINTER if ( ps_debug_hint_func ) ps_debug_hint_func( hint, dimension );#endif } }#endif /* 0 */ static void psh_hint_table_align_hints( PSH_Hint_Table table, PSH_Globals globals, FT_Int dimension, PSH_Glyph glyph ) { PSH_Hint hint; FT_UInt count;#ifdef DEBUG_HINTER PSH_Dimension dim = &globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_Fixed delta = dim->scale_delta; if ( ps_debug_no_vert_hints && dimension == 0 ) { ps_simple_scale( table, scale, delta, dimension ); return; } if ( ps_debug_no_horz_hints && dimension == 1 ) { ps_simple_scale( table, scale, delta, dimension ); return; }#endif /* DEBUG_HINTER*/ hint = table->hints; count = table->max_hints; for ( ; count > 0; count--, hint++ ) psh_hint_align( hint, globals, dimension, glyph ); } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** POINTS INTERPOLATION ROUTINES *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/#define PSH_ZONE_MIN -3200000L#define PSH_ZONE_MAX +3200000L#define xxDEBUG_ZONES#ifdef DEBUG_ZONES#include <stdio.h> static void psh_print_zone( PSH_Zone zone ) { printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n", zone->scale / 65536.0, zone->delta / 64.0, zone->min, zone->max ); }#else#define psh_print_zone( x ) do { } while ( 0 )#endif /* DEBUG_ZONES */ /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** HINTER GLYPH MANAGEMENT *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/#if 1#define psh_corner_is_flat ft_corner_is_flat#define psh_corner_orientation ft_corner_orientation#else FT_LOCAL_DEF( FT_Int ) psh_corner_is_flat( FT_Pos x_in, FT_Pos y_in, FT_Pos x_out, FT_Pos y_out ) { FT_Pos ax = x_in; FT_Pos ay = y_in; FT_Pos d_in, d_out, d_corner; if ( ax < 0 ) ax = -ax; if ( ay < 0 ) ay = -ay; d_in = ax + ay; ax = x_out; if ( ax < 0 ) ax = -ax; ay = y_out; if ( ay < 0 ) ay = -ay; d_out = ax + ay; ax = x_out + x_in; if ( ax < 0 ) ax = -ax; ay = y_out + y_in; if ( ay < 0 ) ay = -ay; d_corner = ax + ay; return ( d_in + d_out - d_corner ) < ( d_corner >> 4 ); } static FT_Int psh_corner_orientation( FT_Pos in_x, FT_Pos in_y, FT_Pos out_x, FT_Pos out_y ) { FT_Int result; /* deal with the trivial cases quickly */ if ( in_y == 0 ) { if ( in_x >= 0 ) result = out_y; else result = -out_y; } else if ( in_x == 0 ) { if ( in_y >= 0 ) result = -out_x; else result = out_x; } else if ( out_y == 0 ) { if ( out_x >= 0 ) result = in_y; else result = -in_y; } else if ( out_x == 0 ) { if ( out_y >= 0 ) result = -in_x; else result = in_x; } else /* general case */ { long long delta = (long long)in_x * out_y - (long long)in_y * out_x; if ( delta == 0 ) result = 0; else result = 1 - 2 * ( delta < 0 ); } return result; }#endif /* !1 */#ifdef COMPUTE_INFLEXS /* compute all inflex points in a given glyph */ static void psh_glyph_compute_inflections( PSH_Glyph glyph ) { FT_UInt n; for ( n = 0; n < glyph->num_contours; n++ ) { PSH_Point first, start, end, before, after; FT_Pos in_x, in_y, out_x, out_y; FT_Int orient_prev, orient_cur; FT_Int finished = 0; /* we need at least 4 points to create an inflection point */ if ( glyph->contours[n].count < 4 ) continue; /* compute first segment in contour */ first = glyph->contours[n].start; start = end = first; do { end = end->next; if ( end == first ) goto Skip; in_x = end->org_u - start->org_u; in_y = end->org_v - start->org_v; } while ( in_x == 0 && in_y == 0 ); /* extend the segment start whenever possible */ before = start; do { do { start = before; before = before->prev; if ( before == first ) goto Skip; out_x = start->org_u - before->org_u; out_y = start->org_v - before->org_v; } while ( out_x == 0 && out_y == 0 ); orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y ); } while ( orient_prev == 0 ); first = start; in_x = out_x; in_y = out_y; /* now, process all segments in the contour */ do { /* first, extend current segment's end whenever possible */ after = end; do { do { end = after; after = after->next; if ( after == first ) finished = 1; out_x = after->org_u - end->org_u; out_y = after->org_v - end->org_v; } while ( out_x == 0 && out_y == 0 ); orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y ); } while ( orient_cur == 0 ); if ( ( orient_cur ^ orient_prev ) < 0 ) { do { psh_point_set_inflex( start ); start = start->next; } while ( start != end ); psh_point_set_inflex( start ); } start = end; end = after; orient_prev = orient_cur; in_x = out_x; in_y = out_y; } while ( !finished ); Skip: ; } }#endif /* COMPUTE_INFLEXS */ static void psh_glyph_done( PSH_Glyph glyph ) { FT_Memory memory = glyph->memory; psh_hint_table_done( &glyph->hint_tables[1], memory ); psh_hint_table_done( &glyph->hint_tables[0], memory ); FT_FREE( glyph->points );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -