📄 afcjk.c
字号:
} return delta; } static void af_cjk_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; FT_Int n_edges; AF_Edge edge; AF_Edge anchor = 0; FT_Pos delta = 0; FT_Int skipped = 0; /* now we align all stem edges. */ for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge edge2; if ( edge->flags & AF_EDGE_DONE ) continue; /* skip all non-stem edges */ edge2 = edge->link; if ( !edge2 ) { skipped++; continue; } /* now align the stem */ if ( edge2 < edge ) { af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; continue; } if ( dim != AF_DIMENSION_VERT && !anchor ) {#if 0 if ( fixedpitch ) { AF_Edge left = edge; AF_Edge right = edge_limit - 1; AF_EdgeRec left1, left2, right1, right2; FT_Pos target, center1, center2; FT_Pos delta1, delta2, d1, d2; while ( right > left && !right->link ) right--; left1 = *left; left2 = *left->link; right1 = *right->link; right2 = *right; delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2; target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16; delta1 = delta; delta1 += af_hint_normal_stem( hints, left, left->link, delta1, 0 ); if ( left->link != right ) af_hint_normal_stem( hints, right->link, right, delta1, 0 ); center1 = left->pos + ( right->pos - left->pos ) / 2; if ( center1 >= target ) delta2 = delta - 32; else delta2 = delta + 32; delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 ); if ( delta1 != delta2 ) { if ( left->link != right ) af_hint_normal_stem( hints, &right1, &right2, delta2, 0 ); center2 = left1.pos + ( right2.pos - left1.pos ) / 2; d1 = center1 - target; d2 = center2 - target; if ( FT_ABS( d2 ) < FT_ABS( d1 ) ) { left->pos = left1.pos; left->link->pos = left2.pos; if ( left->link != right ) { right->link->pos = right1.pos; right->pos = right2.pos; } delta1 = delta2; } } delta = delta1; right->link->flags |= AF_EDGE_DONE; right->flags |= AF_EDGE_DONE; } else#endif /* 0 */ delta = af_hint_normal_stem( hints, edge, edge2, 0, AF_DIMENSION_HORZ ); } else af_hint_normal_stem( hints, edge, edge2, delta, dim );#if 0 printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n", edge - edges, edge2 - edges, ( edge->pos - edge->opos ) / 64.0, ( edge2->pos - edge2->opos ) / 64.0 );#endif anchor = edge; edge->flags |= AF_EDGE_DONE; edge2->flags |= AF_EDGE_DONE; } /* make sure that lowercase m's maintain their symmetry */ /* In general, lowercase m's have six vertical edges if they are sans */ /* serif, or twelve if they are with serifs. This implementation is */ /* based on that assumption, and seems to work very well with most */ /* faces. However, if for a certain face this assumption is not */ /* true, the m is just rendered like before. In addition, any stem */ /* correction will only be applied to symmetrical glyphs (even if the */ /* glyph is not an m), so the potential for unwanted distortion is */ /* relatively low. */ /* We don't handle horizontal edges since we can't easily assure that */ /* the third (lowest) stem aligns with the base line; it might end up */ /* one pixel higher or lower. */ n_edges = edge_limit - edges; if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) { AF_Edge edge1, edge2, edge3; FT_Pos dist1, dist2, span; if ( n_edges == 6 ) { edge1 = edges; edge2 = edges + 2; edge3 = edges + 4; } else { edge1 = edges + 1; edge2 = edges + 5; edge3 = edges + 9; } dist1 = edge2->opos - edge1->opos; dist2 = edge3->opos - edge2->opos; span = dist1 - dist2; if ( span < 0 ) span = -span; if ( edge1->link == edge1 + 1 && edge2->link == edge2 + 1 && edge3->link == edge3 + 1 && span < 8 ) { delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); edge3->pos -= delta; if ( edge3->link ) edge3->link->pos -= delta; /* move the serifs along with the stem */ if ( n_edges == 12 ) { ( edges + 8 )->pos -= delta; ( edges + 11 )->pos -= delta; } edge3->flags |= AF_EDGE_DONE; if ( edge3->link ) edge3->link->flags |= AF_EDGE_DONE; } } if ( !skipped ) return; /* * now hint the remaining edges (serifs and single) in order * to complete our processing */ for ( edge = edges; edge < edge_limit; edge++ ) { if ( edge->flags & AF_EDGE_DONE ) continue; if ( edge->serif ) { af_cjk_align_serif_edge( hints, edge->serif, edge ); edge->flags |= AF_EDGE_DONE; skipped--; } } if ( !skipped ) return; for ( edge = edges; edge < edge_limit; edge++ ) { AF_Edge before, after; if ( edge->flags & AF_EDGE_DONE ) continue; before = after = edge; while ( --before >= edges ) if ( before->flags & AF_EDGE_DONE ) break; while ( ++after < edge_limit ) if ( after->flags & AF_EDGE_DONE ) break; if ( before >= edges || after < edge_limit ) { if ( before < edges ) af_cjk_align_serif_edge( hints, after, edge ); else if ( after >= edge_limit ) af_cjk_align_serif_edge( hints, before, edge ); else edge->pos = before->pos + FT_MulDiv( edge->fpos - before->fpos, after->pos - before->pos, after->fpos - before->fpos ); } } } static void af_cjk_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = & hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Edge edge; FT_Bool snapping; snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ && AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ); for ( edge = edges; edge < edge_limit; edge++ ) { /* move the points of each segment */ /* in each edge to the edge's position */ AF_Segment seg = edge->first; if ( snapping ) { do { AF_Point point = seg->first; for (;;) { if ( dim == AF_DIMENSION_HORZ ) { point->x = edge->pos; point->flags |= AF_FLAG_TOUCH_X; } else { point->y = edge->pos; point->flags |= AF_FLAG_TOUCH_Y; } if ( point == seg->last ) break; point = point->next; } seg = seg->edge_next; } while ( seg != edge->first ); } else { FT_Pos delta = edge->pos - edge->opos; do { AF_Point point = seg->first; for (;;) { if ( dim == AF_DIMENSION_HORZ ) { point->x += delta; point->flags |= AF_FLAG_TOUCH_X; } else { point->y += delta; point->flags |= AF_FLAG_TOUCH_Y; } if ( point == seg->last ) break; point = point->next; } seg = seg->edge_next; } while ( seg != edge->first ); } } } static FT_Error af_cjk_hints_apply( AF_GlyphHints hints, FT_Outline* outline, AF_LatinMetrics metrics ) { FT_Error error; int dim; FT_UNUSED( metrics ); error = af_glyph_hints_reload( hints, outline ); if ( error ) goto Exit; /* analyze glyph outline */ if ( AF_HINTS_DO_HORIZONTAL( hints ) ) { error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ ); if ( error ) goto Exit; } if ( AF_HINTS_DO_VERTICAL( hints ) ) { error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT ); if ( error ) goto Exit; } /* grid-fit the outline */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) {#ifdef AF_USE_WARPER if ( dim == AF_DIMENSION_HORZ && metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL ) { AF_WarperRec warper; FT_Fixed scale; FT_Pos delta; af_warper_compute( &warper, hints, dim, &scale, &delta ); af_glyph_hints_scale_dim( hints, dim, scale, delta ); continue; }#endif /* AF_USE_WARPER */ af_cjk_hint_edges( hints, (AF_Dimension)dim ); af_cjk_align_edge_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); } }#if 0 af_glyph_hints_dump_points( hints ); af_glyph_hints_dump_segments( hints ); af_glyph_hints_dump_edges( hints );#endif af_glyph_hints_save( hints, outline ); Exit: return error; } /*************************************************************************/ /*************************************************************************/ /***** *****/ /***** C J K S C R I P T C L A S S *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ static const AF_Script_UniRangeRec af_cjk_uniranges[] = {#if 0 { 0x0100, 0xFFFF }, /* why this? */#endif { 0x2E80, 0x2EFF }, /* CJK Radicals Supplement */ { 0x2F00, 0x2FDF }, /* Kangxi Radicals */ { 0x3000, 0x303F }, /* CJK Symbols and Punctuation */ { 0x3040, 0x309F }, /* Hiragana */ { 0x30A0, 0x30FF }, /* Katakana */ { 0x3100, 0x312F }, /* Bopomofo */ { 0x3130, 0x318F }, /* Hangul Compatibility Jamo */ { 0x31A0, 0x31BF }, /* Bopomofo Extended */ { 0x31C0, 0x31EF }, /* CJK Strokes */ { 0x31F0, 0x31FF }, /* Katakana Phonetic Extensions */ { 0x3200, 0x32FF }, /* Enclosed CJK Letters and Months */ { 0x3300, 0x33FF }, /* CJK Compatibility */ { 0x3400, 0x4DBF }, /* CJK Unified Ideographs Extension A */ { 0x4DC0, 0x4DFF }, /* Yijing Hexagram Symbols */ { 0x4E00, 0x9FFF }, /* CJK Unified Ideographs */ { 0xF900, 0xFAFF }, /* CJK Compatibility Ideographs */ { 0xFE30, 0xFE4F }, /* CJK Compatibility Forms */ { 0xFF00, 0xFFEF }, /* Halfwidth and Fullwidth Forms */ { 0x20000, 0x2A6DF }, /* CJK Unified Ideographs Extension B */ { 0x2F800, 0x2FA1F }, /* CJK Compatibility Ideographs Supplement */ { 0, 0 } }; FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec af_cjk_script_class = { AF_SCRIPT_CJK, af_cjk_uniranges, sizeof( AF_LatinMetricsRec ), (AF_Script_InitMetricsFunc) af_cjk_metrics_init, (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale, (AF_Script_DoneMetricsFunc) NULL, (AF_Script_InitHintsFunc) af_cjk_hints_init, (AF_Script_ApplyHintsFunc) af_cjk_hints_apply };#else /* !AF_CONFIG_OPTION_CJK */ static const AF_Script_UniRangeRec af_cjk_uniranges[] = { { 0, 0 } }; FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec af_cjk_script_class = { AF_SCRIPT_CJK, af_cjk_uniranges, sizeof( AF_LatinMetricsRec ), (AF_Script_InitMetricsFunc) NULL, (AF_Script_ScaleMetricsFunc)NULL, (AF_Script_DoneMetricsFunc) NULL, (AF_Script_InitHintsFunc) NULL, (AF_Script_ApplyHintsFunc) NULL };#endif /* !AF_CONFIG_OPTION_CJK *//* END */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -