33#ifdef AF_CONFIG_OPTION_CJK
35#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
47#define FT_COMPONENT afcjk
63 af_cjk_metrics_init_widths( AF_CJKMetrics metrics,
67 AF_GlyphHintsRec hints[1];
71 FT_TRACE5((
"cjk standard widths computation (style `%s')\n",
72 af_style_names[metrics->root.style_class->style] ));
73 FT_TRACE5((
"===================================================\n" ));
76 af_glyph_hints_init( hints, face->memory );
78 metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
79 metrics->axis[AF_DIMENSION_VERT].width_count = 0;
85 AF_CJKMetricsRec dummy[1];
86 AF_Scaler scaler = &dummy->root.scaler;
88 AF_StyleClass style_class = metrics->root.style_class;
89 AF_ScriptClass script_class = af_script_classes[style_class->script];
94 void* shaper_buf = &shaper_buf_;
98#ifdef FT_DEBUG_LEVEL_TRACE
102 p = script_class->standard_charstring;
104 if ( ft_hb_enabled( metrics->root.globals ) )
105 shaper_buf = af_shaper_buf_create( metrics->root.globals );
112 unsigned int num_idx;
114#ifdef FT_DEBUG_LEVEL_TRACE
122#ifdef FT_DEBUG_LEVEL_TRACE
124 GET_UTF8_CHAR( ch, p_old );
128 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
133 glyph_index = af_shaper_get_elem( &metrics->root,
142 af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
150 FT_TRACE5((
"standard character: U+%04lX (glyph index %lu)\n",
153 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
154 if ( error || face->glyph->outline.n_points <= 0 )
159 dummy->units_per_em = metrics->units_per_em;
161 scaler->x_scale = 0x10000L;
162 scaler->y_scale = 0x10000L;
167 scaler->render_mode = FT_RENDER_MODE_NORMAL;
170 af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy );
172 error = af_glyph_hints_reload( hints, &face->glyph->outline );
176 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
178 AF_CJKAxis axis = &metrics->axis[dim];
179 AF_AxisHints axhints = &hints->axis[dim];
180 AF_Segment seg, limit, link;
181 FT_UInt num_widths = 0;
184 error = af_latin_hints_compute_segments( hints,
195 af_latin_hints_link_segments( hints,
200 seg = axhints->segments;
201 limit = seg + axhints->num_segments;
203 for ( ; seg < limit; seg++ )
208 if ( link && link->link == seg && link > seg )
213 dist = seg->pos - link->pos;
217 if ( num_widths < AF_CJK_MAX_WIDTHS )
218 axis->widths[num_widths++].org = dist;
224 af_sort_and_quantize_widths( &num_widths, axis->widths,
225 dummy->units_per_em / 100 );
226 axis->width_count = num_widths;
230 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
232 AF_CJKAxis axis = &metrics->axis[dim];
236 stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
237 : AF_LATIN_CONSTANT( metrics, 50 );
240 axis->edge_distance_threshold = stdw / 5;
241 axis->standard_width = stdw;
242 axis->extra_light = 0;
244#ifdef FT_DEBUG_LEVEL_TRACE
249 FT_TRACE5((
"%s widths:\n",
250 dim == AF_DIMENSION_VERT ?
"horizontal"
253 FT_TRACE5((
" %ld (standard)", axis->standard_width ));
254 for ( i = 1; i < axis->width_count; i++ )
255 FT_TRACE5((
" %ld", axis->widths[i].org ));
265 af_glyph_hints_done( hints );
272 af_cjk_metrics_init_blues( AF_CJKMetrics metrics,
275 FT_Pos fills[AF_BLUE_STRING_MAX_LEN];
276 FT_Pos flats[AF_BLUE_STRING_MAX_LEN];
288 AF_StyleClass sc = metrics->root.style_class;
290 AF_Blue_Stringset bss = sc->blue_stringset;
291 const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
295 FT_ULong shaper_buf_;
296 void* shaper_buf = &shaper_buf_;
303 FT_TRACE5((
"cjk blue zones computation\n" ));
304 FT_TRACE5((
"==========================\n" ));
307 if ( ft_hb_enabled( metrics->root.globals ) )
308 shaper_buf = af_shaper_buf_create( metrics->root.globals );
310 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
312 const char* p = &af_blue_strings[bs->string];
317 if ( AF_CJK_IS_HORIZ_BLUE( bs ) )
318 axis = &metrics->axis[AF_DIMENSION_HORZ];
320 axis = &metrics->axis[AF_DIMENSION_VERT];
322#ifdef FT_DEBUG_LEVEL_TRACE
324 FT_String* cjk_blue_name[4] =
326 (FT_String*)
"bottom",
333 FT_TRACE5((
"blue zone %u (%s):\n",
335 cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) |
336 AF_CJK_IS_TOP_BLUE( bs ) ] ));
344 FT_TRACE5((
" [overshoot values]\n" ));
348 FT_ULong glyph_index;
353 unsigned int num_idx;
355#ifdef FT_DEBUG_LEVEL_TRACE
364#ifdef FT_DEBUG_LEVEL_TRACE
366 GET_UTF8_CHAR( ch, p_old );
373 FT_TRACE5((
" [reference values]\n" ));
379 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
384 glyph_index = af_shaper_get_elem( &metrics->root,
389 if ( glyph_index == 0 )
391 FT_TRACE5((
" U+%04lX unavailable\n", ch ));
395 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
396 outline = face->glyph->outline;
397 if ( error || outline.n_points <= 2 )
399 FT_TRACE5((
" U+%04lX contains no (usable) outlines\n", ch ));
404 points = outline.points;
410 FT_Int pp, first, last;
414 for ( nn = 0; nn < outline.n_contours; nn++ )
417 last = outline.contours[nn];
425 if ( AF_CJK_IS_HORIZ_BLUE( bs ) )
427 if ( AF_CJK_IS_RIGHT_BLUE( bs ) )
429 for ( pp = first; pp <= last; pp++ )
430 if ( best_point < 0 || points[pp].x > best_pos )
433 best_pos = points[pp].x;
438 for ( pp = first; pp <= last; pp++ )
439 if ( best_point < 0 || points[pp].x < best_pos )
442 best_pos = points[pp].x;
448 if ( AF_CJK_IS_TOP_BLUE( bs ) )
450 for ( pp = first; pp <= last; pp++ )
451 if ( best_point < 0 || points[pp].y > best_pos )
454 best_pos = points[pp].y;
459 for ( pp = first; pp <= last; pp++ )
460 if ( best_point < 0 || points[pp].y < best_pos )
463 best_pos = points[pp].y;
469 FT_TRACE5((
" U+%04lX: best_pos = %5ld\n", ch, best_pos ));
473 fills[num_fills++] = best_pos;
475 flats[num_flats++] = best_pos;
479 if ( num_flats == 0 && num_fills == 0 )
485 FT_TRACE5((
" empty\n" ));
492 af_sort_pos( num_fills, fills );
493 af_sort_pos( num_flats, flats );
495 blue = &axis->blues[axis->blue_count];
496 blue_ref = &blue->ref.org;
497 blue_shoot = &blue->shoot.org;
501 if ( num_flats == 0 )
504 *blue_shoot = fills[num_fills / 2];
506 else if ( num_fills == 0 )
509 *blue_shoot = flats[num_flats / 2];
513 *blue_ref = fills[num_fills / 2];
514 *blue_shoot = flats[num_flats / 2];
519 if ( *blue_shoot != *blue_ref )
521 FT_Pos ref = *blue_ref;
522 FT_Pos shoot = *blue_shoot;
523 FT_Bool under_ref = FT_BOOL( shoot < ref );
527 if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref )
530 *blue_shoot = ( shoot + ref ) / 2;
532 FT_TRACE5((
" [reference smaller than overshoot,"
533 " taking mean value]\n" ));
538 if ( AF_CJK_IS_TOP_BLUE( bs ) )
539 blue->flags |= AF_CJK_BLUE_TOP;
541 FT_TRACE5((
" -> reference = %ld\n", *blue_ref ));
542 FT_TRACE5((
" overshoot = %ld\n", *blue_shoot ));
546 af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
557 af_cjk_metrics_check_digits( AF_CJKMetrics metrics,
560 FT_Bool started = 0, same_width = 1;
561 FT_Long advance = 0, old_advance = 0;
565 FT_ULong shaper_buf_;
566 void* shaper_buf = &shaper_buf_;
569 const char digits[] =
"0 1 2 3 4 5 6 7 8 9";
577 if ( ft_hb_enabled( metrics->root.globals ) )
578 shaper_buf = af_shaper_buf_create( metrics->root.globals );
582 FT_ULong glyph_index;
583 unsigned int num_idx;
587 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
591 glyph_index = af_shaper_get_elem( &metrics->root,
601 if ( advance != old_advance )
609 old_advance = advance;
614 af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
616 metrics->root.digits_have_same_width = same_width;
622 FT_LOCAL_DEF( FT_Error )
623 af_cjk_metrics_init( AF_StyleMetrics metrics_,
626 AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
627 FT_CharMap oldmap = face->charmap;
630 metrics->units_per_em = face->units_per_EM;
632 if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
634 af_cjk_metrics_init_widths( metrics, face );
635 af_cjk_metrics_init_blues( metrics, face );
636 af_cjk_metrics_check_digits( metrics, face );
639 face->charmap = oldmap;
648 af_cjk_metrics_scale_dim( AF_CJKMetrics metrics,
658 if ( dim == AF_DIMENSION_HORZ )
660 scale = scaler->x_scale;
661 delta = scaler->x_delta;
665 scale = scaler->y_scale;
666 delta = scaler->y_delta;
669 axis = &metrics->axis[dim];
671 if ( axis->org_scale == scale && axis->org_delta == delta )
674 axis->org_scale = scale;
675 axis->org_delta = delta;
681 for ( nn = 0; nn < axis->blue_count; nn++ )
683 AF_CJKBlue blue = &axis->blues[nn];
687 blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
688 blue->ref.fit = blue->ref.cur;
689 blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
690 blue->shoot.fit = blue->shoot.cur;
691 blue->flags &= ~AF_CJK_BLUE_ACTIVE;
694 dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
695 if ( dist <= 48 && dist >= -48 )
697 FT_Pos delta1, delta2;
700 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
703 delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org;
708 delta2 = FT_MulFix( delta2, scale );
710 FT_TRACE5((
"delta: %ld", delta1 ));
714 else if ( delta2 < 64 )
715 delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
718 delta2 = FT_PIX_ROUND( delta2 );
719 FT_TRACE5((
"/%ld\n", delta2 ));
724 blue->shoot.fit = blue->ref.fit - delta2;
726 FT_TRACE5((
">> active cjk blue zone %c%u[%ld/%ld]:\n",
727 ( dim == AF_DIMENSION_HORZ ) ?
'H' :
'V',
728 nn, blue->ref.org, blue->shoot.org ));
729 FT_TRACE5((
" ref: cur=%.2f fit=%.2f\n",
730 (
double)blue->ref.cur / 64,
731 (
double)blue->ref.fit / 64 ));
732 FT_TRACE5((
" shoot: cur=%.2f fit=%.2f\n",
733 (
double)blue->shoot.cur / 64,
734 (
double)blue->shoot.fit / 64 ));
736 blue->flags |= AF_CJK_BLUE_ACTIVE;
745 af_cjk_metrics_scale( AF_StyleMetrics metrics_,
748 AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
753 metrics->root.scaler = *scaler;
755 af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
756 af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
763 FT_CALLBACK_DEF(
void )
764 af_cjk_get_standard_widths( AF_StyleMetrics metrics_,
768 AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
772 *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
775 *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
791 af_cjk_hints_compute_segments( AF_GlyphHints hints,
794 AF_AxisHints axis = &hints->axis[dim];
795 AF_Segment segments = axis->segments;
796 AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
801 error = af_latin_hints_compute_segments( hints, dim );
807 for ( seg = segments; seg < segment_limit; seg++ )
809 AF_Point pt = seg->first;
810 AF_Point last = seg->last;
811 FT_UInt f0 = pt->flags & AF_FLAG_CONTROL;
815 seg->flags &= ~AF_EDGE_ROUND;
817 for ( ; pt != last; f0 = f1 )
820 f1 = pt->flags & AF_FLAG_CONTROL;
826 seg->flags |= AF_EDGE_ROUND;
835 af_cjk_hints_link_segments( AF_GlyphHints hints,
838 AF_AxisHints axis = &hints->axis[dim];
839 AF_Segment segments = axis->segments;
840 AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
841 AF_Direction major_dir = axis->major_dir;
842 AF_Segment seg1, seg2;
843 FT_Pos len_threshold;
844 FT_Pos dist_threshold;
847 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
849 dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
851 dist_threshold = FT_DivFix( 64 * 3, dist_threshold );
854 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
856 if ( seg1->dir != major_dir )
859 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
860 if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 )
862 FT_Pos dist = seg2->pos - seg1->pos;
869 FT_Pos min = seg1->min_coord;
870 FT_Pos max = seg1->max_coord;
874 if ( min < seg2->min_coord )
875 min = seg2->min_coord;
877 if ( max > seg2->max_coord )
878 max = seg2->max_coord;
881 if ( len >= len_threshold )
883 if ( dist * 8 < seg1->score * 9 &&
884 ( dist * 8 < seg1->score * 7 || seg1->len < len ) )
891 if ( dist * 8 < seg2->score * 9 &&
892 ( dist * 8 < seg2->score * 7 || seg2->len < len ) )
913 AF_Segment link1, link2;
916 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
919 if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos )
922 if ( seg1->score >= dist_threshold )
925 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
927 if ( seg2->pos > seg1->pos || seg1 == seg2 )
931 if ( !link2 || link2->link != seg2 || link2->pos < link1->pos )
934 if ( seg1->pos == seg2->pos && link1->pos == link2->pos )
937 if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score )
942 if ( seg1->len >= seg2->len * 3 )
947 for ( seg = segments; seg < segment_limit; seg++ )
949 AF_Segment link = seg->link;
957 else if ( link == link2 )
966 seg1->link = link1->link = NULL;
974 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
980 if ( seg2->link != seg1 )
984 if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 )
985 seg1->serif = seg2->link;
993 af_cjk_hints_compute_edges( AF_GlyphHints hints,
996 AF_AxisHints axis = &hints->axis[dim];
997 FT_Error error = FT_Err_Ok;
998 FT_Memory memory = hints->memory;
999 AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim];
1001 AF_Segment segments = axis->segments;
1002 AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
1006 FT_Pos edge_distance_threshold;
1009 axis->num_edges = 0;
1011 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
1030 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
1032 if ( edge_distance_threshold > 64 / 4 )
1033 edge_distance_threshold = FT_DivFix( 64 / 4, scale );
1035 edge_distance_threshold = laxis->edge_distance_threshold;
1037 for ( seg = segments; seg < segment_limit; seg++ )
1039 AF_Edge found = NULL;
1040 FT_Pos best = 0xFFFFU;
1045 for ( ee = 0; ee < axis->num_edges; ee++ )
1047 AF_Edge edge = axis->edges + ee;
1051 if ( edge->dir != seg->dir )
1054 dist = seg->pos - edge->fpos;
1058 if ( dist < edge_distance_threshold && dist < best )
1060 AF_Segment link = seg->link;
1067 AF_Segment seg1 = edge->first;
1073 AF_Segment link1 = seg1->link;
1078 dist2 = AF_SEGMENT_DIST( link, link1 );
1079 if ( dist2 >= edge_distance_threshold )
1083 }
while ( ( seg1 = seg1->edge_next ) != edge->first );
1085 if ( dist2 >= edge_distance_threshold )
1101 error = af_axis_hints_new_edge( axis, seg->pos,
1102 (AF_Direction)seg->dir, 0,
1112 edge->dir = seg->dir;
1113 edge->fpos = seg->pos;
1114 edge->opos = FT_MulFix( seg->pos, scale );
1115 edge->pos = edge->opos;
1116 seg->edge_next = seg;
1122 seg->edge_next = found->first;
1123 found->last->edge_next = seg;
1149 AF_Edge edges = axis->edges;
1150 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
1154 for ( edge = edges; edge < edge_limit; edge++ )
1161 seg = seg->edge_next;
1163 }
while ( seg != edge->first );
1167 for ( edge = edges; edge < edge_limit; edge++ )
1169 FT_Int is_round = 0;
1170 FT_Int is_straight = 0;
1183 if ( seg->flags & AF_EDGE_ROUND )
1190 is_serif = FT_BOOL( seg->serif && seg->serif->edge != edge );
1192 if ( seg->link || is_serif )
1204 edge2 = edge->serif;
1213 edge_delta = edge->fpos - edge2->fpos;
1214 if ( edge_delta < 0 )
1215 edge_delta = -edge_delta;
1217 seg_delta = AF_SEGMENT_DIST( seg, seg2 );
1219 if ( seg_delta < edge_delta )
1227 edge->serif = edge2;
1228 edge2->flags |= AF_EDGE_SERIF;
1234 seg = seg->edge_next;
1236 }
while ( seg != edge->first );
1240 edge->flags = AF_EDGE_NORMAL;
1242 if ( is_round > 0 && is_round >= is_straight )
1243 edge->flags |= AF_EDGE_ROUND;
1249 if ( edge->serif && edge->link )
1262 af_cjk_hints_detect_features( AF_GlyphHints hints,
1268 error = af_cjk_hints_compute_segments( hints, dim );
1271 af_cjk_hints_link_segments( hints, dim );
1273 error = af_cjk_hints_compute_edges( hints, dim );
1282 af_cjk_hints_compute_blue_edges( AF_GlyphHints hints,
1283 AF_CJKMetrics metrics,
1286 AF_AxisHints axis = &hints->axis[dim];
1287 AF_Edge edge = axis->edges;
1288 AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges );
1289 AF_CJKAxis cjk = &metrics->axis[dim];
1290 FT_Fixed scale = cjk->scale;
1295 best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale );
1297 if ( best_dist0 > 64 / 2 )
1298 best_dist0 = 64 / 2;
1307 for ( ; edge < edge_limit; edge++ )
1310 AF_Width best_blue = NULL;
1311 FT_Pos best_dist = best_dist0;
1314 for ( bb = 0; bb < cjk->blue_count; bb++ )
1316 AF_CJKBlue blue = cjk->blues + bb;
1317 FT_Bool is_top_right_blue, is_major_dir;
1321 if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) )
1329 (FT_Byte)( ( blue->flags & AF_CJK_BLUE_TOP ) != 0 );
1331 FT_BOOL( edge->dir == axis->major_dir );
1336 if ( is_top_right_blue ^ is_major_dir )
1343 if ( FT_ABS( edge->fpos - blue->ref.org ) >
1344 FT_ABS( edge->fpos - blue->shoot.org ) )
1345 compare = &blue->shoot;
1347 compare = &blue->ref;
1349 dist = edge->fpos - compare->org;
1353 dist = FT_MulFix( dist, scale );
1354 if ( dist < best_dist )
1357 best_blue = compare;
1363 edge->blue_edge = best_blue;
1370 FT_LOCAL_DEF( FT_Error )
1371 af_cjk_hints_init( AF_GlyphHints hints,
1372 AF_StyleMetrics metrics_ )
1374 AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
1375 FT_Render_Mode mode;
1376 FT_UInt32 scaler_flags, other_flags;
1379 af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics );
1385 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
1386 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
1387 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
1388 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
1391 mode = metrics->root.scaler.render_mode;
1393 scaler_flags = hints->scaler_flags;
1400 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
1401 other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
1407 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
1408 other_flags |= AF_LATIN_HINTS_VERT_SNAP;
1413 if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD )
1414 other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
1416 if ( mode == FT_RENDER_MODE_MONO )
1417 other_flags |= AF_LATIN_HINTS_MONO;
1419 scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE;
1421 hints->scaler_flags = scaler_flags;
1422 hints->other_flags = other_flags;
1440 af_cjk_snap_width( AF_Width widths,
1445 FT_Pos best = 64 + 32 + 2;
1446 FT_Pos reference = width;
1450 for ( n = 0; n < count; n++ )
1467 scaled = FT_PIX_ROUND( reference );
1469 if ( width >= reference )
1471 if ( width < scaled + 48 )
1476 if ( width > scaled - 48 )
1489 af_cjk_compute_stem_width( AF_GlyphHints hints,
1493 FT_UInt stem_flags )
1495 AF_CJKMetrics metrics = (AF_CJKMetrics)hints->metrics;
1496 AF_CJKAxis axis = &metrics->axis[dim];
1497 FT_Pos dist = width;
1499 FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT );
1501 FT_UNUSED( base_flags );
1502 FT_UNUSED( stem_flags );
1505 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1514 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
1515 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
1519 if ( axis->width_count > 0 )
1521 if ( FT_ABS( dist - axis->widths[0].cur ) < 40 )
1523 dist = axis->widths[0].cur;
1532 dist += ( 54 - dist ) / 2;
1533 else if ( dist < 3 * 64 )
1543 else if ( delta < 22 )
1545 else if ( delta < 42 )
1547 else if ( delta < 54 )
1557 dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
1565 dist = ( dist + 16 ) & ~63;
1571 if ( AF_LATIN_HINTS_DO_MONO( hints ) )
1579 dist = ( dist + 32 ) & ~63;
1588 dist = ( dist + 64 ) >> 1;
1590 else if ( dist < 128 )
1591 dist = ( dist + 22 ) & ~63;
1594 dist = ( dist + 32 ) & ~63;
1610 af_cjk_align_linked_edge( AF_GlyphHints hints,
1615 FT_Pos dist = stem_edge->opos - base_edge->opos;
1617 FT_Pos fitted_width = af_cjk_compute_stem_width( hints, dim, dist,
1622 stem_edge->pos = base_edge->pos + fitted_width;
1624 FT_TRACE5((
" CJKLINK: edge %td @%d (opos=%.2f) linked to %.2f,"
1625 " dist was %.2f, now %.2f\n",
1626 stem_edge - hints->axis[dim].edges, stem_edge->fpos,
1627 (
double)stem_edge->opos / 64,
1628 (
double)stem_edge->pos / 64,
1630 (
double)fitted_width / 64 ));
1638 af_cjk_align_serif_edge( AF_GlyphHints hints,
1644 serif->pos = base->pos + ( serif->opos - base->opos );
1659#define AF_LIGHT_MODE_MAX_HORZ_GAP 9
1660#define AF_LIGHT_MODE_MAX_VERT_GAP 15
1661#define AF_LIGHT_MODE_MAX_DELTA_ABS 14
1665 af_hint_normal_stem( AF_GlyphHints hints,
1671 FT_Pos org_len, cur_len, org_center;
1672 FT_Pos cur_pos1, cur_pos2;
1673 FT_Pos d_off1, u_off1, d_off2, u_off2, delta;
1675 FT_Pos threshold = 64;
1678 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1680 if ( ( edge->flags & AF_EDGE_ROUND ) &&
1681 ( edge2->flags & AF_EDGE_ROUND ) )
1683 if ( dim == AF_DIMENSION_VERT )
1684 threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
1686 threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
1690 if ( dim == AF_DIMENSION_VERT )
1691 threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
1693 threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
1697 org_len = edge2->opos - edge->opos;
1698 cur_len = af_cjk_compute_stem_width( hints, dim, org_len,
1702 org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
1703 cur_pos1 = org_center - cur_len / 2;
1704 cur_pos2 = cur_pos1 + cur_len;
1705 d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
1706 d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
1707 u_off1 = 64 - d_off1;
1708 u_off2 = 64 - d_off2;
1712 if ( d_off1 == 0 || d_off2 == 0 )
1715 if ( cur_len <= threshold )
1717 if ( d_off2 < cur_len )
1719 if ( u_off1 <= d_off2 )
1728 if ( threshold < 64 )
1730 if ( d_off1 >= threshold || u_off1 >= threshold ||
1731 d_off2 >= threshold || u_off2 >= threshold )
1735 offset = cur_len & 63;
1739 if ( u_off1 <= offset || d_off2 <= offset )
1743 offset = 64 - threshold;
1745 d_off1 = threshold - u_off1;
1746 u_off1 = u_off1 - offset;
1747 u_off2 = threshold - d_off2;
1748 d_off2 = d_off2 - offset;
1750 if ( d_off1 <= u_off1 )
1753 if ( d_off2 <= u_off2 )
1756 if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
1764 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1766 if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
1767 delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
1768 else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
1769 delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
1775 if ( edge->opos < edge2->opos )
1777 edge->pos = cur_pos1;
1778 edge2->pos = cur_pos1 + cur_len;
1782 edge->pos = cur_pos1 + cur_len;
1783 edge2->pos = cur_pos1;
1793 af_cjk_hint_edges( AF_GlyphHints hints,
1796 AF_AxisHints axis = &hints->axis[dim];
1797 AF_Edge edges = axis->edges;
1798 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
1801 AF_Edge anchor = NULL;
1804 FT_Bool has_last_stem = FALSE;
1805 FT_Pos last_stem_pos = 0;
1807#ifdef FT_DEBUG_LEVEL_TRACE
1808 FT_UInt num_actions = 0;
1812 FT_TRACE5((
"cjk %s edge hinting (style `%s')\n",
1813 dim == AF_DIMENSION_VERT ?
"horizontal" :
"vertical",
1814 af_style_names[hints->metrics->style_class->style] ));
1818 if ( AF_HINTS_DO_BLUES( hints ) )
1820 for ( edge = edges; edge < edge_limit; edge++ )
1823 AF_Edge edge1, edge2;
1826 if ( edge->flags & AF_EDGE_DONE )
1829 blue = edge->blue_edge;
1837 else if ( edge2 && edge2->blue_edge )
1839 blue = edge2->blue_edge;
1847#ifdef FT_DEBUG_LEVEL_TRACE
1848 FT_TRACE5((
" CJKBLUE: edge %td @%d (opos=%.2f) snapped to %.2f,"
1850 edge1 - edges, edge1->fpos, (
double)edge1->opos / 64,
1851 (
double)blue->fit / 64, (
double)edge1->pos / 64 ));
1856 edge1->pos = blue->fit;
1857 edge1->flags |= AF_EDGE_DONE;
1859 if ( edge2 && !edge2->blue_edge )
1861 af_cjk_align_linked_edge( hints, dim, edge1, edge2 );
1862 edge2->flags |= AF_EDGE_DONE;
1864#ifdef FT_DEBUG_LEVEL_TRACE
1875 for ( edge = edges; edge < edge_limit; edge++ )
1880 if ( edge->flags & AF_EDGE_DONE )
1899 if ( has_last_stem &&
1900 ( edge->pos < last_stem_pos + 64 ||
1901 edge2->pos < last_stem_pos + 64 ) )
1910 if ( edge2->blue_edge )
1912 FT_TRACE5((
"ASSERTION FAILED for edge %td\n", edge2 - edges ));
1914 af_cjk_align_linked_edge( hints, dim, edge2, edge );
1915 edge->flags |= AF_EDGE_DONE;
1917#ifdef FT_DEBUG_LEVEL_TRACE
1926 af_cjk_align_linked_edge( hints, dim, edge2, edge );
1927 edge->flags |= AF_EDGE_DONE;
1929#ifdef FT_DEBUG_LEVEL_TRACE
1937 has_last_stem = TRUE;
1938 last_stem_pos = edge->pos;
1942 if ( dim != AF_DIMENSION_VERT && !anchor )
1948 AF_Edge left = edge;
1949 AF_Edge right = edge_limit - 1;
1950 AF_EdgeRec left1, left2, right1, right2;
1951 FT_Pos target, center1, center2;
1952 FT_Pos delta1, delta2, d1, d2;
1955 while ( right > left && !right->link )
1959 left2 = *left->link;
1960 right1 = *right->link;
1963 delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2;
1964 target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16;
1967 delta1 += af_hint_normal_stem( hints, left, left->link,
1970 if ( left->link != right )
1971 af_hint_normal_stem( hints, right->link, right, delta1, 0 );
1973 center1 = left->pos + ( right->pos - left->pos ) / 2;
1975 if ( center1 >= target )
1976 delta2 = delta - 32;
1978 delta2 = delta + 32;
1980 delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 );
1982 if ( delta1 != delta2 )
1984 if ( left->link != right )
1985 af_hint_normal_stem( hints, &right1, &right2, delta2, 0 );
1987 center2 = left1.pos + ( right2.pos - left1.pos ) / 2;
1989 d1 = center1 - target;
1990 d2 = center2 - target;
1992 if ( FT_ABS( d2 ) < FT_ABS( d1 ) )
1994 left->pos = left1.pos;
1995 left->link->pos = left2.pos;
1997 if ( left->link != right )
1999 right->link->pos = right1.pos;
2000 right->pos = right2.pos;
2008 right->link->flags |= AF_EDGE_DONE;
2009 right->flags |= AF_EDGE_DONE;
2015 delta = af_hint_normal_stem( hints, edge, edge2, 0,
2016 AF_DIMENSION_HORZ );
2019 af_hint_normal_stem( hints, edge, edge2, delta, dim );
2022 printf(
"stem (%d,%d) adjusted (%.1f,%.1f)\n",
2023 edge - edges, edge2 - edges,
2024 (
double)( edge->pos - edge->opos ) / 64,
2025 (
double)( edge2->pos - edge2->opos ) / 64 );
2029 edge->flags |= AF_EDGE_DONE;
2030 edge2->flags |= AF_EDGE_DONE;
2031 has_last_stem = TRUE;
2032 last_stem_pos = edge2->pos;
2050 n_edges = edge_limit - edges;
2051 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
2053 AF_Edge edge1, edge2, edge3;
2054 FT_Pos dist1, dist2, span;
2070 dist1 = edge2->opos - edge1->opos;
2071 dist2 = edge3->opos - edge2->opos;
2073 span = dist1 - dist2;
2077 if ( edge1->link == edge1 + 1 &&
2078 edge2->link == edge2 + 1 &&
2079 edge3->link == edge3 + 1 && span < 8 )
2081 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
2082 edge3->pos -= delta;
2084 edge3->link->pos -= delta;
2087 if ( n_edges == 12 )
2089 ( edges + 8 )->pos -= delta;
2090 ( edges + 11 )->pos -= delta;
2093 edge3->flags |= AF_EDGE_DONE;
2095 edge3->link->flags |= AF_EDGE_DONE;
2106 for ( edge = edges; edge < edge_limit; edge++ )
2108 if ( edge->flags & AF_EDGE_DONE )
2113 af_cjk_align_serif_edge( hints, edge->serif, edge );
2114 edge->flags |= AF_EDGE_DONE;
2122 for ( edge = edges; edge < edge_limit; edge++ )
2124 AF_Edge before, after;
2127 if ( edge->flags & AF_EDGE_DONE )
2130 before = after = edge;
2132 while ( --before >= edges )
2133 if ( before->flags & AF_EDGE_DONE )
2136 while ( ++after < edge_limit )
2137 if ( after->flags & AF_EDGE_DONE )
2140 if ( before >= edges || after < edge_limit )
2142 if ( before < edges )
2143 af_cjk_align_serif_edge( hints, after, edge );
2144 else if ( after >= edge_limit )
2145 af_cjk_align_serif_edge( hints, before, edge );
2148 if ( after->fpos == before->fpos )
2149 edge->pos = before->pos;
2151 edge->pos = before->pos +
2152 FT_MulDiv( edge->fpos - before->fpos,
2153 after->pos - before->pos,
2154 after->fpos - before->fpos );
2161#ifdef FT_DEBUG_LEVEL_TRACE
2163 FT_TRACE5((
" (none)\n" ));
2164 FT_TRACE5((
"\n" ));
2172 af_cjk_align_edge_points( AF_GlyphHints hints,
2175 AF_AxisHints axis = &hints->axis[dim];
2176 AF_Edge edges = axis->edges;
2177 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
2182 snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ &&
2183 AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ||
2184 ( dim == AF_DIMENSION_VERT &&
2185 AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) );
2187 for ( edge = edges; edge < edge_limit; edge++ )
2191 AF_Segment seg = edge->first;
2198 AF_Point point = seg->first;
2203 if ( dim == AF_DIMENSION_HORZ )
2205 point->x = edge->pos;
2206 point->flags |= AF_FLAG_TOUCH_X;
2210 point->y = edge->pos;
2211 point->flags |= AF_FLAG_TOUCH_Y;
2214 if ( point == seg->last )
2217 point = point->next;
2220 seg = seg->edge_next;
2222 }
while ( seg != edge->first );
2226 FT_Pos delta = edge->pos - edge->opos;
2231 AF_Point point = seg->first;
2236 if ( dim == AF_DIMENSION_HORZ )
2239 point->flags |= AF_FLAG_TOUCH_X;
2244 point->flags |= AF_FLAG_TOUCH_Y;
2247 if ( point == seg->last )
2250 point = point->next;
2253 seg = seg->edge_next;
2255 }
while ( seg != edge->first );
2263 FT_LOCAL_DEF( FT_Error )
2264 af_cjk_hints_apply( FT_UInt glyph_index,
2265 AF_GlyphHints hints,
2266 FT_Outline* outline,
2267 AF_StyleMetrics metrics_ )
2269 AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
2274 FT_UNUSED( metrics );
2275 FT_UNUSED( glyph_index );
2278 error = af_glyph_hints_reload( hints, outline );
2283 if ( AF_HINTS_DO_HORIZONTAL( hints ) )
2285 error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ );
2289 af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ );
2292 if ( AF_HINTS_DO_VERTICAL( hints ) )
2294 error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT );
2298 af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT );
2302 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
2304 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
2305 ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
2307 af_cjk_hint_edges( hints, (AF_Dimension)dim );
2308 af_cjk_align_edge_points( hints, (AF_Dimension)dim );
2309 af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
2310 af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
2314 af_glyph_hints_save( hints, outline );
2330 AF_DEFINE_WRITING_SYSTEM_CLASS(
2331 af_cjk_writing_system_class,
2333 AF_WRITING_SYSTEM_CJK,
2335 sizeof ( AF_CJKMetricsRec ),
2337 (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init,
2338 (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale,
2339 (AF_WritingSystem_DoneMetricsFunc) NULL,
2340 (AF_WritingSystem_GetStdWidthsFunc)af_cjk_get_standard_widths,
2342 (AF_WritingSystem_InitHintsFunc) af_cjk_hints_init,
2343 (AF_WritingSystem_ApplyHintsFunc) af_cjk_hints_apply
2350 AF_DEFINE_WRITING_SYSTEM_CLASS(
2351 af_cjk_writing_system_class,
2353 AF_WRITING_SYSTEM_CJK,
2355 sizeof ( AF_CJKMetricsRec ),
2357 (AF_WritingSystem_InitMetricsFunc) NULL,
2358 (AF_WritingSystem_ScaleMetricsFunc)NULL,
2359 (AF_WritingSystem_DoneMetricsFunc) NULL,
2360 (AF_WritingSystem_GetStdWidthsFunc)NULL,
2362 (AF_WritingSystem_InitHintsFunc) NULL,
2363 (AF_WritingSystem_ApplyHintsFunc) NULL