35#define FT_COMPONENT aflatin
39#define FLAT_THRESHOLD( x ) ( x / 14 )
55 af_latin_metrics_init_widths( AF_LatinMetrics metrics,
59 AF_GlyphHintsRec hints[1];
63 FT_TRACE5((
"latin standard widths computation (style `%s')\n",
64 af_style_names[metrics->root.style_class->style] ));
65 FT_TRACE5((
"=====================================================\n" ));
68 af_glyph_hints_init( hints, face->memory );
70 metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
71 metrics->axis[AF_DIMENSION_VERT].width_count = 0;
77 AF_LatinMetricsRec dummy[1];
78 AF_Scaler scaler = &dummy->root.scaler;
80 AF_StyleClass style_class = metrics->root.style_class;
81 AF_ScriptClass script_class = af_script_classes[style_class->script];
86 void* shaper_buf = &shaper_buf_;
90#ifdef FT_DEBUG_LEVEL_TRACE
95 p = script_class->standard_charstring;
97 if ( ft_hb_enabled ( metrics->root.globals ) )
98 shaper_buf = af_shaper_buf_create( metrics->root.globals );
110 unsigned int num_idx;
112#ifdef FT_DEBUG_LEVEL_TRACE
120#ifdef FT_DEBUG_LEVEL_TRACE
122 GET_UTF8_CHAR( ch, p_old );
126 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
131 glyph_index = af_shaper_get_elem( &metrics->root,
140 af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
144 FT_TRACE5((
"standard character missing;"
145 " using fallback stem widths\n" ));
149 FT_TRACE5((
"standard character: U+%04lX (glyph index %lu)\n",
152 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
153 if ( error || face->glyph->outline.n_points <= 0 )
158 dummy->units_per_em = metrics->units_per_em;
160 scaler->x_scale = 0x10000L;
161 scaler->y_scale = 0x10000L;
166 scaler->render_mode = FT_RENDER_MODE_NORMAL;
169 af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy );
171 error = af_glyph_hints_reload( hints, &face->glyph->outline );
175 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
177 AF_LatinAxis axis = &metrics->axis[dim];
178 AF_AxisHints axhints = &hints->axis[dim];
179 AF_Segment seg, limit, link;
180 FT_UInt num_widths = 0;
183 error = af_latin_hints_compute_segments( hints,
194 af_latin_hints_link_segments( hints,
199 seg = axhints->segments;
200 limit = FT_OFFSET( seg, axhints->num_segments );
202 for ( ; seg < limit; seg++ )
207 if ( link && link->link == seg && link > seg )
212 dist = seg->pos - link->pos;
216 if ( num_widths < AF_LATIN_MAX_WIDTHS )
217 axis->widths[num_widths++].org = dist;
223 af_sort_and_quantize_widths( &num_widths, axis->widths,
224 dummy->units_per_em / 100 );
225 axis->width_count = num_widths;
229 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
231 AF_LatinAxis axis = &metrics->axis[dim];
235 stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
236 : AF_LATIN_CONSTANT( metrics, 50 );
239 axis->edge_distance_threshold = stdw / 5;
240 axis->standard_width = stdw;
241 axis->extra_light = 0;
243#ifdef FT_DEBUG_LEVEL_TRACE
248 FT_TRACE5((
"%s widths:\n",
249 dim == AF_DIMENSION_VERT ?
"horizontal"
252 FT_TRACE5((
" %ld (standard)", axis->standard_width ));
253 for ( i = 1; i < axis->width_count; i++ )
254 FT_TRACE5((
" %ld", axis->widths[i].org ));
264 af_glyph_hints_done( hints );
269 af_latin_sort_blue( FT_UInt count,
270 AF_LatinBlue* table )
277 for ( i = 1; i < count; i++ )
279 for ( j = i; j > 0; j-- )
284 if ( table[j - 1]->flags & ( AF_LATIN_BLUE_TOP |
285 AF_LATIN_BLUE_SUB_TOP ) )
286 a = table[j - 1]->ref.org;
288 a = table[j - 1]->shoot.org;
290 if ( table[j]->flags & ( AF_LATIN_BLUE_TOP |
291 AF_LATIN_BLUE_SUB_TOP ) )
292 b = table[j]->ref.org;
294 b = table[j]->shoot.org;
300 table[j] = table[j - 1];
311 af_latin_metrics_init_blues( AF_LatinMetrics metrics,
314 FT_Pos flats [AF_BLUE_STRING_MAX_LEN];
315 FT_Pos rounds[AF_BLUE_STRING_MAX_LEN];
322 AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
325 AF_StyleClass sc = metrics->root.style_class;
327 AF_Blue_Stringset bss = sc->blue_stringset;
328 const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
330 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
334 FT_ULong shaper_buf_;
335 void* shaper_buf = &shaper_buf_;
341 FT_TRACE5((
"latin blue zones computation\n" ));
342 FT_TRACE5((
"============================\n" ));
345 if ( ft_hb_enabled ( metrics->root.globals ) )
346 shaper_buf = af_shaper_buf_create( metrics->root.globals );
348 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
350 const char* p = &af_blue_strings[bs->string];
357#ifdef FT_DEBUG_LEVEL_TRACE
359 FT_Bool have_flag = 0;
362 FT_TRACE5((
"blue zone %u", axis->blue_count ));
364 if ( bs->properties )
368 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
370 FT_TRACE5((
"top" ));
373 else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
375 FT_TRACE5((
"sub top" ));
379 if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
383 FT_TRACE5((
"neutral" ));
387 if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
391 FT_TRACE5((
"small top" ));
395 if ( AF_LATIN_IS_LONG_BLUE( bs ) )
399 FT_TRACE5((
"long" ));
402 if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) )
406 FT_TRACE5((
"capital bottom" ));
409 if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) )
413 FT_TRACE5((
"small bottom" ));
419 FT_TRACE5((
":\n" ));
430 FT_ULong glyph_index;
432 FT_Int best_point, best_contour_first, best_contour_last;
435 FT_Pos best_y_extremum;
436 FT_Bool best_round = 0;
438 unsigned int i, num_idx;
440#ifdef FT_DEBUG_LEVEL_TRACE
449#ifdef FT_DEBUG_LEVEL_TRACE
451 GET_UTF8_CHAR( ch, p_old );
454 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
458 FT_TRACE5((
" U+%04lX unavailable\n", ch ));
462 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
463 best_y_extremum = FT_LONG_MIN;
465 best_y_extremum = FT_LONG_MAX;
469 for ( i = 0; i < num_idx; i++ )
476 glyph_index = af_shaper_get_elem( &metrics->root,
481 if ( glyph_index == 0 )
483 FT_TRACE5((
" U+%04lX unavailable\n", ch ));
487 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
488 outline = face->glyph->outline;
490 if ( error || outline.n_points <= 2 )
492#ifdef FT_DEBUG_LEVEL_TRACE
494 FT_TRACE5((
" U+%04lX contains no (usable) outlines\n", ch ));
496 FT_TRACE5((
" component %u of cluster starting with U+%04lX"
497 " contains no (usable) outlines\n", i, ch ));
503 points = outline.points;
505 best_contour_first = -1;
506 best_contour_last = -1;
511 FT_Int pp, first, last;
515 for ( nn = 0; nn < outline.n_contours; nn++ )
518 last = outline.contours[nn];
527 if ( AF_LATIN_IS_TOP_BLUE( bs ) ||
528 AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
530 for ( pp = first; pp <= last; pp++ )
532 if ( best_point < 0 || points[pp].y > best_y )
535 best_y = points[pp].y;
536 ascender = FT_MAX( ascender, best_y + y_offset );
539 descender = FT_MIN( descender, points[pp].y + y_offset );
544 for ( pp = first; pp <= last; pp++ )
546 if ( best_point < 0 || points[pp].y < best_y )
549 best_y = points[pp].y;
550 descender = FT_MIN( descender, best_y + y_offset );
553 ascender = FT_MAX( ascender, points[pp].y + y_offset );
557 if ( best_point > best_contour_last )
559 best_contour_first = first;
560 best_contour_last = last;
568 if ( best_point >= 0 )
570 FT_Pos best_x = points[best_point].x;
572 FT_Int best_segment_first, best_segment_last;
573 FT_Int best_on_point_first, best_on_point_last;
577 best_segment_first = best_point;
578 best_segment_last = best_point;
580 if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
582 best_on_point_first = best_point;
583 best_on_point_last = best_point;
587 best_on_point_first = -1;
588 best_on_point_last = -1;
599 if ( prev > best_contour_first )
602 prev = best_contour_last;
604 dist = FT_ABS( points[prev].y - best_y );
608 if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
611 best_segment_first = prev;
613 if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
615 best_on_point_first = prev;
616 if ( best_on_point_last < 0 )
617 best_on_point_last = prev;
620 }
while ( prev != best_point );
624 if ( next < best_contour_last )
627 next = best_contour_first;
629 dist = FT_ABS( points[next].y - best_y );
631 if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
634 best_segment_last = next;
636 if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
638 best_on_point_last = next;
639 if ( best_on_point_first < 0 )
640 best_on_point_first = next;
643 }
while ( next != best_point );
645 if ( AF_LATIN_IS_LONG_BLUE( bs ) )
662 FT_Pos length_threshold = metrics->units_per_em / 25;
665 dist = FT_ABS( points[best_segment_last].x -
666 points[best_segment_first].x );
668 if ( dist < length_threshold &&
669 best_segment_last - best_segment_first + 2 <=
670 best_contour_last - best_contour_first )
673 FT_Pos height_threshold = metrics->units_per_em / 4;
694 if ( prev > best_contour_first )
697 prev = best_contour_last;
699 if ( points[prev].x != best_x )
702 }
while ( prev != best_point );
705 if ( prev == best_point )
708 left2right = FT_BOOL( points[prev].x < points[best_point].x );
710 first = best_segment_last;
726 if ( FT_CURVE_TAG( outline.tags[first] ) ==
741 if ( last < best_contour_last )
744 last = best_contour_first;
746 if ( FT_ABS( best_y - points[first].y ) > height_threshold )
754 dist = FT_ABS( points[last].y - points[first].y );
756 if ( FT_ABS( points[last].x - points[first].x ) <=
763 if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
770 l2r = FT_BOOL( points[first].x < points[last].x );
771 d = FT_ABS( points[last].x - points[first].x );
773 if ( l2r == left2right &&
774 d >= length_threshold )
780 if ( last < best_contour_last )
783 last = best_contour_first;
785 d = FT_ABS( points[last].y - points[first].y );
787 if ( FT_ABS( points[next].x - points[first].x ) <=
790 if ( last > best_contour_first )
793 last = best_contour_last;
799 if ( FT_CURVE_TAG( outline.tags[last] ) ==
807 }
while ( last != best_segment_first );
809 best_y = points[first].y;
811 best_segment_first = first;
812 best_segment_last = last;
814 best_on_point_first = p_first;
815 best_on_point_last = p_last;
820 }
while ( last != best_segment_first );
830#ifdef FT_DEBUG_LEVEL_TRACE
832 FT_TRACE5((
" U+%04lX: best_y = %5ld", ch, best_y ));
834 FT_TRACE5((
" component %u of cluster starting with U+%04lX:"
835 " best_y = %5ld", i, ch, best_y ));
846 if ( best_on_point_first >= 0 &&
847 best_on_point_last >= 0 &&
848 ( FT_ABS( points[best_on_point_last].x -
849 points[best_on_point_first].x ) ) >
854 FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
856 FT_CURVE_TAG( outline.tags[best_segment_last] ) !=
859 if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
862 FT_TRACE5((
" (round, skipped)\n" ));
866 FT_TRACE5((
" (%s)\n", round ?
"round" :
"flat" ));
869 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
871 if ( best_y > best_y_extremum )
873 best_y_extremum = best_y;
879 if ( best_y < best_y_extremum )
881 best_y_extremum = best_y;
888 if ( !( best_y_extremum == FT_LONG_MIN ||
889 best_y_extremum == FT_LONG_MAX ) )
892 rounds[num_rounds++] = best_y_extremum;
894 flats[num_flats++] = best_y_extremum;
899 if ( num_flats == 0 && num_rounds == 0 )
905 FT_TRACE5((
" empty\n" ));
912 af_sort_pos( num_rounds, rounds );
913 af_sort_pos( num_flats, flats );
915 blue = &axis->blues[axis->blue_count];
916 blue_ref = &blue->ref.org;
917 blue_shoot = &blue->shoot.org;
921 if ( num_flats == 0 )
924 *blue_shoot = rounds[num_rounds / 2];
926 else if ( num_rounds == 0 )
929 *blue_shoot = flats[num_flats / 2];
933 *blue_ref = flats [num_flats / 2];
934 *blue_shoot = rounds[num_rounds / 2];
940 if ( *blue_shoot != *blue_ref )
942 FT_Pos ref = *blue_ref;
943 FT_Pos shoot = *blue_shoot;
944 FT_Bool over_ref = FT_BOOL( shoot > ref );
947 if ( ( AF_LATIN_IS_TOP_BLUE( bs ) ||
948 AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref )
951 *blue_shoot = ( shoot + ref ) / 2;
953 FT_TRACE5((
" [overshoot smaller than reference,"
954 " taking mean value]\n" ));
958 blue->ascender = ascender;
959 blue->descender = descender;
962 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
963 blue->flags |= AF_LATIN_BLUE_TOP;
964 if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
965 blue->flags |= AF_LATIN_BLUE_SUB_TOP;
966 if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
967 blue->flags |= AF_LATIN_BLUE_NEUTRAL;
968 if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) )
969 blue->flags |= AF_LATIN_BLUE_BOTTOM;
970 if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) )
971 blue->flags |= AF_LATIN_BLUE_BOTTOM_SMALL;
978 if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
979 blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
981 FT_TRACE5((
" -> reference = %ld\n", *blue_ref ));
982 FT_TRACE5((
" overshoot = %ld\n", *blue_shoot ));
986 af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
988 if ( axis->blue_count )
994 AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN];
997 for ( i = 0; i < axis->blue_count; i++ )
998 blue_sorted[i] = &axis->blues[i];
1001 af_latin_sort_blue( axis->blue_count, blue_sorted );
1004 for ( i = 0; i < axis->blue_count - 1; i++ )
1009#ifdef FT_DEBUG_LEVEL_TRACE
1010 FT_Bool a_is_top = 0;
1014 if ( blue_sorted[i]->flags & ( AF_LATIN_BLUE_TOP |
1015 AF_LATIN_BLUE_SUB_TOP ) )
1017 a = &blue_sorted[i]->shoot.org;
1018#ifdef FT_DEBUG_LEVEL_TRACE
1023 a = &blue_sorted[i]->ref.org;
1025 if ( blue_sorted[i + 1]->flags & ( AF_LATIN_BLUE_TOP |
1026 AF_LATIN_BLUE_SUB_TOP ) )
1027 b = &blue_sorted[i + 1]->shoot.org;
1029 b = &blue_sorted[i + 1]->ref.org;
1034 FT_TRACE5((
"blue zone overlap:"
1035 " adjusting %s %td to %ld\n",
1036 a_is_top ?
"overshoot" :
"reference",
1037 blue_sorted[i] - axis->blues,
1042 FT_TRACE5((
"\n" ));
1050 AF_FaceGlobals globals = metrics->root.globals;
1051 FT_UShort* gstyles = globals->glyph_styles;
1056 FT_TRACE5((
"no blue zones found:"
1057 " hinting disabled for this style\n" ));
1059 for ( i = 0; i < globals->glyph_count; i++ )
1061 if ( ( gstyles[i] & AF_STYLE_MASK ) == sc->style )
1062 gstyles[i] = AF_STYLE_NONE_DFLT;
1065 FT_TRACE5((
"\n" ));
1074 FT_LOCAL_DEF(
void )
1075 af_latin_metrics_check_digits( AF_LatinMetrics metrics,
1078 FT_Bool started = 0, same_width = 1;
1079 FT_Long advance = 0, old_advance = 0;
1083 FT_ULong shaper_buf_;
1084 void* shaper_buf = &shaper_buf_;
1087 const char digits[] =
"0 1 2 3 4 5 6 7 8 9";
1095 if ( ft_hb_enabled ( metrics->root.globals ) )
1096 shaper_buf = af_shaper_buf_create( metrics->root.globals );
1100 FT_ULong glyph_index;
1101 unsigned int num_idx;
1105 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
1109 glyph_index = af_shaper_get_elem( &metrics->root,
1119 if ( advance != old_advance )
1127 old_advance = advance;
1132 af_shaper_buf_destroy( metrics->root.globals, shaper_buf );
1134 metrics->root.digits_have_same_width = same_width;
1140 FT_LOCAL_DEF( FT_Error )
1141 af_latin_metrics_init( AF_StyleMetrics metrics_,
1144 AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
1146 FT_Error error = FT_Err_Ok;
1148 FT_CharMap oldmap = face->charmap;
1151 metrics->units_per_em = face->units_per_EM;
1153 if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
1155 af_latin_metrics_init_widths( metrics, face );
1156 if ( af_latin_metrics_init_blues( metrics, face ) )
1162 af_latin_metrics_check_digits( metrics, face );
1165 af_reverse_character_map_new( &metrics->root.reverse_charmap,
1169 face->charmap = oldmap;
1178 af_latin_metrics_scale_dim( AF_LatinMetrics metrics,
1188 if ( dim == AF_DIMENSION_HORZ )
1190 scale = scaler->x_scale;
1191 delta = scaler->x_delta;
1195 scale = scaler->y_scale;
1196 delta = scaler->y_delta;
1199 axis = &metrics->axis[dim];
1201 if ( axis->org_scale == scale && axis->org_delta == delta )
1204 axis->org_scale = scale;
1205 axis->org_delta = delta;
1212 AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
1213 AF_LatinBlue blue = NULL;
1216 for ( nn = 0; nn < Axis->blue_count; nn++ )
1218 if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
1220 blue = &Axis->blues[nn];
1234 scaled = FT_MulFix( blue->shoot.org, scale );
1235 ppem = metrics->root.scaler.face->size->metrics.x_ppem;
1236 limit = metrics->root.globals->increase_x_height;
1243 ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN )
1246 fitted = ( scaled + threshold ) & ~63;
1248 if ( scaled != fitted )
1251 if ( dim == AF_DIMENSION_HORZ )
1253 if ( fitted < scaled )
1254 scale -= scale / 50;
1258 if ( dim == AF_DIMENSION_VERT )
1265 new_scale = FT_MulDiv( scale, fitted, scaled );
1268 max_height = metrics->units_per_em;
1270 for ( nn = 0; nn < Axis->blue_count; nn++ )
1272 max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
1273 max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
1276 dist = FT_MulFix( max_height, new_scale - scale );
1278 if ( -128 < dist && dist < 128 )
1280 FT_TRACE5((
"af_latin_metrics_scale_dim:"
1281 " x height alignment (style `%s'):\n",
1282 af_style_names[metrics->root.style_class->style] ));
1284 " vertical scaling changed"
1285 " from %.5f to %.5f (by %ld%%)\n",
1286 (
double)scale / 65536,
1287 (
double)new_scale / 65536,
1288 ( fitted - scaled ) * 100 / scaled ));
1289 FT_TRACE5((
"\n" ));
1293#ifdef FT_DEBUG_LEVEL_TRACE
1296 FT_TRACE5((
"af_latin_metrics_scale_dim:"
1297 " x height alignment (style `%s'):\n",
1298 af_style_names[metrics->root.style_class->style] ));
1300 " excessive vertical scaling abandoned\n" ));
1301 FT_TRACE5((
"\n" ));
1309 axis->scale = scale;
1310 axis->delta = delta;
1312 if ( dim == AF_DIMENSION_HORZ )
1314 metrics->root.scaler.x_scale = scale;
1315 metrics->root.scaler.x_delta = delta;
1319 metrics->root.scaler.y_scale = scale;
1320 metrics->root.scaler.y_delta = delta;
1323 FT_TRACE5((
"%s widths (style `%s')\n",
1324 dim == AF_DIMENSION_HORZ ?
"horizontal" :
"vertical",
1325 af_style_names[metrics->root.style_class->style] ));
1328 for ( nn = 0; nn < axis->width_count; nn++ )
1330 AF_Width width = axis->widths + nn;
1333 width->cur = FT_MulFix( width->org, scale );
1334 width->fit = width->cur;
1336 FT_TRACE5((
" %ld scaled to %.2f\n",
1338 (
double)width->cur / 64 ));
1341 FT_TRACE5((
"\n" ));
1346 FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1348#ifdef FT_DEBUG_LEVEL_TRACE
1349 if ( axis->extra_light )
1351 FT_TRACE5((
"`%s' style is extra light (at current resolution)\n",
1352 af_style_names[metrics->root.style_class->style] ));
1353 FT_TRACE5((
"\n" ));
1357 if ( dim == AF_DIMENSION_VERT )
1359#ifdef FT_DEBUG_LEVEL_TRACE
1360 if ( axis->blue_count )
1361 FT_TRACE5((
"blue zones (style `%s')\n",
1362 af_style_names[metrics->root.style_class->style] ));
1366 for ( nn = 0; nn < axis->blue_count; nn++ )
1368 AF_LatinBlue blue = &axis->blues[nn];
1372 blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
1373 blue->ref.fit = blue->ref.cur;
1374 blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
1375 blue->shoot.fit = blue->shoot.cur;
1376 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1379 dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
1380 if ( dist <= 48 && dist >= -48 )
1393 delta1 = blue->shoot.org - blue->ref.org;
1398 delta2 = FT_MulFix( delta2, scale );
1402 else if ( delta2 < 64 )
1403 delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
1405 delta2 = FT_PIX_ROUND( delta2 );
1410 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1411 blue->shoot.fit = blue->ref.fit + delta2;
1422 else if ( delta2 < 48 )
1430 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1431 blue->shoot.fit = blue->ref.fit - delta2;
1435 blue->flags |= AF_LATIN_BLUE_ACTIVE;
1443 for ( nn = 0; nn < axis->blue_count; nn++ )
1445 AF_LatinBlue blue = &axis->blues[nn];
1449 if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) )
1451 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
1454 for ( i = 0; i < axis->blue_count; i++ )
1456 AF_LatinBlue b = &axis->blues[i];
1459 if ( b->flags & AF_LATIN_BLUE_SUB_TOP )
1461 if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) )
1464 if ( b->ref.fit <= blue->shoot.fit &&
1465 b->shoot.fit >= blue->ref.fit )
1467 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1473#ifdef FT_DEBUG_LEVEL_TRACE
1474 for ( nn = 0; nn < axis->blue_count; nn++ )
1476 AF_LatinBlue blue = &axis->blues[nn];
1479 FT_TRACE5((
" reference %u: %ld scaled to %.2f%s\n",
1482 (
double)blue->ref.fit / 64,
1483 ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ?
""
1485 FT_TRACE5((
" overshoot %u: %ld scaled to %.2f%s\n",
1488 (
double)blue->shoot.fit / 64,
1489 ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ?
""
1497 FT_CALLBACK_DEF(
void )
1498 af_latin_metrics_done( AF_StyleMetrics metrics_ )
1500 AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
1503 af_reverse_character_map_done( metrics->root.reverse_charmap,
1504 metrics->root.globals->face->memory );
1510 FT_LOCAL_DEF(
void )
1511 af_latin_metrics_scale( AF_StyleMetrics metrics_,
1514 AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
1517 metrics->root.scaler.render_mode = scaler->render_mode;
1518 metrics->root.scaler.face = scaler->face;
1519 metrics->root.scaler.flags = scaler->flags;
1521 af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
1522 af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
1529 FT_CALLBACK_DEF(
void )
1530 af_latin_get_standard_widths( AF_StyleMetrics metrics_,
1534 AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
1538 *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
1541 *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
1556 FT_LOCAL_DEF( FT_Error )
1557 af_latin_hints_compute_segments( AF_GlyphHints hints,
1560 AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics;
1561 AF_AxisHints axis = &hints->axis[dim];
1562 FT_Memory memory = hints->memory;
1563 FT_Error error = FT_Err_Ok;
1564 AF_Segment segment = NULL;
1566 AF_Point* contour = hints->contours;
1567 AF_Point* contour_limit = contour + hints->num_contours;
1568 AF_Direction major_dir, segment_dir;
1570 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
1575 seg0.flags = AF_EDGE_NORMAL;
1577 major_dir = (AF_Direction)FT_ABS( axis->major_dir );
1578 segment_dir = major_dir;
1580 axis->num_segments = 0;
1583 if ( dim == AF_DIMENSION_HORZ )
1585 AF_Point point = hints->points;
1586 AF_Point limit = point + hints->num_points;
1589 for ( ; point < limit; point++ )
1591 point->u = point->fx;
1592 point->v = point->fy;
1597 AF_Point point = hints->points;
1598 AF_Point limit = point + hints->num_points;
1601 for ( ; point < limit; point++ )
1603 point->u = point->fy;
1604 point->v = point->fx;
1609 for ( ; contour < contour_limit; contour++ )
1611 AF_Point point = contour[0];
1612 AF_Point last = point->prev;
1618 FT_Pos min_pos = 32000;
1619 FT_Pos max_pos = -32000;
1620 FT_Pos min_coord = 32000;
1621 FT_Pos max_coord = -32000;
1622 FT_UShort min_flags = AF_FLAG_NONE;
1623 FT_UShort max_flags = AF_FLAG_NONE;
1624 FT_Pos min_on_coord = 32000;
1625 FT_Pos max_on_coord = -32000;
1629 AF_Segment prev_segment = NULL;
1631 FT_Pos prev_min_pos = min_pos;
1632 FT_Pos prev_max_pos = max_pos;
1633 FT_Pos prev_min_coord = min_coord;
1634 FT_Pos prev_max_coord = max_coord;
1635 FT_UShort prev_min_flags = min_flags;
1636 FT_UShort prev_max_flags = max_flags;
1637 FT_Pos prev_min_on_coord = min_on_coord;
1638 FT_Pos prev_max_on_coord = max_on_coord;
1641 if ( !( point->flags & AF_FLAG_IGNORE ) &&
1642 FT_ABS( last->out_dir ) == major_dir &&
1643 FT_ABS( point->out_dir ) == major_dir )
1650 point = point->prev;
1651 if ( FT_ABS( point->out_dir ) != major_dir )
1653 point = point->next;
1656 if ( point == last )
1680 if ( v < min_coord )
1683 min_flags = point->flags;
1685 if ( v > max_coord )
1688 max_flags = point->flags;
1692 if ( !( point->flags & AF_FLAG_CONTROL ) )
1695 if ( v < min_on_coord )
1697 if ( v > max_on_coord )
1701 if ( point->flags & AF_FLAG_IGNORE ||
1702 point->out_dir != segment_dir ||
1709 if ( point->flags & AF_FLAG_IGNORE ||
1711 segment->first != prev_segment->last )
1716 segment->last = point;
1717 segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1718 segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1723 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1724 ( max_on_coord - min_on_coord ) < flat_threshold )
1725 segment->flags |= AF_EDGE_ROUND;
1727 segment->min_coord = (FT_Short)min_coord;
1728 segment->max_coord = (FT_Short)max_coord;
1729 segment->height = segment->max_coord - segment->min_coord;
1731 prev_segment = segment;
1732 prev_min_pos = min_pos;
1733 prev_max_pos = max_pos;
1734 prev_min_coord = min_coord;
1735 prev_max_coord = max_coord;
1736 prev_min_flags = min_flags;
1737 prev_max_flags = max_flags;
1738 prev_min_on_coord = min_on_coord;
1739 prev_max_on_coord = max_on_coord;
1746 if ( prev_segment->last->in_dir == point->in_dir )
1756 if ( prev_min_pos < min_pos )
1757 min_pos = prev_min_pos;
1758 if ( prev_max_pos > max_pos )
1759 max_pos = prev_max_pos;
1761 if ( prev_min_coord < min_coord )
1763 min_coord = prev_min_coord;
1764 min_flags = prev_min_flags;
1766 if ( prev_max_coord > max_coord )
1768 max_coord = prev_max_coord;
1769 max_flags = prev_max_flags;
1772 if ( prev_min_on_coord < min_on_coord )
1773 min_on_coord = prev_min_on_coord;
1774 if ( prev_max_on_coord > max_on_coord )
1775 max_on_coord = prev_max_on_coord;
1777 prev_segment->last = point;
1778 prev_segment->pos = (FT_Short)( ( min_pos +
1780 prev_segment->delta = (FT_Short)( ( max_pos -
1783 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1784 ( max_on_coord - min_on_coord ) < flat_threshold )
1785 prev_segment->flags |= AF_EDGE_ROUND;
1787 prev_segment->flags &= ~AF_EDGE_ROUND;
1789 prev_segment->min_coord = (FT_Short)min_coord;
1790 prev_segment->max_coord = (FT_Short)max_coord;
1791 prev_segment->height = prev_segment->max_coord -
1792 prev_segment->min_coord;
1799 if ( FT_ABS( prev_max_coord - prev_min_coord ) >
1800 FT_ABS( max_coord - min_coord ) )
1804 if ( min_pos < prev_min_pos )
1805 prev_min_pos = min_pos;
1806 if ( max_pos > prev_max_pos )
1807 prev_max_pos = max_pos;
1809 prev_segment->last = point;
1810 prev_segment->pos = (FT_Short)( ( prev_min_pos +
1811 prev_max_pos ) >> 1 );
1812 prev_segment->delta = (FT_Short)( ( prev_max_pos -
1813 prev_min_pos ) >> 1 );
1819 if ( prev_min_pos < min_pos )
1820 min_pos = prev_min_pos;
1821 if ( prev_max_pos > max_pos )
1822 max_pos = prev_max_pos;
1824 segment->last = point;
1825 segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1826 segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1828 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1829 ( max_on_coord - min_on_coord ) < flat_threshold )
1830 segment->flags |= AF_EDGE_ROUND;
1832 segment->min_coord = (FT_Short)min_coord;
1833 segment->max_coord = (FT_Short)max_coord;
1834 segment->height = segment->max_coord -
1837 *prev_segment = *segment;
1839 prev_min_pos = min_pos;
1840 prev_max_pos = max_pos;
1841 prev_min_coord = min_coord;
1842 prev_max_coord = max_coord;
1843 prev_min_flags = min_flags;
1844 prev_max_flags = max_flags;
1845 prev_min_on_coord = min_on_coord;
1846 prev_max_on_coord = max_on_coord;
1850 axis->num_segments--;
1861 if ( point == last )
1871 if ( !( point->flags & AF_FLAG_IGNORE ) &&
1873 ( FT_ABS( point->out_dir ) == major_dir ||
1874 point == point->prev ) )
1891 if ( axis->num_segments > 1000 )
1893 FT_TRACE0((
"af_latin_hints_compute_segments:"
1894 " more than 1000 segments in this glyph;\n" ));
1896 " hinting is suppressed\n" ));
1897 axis->num_segments = 0;
1902 segment_dir = (AF_Direction)point->out_dir;
1904 error = af_axis_hints_new_segment( axis, memory, &segment );
1911 segment->dir = (FT_Char)segment_dir;
1912 segment->first = point;
1913 segment->last = point;
1918 prev_segment = segment - 1;
1920 min_pos = max_pos = point->u;
1921 min_coord = max_coord = point->v;
1922 min_flags = max_flags = point->flags;
1924 if ( point->flags & AF_FLAG_CONTROL )
1926 min_on_coord = 32000;
1927 max_on_coord = -32000;
1930 min_on_coord = max_on_coord = point->v;
1934 if ( point == point->prev )
1939 segment->pos = (FT_Short)min_pos;
1941 if (point->flags & AF_FLAG_CONTROL)
1942 segment->flags |= AF_EDGE_ROUND;
1944 segment->min_coord = (FT_Short)point->v;
1945 segment->max_coord = (FT_Short)point->v;
1946 segment->height = 0;
1953 point = point->next;
1962 AF_Segment segments = axis->segments;
1963 AF_Segment segments_end = FT_OFFSET( segments, axis->num_segments );
1966 for ( segment = segments; segment < segments_end; segment++ )
1968 AF_Point first = segment->first;
1969 AF_Point last = segment->last;
1970 FT_Pos first_v = first->v;
1971 FT_Pos last_v = last->v;
1974 if ( first_v < last_v )
1980 if ( p->v < first_v )
1981 segment->height = (FT_Short)( segment->height +
1982 ( ( first_v - p->v ) >> 1 ) );
1985 if ( p->v > last_v )
1986 segment->height = (FT_Short)( segment->height +
1987 ( ( p->v - last_v ) >> 1 ) );
1995 if ( p->v > first_v )
1996 segment->height = (FT_Short)( segment->height +
1997 ( ( p->v - first_v ) >> 1 ) );
2000 if ( p->v < last_v )
2001 segment->height = (FT_Short)( segment->height +
2002 ( ( last_v - p->v ) >> 1 ) );
2015 FT_LOCAL_DEF(
void )
2016 af_latin_hints_link_segments( AF_GlyphHints hints,
2017 FT_UInt width_count,
2018 AF_WidthRec* widths,
2021 AF_AxisHints axis = &hints->axis[dim];
2022 AF_Segment segments = axis->segments;
2023 AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
2024 FT_Pos len_threshold, len_score, dist_score, max_width;
2025 AF_Segment seg1, seg2;
2029 max_width = widths[width_count - 1].org;
2034 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
2035 if ( len_threshold == 0 )
2039 len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
2047 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
2049 if ( seg1->dir != axis->major_dir )
2054 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
2056 FT_Pos pos1 = seg1->pos;
2057 FT_Pos pos2 = seg2->pos;
2060 if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
2063 FT_Pos min = seg1->min_coord;
2064 FT_Pos max = seg1->max_coord;
2068 if ( min < seg2->min_coord )
2069 min = seg2->min_coord;
2071 if ( max > seg2->max_coord )
2072 max = seg2->max_coord;
2077 if ( len >= len_threshold )
2093 FT_Pos dist = pos2 - pos1;
2095 FT_Pos dist_demerit, score;
2102 FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 );
2105 if ( delta > 10000 )
2106 dist_demerit = 32000;
2107 else if ( delta > 0 )
2108 dist_demerit = delta * delta / dist_score;
2113 dist_demerit = dist;
2115 score = dist_demerit + len_score / len;
2118 if ( score < seg1->score )
2120 seg1->score = score;
2124 if ( score < seg2->score )
2126 seg2->score = score;
2135 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
2141 if ( seg2->link != seg1 )
2144 seg1->serif = seg2->link;
2153 FT_LOCAL_DEF( FT_Error )
2154 af_latin_hints_compute_edges( AF_GlyphHints hints,
2157 AF_AxisHints axis = &hints->axis[dim];
2158 FT_Error error = FT_Err_Ok;
2159 FT_Memory memory = hints->memory;
2160 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
2162 AF_StyleClass style_class = hints->metrics->style_class;
2163 AF_ScriptClass script_class = af_script_classes[style_class->script];
2165 FT_Bool top_to_bottom_hinting = 0;
2167 AF_Segment segments = axis->segments;
2168 AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
2172 AF_Direction up_dir;
2175 FT_Pos edge_distance_threshold;
2176 FT_Pos segment_length_threshold;
2177 FT_Pos segment_width_threshold;
2180 axis->num_edges = 0;
2182 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
2186 up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
2190 if ( dim == AF_DIMENSION_VERT )
2191 top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2198 if ( dim == AF_DIMENSION_HORZ )
2199 segment_length_threshold = FT_DivFix( 64, hints->y_scale );
2201 segment_length_threshold = 0;
2207 segment_width_threshold = FT_DivFix( 32, scale );
2226 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
2228 if ( edge_distance_threshold > 64 / 4 )
2229 edge_distance_threshold = 64 / 4;
2231 edge_distance_threshold = FT_DivFix( edge_distance_threshold,
2234 for ( seg = segments; seg < segment_limit; seg++ )
2236 AF_Edge found = NULL;
2242 if ( seg->height < segment_length_threshold ||
2243 seg->delta > segment_width_threshold ||
2244 seg->dir == AF_DIR_NONE )
2250 2 * seg->height < 3 * segment_length_threshold )
2254 for ( ee = 0; ee < axis->num_edges; ee++ )
2256 AF_Edge edge = axis->edges + ee;
2260 dist = seg->pos - edge->fpos;
2264 if ( dist < edge_distance_threshold && edge->dir == seg->dir )
2278 error = af_axis_hints_new_edge( axis, seg->pos,
2279 (AF_Direction)seg->dir,
2280 top_to_bottom_hinting,
2290 edge->dir = seg->dir;
2291 edge->fpos = seg->pos;
2292 edge->opos = FT_MulFix( seg->pos, scale );
2293 edge->pos = edge->opos;
2294 seg->edge_next = seg;
2300 seg->edge_next = found->first;
2301 found->last->edge_next = seg;
2308 for ( seg = segments; seg < segment_limit; seg++ )
2310 AF_Edge found = NULL;
2314 if ( seg->dir != AF_DIR_NONE )
2318 for ( ee = 0; ee < axis->num_edges; ee++ )
2320 AF_Edge edge = axis->edges + ee;
2324 dist = seg->pos - edge->fpos;
2328 if ( dist < edge_distance_threshold )
2338 seg->edge_next = found->first;
2339 found->last->edge_next = seg;
2366 AF_Edge edges = axis->edges;
2367 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
2371 for ( edge = edges; edge < edge_limit; edge++ )
2378 seg = seg->edge_next;
2380 }
while ( seg != edge->first );
2384 for ( edge = edges; edge < edge_limit; edge++ )
2386 FT_Int is_round = 0;
2387 FT_Int is_straight = 0;
2402 if ( seg->flags & AF_EDGE_ROUND )
2409 if ( seg->dir == up_dir )
2410 ups += seg->max_coord - seg->min_coord;
2412 downs += seg->max_coord - seg->min_coord;
2417 is_serif = FT_BOOL( seg->serif &&
2419 seg->serif->edge != edge );
2421 if ( ( seg->link && seg->link->edge ) || is_serif )
2433 edge2 = edge->serif;
2442 edge_delta = edge->fpos - edge2->fpos;
2443 if ( edge_delta < 0 )
2444 edge_delta = -edge_delta;
2446 seg_delta = seg->pos - seg2->pos;
2447 if ( seg_delta < 0 )
2448 seg_delta = -seg_delta;
2450 if ( seg_delta < edge_delta )
2458 edge->serif = edge2;
2459 edge2->flags |= AF_EDGE_SERIF;
2465 seg = seg->edge_next;
2467 }
while ( seg != edge->first );
2470 edge->flags = AF_EDGE_NORMAL;
2472 if ( is_round > 0 && is_round >= is_straight )
2473 edge->flags |= AF_EDGE_ROUND;
2477 edge->dir = AF_DIR_NONE;
2480 edge->dir = (FT_Char)up_dir;
2482 else if ( ups < downs )
2483 edge->dir = (FT_Char)-up_dir;
2485 else if ( ups == downs )
2493 if ( edge->serif && edge->link )
2505 FT_LOCAL_DEF( FT_Error )
2506 af_latin_hints_detect_features( AF_GlyphHints hints,
2507 FT_UInt width_count,
2508 AF_WidthRec* widths,
2514 error = af_latin_hints_compute_segments( hints, dim );
2517 af_latin_hints_link_segments( hints, width_count, widths, dim );
2519 error = af_latin_hints_compute_edges( hints, dim );
2529 af_latin_hints_compute_blue_edges( AF_GlyphHints hints,
2530 AF_LatinMetrics metrics )
2532 AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
2533 AF_Edge edge = axis->edges;
2534 AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges );
2535 AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
2536 FT_Fixed scale = latin->scale;
2543 for ( ; edge < edge_limit; edge++ )
2546 AF_Width best_blue = NULL;
2547 FT_Bool best_blue_is_neutral = 0;
2551 if ( edge->flags & AF_EDGE_NO_BLUE )
2556 best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
2559 if ( best_dist > 64 / 2 )
2562 for ( bb = 0; bb < latin->blue_count; bb++ )
2564 AF_LatinBlue blue = latin->blues + bb;
2565 FT_Bool is_top_blue, is_neutral_blue, is_major_dir;
2569 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
2577 (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP |
2578 AF_LATIN_BLUE_SUB_TOP ) ) != 0 );
2580 (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
2582 FT_BOOL( edge->dir == axis->major_dir );
2585 if ( is_top_blue ^ is_major_dir || is_neutral_blue )
2591 dist = edge->fpos - blue->ref.org;
2595 dist = FT_MulFix( dist, scale );
2596 if ( dist < best_dist )
2599 best_blue = &blue->ref;
2600 best_blue_is_neutral = is_neutral_blue;
2608 if ( edge->flags & AF_EDGE_ROUND &&
2612 FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
2615 if ( is_top_blue ^ is_under_ref )
2617 dist = edge->fpos - blue->shoot.org;
2621 dist = FT_MulFix( dist, scale );
2622 if ( dist < best_dist )
2625 best_blue = &blue->shoot;
2626 best_blue_is_neutral = is_neutral_blue;
2635 edge->blue_edge = best_blue;
2636 if ( best_blue_is_neutral )
2637 edge->flags |= AF_EDGE_NEUTRAL;
2646 af_latin_hints_init( AF_GlyphHints hints,
2647 AF_StyleMetrics metrics_ )
2649 AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
2651 FT_Render_Mode mode;
2652 FT_UInt32 scaler_flags, other_flags;
2653 FT_Face face = metrics->root.scaler.face;
2656 af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics );
2662 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
2663 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
2664 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
2665 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
2668 mode = metrics->root.scaler.render_mode;
2670 scaler_flags = hints->scaler_flags;
2677 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
2678 other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
2684 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
2685 other_flags |= AF_LATIN_HINTS_VERT_SNAP;
2690 if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD )
2691 other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
2693 if ( mode == FT_RENDER_MODE_MONO )
2694 other_flags |= AF_LATIN_HINTS_MONO;
2703 if ( mode == FT_RENDER_MODE_LIGHT || mode == FT_RENDER_MODE_LCD ||
2704 ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
2705 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
2707 hints->scaler_flags = scaler_flags;
2708 hints->other_flags = other_flags;
2726 af_latin_snap_width( AF_Width widths,
2731 FT_Pos best = 64 + 32 + 2;
2732 FT_Pos reference = width;
2736 for ( n = 0; n < count; n++ )
2753 scaled = FT_PIX_ROUND( reference );
2755 if ( width >= reference )
2757 if ( width < scaled + 48 )
2762 if ( width > scaled - 48 )
2771#define FT_COMPONENT afadjust
2775 af_move_contour_vertically( AF_Point contour,
2778 AF_Point point = contour;
2779 AF_Point first_point = point;
2786 point->y += movement;
2787 point = point->next;
2789 }
while ( point != first_point );
2796 af_move_contours_up( AF_GlyphHints hints,
2803 for ( contour = 0; contour < hints->num_contours; contour++ )
2805 FT_Pos min_y = hints->contour_y_minima[contour];
2806 FT_Pos max_y = hints->contour_y_maxima[contour];
2809 if ( min_y < max_y &&
2811 af_move_contour_vertically( hints->contours[contour],
2818 af_move_contours_down( AF_GlyphHints hints,
2825 for ( contour = 0; contour < hints->num_contours; contour++ )
2827 FT_Pos min_y = hints->contour_y_minima[contour];
2828 FT_Pos max_y = hints->contour_y_maxima[contour];
2831 if ( min_y < max_y &&
2833 af_move_contour_vertically( hints->contours[contour],
2842 af_compute_vertical_extrema( AF_GlyphHints hints )
2847 for ( contour = 0; contour < hints->num_contours; contour++ )
2849 FT_Pos min_y = FT_LONG_MAX;
2850 FT_Pos max_y = FT_LONG_MIN;
2852 AF_Point first_point = hints->contours[contour];
2853 AF_Point point = first_point;
2856 if ( !first_point || first_point->next->next == first_point )
2861 if ( point->y < min_y )
2863 if ( point->y > max_y )
2866 point = point->next;
2868 }
while ( point != first_point );
2871 hints->contour_y_minima[contour] = min_y;
2872 hints->contour_y_maxima[contour] = max_y;
2878 af_find_highest_contour( AF_GlyphHints hints )
2880 FT_Int highest_contour = 0;
2881 FT_Pos highest_min_y = FT_LONG_MAX;
2882 FT_Pos highest_max_y = FT_LONG_MIN;
2893 for ( contour = 0; contour < hints->num_contours; contour++ )
2895 FT_Pos current_min_y = hints->contour_y_minima[contour];
2896 FT_Pos current_max_y = hints->contour_y_maxima[contour];
2901 if ( current_max_y > highest_max_y ||
2902 ( current_max_y == highest_max_y &&
2903 current_min_y > highest_min_y ) )
2905 highest_min_y = current_min_y;
2906 highest_max_y = current_max_y;
2907 highest_contour = contour;
2911 return highest_contour;
2916 af_find_second_highest_contour( AF_GlyphHints hints )
2918 FT_Int highest_contour;
2919 FT_Pos highest_min_y;
2921 FT_Int second_highest_contour = 0;
2922 FT_Pos second_highest_max_y = FT_LONG_MIN;
2927 if ( hints->num_contours < 3 )
2930 highest_contour = af_find_highest_contour( hints );
2931 highest_min_y = hints->contour_y_minima[highest_contour];
2936 for ( contour = 0; contour < hints->num_contours; contour++ )
2938 FT_Pos current_min_y;
2939 FT_Pos current_max_y;
2942 if ( contour == highest_contour )
2945 current_min_y = hints->contour_y_minima[contour];
2946 current_max_y = hints->contour_y_maxima[contour];
2948 if ( current_max_y > second_highest_max_y &&
2949 current_min_y < highest_min_y )
2951 second_highest_max_y = current_max_y;
2952 second_highest_contour = contour;
2956 return second_highest_contour;
2961 af_find_lowest_contour( AF_GlyphHints hints )
2963 FT_Int lowest_contour = 0;
2964 FT_Pos lowest_min_y = FT_LONG_MAX;
2965 FT_Pos lowest_max_y = FT_LONG_MIN;
2970 for ( contour = 0; contour < hints->num_contours; contour++ )
2972 FT_Pos current_min_y = hints->contour_y_minima[contour];
2973 FT_Pos current_max_y = hints->contour_y_maxima[contour];
2976 if ( current_min_y < lowest_min_y ||
2977 ( current_min_y == lowest_min_y &&
2978 current_max_y < lowest_max_y ) )
2980 lowest_min_y = current_min_y;
2981 lowest_max_y = current_max_y;
2982 lowest_contour = contour;
2986 return lowest_contour;
2991 af_find_second_lowest_contour( AF_GlyphHints hints )
2993 FT_Int lowest_contour;
2994 FT_Pos lowest_max_y;
2996 FT_Int second_lowest_contour = 0;
2997 FT_Pos second_lowest_min_y = FT_LONG_MAX;
3002 if ( hints->num_contours < 3 )
3005 lowest_contour = af_find_lowest_contour( hints );
3006 lowest_max_y = hints->contour_y_maxima[lowest_contour];
3008 for ( contour = 0; contour < hints->num_contours; contour++ )
3010 FT_Pos current_min_y;
3011 FT_Pos current_max_y;
3014 if ( contour == lowest_contour )
3017 current_min_y = hints->contour_y_minima[contour];
3018 current_max_y = hints->contour_y_maxima[contour];
3020 if ( current_min_y < second_lowest_min_y &&
3021 current_max_y > lowest_max_y )
3023 second_lowest_min_y = current_min_y;
3024 second_lowest_contour = contour;
3028 return second_lowest_contour;
3035 af_prevent_top_blue_alignment( AF_GlyphHints hints,
3038 AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
3040 AF_Edge edges = axis->edges;
3041 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
3045 for ( edge = edges; edge < edge_limit; edge++ )
3046 if ( edge->pos > pos )
3047 edge->flags |= AF_EDGE_NO_BLUE;
3052 af_prevent_bottom_blue_alignment( AF_GlyphHints hints,
3055 AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
3057 AF_Edge edges = axis->edges;
3058 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
3062 for ( edge = edges; edge < edge_limit; edge++ )
3063 if ( edge->pos < pos )
3064 edge->flags |= AF_EDGE_NO_BLUE;
3069 af_latin_get_base_glyph_blues( AF_GlyphHints hints,
3072 AF_LatinBlue* bottom )
3074 AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics;
3075 AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
3078 FT_UInt bottom_flag;
3083 top_flag = is_capital ? AF_LATIN_BLUE_TOP
3084 : AF_LATIN_BLUE_ADJUSTMENT;
3085 top_flag |= AF_LATIN_BLUE_ACTIVE;
3087 for ( i = 0; i < axis->blue_count; i++ )
3088 if ( ( axis->blues[i].flags & top_flag ) == top_flag )
3090 if ( i < axis->blue_count )
3091 *top = &axis->blues[i];
3093 bottom_flag = is_capital ? AF_LATIN_BLUE_BOTTOM
3094 : AF_LATIN_BLUE_BOTTOM_SMALL;
3095 bottom_flag |= AF_LATIN_BLUE_ACTIVE;
3097 for ( i = 0; i < axis->blue_count; i++ )
3098 if ( ( axis->blues[i].flags & bottom_flag ) == bottom_flag )
3100 if ( i < axis->blue_count )
3101 *bottom = &axis->blues[i];
3110 af_latin_ignore_top( AF_GlyphHints hints,
3111 AF_LatinBlue top_blue,
3112 AF_LatinBlue bottom_blue )
3114 FT_Pos base_glyph_height;
3122 base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur;
3123 limit = top_blue->shoot.cur + base_glyph_height / 7 + 16;
3125 af_prevent_top_blue_alignment( hints, limit );
3130 af_latin_ignore_bottom( AF_GlyphHints hints,
3131 AF_LatinBlue top_blue,
3132 AF_LatinBlue bottom_blue )
3134 FT_Pos base_glyph_height;
3138 base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur;
3139 limit = bottom_blue->shoot.cur - base_glyph_height / 7 - 16;
3141 af_prevent_bottom_blue_alignment( hints, limit );
3146 af_touch_contour( AF_GlyphHints hints,
3149 AF_Point first_point = hints->contours[contour];
3150 AF_Point p = first_point;
3157 p->flags |= AF_FLAG_IGNORE;
3158 if ( !( p->flags & AF_FLAG_CONTROL ) )
3159 p->flags |= AF_FLAG_TOUCH_Y;
3161 }
while ( p != first_point );
3166 af_touch_top_contours( AF_GlyphHints hints,
3167 FT_Int limit_contour )
3169 FT_Pos limit = hints->contour_y_minima[limit_contour];
3174 for ( contour = 0; contour < hints->num_contours; contour++ )
3176 FT_Pos min_y = hints->contour_y_minima[contour];
3177 FT_Pos max_y = hints->contour_y_maxima[contour];
3180 if ( min_y < max_y &&
3182 af_touch_contour( hints, contour );
3188 af_touch_bottom_contours( AF_GlyphHints hints,
3189 FT_Int limit_contour )
3191 FT_Pos limit = hints->contour_y_minima[limit_contour];
3196 for ( contour = 0; contour < hints->num_contours; contour++ )
3198 FT_Pos min_y = hints->contour_y_minima[contour];
3199 FT_Pos max_y = hints->contour_y_maxima[contour];
3202 if ( min_y < max_y &&
3204 af_touch_contour( hints, contour );
3212 af_latin_stretch_top_tilde( AF_GlyphHints hints,
3213 FT_Int tilde_contour )
3215 AF_Point p = hints->contours[tilde_contour];
3216 AF_Point first_point = p;
3218 FT_Pos min_y = hints->contour_y_minima[tilde_contour];
3219 FT_Pos max_y = hints->contour_y_maxima[tilde_contour];
3221 FT_Pos min_measurement = FT_LONG_MAX;
3222 FT_Bool measurement_taken = FALSE;
3225 FT_Pos extremum_threshold;
3226 FT_Pos target_height;
3229 if ( min_y == max_y )
3232 FT_TRACE4((
"af_latin_stretch_top_tilde: min y: %ld, max y: %ld\n",
3235 height = SUB_LONG( max_y, min_y );
3236 extremum_threshold = height / 8;
3251 if ( !( p->flags & AF_FLAG_CONTROL ) &&
3252 p->prev->y == p->y && p->next->y == p->y &&
3253 p->y != min_y && p->y != max_y &&
3254 p->prev->flags & AF_FLAG_CONTROL &&
3255 p->next->flags & AF_FLAG_CONTROL )
3260 AF_Point prev_on = p->prev;
3261 AF_Point next_on = p->next;
3266 while ( prev_on->flags & AF_FLAG_CONTROL )
3267 prev_on = prev_on->prev;
3268 while ( next_on->flags & AF_FLAG_CONTROL )
3269 next_on = next_on->next;
3271 if ( next_on->y > p->y && prev_on->y > p->y )
3272 measurement = p->y - min_y;
3273 else if ( next_on->y < p->y && prev_on->y < p->y )
3274 measurement = max_y - p->y;
3279 if ( measurement < extremum_threshold )
3282 if ( !measurement_taken || measurement < min_measurement )
3284 measurement_taken = TRUE;
3285 min_measurement = measurement;
3289 }
while ( p != first_point );
3291 if ( !measurement_taken )
3292 min_measurement = 0;
3294 FT_TRACE4((
"af_latin_stretch_top_tilde: min measurement %ld\n",
3300 af_touch_top_contours( hints, tilde_contour );
3304 target_height = min_measurement + 64;
3305 if ( height >= target_height )
3316 p->y = ( ( p->y - min_y ) * target_height / height ) + min_y;
3318 }
while ( p != first_point );
3320 return target_height - height;
3325 af_latin_stretch_bottom_tilde( AF_GlyphHints hints,
3326 FT_Int tilde_contour )
3328 AF_Point p = hints->contours[tilde_contour];
3329 AF_Point first_point = p;
3331 FT_Pos min_y = hints->contour_y_minima[tilde_contour];
3332 FT_Pos max_y = hints->contour_y_maxima[tilde_contour];
3334 FT_Pos min_measurement = FT_LONG_MAX;
3335 FT_Bool measurement_taken = FALSE;
3338 FT_Pos extremum_threshold;
3339 FT_Pos target_height;
3342 if ( min_y == max_y )
3345 FT_TRACE4((
"af_latin_stretch_bottom_tilde: min y: %ld, max y: %ld\n",
3348 height = SUB_LONG( max_y, min_y );
3349 extremum_threshold = height / 8;
3355 if ( !( p->flags & AF_FLAG_CONTROL ) &&
3356 p->prev->y == p->y && p->next->y == p->y &&
3357 p->y != min_y && p->y != max_y &&
3358 p->prev->flags & AF_FLAG_CONTROL &&
3359 p->next->flags & AF_FLAG_CONTROL )
3361 AF_Point prev_on = p->prev;
3362 AF_Point next_on = p->next;
3367 while ( prev_on->flags & AF_FLAG_CONTROL )
3368 prev_on = prev_on->prev;
3369 while ( next_on->flags & AF_FLAG_CONTROL )
3370 next_on = next_on->next;
3372 if ( next_on->y > p->y && prev_on->y > p->y )
3373 measurement = p->y - min_y;
3374 else if ( next_on->y < p->y && prev_on->y < p->y )
3375 measurement = max_y - p->y;
3379 if ( measurement < extremum_threshold )
3382 if ( !measurement_taken || measurement < min_measurement )
3384 measurement_taken = TRUE;
3385 min_measurement = measurement;
3389 }
while ( p != first_point );
3391 if ( !measurement_taken )
3392 min_measurement = 0;
3394 FT_TRACE4((
"af_latin_stretch_bottom_tilde: min measurement %ld\n",
3397 af_touch_bottom_contours( hints, tilde_contour );
3399 target_height = min_measurement + 64;
3400 if ( height >= target_height )
3407 p->y = ( ( p->y - max_y ) * target_height / height ) + max_y;
3409 }
while ( p != first_point );
3411 return target_height - height;
3439 af_latin_align_top_tilde( AF_GlyphHints hints,
3440 FT_Int tilde_contour )
3442 AF_Point p = hints->contours[tilde_contour];
3443 AF_Point first_point = p;
3445 FT_Pos min_y = p->y;
3446 FT_Pos max_y = p->y;
3448 FT_Pos min_y_rounded;
3462 }
while ( p != first_point );
3465 min_y_rounded = FT_PIX_ROUND( min_y );
3466 delta = min_y_rounded - min_y;
3467 height = max_y - min_y;
3471 if ( height < 64 * 3 )
3472 delta += ( FT_PIX_ROUND( height ) - height ) / 2;
3474 af_move_contour_vertically( first_point, delta );
3481 af_latin_align_bottom_tilde( AF_GlyphHints hints,
3482 FT_Int tilde_contour )
3484 AF_Point p = hints->contours[tilde_contour];
3485 AF_Point first_point = p;
3487 FT_Pos min_y = p->y;
3488 FT_Pos max_y = p->y;
3490 FT_Pos max_y_rounded;
3503 }
while ( p != first_point );
3505 max_y_rounded = FT_PIX_ROUND( max_y );
3506 delta = max_y_rounded - max_y;
3507 height = max_y - min_y;
3509 if ( height < 64 * 3 )
3510 delta -= ( FT_PIX_ROUND( height ) - height ) / 2;
3512 af_move_contour_vertically( first_point, delta );
3522 af_check_contour_horizontal_overlap( AF_GlyphHints hints,
3523 FT_Int contour_index )
3525 FT_Pos contour_max_x = FT_LONG_MIN;
3526 FT_Pos contour_min_x = FT_LONG_MAX;
3527 FT_Pos others_max_x = FT_LONG_MIN;
3528 FT_Pos others_min_x = FT_LONG_MAX;
3532 FT_Bool horizontal_overlap;
3535 for ( contour = 0; contour < hints->num_contours; contour++ )
3537 AF_Point first_point = hints->contours[contour];
3538 AF_Point p = first_point;
3543 if ( first_point->next->next == first_point )
3550 if ( contour == contour_index )
3552 if ( p->x < contour_min_x )
3553 contour_min_x = p->x;
3554 if ( p->x > contour_max_x )
3555 contour_max_x = p->x;
3559 if ( p->x < others_min_x )
3560 others_min_x = p->x;
3561 if ( p->x > others_max_x )
3562 others_max_x = p->x;
3564 }
while ( p != first_point );
3567 horizontal_overlap =
3568 ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) ||
3569 ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) ||
3570 ( contour_max_x >= others_max_x && contour_min_x <= others_min_x );
3572 return horizontal_overlap;
3577 af_glyph_hints_apply_vertical_separation_adjustments(
3578 AF_GlyphHints hints,
3580 FT_UInt glyph_index,
3581 FT_Pos accent_height_limit,
3582 FT_Hash reverse_charmap )
3584 FT_Bool adjust_top = FALSE;
3585 FT_Bool adjust_below_top = FALSE;
3587 FT_Bool adjust_bottom = FALSE;
3588 FT_Bool adjust_above_bottom = FALSE;
3591 FT_UInt32 adj_type = AF_ADJUST_NONE;
3594 FT_TRACE4((
"Entering"
3595 " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
3597 if ( dim != AF_DIMENSION_VERT )
3600 val = ft_hash_num_lookup( (FT_Int)glyph_index, reverse_charmap );
3603 FT_UInt codepoint = *val;
3606 adj_type = af_adjustment_database_lookup( codepoint );
3610 adjust_top = !!( adj_type & AF_ADJUST_UP );
3611 adjust_below_top = !!( adj_type & AF_ADJUST_UP2 );
3613 adjust_bottom = !!( adj_type & AF_ADJUST_DOWN );
3614 adjust_above_bottom = !!( adj_type & AF_ADJUST_DOWN2 );
3618 if ( ( ( adjust_top || adjust_bottom ) &&
3619 hints->num_contours >= 2 ) ||
3620 ( ( adjust_below_top || adjust_above_bottom ) &&
3621 hints->num_contours >= 3 ) )
3625 af_compute_vertical_extrema( hints );
3628 if ( ( adjust_top && hints->num_contours >= 2 ) ||
3629 ( adjust_below_top && hints->num_contours >= 3 ) )
3631 FT_Int high_contour;
3636 FT_Int tilde_contour;
3639 FT_Pos tilde_height;
3642 FT_Bool horizontal_overlap;
3644 FT_Pos min_distance = 64;
3645 FT_Pos adjustment_amount;
3646 FT_Pos calculated_amount;
3647 FT_Pos centering_adjustment = 0;
3650 FT_Bool is_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP );
3651 FT_Bool is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 );
3654 FT_TRACE4((
"af_glyph_hints_apply_vertical_separation_adjustments:\n"
3655 " Applying vertical adjustment: %s\n",
3656 adjust_top ?
"AF_ADJUST_TOP" :
"AF_ADJUST_TOP2" ));
3658 high_contour = adjust_below_top
3659 ? af_find_second_highest_contour( hints )
3660 : af_find_highest_contour( hints );
3664 horizontal_overlap =
3665 af_check_contour_horizontal_overlap( hints, high_contour );
3666 if ( !horizontal_overlap )
3668 FT_TRACE4((
" High contour does not horizontally overlap"
3669 " with other contours.\n"
3670 " Skipping adjustment.\n" ));
3674 high_min_y = hints->contour_y_minima[high_contour];
3675 high_max_y = hints->contour_y_maxima[high_contour];
3676 high_height = high_max_y - high_min_y;
3678 if ( high_height > accent_height_limit )
3680 FT_TRACE4((
" High contour height (%.2f) exceeds accent height"
3682 " Skipping adjustment.\n",
3683 (
double)high_height / 64,
3684 (
double)accent_height_limit / 64 ));
3692 for ( contour = 0; contour < hints->num_contours; contour++ )
3699 if ( contour == high_contour )
3702 min_y = hints->contour_y_minima[contour];
3703 max_y = hints->contour_y_maxima[contour];
3708 distance = high_min_y - max_y;
3709 if ( distance < 64 &&
3710 distance < min_distance &&
3711 min_y < high_min_y )
3712 min_distance = distance;
3715 adjustment_amount = 64 - min_distance;
3717 if ( is_top_tilde || is_below_top_tilde )
3719 tilde_contour = adjust_top
3721 : ( is_below_top_tilde
3723 : af_find_highest_contour( hints ) );
3725 tilde_min_y = hints->contour_y_minima[tilde_contour];
3726 tilde_max_y = hints->contour_y_maxima[tilde_contour];
3727 tilde_height = tilde_max_y - tilde_min_y;
3734 pos = high_min_y + adjustment_amount;
3735 if ( adjust_below_top && is_top_tilde )
3738 if ( pos % 64 == 0 && tilde_height < 3 * 64 )
3740 centering_adjustment = ( FT_PIX_ROUND( tilde_height ) -
3743 FT_TRACE4((
" Additional tilde centering adjustment: %ld\n",
3744 centering_adjustment ));
3748 if ( ( adjust_top && is_top_tilde ) ||
3749 ( adjust_below_top && is_below_top_tilde ) )
3750 calculated_amount = adjustment_amount + centering_adjustment;
3752 calculated_amount = adjustment_amount;
3755 FT_TRACE4((
" Calculated adjustment amount: %ld%s\n",
3757 ( calculated_amount < -2 ||
3758 ( adjustment_amount > 66 && calculated_amount > 66 ) )
3759 ?
" (out of range [-2;66], not adjusting)" :
"" ));
3761 if ( calculated_amount != 0 &&
3762 calculated_amount >= -2 &&
3763 ( calculated_amount <= 66 || adjustment_amount <= 66 ) )
3766 FT_Pos height_delta = high_height / 8;
3767 FT_Pos min_y_limit = high_min_y - height_delta;
3770 FT_TRACE4((
" Pushing high contour %ld units up\n",
3771 calculated_amount ));
3779 af_move_contours_up( hints, min_y_limit, adjustment_amount );
3781 if ( adjust_below_top && is_top_tilde )
3783 FT_TRACE4((
" Pushing top tilde %ld units up\n",
3784 centering_adjustment ));
3786 af_move_contours_up( hints,
3787 min_y_limit + high_height,
3788 centering_adjustment );
3793 if ( ( adjust_bottom && hints->num_contours >= 2 ) ||
3794 ( adjust_above_bottom && hints->num_contours >= 3 ) )
3801 FT_Int tilde_contour;
3804 FT_Pos tilde_height;
3807 FT_Bool horizontal_overlap;
3809 FT_Pos min_distance = 64;
3810 FT_Pos adjustment_amount;
3811 FT_Pos calculated_amount;
3812 FT_Pos centering_adjustment = 0;
3815 FT_Bool is_bottom_tilde =
3816 !!( adj_type & AF_ADJUST_TILDE_BOTTOM );
3817 FT_Bool is_above_bottom_tilde =
3818 !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 );
3821 FT_TRACE4((
"af_glyph_hints_apply_vertical_separation_adjustments:\n"
3822 " Applying vertical adjustment: %s\n",
3823 adjust_bottom ?
"AF_ADJUST_DOWN":
"AF_ADJUST_DOWN2" ));
3825 low_contour = adjust_above_bottom
3826 ? af_find_second_lowest_contour( hints )
3827 : af_find_lowest_contour( hints );
3829 horizontal_overlap =
3830 af_check_contour_horizontal_overlap( hints, low_contour );
3831 if ( !horizontal_overlap )
3833 FT_TRACE4((
" Low contour does not horizontally overlap"
3834 " with other contours.\n"
3835 " Skipping adjustment.\n" ));
3839 low_min_y = hints->contour_y_minima[low_contour];
3840 low_max_y = hints->contour_y_maxima[low_contour];
3841 low_height = low_max_y - low_min_y;
3843 if ( low_height > accent_height_limit )
3845 FT_TRACE4((
" Low contour height (%.2f) exceeds accent height"
3847 " Skipping adjustment.\n",
3848 (
double)low_height / 64,
3849 (
double)accent_height_limit / 64 ));
3853 for ( contour = 0; contour < hints->num_contours; contour++ )
3860 if ( contour == low_contour )
3863 min_y = hints->contour_y_minima[contour];
3864 max_y = hints->contour_y_maxima[contour];
3866 distance = min_y - low_max_y;
3867 if ( distance < 64 &&
3868 distance < min_distance &&
3870 min_distance = distance;
3873 adjustment_amount = 64 - min_distance;
3875 if ( is_bottom_tilde || is_above_bottom_tilde )
3877 tilde_contour = adjust_bottom
3879 : ( is_above_bottom_tilde
3881 : af_find_lowest_contour( hints ) );
3883 tilde_min_y = hints->contour_y_minima[tilde_contour];
3884 tilde_max_y = hints->contour_y_maxima[tilde_contour];
3885 tilde_height = tilde_max_y - tilde_min_y;
3887 pos = low_max_y - adjustment_amount;
3888 if ( adjust_above_bottom && is_bottom_tilde )
3891 if ( pos % 64 == 0 && tilde_height < 3 * 64 )
3893 centering_adjustment = ( FT_PIX_ROUND( tilde_height ) -
3896 FT_TRACE4((
" Additional tilde centering adjustment: %ld\n",
3897 centering_adjustment ));
3901 if ( ( adjust_bottom && is_bottom_tilde ) ||
3902 ( adjust_above_bottom && is_above_bottom_tilde ) )
3903 calculated_amount = adjustment_amount + centering_adjustment;
3905 calculated_amount = adjustment_amount;
3907 FT_TRACE4((
" Calculated adjustment amount: %ld%s\n",
3909 ( calculated_amount < -2 ||
3910 ( adjustment_amount > 66 && calculated_amount > 66 ) )
3911 ?
" (out of range [-2;66], not adjusting)" :
"" ));
3913 if ( calculated_amount != 0 &&
3914 calculated_amount >= -2 &&
3915 ( calculated_amount <= 66 || adjustment_amount <= 66 ) )
3917 FT_Pos height_delta = low_height / 8;
3918 FT_Pos max_y_limit = low_max_y + height_delta;
3921 FT_TRACE4((
" Pushing low contour %ld units down\n",
3922 calculated_amount ));
3924 af_move_contours_down( hints, max_y_limit, adjustment_amount );
3926 if ( adjust_above_bottom && is_bottom_tilde )
3928 FT_TRACE4((
" Pushing bottom tilde %ld units down\n",
3929 centering_adjustment ));
3931 af_move_contours_down( hints,
3932 max_y_limit - low_height,
3933 centering_adjustment );
3938#ifdef FT_DEBUG_LEVEL_TRACE
3939 if ( !( ( ( adjust_top || adjust_bottom ) &&
3940 hints->num_contours >= 2 ) ||
3941 ( ( adjust_below_top || adjust_above_bottom ) &&
3942 hints->num_contours >= 3 ) ) )
3943 FT_TRACE4((
"af_glyph_hints_apply_vertical_separation_adjustments:\n"
3944 " No vertical adjustment applied\n" ));
3947 FT_TRACE4((
"Exiting"
3948 " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
3953#define FT_COMPONENT aflatin
3961 af_latin_compute_stem_width( AF_GlyphHints hints,
3966 FT_UInt stem_flags )
3968 AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics;
3969 AF_LatinAxis axis = &metrics->axis[dim];
3970 FT_Pos dist = width;
3972 FT_Int vertical = ( dim == AF_DIMENSION_VERT );
3975 if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
3985 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
3986 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
3991 if ( ( stem_flags & AF_EDGE_SERIF ) &&
3996 else if ( base_flags & AF_EDGE_ROUND )
4001 else if ( dist < 56 )
4004 if ( axis->width_count > 0 )
4010 delta = dist - axis->widths[0].cur;
4017 dist = axis->widths[0].cur;
4024 if ( dist < 3 * 64 )
4032 else if ( delta < 32 )
4035 else if ( delta < 54 )
4058 if ( ( ( width > 0 ) && ( base_delta > 0 ) ) ||
4059 ( ( width < 0 ) && ( base_delta < 0 ) ) )
4061 FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem;
4065 bdelta = base_delta;
4066 else if ( ppem < 30 )
4067 bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20;
4073 dist = ( dist - bdelta + 32 ) & ~63;
4081 FT_Pos org_dist = dist;
4084 dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
4092 dist = ( dist + 16 ) & ~63;
4098 if ( AF_LATIN_HINTS_DO_MONO( hints ) )
4106 dist = ( dist + 32 ) & ~63;
4115 dist = ( dist + 64 ) >> 1;
4117 else if ( dist < 128 )
4128 dist = ( dist + 22 ) & ~63;
4129 delta = dist - org_dist;
4137 dist = ( dist + 64 ) >> 1;
4142 dist = ( dist + 32 ) & ~63;
4158 af_latin_align_linked_edge( AF_GlyphHints hints,
4163 FT_Pos dist, base_delta;
4164 FT_Pos fitted_width;
4167 dist = stem_edge->opos - base_edge->opos;
4168 base_delta = base_edge->pos - base_edge->opos;
4170 fitted_width = af_latin_compute_stem_width( hints, dim,
4176 stem_edge->pos = base_edge->pos + fitted_width;
4178 FT_TRACE5((
" LINK: edge %td (opos=%.2f) linked to %.2f,"
4179 " dist was %.2f, now %.2f\n",
4180 stem_edge - hints->axis[dim].edges,
4181 (
double)stem_edge->opos / 64, (
double)stem_edge->pos / 64,
4182 (
double)dist / 64, (
double)fitted_width / 64 ));
4190 af_latin_align_serif_edge( AF_GlyphHints hints,
4196 serif->pos = base->pos + ( serif->opos - base->opos );
4214 af_latin_hint_edges( AF_GlyphHints hints,
4217 AF_AxisHints axis = &hints->axis[dim];
4219 AF_Edge edges = axis->edges;
4220 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
4224 AF_Edge anchor = NULL;
4225 FT_Bool has_non_stem_edges = 0;
4227 AF_StyleClass style_class = hints->metrics->style_class;
4228 AF_ScriptClass script_class = af_script_classes[style_class->script];
4230 FT_Bool top_to_bottom_hinting = 0;
4232#ifdef FT_DEBUG_LEVEL_TRACE
4233 FT_UInt num_actions = 0;
4237 FT_TRACE5((
"latin %s edge hinting (style `%s')\n",
4238 dim == AF_DIMENSION_VERT ?
"horizontal" :
"vertical",
4239 af_style_names[hints->metrics->style_class->style] ));
4241 if ( dim == AF_DIMENSION_VERT )
4242 top_to_bottom_hinting = script_class->top_to_bottom_hinting;
4247 if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
4249 for ( edge = edges; edge < edge_limit; edge++ )
4252 AF_Edge edge1, edge2;
4255 if ( edge->flags & AF_EDGE_DONE )
4270 if ( edge->blue_edge && edge2 && edge2->blue_edge )
4272 FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL;
4273 FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
4278 edge2->blue_edge = NULL;
4279 edge2->flags &= ~AF_EDGE_NEUTRAL;
4283 edge->blue_edge = NULL;
4284 edge->flags &= ~AF_EDGE_NEUTRAL;
4288 blue = edge->blue_edge;
4293 else if ( edge2 && edge2->blue_edge )
4295 blue = edge2->blue_edge;
4303#ifdef FT_DEBUG_LEVEL_TRACE
4305 FT_TRACE5((
" BLUE_ANCHOR: edge %td (opos=%.2f) snapped to %.2f,"
4306 " was %.2f (anchor=edge %td)\n",
4308 (
double)edge1->opos / 64, (
double)blue->fit / 64,
4309 (
double)edge1->pos / 64, edge - edges ));
4311 FT_TRACE5((
" BLUE: edge %td (opos=%.2f) snapped to %.2f,"
4314 (
double)edge1->opos / 64, (
double)blue->fit / 64,
4315 (
double)edge1->pos / 64 ));
4320 edge1->pos = blue->fit;
4321 edge1->flags |= AF_EDGE_DONE;
4323 if ( edge2 && !edge2->blue_edge )
4325 af_latin_align_linked_edge( hints, dim, edge1, edge2 );
4326 edge2->flags |= AF_EDGE_DONE;
4328#ifdef FT_DEBUG_LEVEL_TRACE
4340 for ( edge = edges; edge < edge_limit; edge++ )
4345 if ( edge->flags & AF_EDGE_DONE )
4352 has_non_stem_edges = TRUE;
4359 if ( edge2->blue_edge )
4361 FT_TRACE5((
" ASSERTION FAILED for edge %td\n", edge2 - edges ));
4363 af_latin_align_linked_edge( hints, dim, edge2, edge );
4364 edge->flags |= AF_EDGE_DONE;
4366#ifdef FT_DEBUG_LEVEL_TRACE
4376 FT_Pos org_len, org_center, cur_len;
4377 FT_Pos cur_pos1, error1, error2, u_off, d_off;
4380 org_len = edge2->opos - edge->opos;
4381 cur_len = af_latin_compute_stem_width( hints, dim,
4389 if ( cur_len <= 64 )
4404 org_center = edge->opos + ( org_len >> 1 );
4405 cur_pos1 = FT_PIX_ROUND( org_center );
4407 error1 = org_center - ( cur_pos1 - u_off );
4411 error2 = org_center - ( cur_pos1 + d_off );
4415 if ( error1 < error2 )
4420 edge->pos = cur_pos1 - cur_len / 2;
4421 edge2->pos = edge->pos + cur_len;
4424 edge->pos = FT_PIX_ROUND( edge->opos );
4427 edge->flags |= AF_EDGE_DONE;
4429 FT_TRACE5((
" ANCHOR: edge %td (opos=%.2f) and %td (opos=%.2f)"
4430 " snapped to %.2f and %.2f\n",
4431 edge - edges, (
double)edge->opos / 64,
4432 edge2 - edges, (
double)edge2->opos / 64,
4433 (
double)edge->pos / 64, (
double)edge2->pos / 64 ));
4435 af_latin_align_linked_edge( hints, dim, edge, edge2 );
4437#ifdef FT_DEBUG_LEVEL_TRACE
4443 FT_Pos org_pos, org_len, org_center, cur_len;
4444 FT_Pos cur_pos1, cur_pos2, delta1, delta2;
4447 org_pos = anchor->pos + ( edge->opos - anchor->opos );
4448 org_len = edge2->opos - edge->opos;
4449 org_center = org_pos + ( org_len >> 1 );
4451 cur_len = af_latin_compute_stem_width( hints, dim,
4456 if ( edge2->flags & AF_EDGE_DONE )
4458 FT_TRACE5((
" ADJUST: edge %td (pos=%.2f) moved to %.2f\n",
4459 edge - edges, (
double)edge->pos / 64,
4460 (
double)( edge2->pos - cur_len ) / 64 ));
4462 edge->pos = edge2->pos - cur_len;
4465 else if ( cur_len < 96 )
4467 FT_Pos u_off, d_off;
4470 cur_pos1 = FT_PIX_ROUND( org_center );
4472 if ( cur_len <= 64 )
4483 delta1 = org_center - ( cur_pos1 - u_off );
4487 delta2 = org_center - ( cur_pos1 + d_off );
4491 if ( delta1 < delta2 )
4496 edge->pos = cur_pos1 - cur_len / 2;
4497 edge2->pos = cur_pos1 + cur_len / 2;
4499 FT_TRACE5((
" STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)"
4500 " snapped to %.2f and %.2f\n",
4501 edge - edges, (
double)edge->opos / 64,
4502 edge2 - edges, (
double)edge2->opos / 64,
4503 (
double)edge->pos / 64, (
double)edge2->pos / 64 ));
4508 org_pos = anchor->pos + ( edge->opos - anchor->opos );
4509 org_len = edge2->opos - edge->opos;
4510 org_center = org_pos + ( org_len >> 1 );
4512 cur_len = af_latin_compute_stem_width( hints, dim,
4517 cur_pos1 = FT_PIX_ROUND( org_pos );
4518 delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
4522 cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
4523 delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
4527 edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
4528 edge2->pos = edge->pos + cur_len;
4530 FT_TRACE5((
" STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)"
4531 " snapped to %.2f and %.2f\n",
4532 edge - edges, (
double)edge->opos / 64,
4533 edge2 - edges, (
double)edge2->opos / 64,
4534 (
double)edge->pos / 64, (
double)edge2->pos / 64 ));
4537#ifdef FT_DEBUG_LEVEL_TRACE
4541 edge->flags |= AF_EDGE_DONE;
4542 edge2->flags |= AF_EDGE_DONE;
4544 if ( edge > edges &&
4545 ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
4546 : ( edge->pos < edge[-1].pos ) ) )
4550 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
4552#ifdef FT_DEBUG_LEVEL_TRACE
4553 FT_TRACE5((
" BOUND: edge %td (pos=%.2f) moved to %.2f\n",
4555 (
double)edge->pos / 64,
4556 (
double)edge[-1].pos / 64 ));
4561 edge->pos = edge[-1].pos;
4582 n_edges = edge_limit - edges;
4583 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
4585 AF_Edge edge1, edge2, edge3;
4586 FT_Pos dist1, dist2, span, delta;
4602 dist1 = edge2->opos - edge1->opos;
4603 dist2 = edge3->opos - edge2->opos;
4605 span = dist1 - dist2;
4611 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
4612 edge3->pos -= delta;
4614 edge3->link->pos -= delta;
4617 if ( n_edges == 12 )
4619 ( edges + 8 )->pos -= delta;
4620 ( edges + 11 )->pos -= delta;
4623 edge3->flags |= AF_EDGE_DONE;
4625 edge3->link->flags |= AF_EDGE_DONE;
4629 if ( has_non_stem_edges || !anchor )
4635 for ( edge = edges; edge < edge_limit; edge++ )
4640 if ( edge->flags & AF_EDGE_DONE )
4647 AF_Edge e, top, bottom;
4648 FT_Pos min_pos, max_pos;
4660 delta = edge->serif->opos - edge->opos;
4666 bottom = edge->serif;
4674 if ( delta < 64 + 32 )
4677 min_pos = FT_MIN( FT_MIN( FT_MIN( top->first->first->v,
4678 top->first->last->v ),
4679 FT_MIN( top->last->first->v,
4680 top->last->last->v ) ),
4681 FT_MIN( FT_MIN( bottom->first->first->v,
4682 bottom->first->last->v ),
4683 FT_MIN( bottom->last->first->v,
4684 bottom->last->last->v ) ) );
4685 max_pos = FT_MAX( FT_MAX( FT_MAX( top->first->first->v,
4686 top->first->last->v ),
4687 FT_MAX( top->last->first->v,
4688 top->last->last->v ) ),
4689 FT_MAX( FT_MAX( bottom->first->first->v,
4690 bottom->first->last->v ),
4691 FT_MAX( bottom->last->first->v,
4692 bottom->last->last->v ) ) );
4694 for ( e = bottom + 1; e < top; e++ )
4696 FT_Pos e_min = FT_MIN( FT_MIN( e->first->first->v,
4697 e->first->last->v ),
4698 FT_MIN( e->last->first->v,
4699 e->last->last->v ) );
4700 FT_Pos e_max = FT_MAX( FT_MAX( e->first->first->v,
4701 e->first->last->v ),
4702 FT_MAX( e->last->first->v,
4703 e->last->last->v ) );
4705 if ( !( ( e_min < min_pos && e_max < min_pos ) ||
4706 ( e_min > max_pos && e_max > max_pos ) ) )
4713 if ( delta == 1000 )
4718 if ( delta < 64 + 16 )
4720 af_latin_align_serif_edge( hints, edge->serif, edge );
4721 FT_TRACE5((
" SERIF: edge %td (opos=%.2f) serif to %td (opos=%.2f)"
4722 " aligned to %.2f\n",
4723 edge - edges, (
double)edge->opos / 64,
4724 edge->serif - edges, (
double)edge->serif->opos / 64,
4725 (
double)edge->pos / 64 ));
4729 edge->pos = FT_PIX_ROUND( edge->opos );
4731 FT_TRACE5((
" SERIF_ANCHOR: edge %td (opos=%.2f)"
4732 " snapped to %.2f\n",
4734 (
double)edge->opos / 64, (
double)edge->pos / 64 ));
4738 AF_Edge before, after;
4741 for ( before = edge - 1; before >= edges; before-- )
4742 if ( before->flags & AF_EDGE_DONE )
4745 for ( after = edge + 1; after < edge_limit; after++ )
4746 if ( after->flags & AF_EDGE_DONE )
4749 if ( before >= edges && before < edge &&
4750 after < edge_limit && after > edge )
4752 if ( after->opos == before->opos )
4753 edge->pos = before->pos;
4755 edge->pos = before->pos +
4756 FT_MulDiv( edge->opos - before->opos,
4757 after->pos - before->pos,
4758 after->opos - before->opos );
4760 FT_TRACE5((
" SERIF_LINK1: edge %td (opos=%.2f) snapped to %.2f"
4761 " from %td (opos=%.2f)\n",
4762 edge - edges, (
double)edge->opos / 64,
4763 (
double)edge->pos / 64,
4764 before - edges, (
double)before->opos / 64 ));
4768 edge->pos = anchor->pos +
4769 ( ( edge->opos - anchor->opos + 16 ) & ~31 );
4770 FT_TRACE5((
" SERIF_LINK2: edge %td (opos=%.2f)"
4771 " snapped to %.2f\n",
4773 (
double)edge->opos / 64, (
double)edge->pos / 64 ));
4777#ifdef FT_DEBUG_LEVEL_TRACE
4780 edge->flags |= AF_EDGE_DONE;
4782 if ( edge > edges &&
4783 ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
4784 : ( edge->pos < edge[-1].pos ) ) )
4788 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
4790#ifdef FT_DEBUG_LEVEL_TRACE
4791 FT_TRACE5((
" BOUND: edge %td (pos=%.2f) moved to %.2f\n",
4793 (
double)edge->pos / 64,
4794 (
double)edge[-1].pos / 64 ));
4798 edge->pos = edge[-1].pos;
4802 if ( edge + 1 < edge_limit &&
4803 edge[1].flags & AF_EDGE_DONE &&
4804 ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos )
4805 : ( edge->pos > edge[1].pos ) ) )
4809 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
4811#ifdef FT_DEBUG_LEVEL_TRACE
4812 FT_TRACE5((
" BOUND: edge %td (pos=%.2f) moved to %.2f\n",
4814 (
double)edge->pos / 64,
4815 (
double)edge[1].pos / 64 ));
4820 edge->pos = edge[1].pos;
4826#ifdef FT_DEBUG_LEVEL_TRACE
4828 FT_TRACE5((
" (none)\n" ));
4829 FT_TRACE5((
"\n" ));
4837 af_latin_hints_apply( FT_UInt glyph_index,
4838 AF_GlyphHints hints,
4839 FT_Outline* outline,
4840 AF_StyleMetrics metrics_ )
4842 AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
4849 FT_Pos accent_height_limit = 0;
4852 error = af_glyph_hints_reload( hints, outline );
4857 if ( AF_HINTS_DO_HORIZONTAL( hints ) )
4859 axis = &metrics->axis[AF_DIMENSION_HORZ];
4860 error = af_latin_hints_detect_features( hints,
4863 AF_DIMENSION_HORZ );
4868 if ( AF_HINTS_DO_VERTICAL( hints ) )
4872 FT_Int top_tilde_contour = 0;
4873 FT_Int bottom_tilde_contour = 0;
4875 FT_Int below_top_tilde_contour = 0;
4876 FT_Int above_bottom_tilde_contour = 0;
4878 AF_LatinBlue capital_top_blue = NULL;
4879 AF_LatinBlue capital_bottom_blue = NULL;
4881 AF_LatinBlue small_top_blue = NULL;
4882 AF_LatinBlue small_bottom_blue = NULL;
4884 FT_Bool have_flags = FALSE;
4886 FT_Bool is_top_tilde = FALSE;
4887 FT_Bool is_bottom_tilde = FALSE;
4889 FT_Bool is_below_top_tilde = FALSE;
4890 FT_Bool is_above_bottom_tilde = FALSE;
4892 FT_Bool ignore_capital_top = FALSE;
4893 FT_Bool ignore_capital_bottom = FALSE;
4895 FT_Bool ignore_small_top = FALSE;
4896 FT_Bool ignore_small_bottom = FALSE;
4898 FT_Bool do_height_check = TRUE;
4904 val = ft_hash_num_lookup( (FT_Int)glyph_index,
4905 metrics->root.reverse_charmap );
4908 FT_UInt codepoint = *val;
4909 FT_UInt32 adj_type = af_adjustment_database_lookup( codepoint );
4914 have_flags = !!adj_type;
4916 is_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP );
4917 is_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM );
4919 is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 );
4920 is_above_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 );
4922 ignore_capital_top = !!( adj_type & AF_IGNORE_CAPITAL_TOP );
4923 ignore_capital_bottom = !!( adj_type & AF_IGNORE_CAPITAL_BOTTOM );
4925 ignore_small_top = !!( adj_type & AF_IGNORE_SMALL_TOP );
4926 ignore_small_bottom = !!( adj_type & AF_IGNORE_SMALL_BOTTOM );
4928 do_height_check = !( adj_type & AF_ADJUST_NO_HEIGHT_CHECK );
4932 if ( is_top_tilde || is_bottom_tilde ||
4933 is_below_top_tilde || is_above_bottom_tilde )
4934 af_compute_vertical_extrema( hints );
4937 if ( is_below_top_tilde )
4939 below_top_tilde_contour = af_find_second_highest_contour( hints );
4941 y_offset = af_latin_stretch_top_tilde(
4942 hints, below_top_tilde_contour );
4943 y_offset += af_latin_align_top_tilde(
4944 hints, below_top_tilde_contour );
4946 limit = hints->contour_y_minima[below_top_tilde_contour];
4947 af_move_contours_up( hints, limit, y_offset );
4949 if ( is_above_bottom_tilde )
4951 above_bottom_tilde_contour = af_find_second_lowest_contour( hints );
4953 y_offset = af_latin_stretch_bottom_tilde(
4954 hints, above_bottom_tilde_contour );
4955 y_offset -= af_latin_align_bottom_tilde(
4956 hints, above_bottom_tilde_contour );
4958 limit = hints->contour_y_maxima[above_bottom_tilde_contour];
4959 af_move_contours_down( hints, limit, y_offset );
4964 top_tilde_contour = af_find_highest_contour( hints );
4966 (void)af_latin_stretch_top_tilde( hints, top_tilde_contour );
4967 (void)af_latin_align_top_tilde( hints, top_tilde_contour );
4969 if ( is_bottom_tilde )
4971 bottom_tilde_contour = af_find_lowest_contour( hints );
4973 (void)af_latin_stretch_bottom_tilde( hints, bottom_tilde_contour );
4974 (void)af_latin_align_bottom_tilde( hints, bottom_tilde_contour );
4977 axis = &metrics->axis[AF_DIMENSION_VERT];
4978 error = af_latin_hints_detect_features( hints,
4981 AF_DIMENSION_VERT );
4985 af_latin_get_base_glyph_blues( hints,
4988 &capital_bottom_blue );
4989 af_latin_get_base_glyph_blues( hints,
4992 &small_bottom_blue );
4994 if ( do_height_check )
5002 if ( small_top_blue && small_bottom_blue )
5003 accent_height_limit = 2 * ( small_top_blue->shoot.cur -
5004 small_bottom_blue->shoot.cur ) / 3;
5006 else if ( capital_top_blue && capital_bottom_blue )
5007 accent_height_limit = ( capital_top_blue->shoot.cur -
5008 capital_bottom_blue->shoot.cur ) / 2;
5012 accent_height_limit = FT_MulFix( metrics->units_per_em * 4 / 10,
5013 metrics->root.scaler.y_scale );
5017 if ( capital_top_blue && capital_bottom_blue )
5019 if ( ignore_capital_top )
5020 af_latin_ignore_top( hints,
5021 capital_top_blue, capital_bottom_blue );
5022 if ( ignore_capital_bottom )
5023 af_latin_ignore_bottom( hints,
5024 capital_top_blue, capital_bottom_blue );
5026 if ( small_top_blue && small_bottom_blue )
5028 if ( ignore_small_top )
5029 af_latin_ignore_top( hints,
5030 small_top_blue, small_bottom_blue );
5031 if ( ignore_small_bottom )
5032 af_latin_ignore_bottom( hints,
5033 small_top_blue, small_bottom_blue );
5040 if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) )
5041 af_latin_hints_compute_blue_edges( hints, metrics );
5045 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
5047 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
5048 ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
5050 af_latin_hint_edges( hints, (AF_Dimension)dim );
5051 af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
5052 af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
5053 af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
5054 af_glyph_hints_apply_vertical_separation_adjustments(
5058 accent_height_limit,
5059 metrics->root.reverse_charmap );
5063 af_glyph_hints_save( hints, outline );
5079 AF_DEFINE_WRITING_SYSTEM_CLASS(
5080 af_latin_writing_system_class,
5082 AF_WRITING_SYSTEM_LATIN,
5084 sizeof ( AF_LatinMetricsRec ),
5086 (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,
5087 (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,
5088 (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done,
5089 (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths,
5091 (AF_WritingSystem_InitHintsFunc) af_latin_hints_init,
5092 (AF_WritingSystem_ApplyHintsFunc) af_latin_hints_apply