• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  afhints.c                                                              */
4 /*                                                                         */
5 /*    Auto-fitter hinting routines (body).                                 */
6 /*                                                                         */
7 /*  Copyright 2003, 2004, 2005, 2006, 2007, 2009 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 FT_INTERNAL_CALC_H
22 
23 
24   FT_LOCAL_DEF( FT_Error )
af_axis_hints_new_segment(AF_AxisHints axis,FT_Memory memory,AF_Segment * asegment)25   af_axis_hints_new_segment( AF_AxisHints  axis,
26                              FT_Memory     memory,
27                              AF_Segment   *asegment )
28   {
29     FT_Error    error   = AF_Err_Ok;
30     AF_Segment  segment = NULL;
31 
32 
33     if ( axis->num_segments >= axis->max_segments )
34     {
35       FT_Int  old_max = axis->max_segments;
36       FT_Int  new_max = old_max;
37       FT_Int  big_max = FT_INT_MAX / sizeof ( *segment );
38 
39 
40       if ( old_max >= big_max )
41       {
42         error = AF_Err_Out_Of_Memory;
43         goto Exit;
44       }
45 
46       new_max += ( new_max >> 2 ) + 4;
47       if ( new_max < old_max || new_max > big_max )
48         new_max = big_max;
49 
50       if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
51         goto Exit;
52 
53       axis->max_segments = new_max;
54     }
55 
56     segment = axis->segments + axis->num_segments++;
57 
58   Exit:
59     *asegment = segment;
60     return error;
61   }
62 
63 
64   FT_LOCAL( FT_Error )
af_axis_hints_new_edge(AF_AxisHints axis,FT_Int fpos,AF_Direction dir,FT_Memory memory,AF_Edge * aedge)65   af_axis_hints_new_edge( AF_AxisHints  axis,
66                           FT_Int        fpos,
67                           AF_Direction  dir,
68                           FT_Memory     memory,
69                           AF_Edge      *aedge )
70   {
71     FT_Error  error = AF_Err_Ok;
72     AF_Edge   edge  = NULL;
73     AF_Edge   edges;
74 
75 
76     if ( axis->num_edges >= axis->max_edges )
77     {
78       FT_Int  old_max = axis->max_edges;
79       FT_Int  new_max = old_max;
80       FT_Int  big_max = FT_INT_MAX / sizeof ( *edge );
81 
82 
83       if ( old_max >= big_max )
84       {
85         error = AF_Err_Out_Of_Memory;
86         goto Exit;
87       }
88 
89       new_max += ( new_max >> 2 ) + 4;
90       if ( new_max < old_max || new_max > big_max )
91         new_max = big_max;
92 
93       if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
94         goto Exit;
95 
96       axis->max_edges = new_max;
97     }
98 
99     edges = axis->edges;
100     edge  = edges + axis->num_edges;
101 
102     while ( edge > edges )
103     {
104       if ( edge[-1].fpos < fpos )
105         break;
106 
107       /* we want the edge with same position and minor direction */
108       /* to appear before those in the major one in the list     */
109       if ( edge[-1].fpos == fpos && dir == axis->major_dir )
110         break;
111 
112       edge[0] = edge[-1];
113       edge--;
114     }
115 
116     axis->num_edges++;
117 
118     FT_ZERO( edge );
119     edge->fpos = (FT_Short)fpos;
120     edge->dir  = (FT_Char)dir;
121 
122   Exit:
123     *aedge = edge;
124     return error;
125   }
126 
127 
128 #ifdef AF_DEBUG
129 
130 #include FT_CONFIG_STANDARD_LIBRARY_H
131 
132   static const char*
af_dir_str(AF_Direction dir)133   af_dir_str( AF_Direction  dir )
134   {
135     const char*  result;
136 
137 
138     switch ( dir )
139     {
140     case AF_DIR_UP:
141       result = "up";
142       break;
143     case AF_DIR_DOWN:
144       result = "down";
145       break;
146     case AF_DIR_LEFT:
147       result = "left";
148       break;
149     case AF_DIR_RIGHT:
150       result = "right";
151       break;
152     default:
153       result = "none";
154     }
155 
156     return result;
157   }
158 
159 
160 #define AF_INDEX_NUM( ptr, base )  ( (ptr) ? ( (ptr) - (base) ) : -1 )
161 
162 
163   void
af_glyph_hints_dump_points(AF_GlyphHints hints)164   af_glyph_hints_dump_points( AF_GlyphHints  hints )
165   {
166     AF_Point  points = hints->points;
167     AF_Point  limit  = points + hints->num_points;
168     AF_Point  point;
169 
170 
171     printf( "Table of points:\n" );
172     printf(   "  [ index |  xorg |  yorg |  xscale |  yscale "
173               "|  xfit  |  yfit  |  flags ]\n" );
174 
175     for ( point = points; point < limit; point++ )
176     {
177       printf( "  [ %5d | %5d | %5d | %-5.2f | %-5.2f "
178               "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n",
179               point - points,
180               point->fx,
181               point->fy,
182               point->ox/64.0,
183               point->oy/64.0,
184               point->x/64.0,
185               point->y/64.0,
186               ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
187               ( point->flags & AF_FLAG_INFLECTION )         ? 'i' : ' ',
188               ( point->flags & AF_FLAG_EXTREMA_X )          ? '<' : ' ',
189               ( point->flags & AF_FLAG_EXTREMA_Y )          ? 'v' : ' ',
190               ( point->flags & AF_FLAG_ROUND_X )            ? '(' : ' ',
191               ( point->flags & AF_FLAG_ROUND_Y )            ? 'u' : ' ');
192     }
193     printf( "\n" );
194   }
195 
196 
197   static const char*
af_edge_flags_to_string(AF_Edge_Flags flags)198   af_edge_flags_to_string( AF_Edge_Flags  flags )
199   {
200     static char  temp[32];
201     int          pos = 0;
202 
203 
204     if ( flags & AF_EDGE_ROUND )
205     {
206       ft_memcpy( temp + pos, "round", 5 );
207       pos += 5;
208     }
209     if ( flags & AF_EDGE_SERIF )
210     {
211       if ( pos > 0 )
212         temp[pos++] = ' ';
213       ft_memcpy( temp + pos, "serif", 5 );
214       pos += 5;
215     }
216     if ( pos == 0 )
217       return "normal";
218 
219     temp[pos] = 0;
220 
221     return temp;
222   }
223 
224 
225   /* A function to dump the array of linked segments. */
226   void
af_glyph_hints_dump_segments(AF_GlyphHints hints)227   af_glyph_hints_dump_segments( AF_GlyphHints  hints )
228   {
229     FT_Int  dimension;
230 
231 
232     for ( dimension = 1; dimension >= 0; dimension-- )
233     {
234       AF_AxisHints  axis     = &hints->axis[dimension];
235       AF_Segment    segments = axis->segments;
236       AF_Segment    limit    = segments + axis->num_segments;
237       AF_Segment    seg;
238 
239 
240       printf ( "Table of %s segments:\n",
241                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
242       printf ( "  [ index |  pos  |  dir  | link | serif |"
243                " height  | extra | flags    ]\n" );
244 
245       for ( seg = segments; seg < limit; seg++ )
246       {
247         printf ( "  [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n",
248                  seg - segments,
249                  dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
250                                                 : (int)seg->first->oy / 64.0,
251                  af_dir_str( (AF_Direction)seg->dir ),
252                  AF_INDEX_NUM( seg->link, segments ),
253                  AF_INDEX_NUM( seg->serif, segments ),
254                  seg->height,
255                  seg->height - ( seg->max_coord - seg->min_coord ),
256                  af_edge_flags_to_string( seg->flags ) );
257       }
258       printf( "\n" );
259     }
260   }
261 
262 
263   void
af_glyph_hints_dump_edges(AF_GlyphHints hints)264   af_glyph_hints_dump_edges( AF_GlyphHints  hints )
265   {
266     FT_Int  dimension;
267 
268 
269     for ( dimension = 1; dimension >= 0; dimension-- )
270     {
271       AF_AxisHints  axis  = &hints->axis[dimension];
272       AF_Edge       edges = axis->edges;
273       AF_Edge       limit = edges + axis->num_edges;
274       AF_Edge       edge;
275 
276 
277       /*
278        *  note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
279        *        since they have constant a X coordinate.
280        */
281       printf ( "Table of %s edges:\n",
282                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
283       printf ( "  [ index |  pos  |  dir  | link |"
284                " serif | blue | opos  |  pos  | flags   ]\n" );
285 
286       for ( edge = edges; edge < limit; edge++ )
287       {
288         printf ( "  [ %5d | %5.2g | %5s | %4d |"
289                  " %5d |   %c  | %5.2f | %5.2f | %s ]\n",
290                  edge - edges,
291                  (int)edge->opos / 64.0,
292                  af_dir_str( (AF_Direction)edge->dir ),
293                  AF_INDEX_NUM( edge->link, edges ),
294                  AF_INDEX_NUM( edge->serif, edges ),
295                  edge->blue_edge ? 'y' : 'n',
296                  edge->opos / 64.0,
297                  edge->pos / 64.0,
298                  af_edge_flags_to_string( edge->flags ) );
299       }
300       printf( "\n" );
301     }
302   }
303 
304 #else /* !AF_DEBUG */
305 
306   /* these empty stubs are only used to link the `ftgrid' test program */
307   /* when debugging is disabled                                        */
308 
309   void
af_glyph_hints_dump_points(AF_GlyphHints hints)310   af_glyph_hints_dump_points( AF_GlyphHints  hints )
311   {
312     FT_UNUSED( hints );
313   }
314 
315 
316   void
af_glyph_hints_dump_segments(AF_GlyphHints hints)317   af_glyph_hints_dump_segments( AF_GlyphHints  hints )
318   {
319     FT_UNUSED( hints );
320   }
321 
322 
323   void
af_glyph_hints_dump_edges(AF_GlyphHints hints)324   af_glyph_hints_dump_edges( AF_GlyphHints  hints )
325   {
326     FT_UNUSED( hints );
327   }
328 
329 #endif /* !AF_DEBUG */
330 
331 
332   /* compute the direction value of a given vector */
333   FT_LOCAL_DEF( AF_Direction )
af_direction_compute(FT_Pos dx,FT_Pos dy)334   af_direction_compute( FT_Pos  dx,
335                         FT_Pos  dy )
336   {
337     FT_Pos        ll, ss;  /* long and short arm lengths */
338     AF_Direction  dir;     /* candidate direction        */
339 
340 
341     if ( dy >= dx )
342     {
343       if ( dy >= -dx )
344       {
345         dir = AF_DIR_UP;
346         ll  = dy;
347         ss  = dx;
348       }
349       else
350       {
351         dir = AF_DIR_LEFT;
352         ll  = -dx;
353         ss  = dy;
354       }
355     }
356     else /* dy < dx */
357     {
358       if ( dy >= -dx )
359       {
360         dir = AF_DIR_RIGHT;
361         ll  = dx;
362         ss  = dy;
363       }
364       else
365       {
366         dir = AF_DIR_DOWN;
367         ll  = dy;
368         ss  = dx;
369       }
370     }
371 
372     ss *= 14;
373     if ( FT_ABS( ll ) <= FT_ABS( ss ) )
374       dir = AF_DIR_NONE;
375 
376     return dir;
377   }
378 
379 
380   /* compute all inflex points in a given glyph */
381 
382   static void
af_glyph_hints_compute_inflections(AF_GlyphHints hints)383   af_glyph_hints_compute_inflections( AF_GlyphHints  hints )
384   {
385     AF_Point*  contour       = hints->contours;
386     AF_Point*  contour_limit = contour + hints->num_contours;
387 
388 
389     /* do each contour separately */
390     for ( ; contour < contour_limit; contour++ )
391     {
392       AF_Point  point = contour[0];
393       AF_Point  first = point;
394       AF_Point  start = point;
395       AF_Point  end   = point;
396       AF_Point  before;
397       AF_Point  after;
398       FT_Pos    in_x, in_y, out_x, out_y;
399       AF_Angle  orient_prev, orient_cur;
400       FT_Int    finished = 0;
401 
402 
403       /* compute first segment in contour */
404       first = point;
405 
406       start = end = first;
407       do
408       {
409         end = end->next;
410         if ( end == first )
411           goto Skip;
412 
413         in_x = end->fx - start->fx;
414         in_y = end->fy - start->fy;
415 
416       } while ( in_x == 0 && in_y == 0 );
417 
418       /* extend the segment start whenever possible */
419       before = start;
420       do
421       {
422         do
423         {
424           start  = before;
425           before = before->prev;
426           if ( before == first )
427             goto Skip;
428 
429           out_x = start->fx - before->fx;
430           out_y = start->fy - before->fy;
431 
432         } while ( out_x == 0 && out_y == 0 );
433 
434         orient_prev = ft_corner_orientation( in_x, in_y, out_x, out_y );
435 
436       } while ( orient_prev == 0 );
437 
438       first = start;
439 
440       in_x = out_x;
441       in_y = out_y;
442 
443       /* now process all segments in the contour */
444       do
445       {
446         /* first, extend current segment's end whenever possible */
447         after = end;
448         do
449         {
450           do
451           {
452             end   = after;
453             after = after->next;
454             if ( after == first )
455               finished = 1;
456 
457             out_x = after->fx - end->fx;
458             out_y = after->fy - end->fy;
459 
460           } while ( out_x == 0 && out_y == 0 );
461 
462           orient_cur = ft_corner_orientation( in_x, in_y, out_x, out_y );
463 
464         } while ( orient_cur == 0 );
465 
466         if ( ( orient_prev + orient_cur ) == 0 )
467         {
468           /* we have an inflection point here */
469           do
470           {
471             start->flags |= AF_FLAG_INFLECTION;
472             start = start->next;
473 
474           } while ( start != end );
475 
476           start->flags |= AF_FLAG_INFLECTION;
477         }
478 
479         start = end;
480         end   = after;
481 
482         orient_prev = orient_cur;
483         in_x        = out_x;
484         in_y        = out_y;
485 
486       } while ( !finished );
487 
488     Skip:
489       ;
490     }
491   }
492 
493 
494   FT_LOCAL_DEF( void )
af_glyph_hints_init(AF_GlyphHints hints,FT_Memory memory)495   af_glyph_hints_init( AF_GlyphHints  hints,
496                        FT_Memory      memory )
497   {
498     FT_ZERO( hints );
499     hints->memory = memory;
500   }
501 
502 
503   FT_LOCAL_DEF( void )
af_glyph_hints_done(AF_GlyphHints hints)504   af_glyph_hints_done( AF_GlyphHints  hints )
505   {
506     if ( hints && hints->memory )
507     {
508       FT_Memory  memory = hints->memory;
509       int        dim;
510 
511 
512       /*
513        *  note that we don't need to free the segment and edge
514        *  buffers, since they are really within the hints->points array
515        */
516       for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
517       {
518         AF_AxisHints  axis = &hints->axis[dim];
519 
520 
521         axis->num_segments = 0;
522         axis->max_segments = 0;
523         FT_FREE( axis->segments );
524 
525         axis->num_edges    = 0;
526         axis->max_edges    = 0;
527         FT_FREE( axis->edges );
528       }
529 
530       FT_FREE( hints->contours );
531       hints->max_contours = 0;
532       hints->num_contours = 0;
533 
534       FT_FREE( hints->points );
535       hints->num_points = 0;
536       hints->max_points = 0;
537 
538       hints->memory = NULL;
539     }
540   }
541 
542 
543   FT_LOCAL_DEF( void )
af_glyph_hints_rescale(AF_GlyphHints hints,AF_ScriptMetrics metrics)544   af_glyph_hints_rescale( AF_GlyphHints     hints,
545                           AF_ScriptMetrics  metrics )
546   {
547     hints->metrics      = metrics;
548     hints->scaler_flags = metrics->scaler.flags;
549   }
550 
551 
552   FT_LOCAL_DEF( FT_Error )
af_glyph_hints_reload(AF_GlyphHints hints,FT_Outline * outline,FT_Bool get_inflections)553   af_glyph_hints_reload( AF_GlyphHints  hints,
554                          FT_Outline*    outline,
555                          FT_Bool        get_inflections )
556   {
557     FT_Error   error   = AF_Err_Ok;
558     AF_Point   points;
559     FT_UInt    old_max, new_max;
560     FT_Fixed   x_scale = hints->x_scale;
561     FT_Fixed   y_scale = hints->y_scale;
562     FT_Pos     x_delta = hints->x_delta;
563     FT_Pos     y_delta = hints->y_delta;
564     FT_Memory  memory  = hints->memory;
565 
566 
567     hints->num_points   = 0;
568     hints->num_contours = 0;
569 
570     hints->axis[0].num_segments = 0;
571     hints->axis[0].num_edges    = 0;
572     hints->axis[1].num_segments = 0;
573     hints->axis[1].num_edges    = 0;
574 
575     /* first of all, reallocate the contours array when necessary */
576     new_max = (FT_UInt)outline->n_contours;
577     old_max = hints->max_contours;
578     if ( new_max > old_max )
579     {
580       new_max = ( new_max + 3 ) & ~3;
581 
582       if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
583         goto Exit;
584 
585       hints->max_contours = new_max;
586     }
587 
588     /*
589      *  then reallocate the points arrays if necessary --
590      *  note that we reserve two additional point positions, used to
591      *  hint metrics appropriately
592      */
593     new_max = (FT_UInt)( outline->n_points + 2 );
594     old_max = hints->max_points;
595     if ( new_max > old_max )
596     {
597       new_max = ( new_max + 2 + 7 ) & ~7;
598 
599       if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
600         goto Exit;
601 
602       hints->max_points = new_max;
603     }
604 
605     hints->num_points   = outline->n_points;
606     hints->num_contours = outline->n_contours;
607 
608     /* We can't rely on the value of `FT_Outline.flags' to know the fill   */
609     /* direction used for a glyph, given that some fonts are broken (e.g., */
610     /* the Arphic ones).  We thus recompute it each time we need to.       */
611     /*                                                                     */
612     hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
613     hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
614 
615     if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
616     {
617       hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
618       hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
619     }
620 
621     hints->x_scale = x_scale;
622     hints->y_scale = y_scale;
623     hints->x_delta = x_delta;
624     hints->y_delta = y_delta;
625 
626     hints->xmin_delta = 0;
627     hints->xmax_delta = 0;
628 
629     points = hints->points;
630     if ( hints->num_points == 0 )
631       goto Exit;
632 
633     {
634       AF_Point  point;
635       AF_Point  point_limit = points + hints->num_points;
636 
637 
638       /* compute coordinates & Bezier flags, next and prev */
639       {
640         FT_Vector*  vec           = outline->points;
641         char*       tag           = outline->tags;
642         AF_Point    first         = points;
643         AF_Point    end           = points + outline->contours[0];
644         AF_Point    prev          = end;
645         FT_Int      contour_index = 0;
646 
647 
648         for ( point = points; point < point_limit; point++, vec++, tag++ )
649         {
650           point->fx = (FT_Short)vec->x;
651           point->fy = (FT_Short)vec->y;
652           point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
653           point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
654 
655           switch ( FT_CURVE_TAG( *tag ) )
656           {
657           case FT_CURVE_TAG_CONIC:
658             point->flags = AF_FLAG_CONIC;
659             break;
660           case FT_CURVE_TAG_CUBIC:
661             point->flags = AF_FLAG_CUBIC;
662             break;
663           default:
664             point->flags = 0;
665           }
666 
667           point->prev = prev;
668           prev->next  = point;
669           prev        = point;
670 
671           if ( point == end )
672           {
673             if ( ++contour_index < outline->n_contours )
674             {
675               first = point + 1;
676               end   = points + outline->contours[contour_index];
677               prev  = end;
678             }
679           }
680         }
681       }
682 
683       /* set-up the contours array */
684       {
685         AF_Point*  contour       = hints->contours;
686         AF_Point*  contour_limit = contour + hints->num_contours;
687         short*     end           = outline->contours;
688         short      idx           = 0;
689 
690 
691         for ( ; contour < contour_limit; contour++, end++ )
692         {
693           contour[0] = points + idx;
694           idx        = (short)( end[0] + 1 );
695         }
696       }
697 
698       /* compute directions of in & out vectors */
699       {
700         AF_Point      first  = points;
701         AF_Point      prev   = NULL;
702         FT_Pos        in_x   = 0;
703         FT_Pos        in_y   = 0;
704         AF_Direction  in_dir = AF_DIR_NONE;
705 
706 
707         for ( point = points; point < point_limit; point++ )
708         {
709           AF_Point  next;
710           FT_Pos    out_x, out_y;
711 
712 
713           if ( point == first )
714           {
715             prev   = first->prev;
716             in_x   = first->fx - prev->fx;
717             in_y   = first->fy - prev->fy;
718             in_dir = af_direction_compute( in_x, in_y );
719             first  = prev + 1;
720           }
721 
722           point->in_dir = (FT_Char)in_dir;
723 
724           next  = point->next;
725           out_x = next->fx - point->fx;
726           out_y = next->fy - point->fy;
727 
728           in_dir         = af_direction_compute( out_x, out_y );
729           point->out_dir = (FT_Char)in_dir;
730 
731           if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
732           {
733           Is_Weak_Point:
734             point->flags |= AF_FLAG_WEAK_INTERPOLATION;
735           }
736           else if ( point->out_dir == point->in_dir )
737           {
738             if ( point->out_dir != AF_DIR_NONE )
739               goto Is_Weak_Point;
740 
741             if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
742               goto Is_Weak_Point;
743           }
744           else if ( point->in_dir == -point->out_dir )
745             goto Is_Weak_Point;
746 
747           in_x = out_x;
748           in_y = out_y;
749           prev = point;
750         }
751       }
752     }
753 
754     /* compute inflection points --                 */
755     /* disabled due to no longer perceived benefits */
756     if ( 0 && get_inflections )
757       af_glyph_hints_compute_inflections( hints );
758 
759   Exit:
760     return error;
761   }
762 
763 
764   FT_LOCAL_DEF( void )
af_glyph_hints_save(AF_GlyphHints hints,FT_Outline * outline)765   af_glyph_hints_save( AF_GlyphHints  hints,
766                        FT_Outline*    outline )
767   {
768     AF_Point    point = hints->points;
769     AF_Point    limit = point + hints->num_points;
770     FT_Vector*  vec   = outline->points;
771     char*       tag   = outline->tags;
772 
773 
774     for ( ; point < limit; point++, vec++, tag++ )
775     {
776       vec->x = point->x;
777       vec->y = point->y;
778 
779       if ( point->flags & AF_FLAG_CONIC )
780         tag[0] = FT_CURVE_TAG_CONIC;
781       else if ( point->flags & AF_FLAG_CUBIC )
782         tag[0] = FT_CURVE_TAG_CUBIC;
783       else
784         tag[0] = FT_CURVE_TAG_ON;
785     }
786   }
787 
788 
789   /****************************************************************
790    *
791    *                     EDGE POINT GRID-FITTING
792    *
793    ****************************************************************/
794 
795 
796   FT_LOCAL_DEF( void )
af_glyph_hints_align_edge_points(AF_GlyphHints hints,AF_Dimension dim)797   af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
798                                     AF_Dimension   dim )
799   {
800     AF_AxisHints  axis          = & hints->axis[dim];
801     AF_Segment    segments      = axis->segments;
802     AF_Segment    segment_limit = segments + axis->num_segments;
803     AF_Segment    seg;
804 
805 
806     if ( dim == AF_DIMENSION_HORZ )
807     {
808       for ( seg = segments; seg < segment_limit; seg++ )
809       {
810         AF_Edge   edge = seg->edge;
811         AF_Point  point, first, last;
812 
813 
814         if ( edge == NULL )
815           continue;
816 
817         first = seg->first;
818         last  = seg->last;
819         point = first;
820         for (;;)
821         {
822           point->x      = edge->pos;
823           point->flags |= AF_FLAG_TOUCH_X;
824 
825           if ( point == last )
826             break;
827 
828           point = point->next;
829 
830         }
831       }
832     }
833     else
834     {
835       for ( seg = segments; seg < segment_limit; seg++ )
836       {
837         AF_Edge   edge = seg->edge;
838         AF_Point  point, first, last;
839 
840 
841         if ( edge == NULL )
842           continue;
843 
844         first = seg->first;
845         last  = seg->last;
846         point = first;
847         for (;;)
848         {
849           point->y      = edge->pos;
850           point->flags |= AF_FLAG_TOUCH_Y;
851 
852           if ( point == last )
853             break;
854 
855           point = point->next;
856         }
857       }
858     }
859   }
860 
861 
862   /****************************************************************
863    *
864    *                    STRONG POINT INTERPOLATION
865    *
866    ****************************************************************/
867 
868 
869   /* hint the strong points -- this is equivalent to the TrueType `IP' */
870   /* hinting instruction                                               */
871 
872   FT_LOCAL_DEF( void )
af_glyph_hints_align_strong_points(AF_GlyphHints hints,AF_Dimension dim)873   af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
874                                       AF_Dimension   dim )
875   {
876     AF_Point      points      = hints->points;
877     AF_Point      point_limit = points + hints->num_points;
878     AF_AxisHints  axis        = &hints->axis[dim];
879     AF_Edge       edges       = axis->edges;
880     AF_Edge       edge_limit  = edges + axis->num_edges;
881     AF_Flags      touch_flag;
882 
883 
884     if ( dim == AF_DIMENSION_HORZ )
885       touch_flag = AF_FLAG_TOUCH_X;
886     else
887       touch_flag  = AF_FLAG_TOUCH_Y;
888 
889     if ( edges < edge_limit )
890     {
891       AF_Point  point;
892       AF_Edge   edge;
893 
894 
895       for ( point = points; point < point_limit; point++ )
896       {
897         FT_Pos  u, ou, fu;  /* point position */
898         FT_Pos  delta;
899 
900 
901         if ( point->flags & touch_flag )
902           continue;
903 
904         /* if this point is candidate to weak interpolation, we       */
905         /* interpolate it after all strong points have been processed */
906 
907         if (  ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
908              !( point->flags & AF_FLAG_INFLECTION )         )
909           continue;
910 
911         if ( dim == AF_DIMENSION_VERT )
912         {
913           u  = point->fy;
914           ou = point->oy;
915         }
916         else
917         {
918           u  = point->fx;
919           ou = point->ox;
920         }
921 
922         fu = u;
923 
924         /* is the point before the first edge? */
925         edge  = edges;
926         delta = edge->fpos - u;
927         if ( delta >= 0 )
928         {
929           u = edge->pos - ( edge->opos - ou );
930           goto Store_Point;
931         }
932 
933         /* is the point after the last edge? */
934         edge  = edge_limit - 1;
935         delta = u - edge->fpos;
936         if ( delta >= 0 )
937         {
938           u = edge->pos + ( ou - edge->opos );
939           goto Store_Point;
940         }
941 
942         {
943           FT_UInt  min, max, mid;
944           FT_Pos   fpos;
945 
946 
947           /* find enclosing edges */
948           min = 0;
949           max = edge_limit - edges;
950 
951 #if 1
952           /* for small edge counts, a linear search is better */
953           if ( max <= 8 )
954           {
955             FT_UInt  nn;
956 
957             for ( nn = 0; nn < max; nn++ )
958               if ( edges[nn].fpos >= u )
959                 break;
960 
961             if ( edges[nn].fpos == u )
962             {
963               u = edges[nn].pos;
964               goto Store_Point;
965             }
966             min = nn;
967           }
968           else
969 #endif
970           while ( min < max )
971           {
972             mid  = ( max + min ) >> 1;
973             edge = edges + mid;
974             fpos = edge->fpos;
975 
976             if ( u < fpos )
977               max = mid;
978             else if ( u > fpos )
979               min = mid + 1;
980             else
981             {
982               /* we are on the edge */
983               u = edge->pos;
984               goto Store_Point;
985             }
986           }
987 
988           {
989             AF_Edge  before = edges + min - 1;
990             AF_Edge  after  = edges + min + 0;
991 
992 
993             /* assert( before && after && before != after ) */
994             if ( before->scale == 0 )
995               before->scale = FT_DivFix( after->pos - before->pos,
996                                          after->fpos - before->fpos );
997 
998             u = before->pos + FT_MulFix( fu - before->fpos,
999                                          before->scale );
1000           }
1001         }
1002 
1003       Store_Point:
1004         /* save the point position */
1005         if ( dim == AF_DIMENSION_HORZ )
1006           point->x = u;
1007         else
1008           point->y = u;
1009 
1010         point->flags |= touch_flag;
1011       }
1012     }
1013   }
1014 
1015 
1016   /****************************************************************
1017    *
1018    *                    WEAK POINT INTERPOLATION
1019    *
1020    ****************************************************************/
1021 
1022 
1023   static void
af_iup_shift(AF_Point p1,AF_Point p2,AF_Point ref)1024   af_iup_shift( AF_Point  p1,
1025                 AF_Point  p2,
1026                 AF_Point  ref )
1027   {
1028     AF_Point  p;
1029     FT_Pos    delta = ref->u - ref->v;
1030 
1031     if ( delta == 0 )
1032       return;
1033 
1034     for ( p = p1; p < ref; p++ )
1035       p->u = p->v + delta;
1036 
1037     for ( p = ref + 1; p <= p2; p++ )
1038       p->u = p->v + delta;
1039   }
1040 
1041 
1042   static void
af_iup_interp(AF_Point p1,AF_Point p2,AF_Point ref1,AF_Point ref2)1043   af_iup_interp( AF_Point  p1,
1044                  AF_Point  p2,
1045                  AF_Point  ref1,
1046                  AF_Point  ref2 )
1047   {
1048     AF_Point  p;
1049     FT_Pos    u;
1050     FT_Pos    v1 = ref1->v;
1051     FT_Pos    v2 = ref2->v;
1052     FT_Pos    d1 = ref1->u - v1;
1053     FT_Pos    d2 = ref2->u - v2;
1054 
1055 
1056     if ( p1 > p2 )
1057       return;
1058 
1059     if ( v1 == v2 )
1060     {
1061       for ( p = p1; p <= p2; p++ )
1062       {
1063         u = p->v;
1064 
1065         if ( u <= v1 )
1066           u += d1;
1067         else
1068           u += d2;
1069 
1070         p->u = u;
1071       }
1072       return;
1073     }
1074 
1075     if ( v1 < v2 )
1076     {
1077       for ( p = p1; p <= p2; p++ )
1078       {
1079         u = p->v;
1080 
1081         if ( u <= v1 )
1082           u += d1;
1083         else if ( u >= v2 )
1084           u += d2;
1085         else
1086           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
1087 
1088         p->u = u;
1089       }
1090     }
1091     else
1092     {
1093       for ( p = p1; p <= p2; p++ )
1094       {
1095         u = p->v;
1096 
1097         if ( u <= v2 )
1098           u += d2;
1099         else if ( u >= v1 )
1100           u += d1;
1101         else
1102           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
1103 
1104         p->u = u;
1105       }
1106     }
1107   }
1108 
1109 
1110   FT_LOCAL_DEF( void )
af_glyph_hints_align_weak_points(AF_GlyphHints hints,AF_Dimension dim)1111   af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
1112                                     AF_Dimension   dim )
1113   {
1114     AF_Point   points        = hints->points;
1115     AF_Point   point_limit   = points + hints->num_points;
1116     AF_Point*  contour       = hints->contours;
1117     AF_Point*  contour_limit = contour + hints->num_contours;
1118     AF_Flags   touch_flag;
1119     AF_Point   point;
1120     AF_Point   end_point;
1121     AF_Point   first_point;
1122 
1123 
1124     /* PASS 1: Move segment points to edge positions */
1125 
1126     if ( dim == AF_DIMENSION_HORZ )
1127     {
1128       touch_flag = AF_FLAG_TOUCH_X;
1129 
1130       for ( point = points; point < point_limit; point++ )
1131       {
1132         point->u = point->x;
1133         point->v = point->ox;
1134       }
1135     }
1136     else
1137     {
1138       touch_flag = AF_FLAG_TOUCH_Y;
1139 
1140       for ( point = points; point < point_limit; point++ )
1141       {
1142         point->u = point->y;
1143         point->v = point->oy;
1144       }
1145     }
1146 
1147     point = points;
1148 
1149     for ( ; contour < contour_limit; contour++ )
1150     {
1151       AF_Point  first_touched, last_touched;
1152 
1153 
1154       point       = *contour;
1155       end_point   = point->prev;
1156       first_point = point;
1157 
1158       /* find first touched point */
1159       for (;;)
1160       {
1161         if ( point > end_point )  /* no touched point in contour */
1162           goto NextContour;
1163 
1164         if ( point->flags & touch_flag )
1165           break;
1166 
1167         point++;
1168       }
1169 
1170       first_touched = point;
1171       last_touched  = point;
1172 
1173       for (;;)
1174       {
1175         FT_ASSERT( point <= end_point &&
1176                    ( point->flags & touch_flag ) != 0 );
1177 
1178         /* skip any touched neighbhours */
1179         while ( point < end_point && ( point[1].flags & touch_flag ) != 0 )
1180           point++;
1181 
1182         last_touched = point;
1183 
1184         /* find the next touched point, if any */
1185         point ++;
1186         for (;;)
1187         {
1188           if ( point > end_point )
1189             goto EndContour;
1190 
1191           if ( ( point->flags & touch_flag ) != 0 )
1192             break;
1193 
1194           point++;
1195         }
1196 
1197         /* interpolate between last_touched and point */
1198         af_iup_interp( last_touched + 1, point - 1,
1199                        last_touched, point );
1200       }
1201 
1202     EndContour:
1203       /* special case: only one point was touched */
1204       if ( last_touched == first_touched )
1205       {
1206         af_iup_shift( first_point, end_point, first_touched );
1207       }
1208       else /* interpolate the last part */
1209       {
1210         if ( last_touched < end_point )
1211           af_iup_interp( last_touched + 1, end_point,
1212                          last_touched, first_touched );
1213 
1214         if ( first_touched > points )
1215           af_iup_interp( first_point, first_touched - 1,
1216                          last_touched, first_touched );
1217       }
1218 
1219     NextContour:
1220       ;
1221     }
1222 
1223     /* now save the interpolated values back to x/y */
1224     if ( dim == AF_DIMENSION_HORZ )
1225     {
1226       for ( point = points; point < point_limit; point++ )
1227         point->x = point->u;
1228     }
1229     else
1230     {
1231       for ( point = points; point < point_limit; point++ )
1232         point->y = point->u;
1233     }
1234   }
1235 
1236 
1237 #ifdef AF_USE_WARPER
1238 
1239   FT_LOCAL_DEF( void )
af_glyph_hints_scale_dim(AF_GlyphHints hints,AF_Dimension dim,FT_Fixed scale,FT_Pos delta)1240   af_glyph_hints_scale_dim( AF_GlyphHints  hints,
1241                             AF_Dimension   dim,
1242                             FT_Fixed       scale,
1243                             FT_Pos         delta )
1244   {
1245     AF_Point  points       = hints->points;
1246     AF_Point  points_limit = points + hints->num_points;
1247     AF_Point  point;
1248 
1249 
1250     if ( dim == AF_DIMENSION_HORZ )
1251     {
1252       for ( point = points; point < points_limit; point++ )
1253         point->x = FT_MulFix( point->fx, scale ) + delta;
1254     }
1255     else
1256     {
1257       for ( point = points; point < points_limit; point++ )
1258         point->y = FT_MulFix( point->fy, scale ) + delta;
1259     }
1260   }
1261 
1262 #endif /* AF_USE_WARPER */
1263 
1264 /* END */
1265