📄 pshalgo.c
字号:
FT_UInt count = glyph->num_points; PSH_Point point = glyph->points; psh_hint_table_activate_mask( table, table->hint_masks->masks ); psh_hint_table_find_strong_points( table, point, count, threshold, major_dir ); } /* now, certain points may have been attached to a hint and */ /* not marked as strong; update their flags then */ { FT_UInt count = glyph->num_points; PSH_Point point = glyph->points; for ( ; count > 0; count--, point++ ) if ( point->hint && !psh_point_is_strong( point ) ) psh_point_set_strong( point ); } } /* find points in a glyph which are in a blue zone and have `in' or */ /* `out' tangents parallel to the horizontal axis */ static void psh_glyph_find_blue_points( PSH_Blues blues, PSH_Glyph glyph ) { PSH_Blue_Table table; PSH_Blue_Zone zone; FT_UInt glyph_count = glyph->num_points; FT_UInt blue_count; PSH_Point point = glyph->points; for ( ; glyph_count > 0; glyph_count--, point++ ) { FT_Pos y; /* check tangents */ if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) && !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) ) continue; /* skip strong points */ if ( psh_point_is_strong( point ) ) continue; y = point->org_u; /* look up top zones */ table = &blues->normal_top; blue_count = table->count; zone = table->zones; for ( ; blue_count > 0; blue_count--, zone++ ) { FT_Pos delta = y - zone->org_bottom; if ( delta < -blues->blue_fuzz ) break; if ( y <= zone->org_top + blues->blue_fuzz ) if ( blues->no_overshoots || delta <= blues->blue_threshold ) { point->cur_u = zone->cur_bottom; psh_point_set_strong( point ); psh_point_set_fitted( point ); } } /* look up bottom zones */ table = &blues->normal_bottom; blue_count = table->count; zone = table->zones + blue_count - 1; for ( ; blue_count > 0; blue_count--, zone-- ) { FT_Pos delta = zone->org_top - y; if ( delta < -blues->blue_fuzz ) break; if ( y >= zone->org_bottom - blues->blue_fuzz ) if ( blues->no_overshoots || delta < blues->blue_threshold ) { point->cur_u = zone->cur_top; psh_point_set_strong( point ); psh_point_set_fitted( point ); } } } } /* interpolate strong points with the help of hinted coordinates */ static void psh_glyph_interpolate_strong_points( PSH_Glyph glyph, FT_Int dimension ) { PSH_Dimension dim = &glyph->globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_UInt count = glyph->num_points; PSH_Point point = glyph->points; for ( ; count > 0; count--, point++ ) { PSH_Hint hint = point->hint; if ( hint ) { FT_Pos delta; if ( psh_point_is_edge_min( point ) ) point->cur_u = hint->cur_pos; else if ( psh_point_is_edge_max( point ) ) point->cur_u = hint->cur_pos + hint->cur_len; else { delta = point->org_u - hint->org_pos; if ( delta <= 0 ) point->cur_u = hint->cur_pos + FT_MulFix( delta, scale ); else if ( delta >= hint->org_len ) point->cur_u = hint->cur_pos + hint->cur_len + FT_MulFix( delta - hint->org_len, scale ); else if ( hint->org_len > 0 ) point->cur_u = hint->cur_pos + FT_MulDiv( delta, hint->cur_len, hint->org_len ); else point->cur_u = hint->cur_pos; } psh_point_set_fitted( point ); } } }#define PSH_MAX_STRONG_INTERNAL 16 static void psh_glyph_interpolate_normal_points( PSH_Glyph glyph, FT_Int dimension ) {#if 1 /* first technique: a point is strong if it is a local extremum */ PSH_Dimension dim = &glyph->globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_Memory memory = glyph->memory; PSH_Point* strongs = NULL; PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL]; FT_UInt num_strongs = 0; PSH_Point points = glyph->points; PSH_Point points_end = points + glyph->num_points; PSH_Point point; /* first count the number of strong points */ for ( point = points; point < points_end; point++ ) { if ( psh_point_is_strong( point ) ) num_strongs++; } if ( num_strongs == 0 ) /* nothing to do here */ return; /* allocate an array to store a list of points, */ /* stored in increasing org_u order */ if ( num_strongs <= PSH_MAX_STRONG_INTERNAL ) strongs = strongs_0; else { FT_Error error; if ( FT_NEW_ARRAY( strongs, num_strongs ) ) return; } num_strongs = 0; for ( point = points; point < points_end; point++ ) { PSH_Point* insert; if ( !psh_point_is_strong( point ) ) continue; for ( insert = strongs + num_strongs; insert > strongs; insert-- ) { if ( insert[-1]->org_u <= point->org_u ) break; insert[0] = insert[-1]; } insert[0] = point; num_strongs++; } /* now try to interpolate all normal points */ for ( point = points; point < points_end; point++ ) { if ( psh_point_is_strong( point ) ) continue; /* sometimes, some local extrema are smooth points */ if ( psh_point_is_smooth( point ) ) { if ( point->dir_in == PSH_DIR_NONE || point->dir_in != point->dir_out ) continue; if ( !psh_point_is_extremum( point ) && !psh_point_is_inflex( point ) ) continue; point->flags &= ~PSH_POINT_SMOOTH; } /* find best enclosing point coordinates then interpolate */ { PSH_Point before, after; FT_UInt nn; for ( nn = 0; nn < num_strongs; nn++ ) if ( strongs[nn]->org_u > point->org_u ) break; if ( nn == 0 ) /* point before the first strong point */ { after = strongs[0]; point->cur_u = after->cur_u + FT_MulFix( point->org_u - after->org_u, scale ); } else { before = strongs[nn - 1]; for ( nn = num_strongs; nn > 0; nn-- ) if ( strongs[nn - 1]->org_u < point->org_u ) break; if ( nn == num_strongs ) /* point is after last strong point */ { before = strongs[nn - 1]; point->cur_u = before->cur_u + FT_MulFix( point->org_u - before->org_u, scale ); } else { FT_Pos u; after = strongs[nn]; /* now interpolate point between before and after */ u = point->org_u; if ( u == before->org_u ) point->cur_u = before->cur_u; else if ( u == after->org_u ) point->cur_u = after->cur_u; else point->cur_u = before->cur_u + FT_MulDiv( u - before->org_u, after->cur_u - before->cur_u, after->org_u - before->org_u ); } } psh_point_set_fitted( point ); } } if ( strongs != strongs_0 ) FT_FREE( strongs );#endif /* 1 */ } /* interpolate other points */ static void psh_glyph_interpolate_other_points( PSH_Glyph glyph, FT_Int dimension ) { PSH_Dimension dim = &glyph->globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_Fixed delta = dim->scale_delta; PSH_Contour contour = glyph->contours; FT_UInt num_contours = glyph->num_contours; for ( ; num_contours > 0; num_contours--, contour++ ) { PSH_Point start = contour->start; PSH_Point first, next, point; FT_UInt fit_count; /* count the number of strong points in this contour */ next = start + contour->count; fit_count = 0; first = 0; for ( point = start; point < next; point++ ) if ( psh_point_is_fitted( point ) ) { if ( !first ) first = point; fit_count++; } /* if there are less than 2 fitted points in the contour, we */ /* simply scale and eventually translate the contour points */ if ( fit_count < 2 ) { if ( fit_count == 1 ) delta = first->cur_u - FT_MulFix( first->org_u, scale ); for ( point = start; point < next; point++ ) if ( point != first ) point->cur_u = FT_MulFix( point->org_u, scale ) + delta; goto Next_Contour; } /* there are more than 2 strong points in this contour; we */ /* need to interpolate weak points between them */ start = first; do { point = first; /* skip consecutive fitted points */ for (;;) { next = first->next; if ( next == start ) goto Next_Contour; if ( !psh_point_is_fitted( next ) ) break; first = next; } /* find next fitted point after unfitted one */ for (;;) { next = next->next; if ( psh_point_is_fitted( next ) ) break; } /* now interpolate between them */ { FT_Pos org_a, org_ab, cur_a, cur_ab; FT_Pos org_c, org_ac, cur_c; FT_Fixed scale_ab; if ( first->org_u <= next->org_u ) { org_a = first->org_u; cur_a = first->cur_u; org_ab = next->org_u - org_a; cur_ab = next->cur_u - cur_a; } else { org_a = next->org_u; cur_a = next->cur_u; org_ab = first->org_u - org_a; cur_ab = first->cur_u - cur_a; } scale_ab = 0x10000L; if ( org_ab > 0 ) scale_ab = FT_DivFix( cur_ab, org_ab ); point = first->next; do { org_c = point->org_u; org_ac = org_c - org_a; if ( org_ac <= 0 ) { /* on the left of the interpolation zone */ cur_c = cur_a + FT_MulFix( org_ac, scale ); } else if ( org_ac >= org_ab ) { /* on the right on the interpolation zone */ cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale ); } else { /* within the interpolation zone */ cur_c = cur_a + FT_MulFix( org_ac, scale_ab ); } point->cur_u = cur_c; point = point->next; } while ( point != next ); } /* keep going until all points in the contours have been processed */ first = next; } while ( first != start ); Next_Contour: ; } } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** HIGH-LEVEL INTERFACE *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ FT_Error ps_hints_apply( PS_Hints ps_hints, FT_Outline* outline, PSH_Globals globals, FT_Render_Mode hint_mode ) { PSH_GlyphRec glyphrec; PSH_Glyph glyph = &glyphrec; FT_Error error;#ifdef DEBUG_HINTER FT_Memory memory;#endif FT_Int dimension; /* something to do? */ if ( outline->n_points == 0 || outline->n_contours == 0 ) return PSH_Err_Ok;#ifdef DEBUG_HINTER memory = globals->memory; if ( ps_debug_glyph ) { psh_glyph_done( ps_debug_glyph ); FT_FREE( ps_debug_glyph ); } if ( FT_NEW( glyph ) ) return error; ps_debug_glyph = glyph;#endif /* DEBUG_HINTER */ error = psh_glyph_init( glyph, outline, ps_hints, globals ); if ( error ) goto Exit; /* try to optimize the y_scale so that the top of non-capital letters * is aligned on a pixel boundary whenever possible */ { PSH_Dimension dim_x = &glyph->globals->dimension[0]; PSH_Dimension dim_y = &glyph->globals->dimension[1]; FT_Fixed x_scale = dim_x->scale_mult; FT_Fixed y_scale = dim_y->scale_mult; FT_Fixed scaled; FT_Fixed fitted; scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); fitted = FT_PIX_ROUND( scaled ); if ( fitted != 0 && scaled != fitted ) { y_scale = FT_MulDiv( y_scale, fitted, scaled ); if ( fitted < scaled ) x_scale -= x_scale / 50; psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 ); } } glyph->do_horz_hints = 1; glyph->do_vert_hints = 1; glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || hint_mode == FT_RENDER_MODE_LCD ); glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || hint_mode == FT_RENDER_MODE_LCD_V ); glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); for ( dimension = 0; dimension < 2; dimension++ ) { /* load outline coordinates into glyph */ psh_glyph_load_points( glyph, dimension ); /* compute local extrema */ psh_glyph_compute_extrema( glyph ); /* compute aligned stem/hints positions */ psh_hint_table_align_hints( &glyph->hint_tables[dimension], glyph->globals, dimension, glyph ); /* find strong points, align them, then interpolate others */ psh_glyph_find_strong_points( glyph, dimension ); if ( dimension == 1 ) psh_glyph_find_blue_points( &globals->blues, glyph ); psh_glyph_interpolate_strong_points( glyph, dimension ); psh_glyph_interpolate_normal_points( glyph, dimension ); psh_glyph_interpolate_other_points( glyph, dimension ); /* save hinted coordinates back to outline */ psh_glyph_save_points( glyph, dimension ); } Exit:#ifndef DEBUG_HINTER psh_glyph_done( glyph );#endif return error; }/* END */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -