28#define FT_COMPONENT pshalgo
32 PSH_Hint_Table ps_debug_hint_table = NULL;
33 PSH_HintFunc ps_debug_hint_func = NULL;
34 PSH_Glyph ps_debug_glyph = NULL;
38#define COMPUTE_INFLEXS
52 psh_hint_overlap( PSH_Hint hint1,
55 return ADD_INT( hint1->org_pos, hint1->org_len ) >= hint2->org_pos &&
56 ADD_INT( hint2->org_pos, hint2->org_len ) >= hint1->org_pos;
62 psh_hint_table_done( PSH_Hint_Table table,
65 FT_FREE( table->zones );
69 FT_FREE( table->sort );
70 FT_FREE( table->hints );
73 table->sort_global = NULL;
79 psh_hint_table_deactivate( PSH_Hint_Table table )
81 FT_UInt count = table->max_hints;
82 PSH_Hint hint = table->hints;
85 for ( ; count > 0; count--, hint++ )
87 psh_hint_deactivate( hint );
95 psh_hint_table_record( PSH_Hint_Table table,
98 PSH_Hint hint = table->hints + idx;
101 if ( idx >= table->max_hints )
103 FT_TRACE0((
"psh_hint_table_record: invalid hint index %u\n", idx ));
108 if ( psh_hint_is_active( hint ) )
111 psh_hint_activate( hint );
116 PSH_Hint* sorted = table->sort_global;
117 FT_UInt count = table->num_hints;
122 for ( ; count > 0; count--, sorted++ )
126 if ( psh_hint_overlap( hint, hint2 ) )
128 hint->parent = hint2;
134 if ( table->num_hints < table->max_hints )
135 table->sort_global[table->num_hints++] = hint;
137 FT_TRACE0((
"psh_hint_table_record: too many sorted hints! BUG!\n" ));
142 psh_hint_table_record_mask( PSH_Hint_Table table,
145 FT_Int mask = 0, val = 0;
146 FT_Byte* cursor = hint_mask->bytes;
150 limit = hint_mask->num_bits;
152 for ( idx = 0; idx < limit; idx++ )
161 psh_hint_table_record( table, idx );
170 psh_hint_table_init( PSH_Hint_Table table,
172 PS_Mask_Table hint_masks,
173 PS_Mask_Table counter_masks,
179 FT_UNUSED( counter_masks );
182 count = hints->num_hints;
185 if ( FT_QNEW_ARRAY( table->sort, 2 * count ) ||
186 FT_QNEW_ARRAY( table->hints, count ) ||
187 FT_QNEW_ARRAY( table->zones, 2 * count + 1 ) )
190 table->max_hints = count;
191 table->sort_global = FT_OFFSET( table->sort, count );
192 table->num_hints = 0;
193 table->num_zones = 0;
198 PSH_Hint write = table->hints;
199 PS_Hint read = hints->hints;
202 for ( ; count > 0; count--, write++, read++ )
204 write->org_pos = read->pos;
205 write->org_len = read->len;
206 write->flags = read->flags;
214 PS_Mask mask = hint_masks->masks;
217 count = hint_masks->num_masks;
218 table->hint_masks = hint_masks;
220 for ( ; count > 0; count--, mask++ )
221 psh_hint_table_record_mask( table, mask );
225 if ( table->num_hints != table->max_hints )
230 FT_TRACE0((
"psh_hint_table_init: missing/incorrect hint masks\n" ));
232 count = table->max_hints;
233 for ( idx = 0; idx < count; idx++ )
234 psh_hint_table_record( table, idx );
243 psh_hint_table_activate_mask( PSH_Hint_Table table,
246 FT_Int mask = 0, val = 0;
247 FT_Byte* cursor = hint_mask->bytes;
248 FT_UInt idx, limit, count;
251 limit = hint_mask->num_bits;
254 psh_hint_table_deactivate( table );
256 for ( idx = 0; idx < limit; idx++ )
266 PSH_Hint hint = &table->hints[idx];
269 if ( !psh_hint_is_active( hint ) )
274 PSH_Hint* sort = table->sort;
278 for ( count2 = count; count2 > 0; count2--, sort++ )
281 if ( psh_hint_overlap( hint, hint2 ) )
282 FT_TRACE0((
"psh_hint_table_activate_mask:"
283 " found overlapping hints\n" ))
291 psh_hint_activate( hint );
292 if ( count < table->max_hints )
293 table->sort[count++] = hint;
295 FT_TRACE0((
"psh_hint_tableactivate_mask:"
296 " too many active hints\n" ));
303 table->num_hints = count;
309 PSH_Hint hint1, hint2;
310 PSH_Hint* sort = table->sort;
315 for ( i1 = 1; i1 < count; i1++ )
319 for ( i2 = i1 - 1; i2 < i1; i2-- )
323 if ( hint2->org_pos < hint1->org_pos )
326 sort[i2 + 1] = hint2;
344 psh_dimension_quantize_len( PSH_Dimension dim,
346 FT_Bool do_snapping )
352 FT_Pos delta = len - dim->stdw.widths[0].cur;
360 len = dim->stdw.widths[0].cur;
367 delta = ( len & 63 );
373 else if ( delta < 32 )
376 else if ( delta < 54 )
383 len = FT_PIX_ROUND( len );
387 len = FT_PIX_ROUND( len );
397 ps_simple_scale( PSH_Hint_Table table,
405 for ( count = 0; count < table->max_hints; count++ )
407 PSH_Hint hint = table->hints + count;
410 hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
411 hint->cur_len = FT_MulFix( hint->org_len, scale );
413 if ( ps_debug_hint_func )
414 ps_debug_hint_func( hint, dimension );
422 psh_hint_snap_stem_side_delta( FT_Fixed pos,
425 FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos;
426 FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len;
429 if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) )
437 psh_hint_align( PSH_Hint hint,
442 PSH_Dimension dim = &globals->dimension[dimension];
443 FT_Fixed scale = dim->scale_mult;
444 FT_Fixed delta = dim->scale_delta;
447 if ( !psh_hint_is_fitted( hint ) )
449 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
450 FT_Pos len = FT_MulFix( hint->org_len, scale );
454 PSH_AlignmentRec align;
458 if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
459 ( dimension == 1 && !glyph->do_vert_hints ) )
464 psh_hint_set_fitted( hint );
471 do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
472 ( dimension == 1 && glyph->do_vert_snapping );
474 hint->cur_len = fit_len = len;
477 align.align = PSH_BLUE_ALIGN_NONE;
478 align.align_bot = align.align_top = 0;
480 if ( dimension == 1 )
481 psh_blues_snap_stem( &globals->blues,
482 ADD_INT( hint->org_pos, hint->org_len ),
486 switch ( align.align )
488 case PSH_BLUE_ALIGN_TOP:
490 hint->cur_pos = align.align_top - fit_len;
493 case PSH_BLUE_ALIGN_BOT:
495 hint->cur_pos = align.align_bot;
498 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
500 hint->cur_pos = align.align_bot;
501 hint->cur_len = align.align_top - align.align_bot;
506 PSH_Hint parent = hint->parent;
511 FT_Pos par_org_center, par_cur_center;
512 FT_Pos cur_org_center, cur_delta;
516 if ( !psh_hint_is_fitted( parent ) )
517 psh_hint_align( parent, globals, dimension, glyph );
522 par_org_center = parent->org_pos + ( parent->org_len >> 1 );
523 par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
524 cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
526 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
527 pos = par_cur_center + cur_delta - ( len >> 1 );
531 hint->cur_len = fit_len;
537 if ( glyph->do_stem_adjust )
557 pos = FT_PIX_FLOOR( pos + ( len >> 1 ) );
576 FT_Pos left_nearest = FT_PIX_ROUND( pos );
577 FT_Pos right_nearest = FT_PIX_ROUND( pos + len );
578 FT_Pos left_disp = left_nearest - pos;
579 FT_Pos right_disp = right_nearest - ( pos + len );
583 left_disp = -left_disp;
584 if ( right_disp < 0 )
585 right_disp = -right_disp;
586 if ( left_disp <= right_disp )
594 pos = FT_PIX_ROUND( pos );
599 len = psh_dimension_quantize_len( dim, len, 0 );
605 hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len );
618 len = FT_PIX_ROUND( len );
620 switch ( align.align )
622 case PSH_BLUE_ALIGN_TOP:
623 hint->cur_pos = align.align_top - len;
627 case PSH_BLUE_ALIGN_BOT:
631 case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
639 pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32;
641 pos = FT_PIX_ROUND( pos + ( len >> 1 ) );
643 hint->cur_pos = pos - ( len >> 1 );
648 psh_hint_set_fitted( hint );
651 if ( ps_debug_hint_func )
652 ps_debug_hint_func( hint, dimension );
665 psh_hint_align_light( PSH_Hint hint,
670 PSH_Dimension dim = &globals->dimension[dimension];
671 FT_Fixed scale = dim->scale_mult;
672 FT_Fixed delta = dim->scale_delta;
675 if ( !psh_hint_is_fitted( hint ) )
677 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
678 FT_Pos len = FT_MulFix( hint->org_len, scale );
682 PSH_AlignmentRec align;
686 if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
687 ( dimension == 1 && !glyph->do_vert_hints ) )
692 psh_hint_set_fitted( hint );
698 hint->cur_len = fit_len;
701 align.align = PSH_BLUE_ALIGN_NONE;
702 align.align_bot = align.align_top = 0;
704 if ( dimension == 1 )
705 psh_blues_snap_stem( &globals->blues,
706 ADD_INT( hint->org_pos, hint->org_len ),
710 switch ( align.align )
712 case PSH_BLUE_ALIGN_TOP:
714 hint->cur_pos = align.align_top - fit_len;
717 case PSH_BLUE_ALIGN_BOT:
719 hint->cur_pos = align.align_bot;
722 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
724 hint->cur_pos = align.align_bot;
725 hint->cur_len = align.align_top - align.align_bot;
730 PSH_Hint parent = hint->parent;
735 FT_Pos par_org_center, par_cur_center;
736 FT_Pos cur_org_center, cur_delta;
740 if ( !psh_hint_is_fitted( parent ) )
741 psh_hint_align_light( parent, globals, dimension, glyph );
743 par_org_center = parent->org_pos + ( parent->org_len / 2 );
744 par_cur_center = parent->cur_pos + ( parent->cur_len / 2 );
745 cur_org_center = hint->org_pos + ( hint->org_len / 2 );
747 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
748 pos = par_cur_center + cur_delta - ( len >> 1 );
759 if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
760 pos += psh_hint_snap_stem_side_delta ( pos, len );
788 FT_Fixed frac_len = len & 63;
789 FT_Fixed center = pos + ( len >> 1 );
790 FT_Fixed delta_a, delta_b;
793 if ( ( len / 64 ) & 1 )
795 delta_a = FT_PIX_FLOOR( center ) + 32 - center;
796 delta_b = FT_PIX_ROUND( center ) - center;
800 delta_a = FT_PIX_ROUND( center ) - center;
801 delta_b = FT_PIX_FLOOR( center ) + 32 - center;
811 pos += psh_hint_snap_stem_side_delta ( pos, len );
813 else if ( frac_len < 48 )
815 FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos,
818 if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) )
833 psh_hint_set_fitted( hint );
836 if ( ps_debug_hint_func )
837 ps_debug_hint_func( hint, dimension );
846 psh_hint_table_align_hints( PSH_Hint_Table table,
856 PSH_Dimension dim = &globals->dimension[dimension];
857 FT_Fixed scale = dim->scale_mult;
858 FT_Fixed delta = dim->scale_delta;
861 if ( ps_debug_no_vert_hints && dimension == 0 )
863 ps_simple_scale( table, scale, delta, dimension );
867 if ( ps_debug_no_horz_hints && dimension == 1 )
869 ps_simple_scale( table, scale, delta, dimension );
876 count = table->max_hints;
878 for ( ; count > 0; count--, hint++ )
879 psh_hint_align( hint, globals, dimension, glyph );
896#include FT_CONFIG_STANDARD_LIBRARY_H
899 psh_print_zone( PSH_Zone zone )
901 printf(
"zone [scale,delta,min,max] = [%.5f,%.2f,%d,%d]\n",
902 zone->scale / 65536.0,
919#define psh_corner_is_flat ft_corner_is_flat
920#define psh_corner_orientation ft_corner_orientation
923#ifdef COMPUTE_INFLEXS
927 psh_glyph_compute_inflections( PSH_Glyph glyph )
932 for ( n = 0; n < glyph->num_contours; n++ )
934 PSH_Point first, start, end, before, after;
935 FT_Pos in_x, in_y, out_x, out_y;
936 FT_Int orient_prev, orient_cur;
941 if ( glyph->contours[n].count < 4 )
945 first = glyph->contours[n].start;
954 in_x = end->org_u - start->org_u;
955 in_y = end->org_v - start->org_v;
957 }
while ( in_x == 0 && in_y == 0 );
966 before = before->prev;
967 if ( before == first )
970 out_x = start->org_u - before->org_u;
971 out_y = start->org_v - before->org_v;
973 }
while ( out_x == 0 && out_y == 0 );
975 orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y );
977 }
while ( orient_prev == 0 );
994 if ( after == first )
997 out_x = after->org_u - end->org_u;
998 out_y = after->org_v - end->org_v;
1000 }
while ( out_x == 0 && out_y == 0 );
1002 orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y );
1004 }
while ( orient_cur == 0 );
1006 if ( ( orient_cur ^ orient_prev ) < 0 )
1010 psh_point_set_inflex( start );
1011 start = start->next;
1013 while ( start != end );
1015 psh_point_set_inflex( start );
1020 orient_prev = orient_cur;
1024 }
while ( !finished );
1035 psh_glyph_done( PSH_Glyph glyph )
1037 FT_Memory memory = glyph->memory;
1040 psh_hint_table_done( &glyph->hint_tables[1], memory );
1041 psh_hint_table_done( &glyph->hint_tables[0], memory );
1043 FT_FREE( glyph->points );
1044 FT_FREE( glyph->contours );
1046 glyph->num_points = 0;
1047 glyph->num_contours = 0;
1049 glyph->memory = NULL;
1054 psh_compute_dir( FT_Pos dx,
1058 PSH_Dir result = PSH_DIR_NONE;
1067 result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT;
1069 else if ( ax * 12 < ay )
1072 result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN;
1081 psh_glyph_load_points( PSH_Glyph glyph,
1084 FT_Vector* vec = glyph->outline->points;
1085 PSH_Point point = glyph->points;
1086 FT_UInt count = glyph->num_points;
1089 for ( ; count > 0; count--, point++, vec++ )
1093 if ( dimension == 0 )
1095 point->org_u = vec->x;
1096 point->org_v = vec->y;
1100 point->org_u = vec->y;
1101 point->org_v = vec->x;
1105 point->org_x = vec->x;
1106 point->org_y = vec->y;
1115 psh_glyph_save_points( PSH_Glyph glyph,
1119 PSH_Point point = glyph->points;
1120 FT_Vector* vec = glyph->outline->points;
1121 FT_Byte* tags = glyph->outline->tags;
1124 for ( n = 0; n < glyph->num_points; n++ )
1126 if ( dimension == 0 )
1127 vec[n].x = point->cur_u;
1129 vec[n].y = point->cur_u;
1131 if ( psh_point_is_strong( point ) )
1132 tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
1136 if ( dimension == 0 )
1138 point->cur_x = point->cur_u;
1139 point->flags_x = point->flags2 | point->flags;
1143 point->cur_y = point->cur_u;
1144 point->flags_y = point->flags2 | point->flags;
1155 psh_glyph_init( PSH_Glyph glyph,
1156 FT_Outline* outline,
1158 PSH_Globals globals )
1167 memory = glyph->memory = globals->memory;
1170 if ( FT_QNEW_ARRAY( glyph->points, outline->n_points ) ||
1171 FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) )
1174 glyph->num_points = outline->n_points;
1175 glyph->num_contours = outline->n_contours;
1178 FT_UInt first = 0, next, n;
1179 PSH_Point points = glyph->points;
1180 PSH_Contour contour = glyph->contours;
1183 for ( n = 0; n < glyph->num_contours; n++ )
1189 next = outline->contours[n] + 1;
1190 count = next - first;
1192 contour->start = points + first;
1193 contour->count = count;
1197 point = points + first;
1199 point->prev = points + next - 1;
1200 point->contour = contour;
1202 for ( ; count > 1; count-- )
1204 point[0].next = point + 1;
1205 point[1].prev = point;
1207 point->contour = contour;
1209 point->next = points + first;
1218 PSH_Point points = glyph->points;
1219 PSH_Point point = points;
1220 FT_Vector* vec = outline->points;
1224 for ( n = 0; n < glyph->num_points; n++, point++ )
1226 FT_Int n_prev = (FT_Int)( point->prev - points );
1227 FT_Int n_next = (FT_Int)( point->next - points );
1228 FT_Pos dxi, dyi, dxo, dyo;
1232 if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
1233 psh_point_set_off( point );
1235 dxi = vec[n].x - vec[n_prev].x;
1236 dyi = vec[n].y - vec[n_prev].y;
1238 point->dir_in = psh_compute_dir( dxi, dyi );
1240 dxo = vec[n_next].x - vec[n].x;
1241 dyo = vec[n_next].y - vec[n].y;
1243 point->dir_out = psh_compute_dir( dxo, dyo );
1246 if ( psh_point_is_off( point ) )
1247 psh_point_set_smooth( point );
1249 else if ( point->dir_in == point->dir_out )
1251 if ( point->dir_out != PSH_DIR_NONE ||
1252 psh_corner_is_flat( dxi, dyi, dxo, dyo ) )
1253 psh_point_set_smooth( point );
1258 glyph->outline = outline;
1259 glyph->globals = globals;
1261#ifdef COMPUTE_INFLEXS
1262 psh_glyph_load_points( glyph, 0 );
1263 psh_glyph_compute_inflections( glyph );
1267 error = psh_hint_table_init( &glyph->hint_tables [0],
1268 &ps_hints->dimension[0].hints,
1269 &ps_hints->dimension[0].masks,
1270 &ps_hints->dimension[0].counters,
1275 error = psh_hint_table_init( &glyph->hint_tables [1],
1276 &ps_hints->dimension[1].hints,
1277 &ps_hints->dimension[1].masks,
1278 &ps_hints->dimension[1].counters,
1290 psh_glyph_compute_extrema( PSH_Glyph glyph )
1296 for ( n = 0; n < glyph->num_contours; n++ )
1298 PSH_Point first = glyph->contours[n].start;
1299 PSH_Point point, before, after;
1302 if ( glyph->contours[n].count == 0 )
1310 before = before->prev;
1311 if ( before == first )
1314 }
while ( before->org_u == point->org_u );
1316 first = point = before->next;
1323 after = after->next;
1324 if ( after == first )
1327 }
while ( after->org_u == point->org_u );
1329 if ( before->org_u < point->org_u )
1331 if ( after->org_u < point->org_u )
1339 if ( after->org_u > point->org_u )
1345 psh_point_set_extremum( point );
1346 point = point->next;
1348 }
while ( point != after );
1352 before = after->prev;
1363 for ( n = 0; n < glyph->num_points; n++ )
1365 PSH_Point point, before, after;
1368 point = &glyph->points[n];
1372 if ( psh_point_is_extremum( point ) )
1376 before = before->prev;
1377 if ( before == point )
1380 }
while ( before->org_v == point->org_v );
1384 after = after->next;
1385 if ( after == point )
1388 }
while ( after->org_v == point->org_v );
1391 if ( before->org_v < point->org_v &&
1392 after->org_v > point->org_v )
1394 psh_point_set_positive( point );
1396 else if ( before->org_v > point->org_v &&
1397 after->org_v < point->org_v )
1399 psh_point_set_negative( point );
1410 psh_hint_table_find_strong_points( PSH_Hint_Table table,
1416 PSH_Hint* sort = table->sort;
1417 FT_UInt num_hints = table->num_hints;
1420 for ( ; count > 0; count--, point++ )
1423 FT_Pos org_u = point->org_u;
1426 if ( psh_point_is_strong( point ) )
1430 (PSH_Dir)( ( point->dir_in | point->dir_out ) & major_dir );
1432 if ( point_dir & ( PSH_DIR_DOWN | PSH_DIR_RIGHT ) )
1437 for ( nn = 0; nn < num_hints; nn++ )
1439 PSH_Hint hint = sort[nn];
1440 FT_Pos d = org_u - hint->org_pos;
1443 if ( d < threshold && -d < threshold )
1445 psh_point_set_strong( point );
1446 point->flags2 |= PSH_POINT_EDGE_MIN;
1452 else if ( point_dir & ( PSH_DIR_UP | PSH_DIR_LEFT ) )
1457 for ( nn = 0; nn < num_hints; nn++ )
1459 PSH_Hint hint = sort[nn];
1460 FT_Pos d = org_u - hint->org_pos - hint->org_len;
1463 if ( d < threshold && -d < threshold )
1465 psh_point_set_strong( point );
1466 point->flags2 |= PSH_POINT_EDGE_MAX;
1474 else if ( psh_point_is_extremum( point ) )
1477 FT_UInt nn, min_flag, max_flag;
1480 if ( major_dir == PSH_DIR_HORIZONTAL )
1482 min_flag = PSH_POINT_POSITIVE;
1483 max_flag = PSH_POINT_NEGATIVE;
1487 min_flag = PSH_POINT_NEGATIVE;
1488 max_flag = PSH_POINT_POSITIVE;
1491 if ( point->flags2 & min_flag )
1493 for ( nn = 0; nn < num_hints; nn++ )
1495 PSH_Hint hint = sort[nn];
1496 FT_Pos d = org_u - hint->org_pos;
1499 if ( d < threshold && -d < threshold )
1501 point->flags2 |= PSH_POINT_EDGE_MIN;
1503 psh_point_set_strong( point );
1508 else if ( point->flags2 & max_flag )
1510 for ( nn = 0; nn < num_hints; nn++ )
1512 PSH_Hint hint = sort[nn];
1513 FT_Pos d = org_u - hint->org_pos - hint->org_len;
1516 if ( d < threshold && -d < threshold )
1518 point->flags2 |= PSH_POINT_EDGE_MAX;
1520 psh_point_set_strong( point );
1528 for ( nn = 0; nn < num_hints; nn++ )
1530 PSH_Hint hint = sort[nn];
1533 if ( org_u >= hint->org_pos &&
1534 org_u <= ADD_INT( hint->org_pos, hint->org_len ) )
1549#define PSH_STRONG_THRESHOLD 32
1553#define PSH_STRONG_THRESHOLD_MAXIMUM 12
1558 psh_glyph_find_strong_points( PSH_Glyph glyph,
1564 PSH_Hint_Table table = &glyph->hint_tables[dimension];
1565 PS_Mask mask = table->hint_masks->masks;
1566 FT_UInt num_masks = table->hint_masks->num_masks;
1568 PSH_Dir major_dir = ( dimension == 0 ) ? PSH_DIR_VERTICAL
1569 : PSH_DIR_HORIZONTAL;
1570 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1571 FT_Fixed scale = dim->scale_mult;
1575 threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale );
1576 if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM )
1577 threshold = PSH_STRONG_THRESHOLD_MAXIMUM;
1580 if ( num_masks > 1 && glyph->num_points > 0 )
1583 first = mask->end_point > glyph->num_points
1587 for ( ; num_masks > 1; num_masks--, mask++ )
1589 FT_UInt next = FT_MIN( mask->end_point, glyph->num_points );
1594 FT_UInt count = next - first;
1595 PSH_Point point = glyph->points + first;
1598 psh_hint_table_activate_mask( table, mask );
1600 psh_hint_table_find_strong_points( table, point, count,
1601 threshold, major_dir );
1608 if ( num_masks == 1 )
1610 FT_UInt count = glyph->num_points;
1611 PSH_Point point = glyph->points;
1614 psh_hint_table_activate_mask( table, table->hint_masks->masks );
1616 psh_hint_table_find_strong_points( table, point, count,
1617 threshold, major_dir );
1623 FT_UInt count = glyph->num_points;
1624 PSH_Point point = glyph->points;
1627 for ( ; count > 0; count--, point++ )
1628 if ( point->hint && !psh_point_is_strong( point ) )
1629 psh_point_set_strong( point );
1637 psh_glyph_find_blue_points( PSH_Blues blues,
1640 PSH_Blue_Table table;
1642 FT_UInt glyph_count = glyph->num_points;
1644 PSH_Point point = glyph->points;
1647 for ( ; glyph_count > 0; glyph_count--, point++ )
1653 if ( !( point->dir_in & PSH_DIR_HORIZONTAL ) &&
1654 !( point->dir_out & PSH_DIR_HORIZONTAL ) )
1658 if ( psh_point_is_strong( point ) )
1664 table = &blues->normal_top;
1665 blue_count = table->count;
1666 zone = table->zones;
1668 for ( ; blue_count > 0; blue_count--, zone++ )
1670 FT_Pos delta = y - zone->org_bottom;
1673 if ( delta < -blues->blue_fuzz )
1676 if ( y <= zone->org_top + blues->blue_fuzz )
1677 if ( blues->no_overshoots || delta <= blues->blue_threshold )
1679 point->cur_u = zone->cur_bottom;
1680 psh_point_set_strong( point );
1681 psh_point_set_fitted( point );
1686 table = &blues->normal_bottom;
1687 blue_count = table->count;
1688 zone = table->zones + blue_count - 1;
1690 for ( ; blue_count > 0; blue_count--, zone-- )
1692 FT_Pos delta = zone->org_top - y;
1695 if ( delta < -blues->blue_fuzz )
1698 if ( y >= zone->org_bottom - blues->blue_fuzz )
1699 if ( blues->no_overshoots || delta < blues->blue_threshold )
1701 point->cur_u = zone->cur_top;
1702 psh_point_set_strong( point );
1703 psh_point_set_fitted( point );
1712 psh_glyph_interpolate_strong_points( PSH_Glyph glyph,
1715 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1716 FT_Fixed scale = dim->scale_mult;
1718 FT_UInt count = glyph->num_points;
1719 PSH_Point point = glyph->points;
1722 for ( ; count > 0; count--, point++ )
1724 PSH_Hint hint = point->hint;
1732 if ( psh_point_is_edge_min( point ) )
1733 point->cur_u = hint->cur_pos;
1735 else if ( psh_point_is_edge_max( point ) )
1736 point->cur_u = hint->cur_pos + hint->cur_len;
1740 delta = point->org_u - hint->org_pos;
1743 point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
1745 else if ( delta >= hint->org_len )
1746 point->cur_u = hint->cur_pos + hint->cur_len +
1747 FT_MulFix( delta - hint->org_len, scale );
1750 point->cur_u = hint->cur_pos +
1751 FT_MulDiv( delta, hint->cur_len,
1754 psh_point_set_fitted( point );
1760#define PSH_MAX_STRONG_INTERNAL 16
1763 psh_glyph_interpolate_normal_points( PSH_Glyph glyph,
1770 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1771 FT_Fixed scale = dim->scale_mult;
1772 FT_Memory memory = glyph->memory;
1774 PSH_Point* strongs = NULL;
1775 PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL];
1776 FT_UInt num_strongs = 0;
1778 PSH_Point points = glyph->points;
1779 PSH_Point points_end = points + glyph->num_points;
1784 for ( point = points; point < points_end; point++ )
1786 if ( psh_point_is_strong( point ) )
1790 if ( num_strongs == 0 )
1795 if ( num_strongs <= PSH_MAX_STRONG_INTERNAL )
1796 strongs = strongs_0;
1802 if ( FT_QNEW_ARRAY( strongs, num_strongs ) )
1807 for ( point = points; point < points_end; point++ )
1812 if ( !psh_point_is_strong( point ) )
1815 for ( insert = strongs + num_strongs; insert > strongs; insert-- )
1817 if ( insert[-1]->org_u <= point->org_u )
1820 insert[0] = insert[-1];
1827 for ( point = points; point < points_end; point++ )
1829 if ( psh_point_is_strong( point ) )
1833 if ( psh_point_is_smooth( point ) )
1835 if ( point->dir_in == PSH_DIR_NONE ||
1836 point->dir_in != point->dir_out )
1839 if ( !psh_point_is_extremum( point ) &&
1840 !psh_point_is_inflex( point ) )
1843 point->flags &= ~PSH_POINT_SMOOTH;
1848 PSH_Point before, after;
1852 for ( nn = 0; nn < num_strongs; nn++ )
1853 if ( strongs[nn]->org_u > point->org_u )
1860 point->cur_u = after->cur_u +
1861 FT_MulFix( point->org_u - after->org_u,
1866 before = strongs[nn - 1];
1868 for ( nn = num_strongs; nn > 0; nn-- )
1869 if ( strongs[nn - 1]->org_u < point->org_u )
1872 if ( nn == num_strongs )
1874 before = strongs[nn - 1];
1876 point->cur_u = before->cur_u +
1877 FT_MulFix( point->org_u - before->org_u,
1885 after = strongs[nn];
1890 if ( u == before->org_u )
1891 point->cur_u = before->cur_u;
1893 else if ( u == after->org_u )
1894 point->cur_u = after->cur_u;
1897 point->cur_u = before->cur_u +
1898 FT_MulDiv( u - before->org_u,
1899 after->cur_u - before->cur_u,
1900 after->org_u - before->org_u );
1903 psh_point_set_fitted( point );
1907 if ( strongs != strongs_0 )
1917 psh_glyph_interpolate_other_points( PSH_Glyph glyph,
1920 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1921 FT_Fixed scale = dim->scale_mult;
1922 FT_Fixed delta = dim->scale_delta;
1923 PSH_Contour contour = glyph->contours;
1924 FT_UInt num_contours = glyph->num_contours;
1927 for ( ; num_contours > 0; num_contours--, contour++ )
1929 PSH_Point start = contour->start;
1930 PSH_Point first, next, point;
1935 next = start + contour->count;
1939 for ( point = start; point < next; point++ )
1940 if ( psh_point_is_fitted( point ) )
1950 if ( fit_count < 2 )
1952 if ( fit_count == 1 )
1953 delta = first->cur_u - FT_MulFix( first->org_u, scale );
1955 for ( point = start; point < next; point++ )
1956 if ( point != first )
1957 point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
1971 if ( next == start )
1974 if ( !psh_point_is_fitted( next ) )
1984 if ( psh_point_is_fitted( next ) )
1990 FT_Pos org_a, org_ab, cur_a, cur_ab;
1991 FT_Pos org_c, org_ac, cur_c;
1995 if ( first->org_u <= next->org_u )
1997 org_a = first->org_u;
1998 cur_a = first->cur_u;
1999 org_ab = next->org_u - org_a;
2000 cur_ab = next->cur_u - cur_a;
2004 org_a = next->org_u;
2005 cur_a = next->cur_u;
2006 org_ab = first->org_u - org_a;
2007 cur_ab = first->cur_u - cur_a;
2010 scale_ab = 0x10000L;
2012 scale_ab = FT_DivFix( cur_ab, org_ab );
2014 point = first->next;
2017 org_c = point->org_u;
2018 org_ac = org_c - org_a;
2023 cur_c = cur_a + FT_MulFix( org_ac, scale );
2025 else if ( org_ac >= org_ab )
2028 cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
2033 cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
2036 point->cur_u = cur_c;
2038 point = point->next;
2040 }
while ( point != next );
2046 }
while ( first != start );
2063 ps_hints_apply( PS_Hints ps_hints,
2064 FT_Outline* outline,
2065 PSH_Globals globals,
2066 FT_Render_Mode hint_mode )
2068 PSH_GlyphRec glyphrec;
2069 PSH_Glyph glyph = &glyphrec;
2078 if ( outline->n_points == 0 || outline->n_contours == 0 )
2083 memory = globals->memory;
2085 if ( ps_debug_glyph )
2087 psh_glyph_done( ps_debug_glyph );
2088 FT_FREE( ps_debug_glyph );
2091 if ( FT_NEW( glyph ) )
2094 ps_debug_glyph = glyph;
2098 error = psh_glyph_init( glyph, outline, ps_hints, globals );
2106 PSH_Dimension dim_x = &glyph->globals->dimension[0];
2107 PSH_Dimension dim_y = &glyph->globals->dimension[1];
2109 FT_Fixed x_scale = dim_x->scale_mult;
2110 FT_Fixed y_scale = dim_y->scale_mult;
2112 FT_Fixed old_x_scale = x_scale;
2113 FT_Fixed old_y_scale = y_scale;
2115 FT_Fixed scaled = 0;
2116 FT_Fixed fitted = 0;
2118 FT_Bool rescale = FALSE;
2121 if ( globals->blues.normal_top.count )
2123 scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale );
2124 fitted = FT_PIX_ROUND( scaled );
2127 if ( fitted != 0 && scaled != fitted )
2131 y_scale = FT_MulDiv( y_scale, fitted, scaled );
2133 if ( fitted < scaled )
2134 x_scale -= x_scale / 50;
2136 psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 );
2139 glyph->do_horz_hints = 1;
2140 glyph->do_vert_hints = 1;
2142 glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
2143 hint_mode == FT_RENDER_MODE_LCD );
2145 glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
2146 hint_mode == FT_RENDER_MODE_LCD_V );
2148 glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
2150 for ( dimension = 0; dimension < 2; dimension++ )
2153 psh_glyph_load_points( glyph, dimension );
2156 psh_glyph_compute_extrema( glyph );
2159 psh_hint_table_align_hints( &glyph->hint_tables[dimension],
2165 psh_glyph_find_strong_points( glyph, dimension );
2166 if ( dimension == 1 )
2167 psh_glyph_find_blue_points( &globals->blues, glyph );
2168 psh_glyph_interpolate_strong_points( glyph, dimension );
2169 psh_glyph_interpolate_normal_points( glyph, dimension );
2170 psh_glyph_interpolate_other_points( glyph, dimension );
2173 psh_glyph_save_points( glyph, dimension );
2176 psh_globals_set_scale( glyph->globals,
2177 old_x_scale, old_y_scale, 0, 0 );
2184 psh_glyph_done( glyph );