"Fossies" - the Fresh Open Source Software Archive 
Member "SDL2_ttf-2.20.2/external/freetype/src/autofit/afhints.c" (25 May 2022, 46934 Bytes) of package /linux/misc/SDL2_ttf-2.20.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "afhints.c" see the
Fossies "Dox" file reference documentation.
1 /****************************************************************************
2 *
3 * afhints.c
4 *
5 * Auto-fitter hinting routines (body).
6 *
7 * Copyright (C) 2003-2022 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
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.
15 *
16 */
17
18
19 #include "afhints.h"
20 #include "aferrors.h"
21 #include <freetype/internal/ftcalc.h>
22 #include <freetype/internal/ftdebug.h>
23
24
25 /**************************************************************************
26 *
27 * The macro FT_COMPONENT is used in trace mode. It is an implicit
28 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
29 * messages during execution.
30 */
31 #undef FT_COMPONENT
32 #define FT_COMPONENT afhints
33
34
35 FT_LOCAL_DEF( void )
36 af_sort_pos( FT_UInt count,
37 FT_Pos* table )
38 {
39 FT_UInt i, j;
40 FT_Pos swap;
41
42
43 for ( i = 1; i < count; i++ )
44 {
45 for ( j = i; j > 0; j-- )
46 {
47 if ( table[j] >= table[j - 1] )
48 break;
49
50 swap = table[j];
51 table[j] = table[j - 1];
52 table[j - 1] = swap;
53 }
54 }
55 }
56
57
58 FT_LOCAL_DEF( void )
59 af_sort_and_quantize_widths( FT_UInt* count,
60 AF_Width table,
61 FT_Pos threshold )
62 {
63 FT_UInt i, j;
64 FT_UInt cur_idx;
65 FT_Pos cur_val;
66 FT_Pos sum;
67 AF_WidthRec swap;
68
69
70 if ( *count == 1 )
71 return;
72
73 /* sort */
74 for ( i = 1; i < *count; i++ )
75 {
76 for ( j = i; j > 0; j-- )
77 {
78 if ( table[j].org >= table[j - 1].org )
79 break;
80
81 swap = table[j];
82 table[j] = table[j - 1];
83 table[j - 1] = swap;
84 }
85 }
86
87 cur_idx = 0;
88 cur_val = table[cur_idx].org;
89
90 /* compute and use mean values for clusters not larger than */
91 /* `threshold'; this is very primitive and might not yield */
92 /* the best result, but normally, using reference character */
93 /* `o', `*count' is 2, so the code below is fully sufficient */
94 for ( i = 1; i < *count; i++ )
95 {
96 if ( table[i].org - cur_val > threshold ||
97 i == *count - 1 )
98 {
99 sum = 0;
100
101 /* fix loop for end of array */
102 if ( table[i].org - cur_val <= threshold &&
103 i == *count - 1 )
104 i++;
105
106 for ( j = cur_idx; j < i; j++ )
107 {
108 sum += table[j].org;
109 table[j].org = 0;
110 }
111 table[cur_idx].org = sum / (FT_Pos)j;
112
113 if ( i < *count - 1 )
114 {
115 cur_idx = i + 1;
116 cur_val = table[cur_idx].org;
117 }
118 }
119 }
120
121 cur_idx = 1;
122
123 /* compress array to remove zero values */
124 for ( i = 1; i < *count; i++ )
125 {
126 if ( table[i].org )
127 table[cur_idx++] = table[i];
128 }
129
130 *count = cur_idx;
131 }
132
133 /* Get new segment for given axis. */
134
135 FT_LOCAL_DEF( FT_Error )
136 af_axis_hints_new_segment( AF_AxisHints axis,
137 FT_Memory memory,
138 AF_Segment *asegment )
139 {
140 FT_Error error = FT_Err_Ok;
141 AF_Segment segment = NULL;
142
143
144 if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
145 {
146 if ( !axis->segments )
147 {
148 axis->segments = axis->embedded.segments;
149 axis->max_segments = AF_SEGMENTS_EMBEDDED;
150 }
151 }
152 else if ( axis->num_segments >= axis->max_segments )
153 {
154 FT_Int old_max = axis->max_segments;
155 FT_Int new_max = old_max;
156 FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
157
158
159 if ( old_max >= big_max )
160 {
161 error = FT_THROW( Out_Of_Memory );
162 goto Exit;
163 }
164
165 new_max += ( new_max >> 2 ) + 4;
166 if ( new_max < old_max || new_max > big_max )
167 new_max = big_max;
168
169 if ( axis->segments == axis->embedded.segments )
170 {
171 if ( FT_NEW_ARRAY( axis->segments, new_max ) )
172 goto Exit;
173 ft_memcpy( axis->segments, axis->embedded.segments,
174 sizeof ( axis->embedded.segments ) );
175 }
176 else
177 {
178 if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
179 goto Exit;
180 }
181
182 axis->max_segments = new_max;
183 }
184
185 segment = axis->segments + axis->num_segments++;
186
187 Exit:
188 *asegment = segment;
189 return error;
190 }
191
192
193 /* Get new edge for given axis, direction, and position, */
194 /* without initializing the edge itself. */
195
196 FT_LOCAL( FT_Error )
197 af_axis_hints_new_edge( AF_AxisHints axis,
198 FT_Int fpos,
199 AF_Direction dir,
200 FT_Bool top_to_bottom_hinting,
201 FT_Memory memory,
202 AF_Edge *anedge )
203 {
204 FT_Error error = FT_Err_Ok;
205 AF_Edge edge = NULL;
206 AF_Edge edges;
207
208
209 if ( axis->num_edges < AF_EDGES_EMBEDDED )
210 {
211 if ( !axis->edges )
212 {
213 axis->edges = axis->embedded.edges;
214 axis->max_edges = AF_EDGES_EMBEDDED;
215 }
216 }
217 else if ( axis->num_edges >= axis->max_edges )
218 {
219 FT_Int old_max = axis->max_edges;
220 FT_Int new_max = old_max;
221 FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
222
223
224 if ( old_max >= big_max )
225 {
226 error = FT_THROW( Out_Of_Memory );
227 goto Exit;
228 }
229
230 new_max += ( new_max >> 2 ) + 4;
231 if ( new_max < old_max || new_max > big_max )
232 new_max = big_max;
233
234 if ( axis->edges == axis->embedded.edges )
235 {
236 if ( FT_NEW_ARRAY( axis->edges, new_max ) )
237 goto Exit;
238 ft_memcpy( axis->edges, axis->embedded.edges,
239 sizeof ( axis->embedded.edges ) );
240 }
241 else
242 {
243 if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
244 goto Exit;
245 }
246
247 axis->max_edges = new_max;
248 }
249
250 edges = axis->edges;
251 edge = edges + axis->num_edges;
252
253 while ( edge > edges )
254 {
255 if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos )
256 : ( edge[-1].fpos < fpos ) )
257 break;
258
259 /* we want the edge with same position and minor direction */
260 /* to appear before those in the major one in the list */
261 if ( edge[-1].fpos == fpos && dir == axis->major_dir )
262 break;
263
264 edge[0] = edge[-1];
265 edge--;
266 }
267
268 axis->num_edges++;
269
270 Exit:
271 *anedge = edge;
272 return error;
273 }
274
275
276 #ifdef FT_DEBUG_AUTOFIT
277
278 #include FT_CONFIG_STANDARD_LIBRARY_H
279
280 /* The dump functions are used in the `ftgrid' demo program, too. */
281 #define AF_DUMP( varformat ) \
282 do \
283 { \
284 if ( to_stdout ) \
285 printf varformat; \
286 else \
287 FT_TRACE7( varformat ); \
288 } while ( 0 )
289
290
291 static const char*
292 af_dir_str( AF_Direction dir )
293 {
294 const char* result;
295
296
297 switch ( dir )
298 {
299 case AF_DIR_UP:
300 result = "up";
301 break;
302 case AF_DIR_DOWN:
303 result = "down";
304 break;
305 case AF_DIR_LEFT:
306 result = "left";
307 break;
308 case AF_DIR_RIGHT:
309 result = "right";
310 break;
311 default:
312 result = "none";
313 }
314
315 return result;
316 }
317
318
319 #define AF_INDEX_NUM( ptr, base ) (int)( (ptr) ? ( (ptr) - (base) ) : -1 )
320
321
322 static char*
323 af_print_idx( char* p,
324 int idx )
325 {
326 if ( idx == -1 )
327 {
328 p[0] = '-';
329 p[1] = '-';
330 p[2] = '\0';
331 }
332 else
333 ft_sprintf( p, "%d", idx );
334
335 return p;
336 }
337
338
339 static int
340 af_get_segment_index( AF_GlyphHints hints,
341 int point_idx,
342 int dimension )
343 {
344 AF_AxisHints axis = &hints->axis[dimension];
345 AF_Point point = hints->points + point_idx;
346 AF_Segment segments = axis->segments;
347 AF_Segment limit = segments + axis->num_segments;
348 AF_Segment segment;
349
350
351 for ( segment = segments; segment < limit; segment++ )
352 {
353 if ( segment->first <= segment->last )
354 {
355 if ( point >= segment->first && point <= segment->last )
356 break;
357 }
358 else
359 {
360 AF_Point p = segment->first;
361
362
363 for (;;)
364 {
365 if ( point == p )
366 goto Exit;
367
368 if ( p == segment->last )
369 break;
370
371 p = p->next;
372 }
373 }
374 }
375
376 Exit:
377 if ( segment == limit )
378 return -1;
379
380 return (int)( segment - segments );
381 }
382
383
384 static int
385 af_get_edge_index( AF_GlyphHints hints,
386 int segment_idx,
387 int dimension )
388 {
389 AF_AxisHints axis = &hints->axis[dimension];
390 AF_Edge edges = axis->edges;
391 AF_Segment segment = axis->segments + segment_idx;
392
393
394 return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
395 }
396
397
398 static int
399 af_get_strong_edge_index( AF_GlyphHints hints,
400 AF_Edge* strong_edges,
401 int dimension )
402 {
403 AF_AxisHints axis = &hints->axis[dimension];
404 AF_Edge edges = axis->edges;
405
406
407 return AF_INDEX_NUM( strong_edges[dimension], edges );
408 }
409
410
411 #ifdef __cplusplus
412 extern "C" {
413 #endif
414 void
415 af_glyph_hints_dump_points( AF_GlyphHints hints,
416 FT_Bool to_stdout )
417 {
418 AF_Point points = hints->points;
419 AF_Point limit = points + hints->num_points;
420 AF_Point* contour = hints->contours;
421 AF_Point* climit = contour + hints->num_contours;
422 AF_Point point;
423
424
425 AF_DUMP(( "Table of points:\n" ));
426
427 if ( hints->num_points )
428 {
429 AF_DUMP(( " index hedge hseg vedge vseg flags "
430 /* " XXXXX XXXXX XXXXX XXXXX XXXXX XXXXXX" */
431 " xorg yorg xscale yscale xfit yfit "
432 /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
433 " hbef haft vbef vaft" ));
434 /* " XXXXX XXXXX XXXXX XXXXX" */
435 }
436 else
437 AF_DUMP(( " (none)\n" ));
438
439 for ( point = points; point < limit; point++ )
440 {
441 int point_idx = AF_INDEX_NUM( point, points );
442 int segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
443 int segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
444
445 char buf1[16], buf2[16], buf3[16], buf4[16];
446 char buf5[16], buf6[16], buf7[16], buf8[16];
447
448
449 /* insert extra newline at the beginning of a contour */
450 if ( contour < climit && *contour == point )
451 {
452 AF_DUMP(( "\n" ));
453 contour++;
454 }
455
456 AF_DUMP(( " %5d %5s %5s %5s %5s %s"
457 " %5d %5d %7.2f %7.2f %7.2f %7.2f"
458 " %5s %5s %5s %5s\n",
459 point_idx,
460 af_print_idx( buf1,
461 af_get_edge_index( hints, segment_idx_1, 1 ) ),
462 af_print_idx( buf2, segment_idx_1 ),
463 af_print_idx( buf3,
464 af_get_edge_index( hints, segment_idx_0, 0 ) ),
465 af_print_idx( buf4, segment_idx_0 ),
466 ( point->flags & AF_FLAG_NEAR )
467 ? " near "
468 : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
469 ? " weak "
470 : "strong",
471
472 point->fx,
473 point->fy,
474 point->ox / 64.0,
475 point->oy / 64.0,
476 point->x / 64.0,
477 point->y / 64.0,
478
479 af_print_idx( buf5, af_get_strong_edge_index( hints,
480 point->before,
481 1 ) ),
482 af_print_idx( buf6, af_get_strong_edge_index( hints,
483 point->after,
484 1 ) ),
485 af_print_idx( buf7, af_get_strong_edge_index( hints,
486 point->before,
487 0 ) ),
488 af_print_idx( buf8, af_get_strong_edge_index( hints,
489 point->after,
490 0 ) ) ));
491 }
492 AF_DUMP(( "\n" ));
493 }
494 #ifdef __cplusplus
495 }
496 #endif
497
498
499 static const char*
500 af_edge_flags_to_string( FT_UInt flags )
501 {
502 static char temp[32];
503 int pos = 0;
504
505
506 if ( flags & AF_EDGE_ROUND )
507 {
508 ft_memcpy( temp + pos, "round", 5 );
509 pos += 5;
510 }
511 if ( flags & AF_EDGE_SERIF )
512 {
513 if ( pos > 0 )
514 temp[pos++] = ' ';
515 ft_memcpy( temp + pos, "serif", 5 );
516 pos += 5;
517 }
518 if ( pos == 0 )
519 return "normal";
520
521 temp[pos] = '\0';
522
523 return temp;
524 }
525
526
527 /* Dump the array of linked segments. */
528
529 #ifdef __cplusplus
530 extern "C" {
531 #endif
532 void
533 af_glyph_hints_dump_segments( AF_GlyphHints hints,
534 FT_Bool to_stdout )
535 {
536 FT_Int dimension;
537
538
539 for ( dimension = 1; dimension >= 0; dimension-- )
540 {
541 AF_AxisHints axis = &hints->axis[dimension];
542 AF_Point points = hints->points;
543 AF_Edge edges = axis->edges;
544 AF_Segment segments = axis->segments;
545 AF_Segment limit = segments + axis->num_segments;
546 AF_Segment seg;
547
548 char buf1[16], buf2[16], buf3[16];
549
550
551 AF_DUMP(( "Table of %s segments:\n",
552 dimension == AF_DIMENSION_HORZ ? "vertical"
553 : "horizontal" ));
554 if ( axis->num_segments )
555 {
556 AF_DUMP(( " index pos delta dir from to "
557 /* " XXXXX XXXXX XXXXX XXXXX XXXX XXXX" */
558 " link serif edge"
559 /* " XXXX XXXXX XXXX" */
560 " height extra flags\n" ));
561 /* " XXXXXX XXXXX XXXXXXXXXXX" */
562 }
563 else
564 AF_DUMP(( " (none)\n" ));
565
566 for ( seg = segments; seg < limit; seg++ )
567 AF_DUMP(( " %5d %5d %5d %5s %4d %4d"
568 " %4s %5s %4s"
569 " %6d %5d %11s\n",
570 AF_INDEX_NUM( seg, segments ),
571 seg->pos,
572 seg->delta,
573 af_dir_str( (AF_Direction)seg->dir ),
574 AF_INDEX_NUM( seg->first, points ),
575 AF_INDEX_NUM( seg->last, points ),
576
577 af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
578 af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
579 af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
580
581 seg->height,
582 seg->height - ( seg->max_coord - seg->min_coord ),
583 af_edge_flags_to_string( seg->flags ) ));
584 AF_DUMP(( "\n" ));
585 }
586 }
587 #ifdef __cplusplus
588 }
589 #endif
590
591
592 /* Fetch number of segments. */
593
594 #ifdef __cplusplus
595 extern "C" {
596 #endif
597 FT_Error
598 af_glyph_hints_get_num_segments( AF_GlyphHints hints,
599 FT_Int dimension,
600 FT_Int* num_segments )
601 {
602 AF_Dimension dim;
603 AF_AxisHints axis;
604
605
606 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
607
608 axis = &hints->axis[dim];
609 *num_segments = axis->num_segments;
610
611 return FT_Err_Ok;
612 }
613 #ifdef __cplusplus
614 }
615 #endif
616
617
618 /* Fetch offset of segments into user supplied offset array. */
619
620 #ifdef __cplusplus
621 extern "C" {
622 #endif
623 FT_Error
624 af_glyph_hints_get_segment_offset( AF_GlyphHints hints,
625 FT_Int dimension,
626 FT_Int idx,
627 FT_Pos *offset,
628 FT_Bool *is_blue,
629 FT_Pos *blue_offset )
630 {
631 AF_Dimension dim;
632 AF_AxisHints axis;
633 AF_Segment seg;
634
635
636 if ( !offset )
637 return FT_THROW( Invalid_Argument );
638
639 dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
640
641 axis = &hints->axis[dim];
642
643 if ( idx < 0 || idx >= axis->num_segments )
644 return FT_THROW( Invalid_Argument );
645
646 seg = &axis->segments[idx];
647 *offset = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
648 : seg->first->fy;
649 if ( seg->edge )
650 *is_blue = FT_BOOL( seg->edge->blue_edge );
651 else
652 *is_blue = FALSE;
653
654 if ( *is_blue )
655 *blue_offset = seg->edge->blue_edge->org;
656 else
657 *blue_offset = 0;
658
659 return FT_Err_Ok;
660 }
661 #ifdef __cplusplus
662 }
663 #endif
664
665
666 /* Dump the array of linked edges. */
667
668 #ifdef __cplusplus
669 extern "C" {
670 #endif
671 void
672 af_glyph_hints_dump_edges( AF_GlyphHints hints,
673 FT_Bool to_stdout )
674 {
675 FT_Int dimension;
676
677
678 for ( dimension = 1; dimension >= 0; dimension-- )
679 {
680 AF_AxisHints axis = &hints->axis[dimension];
681 AF_Edge edges = axis->edges;
682 AF_Edge limit = edges + axis->num_edges;
683 AF_Edge edge;
684
685 char buf1[16], buf2[16];
686
687
688 /*
689 * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
690 * since they have a constant X coordinate.
691 */
692 if ( dimension == AF_DIMENSION_HORZ )
693 AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
694 "vertical",
695 65536.0 * 64.0 / hints->x_scale,
696 10.0 * hints->x_scale / 65536.0 / 64.0 ));
697 else
698 AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
699 "horizontal",
700 65536.0 * 64.0 / hints->y_scale,
701 10.0 * hints->y_scale / 65536.0 / 64.0 ));
702
703 if ( axis->num_edges )
704 {
705 AF_DUMP(( " index pos dir link serif"
706 /* " XXXXX XXXX.XX XXXXX XXXX XXXXX" */
707 " blue opos pos flags\n" ));
708 /* " X XXXX.XX XXXX.XX XXXXXXXXXXX" */
709 }
710 else
711 AF_DUMP(( " (none)\n" ));
712
713 for ( edge = edges; edge < limit; edge++ )
714 AF_DUMP(( " %5d %7.2f %5s %4s %5s"
715 " %c %7.2f %7.2f %11s\n",
716 AF_INDEX_NUM( edge, edges ),
717 (int)edge->opos / 64.0,
718 af_dir_str( (AF_Direction)edge->dir ),
719 af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
720 af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
721
722 edge->blue_edge ? 'y' : 'n',
723 edge->opos / 64.0,
724 edge->pos / 64.0,
725 af_edge_flags_to_string( edge->flags ) ));
726 AF_DUMP(( "\n" ));
727 }
728 }
729 #ifdef __cplusplus
730 }
731 #endif
732
733 #undef AF_DUMP
734
735 #endif /* !FT_DEBUG_AUTOFIT */
736
737
738 /* Compute the direction value of a given vector. */
739
740 FT_LOCAL_DEF( AF_Direction )
741 af_direction_compute( FT_Pos dx,
742 FT_Pos dy )
743 {
744 FT_Pos ll, ss; /* long and short arm lengths */
745 AF_Direction dir; /* candidate direction */
746
747
748 if ( dy >= dx )
749 {
750 if ( dy >= -dx )
751 {
752 dir = AF_DIR_UP;
753 ll = dy;
754 ss = dx;
755 }
756 else
757 {
758 dir = AF_DIR_LEFT;
759 ll = -dx;
760 ss = dy;
761 }
762 }
763 else /* dy < dx */
764 {
765 if ( dy >= -dx )
766 {
767 dir = AF_DIR_RIGHT;
768 ll = dx;
769 ss = dy;
770 }
771 else
772 {
773 dir = AF_DIR_DOWN;
774 ll = -dy;
775 ss = dx;
776 }
777 }
778
779 /* return no direction if arm lengths do not differ enough */
780 /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
781 /* the long arm is never negative */
782 if ( ll <= 14 * FT_ABS( ss ) )
783 dir = AF_DIR_NONE;
784
785 return dir;
786 }
787
788
789 FT_LOCAL_DEF( void )
790 af_glyph_hints_init( AF_GlyphHints hints,
791 FT_Memory memory )
792 {
793 /* no need to initialize the embedded items */
794 FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) );
795 hints->memory = memory;
796 }
797
798
799 FT_LOCAL_DEF( void )
800 af_glyph_hints_done( AF_GlyphHints hints )
801 {
802 FT_Memory memory;
803 int dim;
804
805
806 if ( !( hints && hints->memory ) )
807 return;
808
809 memory = hints->memory;
810
811 /*
812 * note that we don't need to free the segment and edge
813 * buffers since they are really within the hints->points array
814 */
815 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
816 {
817 AF_AxisHints axis = &hints->axis[dim];
818
819
820 axis->num_segments = 0;
821 axis->max_segments = 0;
822 if ( axis->segments != axis->embedded.segments )
823 FT_FREE( axis->segments );
824
825 axis->num_edges = 0;
826 axis->max_edges = 0;
827 if ( axis->edges != axis->embedded.edges )
828 FT_FREE( axis->edges );
829 }
830
831 if ( hints->contours != hints->embedded.contours )
832 FT_FREE( hints->contours );
833 hints->max_contours = 0;
834 hints->num_contours = 0;
835
836 if ( hints->points != hints->embedded.points )
837 FT_FREE( hints->points );
838 hints->max_points = 0;
839 hints->num_points = 0;
840
841 hints->memory = NULL;
842 }
843
844
845 /* Reset metrics. */
846
847 FT_LOCAL_DEF( void )
848 af_glyph_hints_rescale( AF_GlyphHints hints,
849 AF_StyleMetrics metrics )
850 {
851 hints->metrics = metrics;
852 hints->scaler_flags = metrics->scaler.flags;
853 }
854
855
856 /* Recompute all AF_Point in AF_GlyphHints from the definitions */
857 /* in a source outline. */
858
859 FT_LOCAL_DEF( FT_Error )
860 af_glyph_hints_reload( AF_GlyphHints hints,
861 FT_Outline* outline )
862 {
863 FT_Error error = FT_Err_Ok;
864 AF_Point points;
865 FT_Int old_max, new_max;
866 FT_Fixed x_scale = hints->x_scale;
867 FT_Fixed y_scale = hints->y_scale;
868 FT_Pos x_delta = hints->x_delta;
869 FT_Pos y_delta = hints->y_delta;
870 FT_Memory memory = hints->memory;
871
872
873 hints->num_points = 0;
874 hints->num_contours = 0;
875
876 hints->axis[0].num_segments = 0;
877 hints->axis[0].num_edges = 0;
878 hints->axis[1].num_segments = 0;
879 hints->axis[1].num_edges = 0;
880
881 /* first of all, reallocate the contours array if necessary */
882 new_max = outline->n_contours;
883 old_max = hints->max_contours;
884
885 if ( new_max <= AF_CONTOURS_EMBEDDED )
886 {
887 if ( !hints->contours )
888 {
889 hints->contours = hints->embedded.contours;
890 hints->max_contours = AF_CONTOURS_EMBEDDED;
891 }
892 }
893 else if ( new_max > old_max )
894 {
895 if ( hints->contours == hints->embedded.contours )
896 hints->contours = NULL;
897
898 new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */
899
900 if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
901 goto Exit;
902
903 hints->max_contours = new_max;
904 }
905
906 /*
907 * then reallocate the points arrays if necessary --
908 * note that we reserve two additional point positions, used to
909 * hint metrics appropriately
910 */
911 new_max = outline->n_points + 2;
912 old_max = hints->max_points;
913
914 if ( new_max <= AF_POINTS_EMBEDDED )
915 {
916 if ( !hints->points )
917 {
918 hints->points = hints->embedded.points;
919 hints->max_points = AF_POINTS_EMBEDDED;
920 }
921 }
922 else if ( new_max > old_max )
923 {
924 if ( hints->points == hints->embedded.points )
925 hints->points = NULL;
926
927 new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */
928
929 if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
930 goto Exit;
931
932 hints->max_points = new_max;
933 }
934
935 hints->num_points = outline->n_points;
936 hints->num_contours = outline->n_contours;
937
938 /* We can't rely on the value of `FT_Outline.flags' to know the fill */
939 /* direction used for a glyph, given that some fonts are broken (e.g., */
940 /* the Arphic ones). We thus recompute it each time we need to. */
941 /* */
942 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
943 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
944
945 if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
946 {
947 hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
948 hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
949 }
950
951 hints->x_scale = x_scale;
952 hints->y_scale = y_scale;
953 hints->x_delta = x_delta;
954 hints->y_delta = y_delta;
955
956 points = hints->points;
957 if ( hints->num_points == 0 )
958 goto Exit;
959
960 {
961 AF_Point point;
962 AF_Point point_limit = points + hints->num_points;
963
964 /* value 20 in `near_limit' is heuristic */
965 FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM;
966 FT_Int near_limit = 20 * units_per_em / 2048;
967
968
969 /* compute coordinates & Bezier flags, next and prev */
970 {
971 FT_Vector* vec = outline->points;
972 char* tag = outline->tags;
973 FT_Short endpoint = outline->contours[0];
974 AF_Point end = points + endpoint;
975 AF_Point prev = end;
976 FT_Int contour_index = 0;
977
978
979 for ( point = points; point < point_limit; point++, vec++, tag++ )
980 {
981 FT_Pos out_x, out_y;
982
983
984 point->in_dir = (FT_Char)AF_DIR_NONE;
985 point->out_dir = (FT_Char)AF_DIR_NONE;
986
987 point->fx = (FT_Short)vec->x;
988 point->fy = (FT_Short)vec->y;
989 point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
990 point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
991
992 end->fx = (FT_Short)outline->points[endpoint].x;
993 end->fy = (FT_Short)outline->points[endpoint].y;
994
995 switch ( FT_CURVE_TAG( *tag ) )
996 {
997 case FT_CURVE_TAG_CONIC:
998 point->flags = AF_FLAG_CONIC;
999 break;
1000 case FT_CURVE_TAG_CUBIC:
1001 point->flags = AF_FLAG_CUBIC;
1002 break;
1003 default:
1004 point->flags = AF_FLAG_NONE;
1005 }
1006
1007 out_x = point->fx - prev->fx;
1008 out_y = point->fy - prev->fy;
1009
1010 if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
1011 prev->flags |= AF_FLAG_NEAR;
1012
1013 point->prev = prev;
1014 prev->next = point;
1015 prev = point;
1016
1017 if ( point == end )
1018 {
1019 if ( ++contour_index < outline->n_contours )
1020 {
1021 endpoint = outline->contours[contour_index];
1022 end = points + endpoint;
1023 prev = end;
1024 }
1025 }
1026
1027 #ifdef FT_DEBUG_AUTOFIT
1028 point->before[0] = NULL;
1029 point->before[1] = NULL;
1030 point->after[0] = NULL;
1031 point->after[1] = NULL;
1032 #endif
1033
1034 }
1035 }
1036
1037 /* set up the contours array */
1038 {
1039 AF_Point* contour = hints->contours;
1040 AF_Point* contour_limit = contour + hints->num_contours;
1041 short* end = outline->contours;
1042 short idx = 0;
1043
1044
1045 for ( ; contour < contour_limit; contour++, end++ )
1046 {
1047 contour[0] = points + idx;
1048 idx = (short)( end[0] + 1 );
1049 }
1050 }
1051
1052 {
1053 /*
1054 * Compute directions of `in' and `out' vectors.
1055 *
1056 * Note that distances between points that are very near to each
1057 * other are accumulated. In other words, the auto-hinter either
1058 * prepends the small vectors between near points to the first
1059 * non-near vector, or the sum of small vector lengths exceeds a
1060 * threshold, thus `grouping' the small vectors. All intermediate
1061 * points are tagged as weak; the directions are adjusted also to
1062 * be equal to the accumulated one.
1063 */
1064
1065 FT_Int near_limit2 = 2 * near_limit - 1;
1066
1067 AF_Point* contour;
1068 AF_Point* contour_limit = hints->contours + hints->num_contours;
1069
1070
1071 for ( contour = hints->contours; contour < contour_limit; contour++ )
1072 {
1073 AF_Point first = *contour;
1074 AF_Point next, prev, curr;
1075
1076 FT_Pos out_x, out_y;
1077
1078
1079 /* since the first point of a contour could be part of a */
1080 /* series of near points, go backwards to find the first */
1081 /* non-near point and adjust `first' */
1082
1083 point = first;
1084 prev = first->prev;
1085
1086 while ( prev != first )
1087 {
1088 out_x = point->fx - prev->fx;
1089 out_y = point->fy - prev->fy;
1090
1091 /*
1092 * We use Taxicab metrics to measure the vector length.
1093 *
1094 * Note that the accumulated distances so far could have the
1095 * opposite direction of the distance measured here. For this
1096 * reason we use `near_limit2' for the comparison to get a
1097 * non-near point even in the worst case.
1098 */
1099 if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 )
1100 break;
1101
1102 point = prev;
1103 prev = prev->prev;
1104 }
1105
1106 /* adjust first point */
1107 first = point;
1108
1109 /* now loop over all points of the contour to get */
1110 /* `in' and `out' vector directions */
1111
1112 curr = first;
1113
1114 /*
1115 * We abuse the `u' and `v' fields to store index deltas to the
1116 * next and previous non-near point, respectively.
1117 *
1118 * To avoid problems with not having non-near points, we point to
1119 * `first' by default as the next non-near point.
1120 *
1121 */
1122 curr->u = (FT_Pos)( first - curr );
1123 first->v = -curr->u;
1124
1125 out_x = 0;
1126 out_y = 0;
1127
1128 next = first;
1129 do
1130 {
1131 AF_Direction out_dir;
1132
1133
1134 point = next;
1135 next = point->next;
1136
1137 out_x += next->fx - point->fx;
1138 out_y += next->fy - point->fy;
1139
1140 if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
1141 {
1142 next->flags |= AF_FLAG_WEAK_INTERPOLATION;
1143 continue;
1144 }
1145
1146 curr->u = (FT_Pos)( next - curr );
1147 next->v = -curr->u;
1148
1149 out_dir = af_direction_compute( out_x, out_y );
1150
1151 /* adjust directions for all points inbetween; */
1152 /* the loop also updates position of `curr' */
1153 curr->out_dir = (FT_Char)out_dir;
1154 for ( curr = curr->next; curr != next; curr = curr->next )
1155 {
1156 curr->in_dir = (FT_Char)out_dir;
1157 curr->out_dir = (FT_Char)out_dir;
1158 }
1159 next->in_dir = (FT_Char)out_dir;
1160
1161 curr->u = (FT_Pos)( first - curr );
1162 first->v = -curr->u;
1163
1164 out_x = 0;
1165 out_y = 0;
1166
1167 } while ( next != first );
1168 }
1169
1170 /*
1171 * The next step is to `simplify' an outline's topology so that we
1172 * can identify local extrema more reliably: A series of
1173 * non-horizontal or non-vertical vectors pointing into the same
1174 * quadrant are handled as a single, long vector. From a
1175 * topological point of the view, the intermediate points are of no
1176 * interest and thus tagged as weak.
1177 */
1178
1179 for ( point = points; point < point_limit; point++ )
1180 {
1181 if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
1182 continue;
1183
1184 if ( point->in_dir == AF_DIR_NONE &&
1185 point->out_dir == AF_DIR_NONE )
1186 {
1187 /* check whether both vectors point into the same quadrant */
1188
1189 FT_Pos in_x, in_y;
1190 FT_Pos out_x, out_y;
1191
1192 AF_Point next_u = point + point->u;
1193 AF_Point prev_v = point + point->v;
1194
1195
1196 in_x = point->fx - prev_v->fx;
1197 in_y = point->fy - prev_v->fy;
1198
1199 out_x = next_u->fx - point->fx;
1200 out_y = next_u->fy - point->fy;
1201
1202 if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 )
1203 {
1204 /* yes, so tag current point as weak */
1205 /* and update index deltas */
1206
1207 point->flags |= AF_FLAG_WEAK_INTERPOLATION;
1208
1209 prev_v->u = (FT_Pos)( next_u - prev_v );
1210 next_u->v = -prev_v->u;
1211 }
1212 }
1213 }
1214
1215 /*
1216 * Finally, check for remaining weak points. Everything else not
1217 * collected in edges so far is then implicitly classified as strong
1218 * points.
1219 */
1220
1221 for ( point = points; point < point_limit; point++ )
1222 {
1223 if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
1224 continue;
1225
1226 if ( point->flags & AF_FLAG_CONTROL )
1227 {
1228 /* control points are always weak */
1229 Is_Weak_Point:
1230 point->flags |= AF_FLAG_WEAK_INTERPOLATION;
1231 }
1232 else if ( point->out_dir == point->in_dir )
1233 {
1234 if ( point->out_dir != AF_DIR_NONE )
1235 {
1236 /* current point lies on a horizontal or */
1237 /* vertical segment (but doesn't start or end it) */
1238 goto Is_Weak_Point;
1239 }
1240
1241 {
1242 AF_Point next_u = point + point->u;
1243 AF_Point prev_v = point + point->v;
1244
1245
1246 if ( ft_corner_is_flat( point->fx - prev_v->fx,
1247 point->fy - prev_v->fy,
1248 next_u->fx - point->fx,
1249 next_u->fy - point->fy ) )
1250 {
1251 /* either the `in' or the `out' vector is much more */
1252 /* dominant than the other one, so tag current point */
1253 /* as weak and update index deltas */
1254
1255 prev_v->u = (FT_Pos)( next_u - prev_v );
1256 next_u->v = -prev_v->u;
1257
1258 goto Is_Weak_Point;
1259 }
1260 }
1261 }
1262 else if ( point->in_dir == -point->out_dir )
1263 {
1264 /* current point forms a spike */
1265 goto Is_Weak_Point;
1266 }
1267 }
1268 }
1269 }
1270
1271 Exit:
1272 return error;
1273 }
1274
1275
1276 /* Store the hinted outline in an FT_Outline structure. */
1277
1278 FT_LOCAL_DEF( void )
1279 af_glyph_hints_save( AF_GlyphHints hints,
1280 FT_Outline* outline )
1281 {
1282 AF_Point point = hints->points;
1283 AF_Point limit = point + hints->num_points;
1284 FT_Vector* vec = outline->points;
1285 char* tag = outline->tags;
1286
1287
1288 for ( ; point < limit; point++, vec++, tag++ )
1289 {
1290 vec->x = point->x;
1291 vec->y = point->y;
1292
1293 if ( point->flags & AF_FLAG_CONIC )
1294 tag[0] = FT_CURVE_TAG_CONIC;
1295 else if ( point->flags & AF_FLAG_CUBIC )
1296 tag[0] = FT_CURVE_TAG_CUBIC;
1297 else
1298 tag[0] = FT_CURVE_TAG_ON;
1299 }
1300 }
1301
1302
1303 /****************************************************************
1304 *
1305 * EDGE POINT GRID-FITTING
1306 *
1307 ****************************************************************/
1308
1309
1310 /* Align all points of an edge to the same coordinate value, */
1311 /* either horizontally or vertically. */
1312
1313 FT_LOCAL_DEF( void )
1314 af_glyph_hints_align_edge_points( AF_GlyphHints hints,
1315 AF_Dimension dim )
1316 {
1317 AF_AxisHints axis = & hints->axis[dim];
1318 AF_Segment segments = axis->segments;
1319 AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments );
1320 AF_Segment seg;
1321
1322
1323 if ( dim == AF_DIMENSION_HORZ )
1324 {
1325 for ( seg = segments; seg < segment_limit; seg++ )
1326 {
1327 AF_Edge edge = seg->edge;
1328 AF_Point point, first, last;
1329
1330
1331 if ( !edge )
1332 continue;
1333
1334 first = seg->first;
1335 last = seg->last;
1336 point = first;
1337 for (;;)
1338 {
1339 point->x = edge->pos;
1340 point->flags |= AF_FLAG_TOUCH_X;
1341
1342 if ( point == last )
1343 break;
1344
1345 point = point->next;
1346 }
1347 }
1348 }
1349 else
1350 {
1351 for ( seg = segments; seg < segment_limit; seg++ )
1352 {
1353 AF_Edge edge = seg->edge;
1354 AF_Point point, first, last;
1355
1356
1357 if ( !edge )
1358 continue;
1359
1360 first = seg->first;
1361 last = seg->last;
1362 point = first;
1363 for (;;)
1364 {
1365 point->y = edge->pos;
1366 point->flags |= AF_FLAG_TOUCH_Y;
1367
1368 if ( point == last )
1369 break;
1370
1371 point = point->next;
1372 }
1373 }
1374 }
1375 }
1376
1377
1378 /****************************************************************
1379 *
1380 * STRONG POINT INTERPOLATION
1381 *
1382 ****************************************************************/
1383
1384
1385 /* Hint the strong points -- this is equivalent to the TrueType `IP' */
1386 /* hinting instruction. */
1387
1388 FT_LOCAL_DEF( void )
1389 af_glyph_hints_align_strong_points( AF_GlyphHints hints,
1390 AF_Dimension dim )
1391 {
1392 AF_Point points = hints->points;
1393 AF_Point point_limit = points + hints->num_points;
1394 AF_AxisHints axis = &hints->axis[dim];
1395 AF_Edge edges = axis->edges;
1396 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
1397 FT_UInt touch_flag;
1398
1399
1400 if ( dim == AF_DIMENSION_HORZ )
1401 touch_flag = AF_FLAG_TOUCH_X;
1402 else
1403 touch_flag = AF_FLAG_TOUCH_Y;
1404
1405 if ( edges < edge_limit )
1406 {
1407 AF_Point point;
1408 AF_Edge edge;
1409
1410
1411 for ( point = points; point < point_limit; point++ )
1412 {
1413 FT_Pos u, ou, fu; /* point position */
1414 FT_Pos delta;
1415
1416
1417 if ( point->flags & touch_flag )
1418 continue;
1419
1420 /* if this point is candidate to weak interpolation, we */
1421 /* interpolate it after all strong points have been processed */
1422
1423 if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) )
1424 continue;
1425
1426 if ( dim == AF_DIMENSION_VERT )
1427 {
1428 u = point->fy;
1429 ou = point->oy;
1430 }
1431 else
1432 {
1433 u = point->fx;
1434 ou = point->ox;
1435 }
1436
1437 fu = u;
1438
1439 /* is the point before the first edge? */
1440 edge = edges;
1441 delta = edge->fpos - u;
1442 if ( delta >= 0 )
1443 {
1444 u = edge->pos - ( edge->opos - ou );
1445
1446 #ifdef FT_DEBUG_AUTOFIT
1447 point->before[dim] = edge;
1448 point->after[dim] = NULL;
1449 #endif
1450
1451 goto Store_Point;
1452 }
1453
1454 /* is the point after the last edge? */
1455 edge = edge_limit - 1;
1456 delta = u - edge->fpos;
1457 if ( delta >= 0 )
1458 {
1459 u = edge->pos + ( ou - edge->opos );
1460
1461 #ifdef FT_DEBUG_AUTOFIT
1462 point->before[dim] = NULL;
1463 point->after[dim] = edge;
1464 #endif
1465
1466 goto Store_Point;
1467 }
1468
1469 {
1470 FT_PtrDist min, max, mid;
1471 FT_Pos fpos;
1472
1473
1474 /* find enclosing edges */
1475 min = 0;
1476 max = edge_limit - edges;
1477
1478 #if 1
1479 /* for a small number of edges, a linear search is better */
1480 if ( max <= 8 )
1481 {
1482 FT_PtrDist nn;
1483
1484
1485 for ( nn = 0; nn < max; nn++ )
1486 if ( edges[nn].fpos >= u )
1487 break;
1488
1489 if ( edges[nn].fpos == u )
1490 {
1491 u = edges[nn].pos;
1492 goto Store_Point;
1493 }
1494 min = nn;
1495 }
1496 else
1497 #endif
1498 while ( min < max )
1499 {
1500 mid = ( max + min ) >> 1;
1501 edge = edges + mid;
1502 fpos = edge->fpos;
1503
1504 if ( u < fpos )
1505 max = mid;
1506 else if ( u > fpos )
1507 min = mid + 1;
1508 else
1509 {
1510 /* we are on the edge */
1511 u = edge->pos;
1512
1513 #ifdef FT_DEBUG_AUTOFIT
1514 point->before[dim] = NULL;
1515 point->after[dim] = NULL;
1516 #endif
1517
1518 goto Store_Point;
1519 }
1520 }
1521
1522 /* point is not on an edge */
1523 {
1524 AF_Edge before = edges + min - 1;
1525 AF_Edge after = edges + min + 0;
1526
1527
1528 #ifdef FT_DEBUG_AUTOFIT
1529 point->before[dim] = before;
1530 point->after[dim] = after;
1531 #endif
1532
1533 /* assert( before && after && before != after ) */
1534 if ( before->scale == 0 )
1535 before->scale = FT_DivFix( after->pos - before->pos,
1536 after->fpos - before->fpos );
1537
1538 u = before->pos + FT_MulFix( fu - before->fpos,
1539 before->scale );
1540 }
1541 }
1542
1543 Store_Point:
1544 /* save the point position */
1545 if ( dim == AF_DIMENSION_HORZ )
1546 point->x = u;
1547 else
1548 point->y = u;
1549
1550 point->flags |= touch_flag;
1551 }
1552 }
1553 }
1554
1555
1556 /****************************************************************
1557 *
1558 * WEAK POINT INTERPOLATION
1559 *
1560 ****************************************************************/
1561
1562
1563 /* Shift the original coordinates of all points between `p1' and */
1564 /* `p2' to get hinted coordinates, using the same difference as */
1565 /* given by `ref'. */
1566
1567 static void
1568 af_iup_shift( AF_Point p1,
1569 AF_Point p2,
1570 AF_Point ref )
1571 {
1572 AF_Point p;
1573 FT_Pos delta = ref->u - ref->v;
1574
1575
1576 if ( delta == 0 )
1577 return;
1578
1579 for ( p = p1; p < ref; p++ )
1580 p->u = p->v + delta;
1581
1582 for ( p = ref + 1; p <= p2; p++ )
1583 p->u = p->v + delta;
1584 }
1585
1586
1587 /* Interpolate the original coordinates of all points between `p1' and */
1588 /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */
1589 /* reference points. The `u' and `v' members are the current and */
1590 /* original coordinate values, respectively. */
1591 /* */
1592 /* Details can be found in the TrueType bytecode specification. */
1593
1594 static void
1595 af_iup_interp( AF_Point p1,
1596 AF_Point p2,
1597 AF_Point ref1,
1598 AF_Point ref2 )
1599 {
1600 AF_Point p;
1601 FT_Pos u, v1, v2, u1, u2, d1, d2;
1602
1603
1604 if ( p1 > p2 )
1605 return;
1606
1607 if ( ref1->v > ref2->v )
1608 {
1609 p = ref1;
1610 ref1 = ref2;
1611 ref2 = p;
1612 }
1613
1614 v1 = ref1->v;
1615 v2 = ref2->v;
1616 u1 = ref1->u;
1617 u2 = ref2->u;
1618 d1 = u1 - v1;
1619 d2 = u2 - v2;
1620
1621 if ( u1 == u2 || v1 == v2 )
1622 {
1623 for ( p = p1; p <= p2; p++ )
1624 {
1625 u = p->v;
1626
1627 if ( u <= v1 )
1628 u += d1;
1629 else if ( u >= v2 )
1630 u += d2;
1631 else
1632 u = u1;
1633
1634 p->u = u;
1635 }
1636 }
1637 else
1638 {
1639 FT_Fixed scale = FT_DivFix( u2 - u1, v2 - v1 );
1640
1641
1642 for ( p = p1; p <= p2; p++ )
1643 {
1644 u = p->v;
1645
1646 if ( u <= v1 )
1647 u += d1;
1648 else if ( u >= v2 )
1649 u += d2;
1650 else
1651 u = u1 + FT_MulFix( u - v1, scale );
1652
1653 p->u = u;
1654 }
1655 }
1656 }
1657
1658
1659 /* Hint the weak points -- this is equivalent to the TrueType `IUP' */
1660 /* hinting instruction. */
1661
1662 FT_LOCAL_DEF( void )
1663 af_glyph_hints_align_weak_points( AF_GlyphHints hints,
1664 AF_Dimension dim )
1665 {
1666 AF_Point points = hints->points;
1667 AF_Point point_limit = points + hints->num_points;
1668 AF_Point* contour = hints->contours;
1669 AF_Point* contour_limit = contour + hints->num_contours;
1670 FT_UInt touch_flag;
1671 AF_Point point;
1672 AF_Point end_point;
1673 AF_Point first_point;
1674
1675
1676 /* PASS 1: Move segment points to edge positions */
1677
1678 if ( dim == AF_DIMENSION_HORZ )
1679 {
1680 touch_flag = AF_FLAG_TOUCH_X;
1681
1682 for ( point = points; point < point_limit; point++ )
1683 {
1684 point->u = point->x;
1685 point->v = point->ox;
1686 }
1687 }
1688 else
1689 {
1690 touch_flag = AF_FLAG_TOUCH_Y;
1691
1692 for ( point = points; point < point_limit; point++ )
1693 {
1694 point->u = point->y;
1695 point->v = point->oy;
1696 }
1697 }
1698
1699 for ( ; contour < contour_limit; contour++ )
1700 {
1701 AF_Point first_touched, last_touched;
1702
1703
1704 point = *contour;
1705 end_point = point->prev;
1706 first_point = point;
1707
1708 /* find first touched point */
1709 for (;;)
1710 {
1711 if ( point > end_point ) /* no touched point in contour */
1712 goto NextContour;
1713
1714 if ( point->flags & touch_flag )
1715 break;
1716
1717 point++;
1718 }
1719
1720 first_touched = point;
1721
1722 for (;;)
1723 {
1724 FT_ASSERT( point <= end_point &&
1725 ( point->flags & touch_flag ) != 0 );
1726
1727 /* skip any touched neighbours */
1728 while ( point < end_point &&
1729 ( point[1].flags & touch_flag ) != 0 )
1730 point++;
1731
1732 last_touched = point;
1733
1734 /* find the next touched point, if any */
1735 point++;
1736 for (;;)
1737 {
1738 if ( point > end_point )
1739 goto EndContour;
1740
1741 if ( ( point->flags & touch_flag ) != 0 )
1742 break;
1743
1744 point++;
1745 }
1746
1747 /* interpolate between last_touched and point */
1748 af_iup_interp( last_touched + 1, point - 1,
1749 last_touched, point );
1750 }
1751
1752 EndContour:
1753 /* special case: only one point was touched */
1754 if ( last_touched == first_touched )
1755 af_iup_shift( first_point, end_point, first_touched );
1756
1757 else /* interpolate the last part */
1758 {
1759 if ( last_touched < end_point )
1760 af_iup_interp( last_touched + 1, end_point,
1761 last_touched, first_touched );
1762
1763 if ( first_touched > points )
1764 af_iup_interp( first_point, first_touched - 1,
1765 last_touched, first_touched );
1766 }
1767
1768 NextContour:
1769 ;
1770 }
1771
1772 /* now save the interpolated values back to x/y */
1773 if ( dim == AF_DIMENSION_HORZ )
1774 {
1775 for ( point = points; point < point_limit; point++ )
1776 point->x = point->u;
1777 }
1778 else
1779 {
1780 for ( point = points; point < point_limit; point++ )
1781 point->y = point->u;
1782 }
1783 }
1784
1785
1786 /* END */