📄 pshalgo2.c
字号:
#ifdef DEBUG_ZONES#include <stdio.h> static void psh2_print_zone( PSH2_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 psh2_print_zone( x ) do { } while ( 0 )#endif#if 0 /* setup interpolation zones once the hints have been grid-fitted */ /* by the optimizer */ static void psh2_hint_table_setup_zones( PSH2_Hint_Table table, FT_Fixed scale, FT_Fixed delta ) { FT_UInt count; PSH2_Zone zone; PSH2_Hint *sort, hint, hint2; zone = table->zones; /* special case, no hints defined */ if ( table->num_hints == 0 ) { zone->scale = scale; zone->delta = delta; zone->min = PSH2_ZONE_MIN; zone->max = PSH2_ZONE_MAX; table->num_zones = 1; table->zone = zone; return; } /* the first zone is before the first hint */ /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */ sort = table->sort; hint = sort[0]; zone->scale = scale; zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale ); zone->min = PSH2_ZONE_MIN; zone->max = hint->org_pos; psh2_print_zone( zone ); zone++; for ( count = table->num_hints; count > 0; count-- ) { FT_Fixed scale2; if ( hint->org_len > 0 ) { /* setup a zone for inner-stem interpolation */ /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */ /* x' = x*s2 + x0' - x0*s2 */ scale2 = FT_DivFix( hint->cur_len, hint->org_len ); zone->scale = scale2; zone->min = hint->org_pos; zone->max = hint->org_pos + hint->org_len; zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 ); psh2_print_zone( zone ); zone++; } if ( count == 1 ) break; sort++; hint2 = sort[0]; /* setup zone for inter-stem interpolation */ /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */ /* x' = x*s3 + x1' - x1*s3 */ scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len), hint2->org_pos - (hint->org_pos + hint->org_len) ); zone->scale = scale2; zone->min = hint->org_pos + hint->org_len; zone->max = hint2->org_pos; zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 ); psh2_print_zone( zone ); zone++; hint = hint2; } /* the last zone */ zone->scale = scale; zone->min = hint->org_pos + hint->org_len; zone->max = PSH2_ZONE_MAX; zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale ); psh2_print_zone( zone ); zone++; table->num_zones = zone - table->zones; table->zone = table->zones; }#endif#if 0 /* tune a single coordinate with the current interpolation zones */ static FT_Pos psh2_hint_table_tune_coord( PSH2_Hint_Table table, FT_Int coord ) { PSH2_Zone zone; zone = table->zone; if ( coord < zone->min ) { do { if ( zone == table->zones ) break; zone--; } while ( coord < zone->min ); table->zone = zone; } else if ( coord > zone->max ) { do { if ( zone == table->zones + table->num_zones - 1 ) break; zone++; } while ( coord > zone->max ); table->zone = zone; } return FT_MulFix( coord, zone->scale ) + zone->delta; }#endif#if 0 /* tune a given outline with current interpolation zones */ /* the function only works in a single dimension.. */ static void psh2_hint_table_tune_outline( PSH2_Hint_Table table, FT_Outline* outline, PSH_Globals globals, FT_Int dimension ) { FT_UInt count, first, last; PS_Mask_Table hint_masks = table->hint_masks; PS_Mask mask; PSH_Dimension dim = &globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_Fixed delta = dim->scale_delta; if ( hint_masks && hint_masks->num_masks > 0 ) { first = 0; mask = hint_masks->masks; count = hint_masks->num_masks; for ( ; count > 0; count--, mask++ ) { last = mask->end_point; if ( last > first ) { FT_Vector* vec; FT_Int count2; psh2_hint_table_activate_mask( table, mask ); psh2_hint_table_optimize( table, globals, outline, dimension ); psh2_hint_table_setup_zones( table, scale, delta ); last = mask->end_point; vec = outline->points + first; count2 = last - first; for ( ; count2 > 0; count2--, vec++ ) { FT_Pos x, *px; px = dimension ? &vec->y : &vec->x; x = *px; *px = psh2_hint_table_tune_coord( table, (FT_Int)x ); } } first = last; } } else /* no hints in this glyph, simply scale the outline */ { FT_Vector* vec; vec = outline->points; count = outline->n_points; if ( dimension == 0 ) { for ( ; count > 0; count--, vec++ ) vec->x = FT_MulFix( vec->x, scale ) + delta; } else { for ( ; count > 0; count--, vec++ ) vec->y = FT_MulFix( vec->y, scale ) + delta; } } }#endif /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** HINTER GLYPH MANAGEMENT *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ static int psh2_point_is_extremum( PSH2_Point point ) { PSH2_Point before = point; PSH2_Point after = point; FT_Pos d_before; FT_Pos d_after; do { before = before->prev; if ( before == point ) return 0; d_before = before->org_u - point->org_u; } while ( d_before == 0 ); do { after = after->next; if ( after == point ) return 0; d_after = after->org_u - point->org_u; } while ( d_after == 0 ); return ( ( d_before > 0 && d_after > 0 ) || ( d_before < 0 && d_after < 0 ) ); } static void psh2_glyph_done( PSH2_Glyph glyph ) { FT_Memory memory = glyph->memory; psh2_hint_table_done( &glyph->hint_tables[1], memory ); psh2_hint_table_done( &glyph->hint_tables[0], memory ); FT_FREE( glyph->points ); FT_FREE( glyph->contours ); glyph->num_points = 0; glyph->num_contours = 0; glyph->memory = 0; } static int psh2_compute_dir( FT_Pos dx, FT_Pos dy ) { FT_Pos ax, ay; int result = PSH2_DIR_NONE; ax = ( dx >= 0 ) ? dx : -dx; ay = ( dy >= 0 ) ? dy : -dy; if ( ay * 12 < ax ) { /* |dy| <<< |dx| means a near-horizontal segment */ result = ( dx >= 0 ) ? PSH2_DIR_RIGHT : PSH2_DIR_LEFT; } else if ( ax * 12 < ay ) { /* |dx| <<< |dy| means a near-vertical segment */ result = ( dy >= 0 ) ? PSH2_DIR_UP : PSH2_DIR_DOWN; } return result; } static FT_Error psh2_glyph_init( PSH2_Glyph glyph, FT_Outline* outline, PS_Hints ps_hints, PSH_Globals globals ) { FT_Error error; FT_Memory memory; /* clear all fields */ ft_memset( glyph, 0, sizeof ( *glyph ) ); memory = globals->memory; /* allocate and setup points + contours arrays */ if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) || FT_NEW_ARRAY( glyph->contours, outline->n_contours ) ) goto Exit; glyph->num_points = outline->n_points; glyph->num_contours = outline->n_contours; { FT_UInt first = 0, next, n; PSH2_Point points = glyph->points; PSH2_Contour contour = glyph->contours; for ( n = 0; n < glyph->num_contours; n++ ) { FT_Int count; PSH2_Point point; next = outline->contours[n] + 1; count = next - first; contour->start = points + first; contour->count = (FT_UInt)count; if ( count > 0 ) { point = points + first; point->prev = points + next - 1; point->contour = contour; for ( ; count > 1; count-- ) { point[0].next = point + 1; point[1].prev = point; point++; point->contour = contour; } point->next = points + first; } contour++; first = next; } } { PSH2_Point points = glyph->points; PSH2_Point point = points; FT_Vector* vec = outline->points; FT_UInt n; for ( n = 0; n < glyph->num_points; n++, point++ ) { FT_Int n_prev = point->prev - points; FT_Int n_next = point->next - points; FT_Pos dxi, dyi, dxo, dyo; if ( !( outline->tags[n] & FT_Curve_Tag_On ) ) point->flags = PSH2_POINT_OFF; dxi = vec[n].x - vec[n_prev].x; dyi = vec[n].y - vec[n_prev].y; point->dir_in = (FT_Char)psh2_compute_dir( dxi, dyi ); dxo = vec[n_next].x - vec[n].x; dyo = vec[n_next].y - vec[n].y; point->dir_out = (FT_Char)psh2_compute_dir( dxo, dyo ); /* detect smooth points */ if ( point->flags & PSH2_POINT_OFF ) point->flags |= PSH2_POINT_SMOOTH; else if ( point->dir_in != PSH2_DIR_NONE || point->dir_out != PSH2_DIR_NONE ) { if ( point->dir_in == point->dir_out ) point->flags |= PSH2_POINT_SMOOTH; } else { FT_Angle angle_in, angle_out, diff; angle_in = FT_Atan2( dxi, dyi ); angle_out = FT_Atan2( dxo, dyo ); diff = angle_in - angle_out; if ( diff < 0 ) diff = -diff; if ( diff > FT_ANGLE_PI ) diff = FT_ANGLE_2PI - diff; if ( diff < FT_ANGLE_PI / 16 ) point->flags |= PSH2_POINT_SMOOTH; } } } glyph->memory = memory; glyph->outline = outline; glyph->globals = globals; /* now deal with hints tables */ error = psh2_hint_table_init( &glyph->hint_tables [0], &ps_hints->dimension[0].hints, &ps_hints->dimension[0].masks, &ps_hints->dimension[0].counters, memory ); if ( error ) goto Exit; error = psh2_hint_table_init( &glyph->hint_tables [1], &ps_hints->dimension[1].hints, &ps_hints->dimension[1].masks, &ps_hints->dimension[1].counters, memory ); if ( error ) goto Exit; Exit: return error; } /* load outline point coordinates into hinter glyph */ static void psh2_glyph_load_points( PSH2_Glyph glyph, FT_Int dimension ) { FT_Vector* vec = glyph->outline->points; PSH2_Point point = glyph->points; FT_UInt count = glyph->num_points; for ( ; count > 0; count--, point++, vec++ ) { point->flags &= PSH2_POINT_OFF | PSH2_POINT_SMOOTH; point->hint = 0; if ( dimension == 0 ) point->org_u = vec->x; else point->org_u = vec->y;#ifdef DEBUG_HINTER point->org_x = vec->x; point->org_y = vec->y;#endif } } /* save hinted point coordinates back to outline */ static void psh2_glyph_save_points( PSH2_Glyph glyph, FT_Int dimension ) { FT_UInt n; PSH2_Point point = glyph->points; FT_Vector* vec = glyph->outline->points; char* tags = glyph->outline->tags; for ( n = 0; n < glyph->num_points; n++ ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -