source: trunk/poppler/freetype2/src/autofit/afhints.c @ 182

Last change on this file since 182 was 182, checked in by Eugene Romanenko, 15 years ago

freetype update to version 2.3.0

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