1 /***************************************************************************/
5 /* PostScript hinting algorithm 2 (body). */
7 /* Copyright 2001, 2002 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used */
11 /* modified and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
20 #include FT_INTERNAL_OBJECTS_H
21 #include FT_INTERNAL_DEBUG_H
25 #define FT_COMPONENT trace_pshalgo2
28 PSH2_Hint_Table ps2_debug_hint_table = 0;
29 PSH2_HintFunc ps2_debug_hint_func = 0;
30 PSH2_Glyph ps2_debug_glyph = 0;
34 /*************************************************************************/
35 /*************************************************************************/
37 /***** BASIC HINTS RECORDINGS *****/
39 /*************************************************************************/
40 /*************************************************************************/
42 /* return true iff two stem hints overlap */
44 psh2_hint_overlap( PSH2_Hint hint1,
47 return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
48 hint2->org_pos + hint2->org_len >= hint1->org_pos );
52 /* destroy hints table */
54 psh2_hint_table_done( PSH2_Hint_Table table,
57 FT_FREE( table->zones );
61 FT_FREE( table->sort );
62 FT_FREE( table->hints );
65 table->sort_global = 0;
69 /* deactivate all hints in a table */
71 psh2_hint_table_deactivate( PSH2_Hint_Table table )
73 FT_UInt count = table->max_hints;
74 PSH2_Hint hint = table->hints;
77 for ( ; count > 0; count--, hint++ )
79 psh2_hint_deactivate( hint );
85 /* internal function used to record a new hint */
87 psh2_hint_table_record( PSH2_Hint_Table table,
90 PSH2_Hint hint = table->hints + idx;
93 if ( idx >= table->max_hints )
95 FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
99 /* ignore active hints */
100 if ( psh2_hint_is_active( hint ) )
103 psh2_hint_activate( hint );
105 /* now scan the current active hint set in order to determine */
106 /* if we are overlapping with another segment */
108 PSH2_Hint* sorted = table->sort_global;
109 FT_UInt count = table->num_hints;
114 for ( ; count > 0; count--, sorted++ )
118 if ( psh2_hint_overlap( hint, hint2 ) )
120 hint->parent = hint2;
126 if ( table->num_hints < table->max_hints )
127 table->sort_global[table->num_hints++] = hint;
129 FT_ERROR(( "%s.activate: too many sorted hints! BUG!\n",
135 psh2_hint_table_record_mask( PSH2_Hint_Table table,
138 FT_Int mask = 0, val = 0;
139 FT_Byte* cursor = hint_mask->bytes;
143 limit = hint_mask->num_bits;
145 for ( idx = 0; idx < limit; idx++ )
154 psh2_hint_table_record( table, idx );
161 /* create hints table */
163 psh2_hint_table_init( PSH2_Hint_Table table,
165 PS_Mask_Table hint_masks,
166 PS_Mask_Table counter_masks,
169 FT_UInt count = hints->num_hints;
172 FT_UNUSED( counter_masks );
175 /* allocate our tables */
176 if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
177 FT_NEW_ARRAY( table->hints, count ) ||
178 FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
181 table->max_hints = count;
182 table->sort_global = table->sort + count;
183 table->num_hints = 0;
184 table->num_zones = 0;
187 /* now, initialize the "hints" array */
189 PSH2_Hint write = table->hints;
190 PS_Hint read = hints->hints;
193 for ( ; count > 0; count--, write++, read++ )
195 write->org_pos = read->pos;
196 write->org_len = read->len;
197 write->flags = read->flags;
201 /* we now need to determine the initial "parent" stems; first */
202 /* activate the hints that are given by the initial hint masks */
205 FT_UInt Count = hint_masks->num_masks;
206 PS_Mask Mask = hint_masks->masks;
209 table->hint_masks = hint_masks;
211 for ( ; Count > 0; Count--, Mask++ )
212 psh2_hint_table_record_mask( table, Mask );
215 /* now, do a linear parse in case some hints were left alone */
216 if ( table->num_hints != table->max_hints )
218 FT_UInt Index, Count;
221 FT_ERROR(( "%s.init: missing/incorrect hint masks!\n" ));
222 Count = table->max_hints;
223 for ( Index = 0; Index < Count; Index++ )
224 psh2_hint_table_record( table, Index );
233 psh2_hint_table_activate_mask( PSH2_Hint_Table table,
236 FT_Int mask = 0, val = 0;
237 FT_Byte* cursor = hint_mask->bytes;
238 FT_UInt idx, limit, count;
241 limit = hint_mask->num_bits;
244 psh2_hint_table_deactivate( table );
246 for ( idx = 0; idx < limit; idx++ )
256 PSH2_Hint hint = &table->hints[idx];
259 if ( !psh2_hint_is_active( hint ) )
264 PSH2_Hint* sort = table->sort;
267 for ( count2 = count; count2 > 0; count2--, sort++ )
270 if ( psh2_hint_overlap( hint, hint2 ) )
271 FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
280 psh2_hint_activate( hint );
281 if ( count < table->max_hints )
282 table->sort[count++] = hint;
284 FT_ERROR(( "%s.activate_mask: too many active hints\n",
292 table->num_hints = count;
294 /* now, sort the hints; they are guaranteed to not overlap */
295 /* so we can compare their "org_pos" field directly */
298 PSH2_Hint hint1, hint2;
299 PSH2_Hint* sort = table->sort;
302 /* a simple bubble sort will do, since in 99% of cases, the hints */
303 /* will be already sorted -- and the sort will be linear */
304 for ( i1 = 1; i1 < (FT_Int)count; i1++ )
307 for ( i2 = i1 - 1; i2 >= 0; i2-- )
311 if ( hint2->org_pos < hint1->org_pos )
314 sort[i2 + 1] = hint2;
322 /*************************************************************************/
323 /*************************************************************************/
325 /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
327 /*************************************************************************/
328 /*************************************************************************/
332 ps2_simple_scale( PSH2_Hint_Table table,
341 for ( count = 0; count < table->max_hints; count++ )
343 hint = table->hints + count;
345 hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
346 hint->cur_len = FT_MulFix( hint->org_len, scale );
348 if ( ps2_debug_hint_func )
349 ps2_debug_hint_func( hint, dimension );
356 psh2_hint_align( PSH2_Hint hint,
360 PSH_Dimension dim = &globals->dimension[dimension];
361 FT_Fixed scale = dim->scale_mult;
362 FT_Fixed delta = dim->scale_delta;
365 if ( !psh2_hint_is_fitted(hint) )
367 FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
368 FT_Pos len = FT_MulFix( hint->org_len, scale );
373 PSH_AlignmentRec align;
376 /* compute fitted width/height */
380 fit_len = psh_dimension_snap_width( dim, hint->org_len );
384 fit_len = ( fit_len + 32 ) & -64;
387 hint->cur_len = fit_len;
389 /* check blue zones for horizontal stems */
390 align.align = PSH_BLUE_ALIGN_NONE;
391 align.align_bot = align.align_top = 0;
393 if ( dimension == 1 )
394 psh_blues_snap_stem( &globals->blues,
395 hint->org_pos + hint->org_len,
399 switch ( align.align )
401 case PSH_BLUE_ALIGN_TOP:
402 /* the top of the stem is aligned against a blue zone */
403 hint->cur_pos = align.align_top - fit_len;
406 case PSH_BLUE_ALIGN_BOT:
407 /* the bottom of the stem is aligned against a blue zone */
408 hint->cur_pos = align.align_bot;
411 case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
412 /* both edges of the stem are aligned against blue zones */
413 hint->cur_pos = align.align_bot;
414 hint->cur_len = align.align_top - align.align_bot;
419 PSH2_Hint parent = hint->parent;
424 FT_Pos par_org_center, par_cur_center;
425 FT_Pos cur_org_center, cur_delta;
428 /* ensure that parent is already fitted */
429 if ( !psh2_hint_is_fitted( parent ) )
430 psh2_hint_align( parent, globals, dimension );
432 par_org_center = parent->org_pos + ( parent->org_len / 2);
433 par_cur_center = parent->cur_pos + ( parent->cur_len / 2);
434 cur_org_center = hint->org_pos + ( hint->org_len / 2);
436 cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
438 if ( cur_delta >= 0 )
439 cur_delta = ( cur_delta + 16 ) & -64;
441 cur_delta = -( (-cur_delta + 16 ) & -64 );
443 pos = par_cur_center + cur_delta - ( len >> 1 );
446 /* normal processing */
447 if ( ( fit_len / 64 ) & 1 )
449 /* odd number of pixels */
450 fit_center = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
454 /* even number of pixels */
455 fit_center = ( pos + ( len >> 1 ) + 32 ) & -64;
458 hint->cur_pos = fit_center - ( fit_len >> 1 );
462 psh2_hint_set_fitted( hint );
465 if ( ps2_debug_hint_func )
466 ps2_debug_hint_func( hint, dimension );
473 psh2_hint_table_align_hints( PSH2_Hint_Table table,
481 PSH_Dimension dim = &globals->dimension[dimension];
482 FT_Fixed scale = dim->scale_mult;
483 FT_Fixed delta = dim->scale_delta;
486 if ( ps_debug_no_vert_hints && dimension == 0 )
488 ps2_simple_scale( table, scale, delta, dimension );
492 if ( ps_debug_no_horz_hints && dimension == 1 )
494 ps2_simple_scale( table, scale, delta, dimension );
500 count = table->max_hints;
502 for ( ; count > 0; count--, hint++ )
503 psh2_hint_align( hint, globals, dimension );
507 /*************************************************************************/
508 /*************************************************************************/
510 /***** POINTS INTERPOLATION ROUTINES *****/
512 /*************************************************************************/
513 /*************************************************************************/
515 #define PSH2_ZONE_MIN -3200000
516 #define PSH2_ZONE_MAX +3200000
518 #define xxDEBUG_ZONES
526 psh2_print_zone( PSH2_Zone zone )
528 printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
537 #define psh2_print_zone( x ) do { } while ( 0 )
542 /* setup interpolation zones once the hints have been grid-fitted */
543 /* by the optimizer */
545 psh2_hint_table_setup_zones( PSH2_Hint_Table table,
551 PSH2_Hint *sort, hint, hint2;
556 /* special case, no hints defined */
557 if ( table->num_hints == 0 )
561 zone->min = PSH2_ZONE_MIN;
562 zone->max = PSH2_ZONE_MAX;
564 table->num_zones = 1;
569 /* the first zone is before the first hint */
570 /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
575 zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
576 zone->min = PSH2_ZONE_MIN;
577 zone->max = hint->org_pos;
579 psh2_print_zone( zone );
583 for ( count = table->num_hints; count > 0; count-- )
588 if ( hint->org_len > 0 )
590 /* setup a zone for inner-stem interpolation */
591 /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
592 /* x' = x*s2 + x0' - x0*s2 */
594 scale2 = FT_DivFix( hint->cur_len, hint->org_len );
595 zone->scale = scale2;
596 zone->min = hint->org_pos;
597 zone->max = hint->org_pos + hint->org_len;
598 zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
600 psh2_print_zone( zone );
611 /* setup zone for inter-stem interpolation */
612 /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
613 /* x' = x*s3 + x1' - x1*s3 */
615 scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
616 hint2->org_pos - (hint->org_pos + hint->org_len) );
617 zone->scale = scale2;
618 zone->min = hint->org_pos + hint->org_len;
619 zone->max = hint2->org_pos;
620 zone->delta = hint->cur_pos + hint->cur_len -
621 FT_MulFix( zone->min, scale2 );
623 psh2_print_zone( zone );
632 zone->min = hint->org_pos + hint->org_len;
633 zone->max = PSH2_ZONE_MAX;
634 zone->delta = hint->cur_pos + hint->cur_len -
635 FT_MulFix( zone->min, scale );
637 psh2_print_zone( zone );
641 table->num_zones = zone - table->zones;
642 table->zone = table->zones;
647 /* tune a single coordinate with the current interpolation zones */
649 psh2_hint_table_tune_coord( PSH2_Hint_Table table,
657 if ( coord < zone->min )
661 if ( zone == table->zones )
666 } while ( coord < zone->min );
669 else if ( coord > zone->max )
673 if ( zone == table->zones + table->num_zones - 1 )
678 } while ( coord > zone->max );
682 return FT_MulFix( coord, zone->scale ) + zone->delta;
687 /* tune a given outline with current interpolation zones */
688 /* the function only works in a single dimension.. */
690 psh2_hint_table_tune_outline( PSH2_Hint_Table table,
696 FT_UInt count, first, last;
697 PS_Mask_Table hint_masks = table->hint_masks;
699 PSH_Dimension dim = &globals->dimension[dimension];
700 FT_Fixed scale = dim->scale_mult;
701 FT_Fixed delta = dim->scale_delta;
704 if ( hint_masks && hint_masks->num_masks > 0 )
707 mask = hint_masks->masks;
708 count = hint_masks->num_masks;
710 for ( ; count > 0; count--, mask++ )
712 last = mask->end_point;
720 psh2_hint_table_activate_mask( table, mask );
721 psh2_hint_table_optimize( table, globals, outline, dimension );
722 psh2_hint_table_setup_zones( table, scale, delta );
723 last = mask->end_point;
725 vec = outline->points + first;
726 count2 = last - first;
728 for ( ; count2 > 0; count2--, vec++ )
733 px = dimension ? &vec->y : &vec->x;
736 *px = psh2_hint_table_tune_coord( table, (FT_Int)x );
743 else /* no hints in this glyph, simply scale the outline */
748 vec = outline->points;
749 count = outline->n_points;
751 if ( dimension == 0 )
753 for ( ; count > 0; count--, vec++ )
754 vec->x = FT_MulFix( vec->x, scale ) + delta;
758 for ( ; count > 0; count--, vec++ )
759 vec->y = FT_MulFix( vec->y, scale ) + delta;
766 /*************************************************************************/
767 /*************************************************************************/
769 /***** HINTER GLYPH MANAGEMENT *****/
771 /*************************************************************************/
772 /*************************************************************************/
775 psh2_point_is_extremum( PSH2_Point point )
777 PSH2_Point before = point;
778 PSH2_Point after = point;
785 before = before->prev;
786 if ( before == point )
789 d_before = before->org_u - point->org_u;
791 } while ( d_before == 0 );
796 if ( after == point )
799 d_after = after->org_u - point->org_u;
801 } while ( d_after == 0 );
803 return ( ( d_before > 0 && d_after > 0 ) ||
804 ( d_before < 0 && d_after < 0 ) );
809 psh2_glyph_done( PSH2_Glyph glyph )
811 FT_Memory memory = glyph->memory;
814 psh2_hint_table_done( &glyph->hint_tables[1], memory );
815 psh2_hint_table_done( &glyph->hint_tables[0], memory );
817 FT_FREE( glyph->points );
818 FT_FREE( glyph->contours );
820 glyph->num_points = 0;
821 glyph->num_contours = 0;
828 psh2_compute_dir( FT_Pos dx,
832 int result = PSH2_DIR_NONE;
835 ax = ( dx >= 0 ) ? dx : -dx;
836 ay = ( dy >= 0 ) ? dy : -dy;
840 /* |dy| <<< |dx| means a near-horizontal segment */
841 result = ( dx >= 0 ) ? PSH2_DIR_RIGHT : PSH2_DIR_LEFT;
843 else if ( ax * 12 < ay )
845 /* |dx| <<< |dy| means a near-vertical segment */
846 result = ( dy >= 0 ) ? PSH2_DIR_UP : PSH2_DIR_DOWN;
854 psh2_glyph_init( PSH2_Glyph glyph,
857 PSH_Globals globals )
863 /* clear all fields */
864 FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
866 memory = globals->memory;
868 /* allocate and setup points + contours arrays */
869 if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
870 FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
873 glyph->num_points = outline->n_points;
874 glyph->num_contours = outline->n_contours;
877 FT_UInt first = 0, next, n;
878 PSH2_Point points = glyph->points;
879 PSH2_Contour contour = glyph->contours;
882 for ( n = 0; n < glyph->num_contours; n++ )
888 next = outline->contours[n] + 1;
889 count = next - first;
891 contour->start = points + first;
892 contour->count = (FT_UInt)count;
896 point = points + first;
898 point->prev = points + next - 1;
899 point->contour = contour;
901 for ( ; count > 1; count-- )
903 point[0].next = point + 1;
904 point[1].prev = point;
906 point->contour = contour;
908 point->next = points + first;
917 PSH2_Point points = glyph->points;
918 PSH2_Point point = points;
919 FT_Vector* vec = outline->points;
923 for ( n = 0; n < glyph->num_points; n++, point++ )
925 FT_Int n_prev = point->prev - points;
926 FT_Int n_next = point->next - points;
927 FT_Pos dxi, dyi, dxo, dyo;
930 if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
931 point->flags = PSH2_POINT_OFF;
933 dxi = vec[n].x - vec[n_prev].x;
934 dyi = vec[n].y - vec[n_prev].y;
936 point->dir_in = (FT_Char)psh2_compute_dir( dxi, dyi );
938 dxo = vec[n_next].x - vec[n].x;
939 dyo = vec[n_next].y - vec[n].y;
941 point->dir_out = (FT_Char)psh2_compute_dir( dxo, dyo );
943 /* detect smooth points */
944 if ( point->flags & PSH2_POINT_OFF )
945 point->flags |= PSH2_POINT_SMOOTH;
946 else if ( point->dir_in != PSH2_DIR_NONE ||
947 point->dir_out != PSH2_DIR_NONE )
949 if ( point->dir_in == point->dir_out )
950 point->flags |= PSH2_POINT_SMOOTH;
954 FT_Angle angle_in, angle_out, diff;
957 angle_in = FT_Atan2( dxi, dyi );
958 angle_out = FT_Atan2( dxo, dyo );
960 diff = angle_in - angle_out;
964 if ( diff > FT_ANGLE_PI )
965 diff = FT_ANGLE_2PI - diff;
967 if ( diff < FT_ANGLE_PI / 16 )
968 point->flags |= PSH2_POINT_SMOOTH;
973 glyph->memory = memory;
974 glyph->outline = outline;
975 glyph->globals = globals;
977 /* now deal with hints tables */
978 error = psh2_hint_table_init( &glyph->hint_tables [0],
979 &ps_hints->dimension[0].hints,
980 &ps_hints->dimension[0].masks,
981 &ps_hints->dimension[0].counters,
986 error = psh2_hint_table_init( &glyph->hint_tables [1],
987 &ps_hints->dimension[1].hints,
988 &ps_hints->dimension[1].masks,
989 &ps_hints->dimension[1].counters,
999 /* load outline point coordinates into hinter glyph */
1001 psh2_glyph_load_points( PSH2_Glyph glyph,
1004 FT_Vector* vec = glyph->outline->points;
1005 PSH2_Point point = glyph->points;
1006 FT_UInt count = glyph->num_points;
1009 for ( ; count > 0; count--, point++, vec++ )
1011 point->flags &= PSH2_POINT_OFF | PSH2_POINT_SMOOTH;
1013 if ( dimension == 0 )
1014 point->org_u = vec->x;
1016 point->org_u = vec->y;
1019 point->org_x = vec->x;
1020 point->org_y = vec->y;
1026 /* save hinted point coordinates back to outline */
1028 psh2_glyph_save_points( PSH2_Glyph glyph,
1032 PSH2_Point point = glyph->points;
1033 FT_Vector* vec = glyph->outline->points;
1034 char* tags = glyph->outline->tags;
1037 for ( n = 0; n < glyph->num_points; n++ )
1039 if ( dimension == 0 )
1040 vec[n].x = point->cur_u;
1042 vec[n].y = point->cur_u;
1044 if ( psh2_point_is_strong( point ) )
1045 tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
1048 if ( dimension == 0 )
1050 point->cur_x = point->cur_u;
1051 point->flags_x = point->flags;
1055 point->cur_y = point->cur_u;
1056 point->flags_y = point->flags;
1064 #define PSH2_STRONG_THRESHOLD 10
1068 psh2_hint_table_find_strong_point( PSH2_Hint_Table table,
1072 PSH2_Hint* sort = table->sort;
1073 FT_UInt num_hints = table->num_hints;
1076 for ( ; num_hints > 0; num_hints--, sort++ )
1078 PSH2_Hint hint = sort[0];
1081 if ( ABS( point->dir_in ) == major_dir ||
1082 ABS( point->dir_out ) == major_dir )
1087 d = point->org_u - hint->org_pos;
1088 if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
1091 psh2_point_set_strong( point );
1097 if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
1102 if ( point->org_u >= hint->org_pos &&
1103 point->org_u <= hint->org_pos + hint->org_len &&
1104 psh2_point_is_extremum( point ) )
1106 /* attach to hint, but don't mark as strong */
1115 /* find strong points in a glyph */
1117 psh2_glyph_find_strong_points( PSH2_Glyph glyph,
1120 /* a point is strong if it is located on a stem */
1121 /* edge and has an "in" or "out" tangent to the hint's direction */
1123 PSH2_Hint_Table table = &glyph->hint_tables[dimension];
1124 PS_Mask mask = table->hint_masks->masks;
1125 FT_UInt num_masks = table->hint_masks->num_masks;
1127 FT_Int major_dir = dimension == 0 ? PSH2_DIR_UP : PSH2_DIR_RIGHT;
1130 /* process secondary hints to "selected" points */
1131 if ( num_masks > 1 && glyph->num_points > 0 )
1133 first = mask->end_point;
1135 for ( ; num_masks > 1; num_masks--, mask++ )
1141 next = mask->end_point;
1142 count = next - first;
1145 PSH2_Point point = glyph->points + first;
1148 psh2_hint_table_activate_mask( table, mask );
1150 for ( ; count > 0; count--, point++ )
1151 psh2_hint_table_find_strong_point( table, point, major_dir );
1157 /* process primary hints for all points */
1158 if ( num_masks == 1 )
1160 FT_UInt count = glyph->num_points;
1161 PSH2_Point point = glyph->points;
1164 psh2_hint_table_activate_mask( table, table->hint_masks->masks );
1165 for ( ; count > 0; count--, point++ )
1167 if ( !psh2_point_is_strong( point ) )
1168 psh2_hint_table_find_strong_point( table, point, major_dir );
1172 /* now, certain points may have been attached to hint and */
1173 /* not marked as strong; update their flags then */
1175 FT_UInt count = glyph->num_points;
1176 PSH2_Point point = glyph->points;
1179 for ( ; count > 0; count--, point++ )
1180 if ( point->hint && !psh2_point_is_strong( point ) )
1181 psh2_point_set_strong( point );
1187 /* interpolate strong points with the help of hinted coordinates */
1189 psh2_glyph_interpolate_strong_points( PSH2_Glyph glyph,
1192 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1193 FT_Fixed scale = dim->scale_mult;
1197 FT_UInt count = glyph->num_points;
1198 PSH2_Point point = glyph->points;
1201 for ( ; count > 0; count--, point++ )
1203 PSH2_Hint hint = point->hint;
1211 delta = point->org_u - hint->org_pos;
1214 point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
1216 else if ( delta >= hint->org_len )
1217 point->cur_u = hint->cur_pos + hint->cur_len +
1218 FT_MulFix( delta - hint->org_len, scale );
1220 else if ( hint->org_len > 0 )
1221 point->cur_u = hint->cur_pos +
1222 FT_MulDiv( delta, hint->cur_len, hint->org_len );
1224 point->cur_u = hint->cur_pos;
1226 psh2_point_set_fitted( point );
1234 psh2_glyph_interpolate_normal_points( PSH2_Glyph glyph,
1238 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1239 FT_Fixed scale = dim->scale_mult;
1242 /* first technique: a point is strong if it is a local extrema */
1244 FT_UInt count = glyph->num_points;
1245 PSH2_Point point = glyph->points;
1248 for ( ; count > 0; count--, point++ )
1250 if ( psh2_point_is_strong( point ) )
1253 /* sometimes, some local extremas are smooth points */
1254 if ( psh2_point_is_smooth( point ) )
1256 if ( point->dir_in == PSH2_DIR_NONE ||
1257 point->dir_in != point->dir_out )
1260 if ( !psh2_point_is_extremum( point ) )
1263 point->flags &= ~PSH2_POINT_SMOOTH;
1266 /* find best enclosing point coordinates */
1268 PSH2_Point before = 0;
1269 PSH2_Point after = 0;
1271 FT_Pos diff_before = -32000;
1272 FT_Pos diff_after = 32000;
1273 FT_Pos u = point->org_u;
1275 FT_Int count2 = glyph->num_points;
1276 PSH2_Point cur = glyph->points;
1279 for ( ; count2 > 0; count2--, cur++ )
1281 if ( psh2_point_is_strong( cur ) )
1283 FT_Pos diff = cur->org_u - u;;
1288 if ( diff > diff_before )
1294 else if ( diff >= 0 )
1296 if ( diff < diff_after )
1310 /* we are before the first strong point coordinate; */
1311 /* simply translate the point */
1312 point->cur_u = after->cur_u +
1313 FT_MulFix( point->org_u - after->org_u, scale );
1317 /* we are after the last strong point coordinate; */
1318 /* simply translate the point */
1319 point->cur_u = before->cur_u +
1320 FT_MulFix( point->org_u - before->org_u, scale );
1324 if ( diff_before == 0 )
1325 point->cur_u = before->cur_u;
1327 else if ( diff_after == 0 )
1328 point->cur_u = after->cur_u;
1331 point->cur_u = before->cur_u +
1332 FT_MulDiv( u - before->org_u,
1333 after->cur_u - before->cur_u,
1334 after->org_u - before->org_u );
1337 psh2_point_set_fitted( point );
1345 /* interpolate other points */
1347 psh2_glyph_interpolate_other_points( PSH2_Glyph glyph,
1350 PSH_Dimension dim = &glyph->globals->dimension[dimension];
1351 FT_Fixed scale = dim->scale_mult;
1352 FT_Fixed delta = dim->scale_delta;
1353 PSH2_Contour contour = glyph->contours;
1354 FT_UInt num_contours = glyph->num_contours;
1357 for ( ; num_contours > 0; num_contours--, contour++ )
1359 PSH2_Point start = contour->start;
1360 PSH2_Point first, next, point;
1364 /* count the number of strong points in this contour */
1365 next = start + contour->count;
1369 for ( point = start; point < next; point++ )
1370 if ( psh2_point_is_fitted( point ) )
1378 /* if there are less than 2 fitted points in the contour, we */
1379 /* simply scale and eventually translate the contour points */
1380 if ( fit_count < 2 )
1382 if ( fit_count == 1 )
1383 delta = first->cur_u - FT_MulFix( first->org_u, scale );
1385 for ( point = start; point < next; point++ )
1386 if ( point != first )
1387 point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
1392 /* there are more than 2 strong points in this contour; we */
1393 /* need to interpolate weak points between them */
1399 /* skip consecutive fitted points */
1403 if ( next == start )
1406 if ( !psh2_point_is_fitted( next ) )
1412 /* find next fitted point after unfitted one */
1416 if ( psh2_point_is_fitted( next ) )
1420 /* now interpolate between them */
1422 FT_Pos org_a, org_ab, cur_a, cur_ab;
1423 FT_Pos org_c, org_ac, cur_c;
1427 if ( first->org_u <= next->org_u )
1429 org_a = first->org_u;
1430 cur_a = first->cur_u;
1431 org_ab = next->org_u - org_a;
1432 cur_ab = next->cur_u - cur_a;
1436 org_a = next->org_u;
1437 cur_a = next->cur_u;
1438 org_ab = first->org_u - org_a;
1439 cur_ab = first->cur_u - cur_a;
1442 scale_ab = 0x10000L;
1444 scale_ab = FT_DivFix( cur_ab, org_ab );
1446 point = first->next;
1449 org_c = point->org_u;
1450 org_ac = org_c - org_a;
1454 /* on the left of the interpolation zone */
1455 cur_c = cur_a + FT_MulFix( org_ac, scale );
1457 else if ( org_ac >= org_ab )
1459 /* on the right on the interpolation zone */
1460 cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
1464 /* within the interpolation zone */
1465 cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
1468 point->cur_u = cur_c;
1470 point = point->next;
1472 } while ( point != next );
1475 /* keep going until all points in the contours have been processed */
1478 } while ( first != start );
1486 /*************************************************************************/
1487 /*************************************************************************/
1489 /***** HIGH-LEVEL INTERFACE *****/
1491 /*************************************************************************/
1492 /*************************************************************************/
1495 ps2_hints_apply( PS_Hints ps_hints,
1496 FT_Outline* outline,
1497 PSH_Globals globals,
1498 FT_Render_Mode hint_mode )
1500 PSH2_GlyphRec glyphrec;
1501 PSH2_Glyph glyph = &glyphrec;
1508 FT_UNUSED( hint_mode );
1511 memory = globals->memory;
1513 if ( ps2_debug_glyph )
1515 psh2_glyph_done( ps2_debug_glyph );
1516 FT_FREE( ps2_debug_glyph );
1519 if ( FT_NEW( glyph ) )
1522 ps2_debug_glyph = glyph;
1525 error = psh2_glyph_init( glyph, outline, ps_hints, globals );
1529 for ( dimension = 0; dimension < 2; dimension++ )
1531 /* load outline coordinates into glyph */
1532 psh2_glyph_load_points( glyph, dimension );
1534 /* compute aligned stem/hints positions */
1535 psh2_hint_table_align_hints( &glyph->hint_tables[dimension],
1539 /* find strong points, align them, then interpolate others */
1540 psh2_glyph_find_strong_points( glyph, dimension );
1541 psh2_glyph_interpolate_strong_points( glyph, dimension );
1542 psh2_glyph_interpolate_normal_points( glyph, dimension );
1543 psh2_glyph_interpolate_other_points( glyph, dimension );
1545 /* save hinted coordinates back to outline */
1546 psh2_glyph_save_points( glyph, dimension );
1550 #ifndef DEBUG_HINTER
1551 psh2_glyph_done( glyph );