📄 pshalgo.c
字号:
FT_FREE( glyph->contours ); glyph->num_points = 0; glyph->num_contours = 0; glyph->memory = 0; } static int psh_compute_dir( FT_Pos dx, FT_Pos dy ) { FT_Pos ax, ay; int result = PSH_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 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT; } else if ( ax * 12 < ay ) { /* |dx| <<< |dy| means a near-vertical segment */ result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN; } return result; } /* load outline point coordinates into hinter glyph */ static void psh_glyph_load_points( PSH_Glyph glyph, FT_Int dimension ) { FT_Vector* vec = glyph->outline->points; PSH_Point point = glyph->points; FT_UInt count = glyph->num_points; for ( ; count > 0; count--, point++, vec++ ) { point->flags2 = 0; point->hint = NULL; if ( dimension == 0 ) { point->org_u = vec->x; point->org_v = vec->y; } else { point->org_u = vec->y; point->org_v = vec->x; }#ifdef DEBUG_HINTER point->org_x = vec->x; point->org_y = vec->y;#endif } } /* save hinted point coordinates back to outline */ static void psh_glyph_save_points( PSH_Glyph glyph, FT_Int dimension ) { FT_UInt n; PSH_Point point = glyph->points; FT_Vector* vec = glyph->outline->points; char* tags = glyph->outline->tags; for ( n = 0; n < glyph->num_points; n++ ) { if ( dimension == 0 ) vec[n].x = point->cur_u; else vec[n].y = point->cur_u; if ( psh_point_is_strong( point ) ) tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );#ifdef DEBUG_HINTER if ( dimension == 0 ) { point->cur_x = point->cur_u; point->flags_x = point->flags2 | point->flags; } else { point->cur_y = point->cur_u; point->flags_y = point->flags2 | point->flags; }#endif point++; } } static FT_Error psh_glyph_init( PSH_Glyph glyph, FT_Outline* outline, PS_Hints ps_hints, PSH_Globals globals ) { FT_Error error; FT_Memory memory; /* clear all fields */ FT_MEM_ZERO( glyph, sizeof ( *glyph ) ); memory = 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; PSH_Point points = glyph->points; PSH_Contour contour = glyph->contours; for ( n = 0; n < glyph->num_contours; n++ ) { FT_Int count; PSH_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; } } { PSH_Point points = glyph->points; PSH_Point point = points; FT_Vector* vec = outline->points; FT_UInt n; for ( n = 0; n < glyph->num_points; n++, point++ ) { FT_Int n_prev = (FT_Int)( point->prev - points ); FT_Int n_next = (FT_Int)( point->next - points ); FT_Pos dxi, dyi, dxo, dyo; if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) point->flags = PSH_POINT_OFF; dxi = vec[n].x - vec[n_prev].x; dyi = vec[n].y - vec[n_prev].y; point->dir_in = (FT_Char)psh_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)psh_compute_dir( dxo, dyo ); /* detect smooth points */ if ( point->flags & PSH_POINT_OFF ) point->flags |= PSH_POINT_SMOOTH; else if ( point->dir_in == point->dir_out ) { if ( point->dir_out != PSH_DIR_NONE || psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) point->flags |= PSH_POINT_SMOOTH; } } } glyph->outline = outline; glyph->globals = globals;#ifdef COMPUTE_INFLEXS psh_glyph_load_points( glyph, 0 ); psh_glyph_compute_inflections( glyph );#endif /* COMPUTE_INFLEXS */ /* now deal with hints tables */ error = psh_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 = psh_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; } /* compute all extrema in a glyph for a given dimension */ static void psh_glyph_compute_extrema( PSH_Glyph glyph ) { FT_UInt n; /* first of all, compute all local extrema */ for ( n = 0; n < glyph->num_contours; n++ ) { PSH_Point first = glyph->contours[n].start; PSH_Point point, before, after; if ( glyph->contours[n].count == 0 ) continue; point = first; before = point; after = point; do { before = before->prev; if ( before == first ) goto Skip; } while ( before->org_u == point->org_u ); first = point = before->next; for (;;) { after = point; do { after = after->next; if ( after == first ) goto Next; } while ( after->org_u == point->org_u ); if ( before->org_u < point->org_u ) { if ( after->org_u < point->org_u ) { /* local maximum */ goto Extremum; } } else /* before->org_u > point->org_u */ { if ( after->org_u > point->org_u ) { /* local minimum */ Extremum: do { psh_point_set_extremum( point ); point = point->next; } while ( point != after ); } } before = after->prev; point = after; } /* for */ Next: ; } /* for each extremum, determine its direction along the */ /* orthogonal axis */ for ( n = 0; n < glyph->num_points; n++ ) { PSH_Point point, before, after; point = &glyph->points[n]; before = point; after = point; if ( psh_point_is_extremum( point ) ) { do { before = before->prev; if ( before == point ) goto Skip; } while ( before->org_v == point->org_v ); do { after = after->next; if ( after == point ) goto Skip; } while ( after->org_v == point->org_v ); } if ( before->org_v < point->org_v && after->org_v > point->org_v ) { psh_point_set_positive( point ); } else if ( before->org_v > point->org_v && after->org_v < point->org_v ) { psh_point_set_negative( point ); } Skip: ; } } /* major_dir is the direction for points on the bottom/left of the stem; */ /* Points on the top/right of the stem will have a direction of */ /* -major_dir. */ static void psh_hint_table_find_strong_points( PSH_Hint_Table table, PSH_Point point, FT_UInt count, FT_Int threshold, FT_Int major_dir ) { PSH_Hint* sort = table->sort; FT_UInt num_hints = table->num_hints; for ( ; count > 0; count--, point++ ) { FT_Int point_dir = 0; FT_Pos org_u = point->org_u; if ( psh_point_is_strong( point ) ) continue; if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) ) point_dir = point->dir_in; else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) ) point_dir = point->dir_out; if ( point_dir ) { if ( point_dir == major_dir ) { FT_UInt nn; for ( nn = 0; nn < num_hints; nn++ ) { PSH_Hint hint = sort[nn]; FT_Pos d = org_u - hint->org_pos; if ( d < threshold && -d < threshold ) { psh_point_set_strong( point ); point->flags2 |= PSH_POINT_EDGE_MIN; point->hint = hint; break; } } } else if ( point_dir == -major_dir ) { FT_UInt nn; for ( nn = 0; nn < num_hints; nn++ ) { PSH_Hint hint = sort[nn]; FT_Pos d = org_u - hint->org_pos - hint->org_len; if ( d < threshold && -d < threshold ) { psh_point_set_strong( point ); point->flags2 |= PSH_POINT_EDGE_MAX; point->hint = hint; break; } } } }#if 1 else if ( psh_point_is_extremum( point ) ) { /* treat extrema as special cases for stem edge alignment */ FT_UInt nn, min_flag, max_flag; if ( major_dir == PSH_DIR_HORIZONTAL ) { min_flag = PSH_POINT_POSITIVE; max_flag = PSH_POINT_NEGATIVE; } else { min_flag = PSH_POINT_NEGATIVE; max_flag = PSH_POINT_POSITIVE; } if ( point->flags2 & min_flag ) { for ( nn = 0; nn < num_hints; nn++ ) { PSH_Hint hint = sort[nn]; FT_Pos d = org_u - hint->org_pos; if ( d < threshold && -d < threshold ) { point->flags2 |= PSH_POINT_EDGE_MIN; point->hint = hint; psh_point_set_strong( point ); break; } } } else if ( point->flags2 & max_flag ) { for ( nn = 0; nn < num_hints; nn++ ) { PSH_Hint hint = sort[nn]; FT_Pos d = org_u - hint->org_pos - hint->org_len; if ( d < threshold && -d < threshold ) { point->flags2 |= PSH_POINT_EDGE_MAX; point->hint = hint; psh_point_set_strong( point ); break; } } } if ( point->hint == NULL ) { for ( nn = 0; nn < num_hints; nn++ ) { PSH_Hint hint = sort[nn]; if ( org_u >= hint->org_pos && org_u <= hint->org_pos + hint->org_len ) { point->hint = hint; break; } } } }#endif /* 1 */ } } /* the accepted shift for strong points in fractional pixels */#define PSH_STRONG_THRESHOLD 32 /* the maximum shift value in font units */#define PSH_STRONG_THRESHOLD_MAXIMUM 30 /* find strong points in a glyph */ static void psh_glyph_find_strong_points( PSH_Glyph glyph, FT_Int dimension ) { /* a point is `strong' if it is located on a stem edge and */ /* has an `in' or `out' tangent parallel to the hint's direction */ PSH_Hint_Table table = &glyph->hint_tables[dimension]; PS_Mask mask = table->hint_masks->masks; FT_UInt num_masks = table->hint_masks->num_masks; FT_UInt first = 0; FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL : PSH_DIR_HORIZONTAL; PSH_Dimension dim = &glyph->globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; FT_Int threshold; threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale ); if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM ) threshold = PSH_STRONG_THRESHOLD_MAXIMUM; /* process secondary hints to `selected' points */ if ( num_masks > 1 && glyph->num_points > 0 ) { first = mask->end_point; mask++; for ( ; num_masks > 1; num_masks--, mask++ ) { FT_UInt next; FT_Int count; next = mask->end_point; count = next - first; if ( count > 0 ) { PSH_Point point = glyph->points + first; psh_hint_table_activate_mask( table, mask ); psh_hint_table_find_strong_points( table, point, count, threshold, major_dir ); } first = next; } } /* process primary hints for all points */ if ( num_masks == 1 ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -