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

Last change on this file since 200 was 200, checked in by Eugene Romanenko, 14 years ago

PDF plugin: update freetype to 2.3.1 release

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    hints->xmin_delta = 0;
731    hints->xmax_delta = 0;
732
733    points = hints->points;
734    if ( hints->num_points == 0 )
735      goto Exit;
736
737    {
738      AF_Point  point;
739      AF_Point  point_limit = points + hints->num_points;
740
741
742      /* compute coordinates & Bezier flags */
743      {
744        FT_Vector*  vec = outline->points;
745        char*       tag = outline->tags;
746
747
748        for ( point = points; point < point_limit; point++, vec++, tag++ )
749        {
750          point->fx = (FT_Short)vec->x;
751          point->fy = (FT_Short)vec->y;
752          point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
753          point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
754
755          switch ( FT_CURVE_TAG( *tag ) )
756          {
757          case FT_CURVE_TAG_CONIC:
758            point->flags = AF_FLAG_CONIC;
759            break;
760          case FT_CURVE_TAG_CUBIC:
761            point->flags = AF_FLAG_CUBIC;
762            break;
763          default:
764            point->flags = 0;
765          }
766        }
767      }
768
769      /* compute `next' and `prev' */
770      {
771        FT_Int    contour_index;
772        AF_Point  prev;
773        AF_Point  first;
774        AF_Point  end;
775
776
777        contour_index = 0;
778
779        first = points;
780        end   = points + outline->contours[0];
781        prev  = end;
782
783        for ( point = points; point < point_limit; point++ )
784        {
785          point->prev = prev;
786          if ( point < end )
787          {
788            point->next = point + 1;
789            prev        = point;
790          }
791          else
792          {
793            point->next = first;
794            contour_index++;
795            if ( point + 1 < point_limit )
796            {
797              end   = points + outline->contours[contour_index];
798              first = point + 1;
799              prev  = end;
800            }
801          }
802        }
803      }
804
805      /* set-up the contours array */
806      {
807        AF_Point*  contour       = hints->contours;
808        AF_Point*  contour_limit = contour + hints->num_contours;
809        short*     end           = outline->contours;
810        short      idx           = 0;
811
812
813        for ( ; contour < contour_limit; contour++, end++ )
814        {
815          contour[0] = points + idx;
816          idx        = (short)( end[0] + 1 );
817        }
818      }
819
820      /* compute directions of in & out vectors */
821      {
822        for ( point = points; point < point_limit; point++ )
823        {
824          AF_Point  prev;
825          AF_Point  next;
826          FT_Pos    in_x, in_y, out_x, out_y;
827
828
829          prev   = point->prev;
830          in_x   = point->fx - prev->fx;
831          in_y   = point->fy - prev->fy;
832
833          point->in_dir = (FT_Char)af_direction_compute( in_x, in_y );
834
835          next   = point->next;
836          out_x  = next->fx - point->fx;
837          out_y  = next->fy - point->fy;
838
839          point->out_dir = (FT_Char)af_direction_compute( out_x, out_y );
840
841          if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
842          {
843          Is_Weak_Point:
844            point->flags |= AF_FLAG_WEAK_INTERPOLATION;
845          }
846          else if ( point->out_dir == point->in_dir )
847          {
848
849#if 1
850
851            if ( point->out_dir != AF_DIR_NONE )
852              goto Is_Weak_Point;
853
854            if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
855              goto Is_Weak_Point;
856
857#else /* old code */
858
859            AF_Angle  angle_in, angle_out, delta;
860
861
862            if ( point->out_dir != AF_DIR_NONE )
863              goto Is_Weak_Point;
864
865            angle_in  = af_angle_atan( in_x, in_y );
866            angle_out = af_angle_atan( out_x, out_y );
867
868            AF_ANGLE_DIFF( delta, angle_in, angle_out );
869
870            if ( delta < 2 && delta > -2 )
871              goto Is_Weak_Point;
872
873#endif /* old code */
874
875          }
876          else if ( point->in_dir == -point->out_dir )
877            goto Is_Weak_Point;
878        }
879      }
880    }
881
882    /* compute inflection points */
883    af_glyph_hints_compute_inflections( hints );
884
885  Exit:
886    return error;
887  }
888
889
890  FT_LOCAL_DEF( void )
891  af_glyph_hints_save( AF_GlyphHints  hints,
892                       FT_Outline*    outline )
893  {
894    AF_Point    point = hints->points;
895    AF_Point    limit = point + hints->num_points;
896    FT_Vector*  vec   = outline->points;
897    char*       tag   = outline->tags;
898
899
900    for ( ; point < limit; point++, vec++, tag++ )
901    {
902      vec->x = point->x;
903      vec->y = point->y;
904
905      if ( point->flags & AF_FLAG_CONIC )
906        tag[0] = FT_CURVE_TAG_CONIC;
907      else if ( point->flags & AF_FLAG_CUBIC )
908        tag[0] = FT_CURVE_TAG_CUBIC;
909      else
910        tag[0] = FT_CURVE_TAG_ON;
911    }
912  }
913
914
915  /****************************************************************
916   *
917   *                     EDGE POINT GRID-FITTING
918   *
919   ****************************************************************/
920
921
922  FT_LOCAL_DEF( void )
923  af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
924                                    AF_Dimension   dim )
925  {
926    AF_AxisHints  axis       = & hints->axis[dim];
927    AF_Edge       edges      = axis->edges;
928    AF_Edge       edge_limit = edges + axis->num_edges;
929    AF_Edge       edge;
930
931
932    for ( edge = edges; edge < edge_limit; edge++ )
933    {
934      /* move the points of each segment     */
935      /* in each edge to the edge's position */
936      AF_Segment  seg = edge->first;
937
938
939      do
940      {
941        AF_Point  point = seg->first;
942
943
944        for (;;)
945        {
946          if ( dim == AF_DIMENSION_HORZ )
947          {
948            point->x      = edge->pos;
949            point->flags |= AF_FLAG_TOUCH_X;
950          }
951          else
952          {
953            point->y      = edge->pos;
954            point->flags |= AF_FLAG_TOUCH_Y;
955          }
956
957          if ( point == seg->last )
958            break;
959
960          point = point->next;
961        }
962
963        seg = seg->edge_next;
964
965      } while ( seg != edge->first );
966    }
967  }
968
969
970  /****************************************************************
971   *
972   *                    STRONG POINT INTERPOLATION
973   *
974   ****************************************************************/
975
976
977  /* hint the strong points -- this is equivalent to the TrueType `IP' */
978  /* hinting instruction                                               */
979
980  FT_LOCAL_DEF( void )
981  af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
982                                      AF_Dimension   dim )
983  {
984    AF_Point      points      = hints->points;
985    AF_Point      point_limit = points + hints->num_points;
986    AF_AxisHints  axis        = &hints->axis[dim];
987    AF_Edge       edges       = axis->edges;
988    AF_Edge       edge_limit  = edges + axis->num_edges;
989    AF_Flags      touch_flag;
990
991
992    if ( dim == AF_DIMENSION_HORZ )
993      touch_flag = AF_FLAG_TOUCH_X;
994    else
995      touch_flag  = AF_FLAG_TOUCH_Y;
996
997    if ( edges < edge_limit )
998    {
999      AF_Point  point;
1000      AF_Edge   edge;
1001
1002
1003      for ( point = points; point < point_limit; point++ )
1004      {
1005        FT_Pos  u, ou, fu;  /* point position */
1006        FT_Pos  delta;
1007
1008
1009        if ( point->flags & touch_flag )
1010          continue;
1011
1012        /* if this point is candidate to weak interpolation, we       */
1013        /* interpolate it after all strong points have been processed */
1014
1015        if (  ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
1016             !( point->flags & AF_FLAG_INFLECTION )         )
1017          continue;
1018
1019        if ( dim == AF_DIMENSION_VERT )
1020        {
1021          u  = point->fy;
1022          ou = point->oy;
1023        }
1024        else
1025        {
1026          u  = point->fx;
1027          ou = point->ox;
1028        }
1029
1030        fu = u;
1031
1032        /* is the point before the first edge? */
1033        edge  = edges;
1034        delta = edge->fpos - u;
1035        if ( delta >= 0 )
1036        {
1037          u = edge->pos - ( edge->opos - ou );
1038          goto Store_Point;
1039        }
1040
1041        /* is the point after the last edge? */
1042        edge  = edge_limit - 1;
1043        delta = u - edge->fpos;
1044        if ( delta >= 0 )
1045        {
1046          u = edge->pos + ( ou - edge->opos );
1047          goto Store_Point;
1048        }
1049
1050        {
1051          FT_UInt  min, max, mid;
1052          FT_Pos   fpos;
1053
1054
1055          /* find enclosing edges */
1056          min = 0;
1057          max = edge_limit - edges;
1058
1059          while ( min < max )
1060          {
1061            mid  = ( max + min ) >> 1;
1062            edge = edges + mid;
1063            fpos = edge->fpos;
1064
1065            if ( u < fpos )
1066              max = mid;
1067            else if ( u > fpos )
1068              min = mid + 1;
1069            else
1070            {
1071              /* we are on the edge */
1072              u = edge->pos;
1073              goto Store_Point;
1074            }
1075          }
1076
1077          {
1078            AF_Edge  before = edges + min - 1;
1079            AF_Edge  after  = edges + min + 0;
1080
1081
1082            /* assert( before && after && before != after ) */
1083            if ( before->scale == 0 )
1084              before->scale = FT_DivFix( after->pos - before->pos,
1085                                         after->fpos - before->fpos );
1086
1087            u = before->pos + FT_MulFix( fu - before->fpos,
1088                                         before->scale );
1089          }
1090        }
1091
1092      Store_Point:
1093        /* save the point position */
1094        if ( dim == AF_DIMENSION_HORZ )
1095          point->x = u;
1096        else
1097          point->y = u;
1098
1099        point->flags |= touch_flag;
1100      }
1101    }
1102  }
1103
1104
1105  /****************************************************************
1106   *
1107   *                    WEAK POINT INTERPOLATION
1108   *
1109   ****************************************************************/
1110
1111
1112  static void
1113  af_iup_shift( AF_Point  p1,
1114                AF_Point  p2,
1115                AF_Point  ref )
1116  {
1117    AF_Point  p;
1118    FT_Pos    delta = ref->u - ref->v;
1119
1120
1121    for ( p = p1; p < ref; p++ )
1122      p->u = p->v + delta;
1123
1124    for ( p = ref + 1; p <= p2; p++ )
1125      p->u = p->v + delta;
1126  }
1127
1128
1129  static void
1130  af_iup_interp( AF_Point  p1,
1131                 AF_Point  p2,
1132                 AF_Point  ref1,
1133                 AF_Point  ref2 )
1134  {
1135    AF_Point  p;
1136    FT_Pos    u;
1137    FT_Pos    v1 = ref1->v;
1138    FT_Pos    v2 = ref2->v;
1139    FT_Pos    d1 = ref1->u - v1;
1140    FT_Pos    d2 = ref2->u - v2;
1141
1142
1143    if ( p1 > p2 )
1144      return;
1145
1146    if ( v1 == v2 )
1147    {
1148      for ( p = p1; p <= p2; p++ )
1149      {
1150        u = p->v;
1151
1152        if ( u <= v1 )
1153          u += d1;
1154        else
1155          u += d2;
1156
1157        p->u = u;
1158      }
1159      return;
1160    }
1161
1162    if ( v1 < v2 )
1163    {
1164      for ( p = p1; p <= p2; p++ )
1165      {
1166        u = p->v;
1167
1168        if ( u <= v1 )
1169          u += d1;
1170        else if ( u >= v2 )
1171          u += d2;
1172        else
1173          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
1174
1175        p->u = u;
1176      }
1177    }
1178    else
1179    {
1180      for ( p = p1; p <= p2; p++ )
1181      {
1182        u = p->v;
1183
1184        if ( u <= v2 )
1185          u += d2;
1186        else if ( u >= v1 )
1187          u += d1;
1188        else
1189          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
1190
1191        p->u = u;
1192      }
1193    }
1194  }
1195
1196
1197  FT_LOCAL_DEF( void )
1198  af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
1199                                    AF_Dimension   dim )
1200  {
1201    AF_Point   points        = hints->points;
1202    AF_Point   point_limit   = points + hints->num_points;
1203    AF_Point*  contour       = hints->contours;
1204    AF_Point*  contour_limit = contour + hints->num_contours;
1205    AF_Flags   touch_flag;
1206    AF_Point   point;
1207    AF_Point   end_point;
1208    AF_Point   first_point;
1209
1210
1211    /* PASS 1: Move segment points to edge positions */
1212
1213    if ( dim == AF_DIMENSION_HORZ )
1214    {
1215      touch_flag = AF_FLAG_TOUCH_X;
1216
1217      for ( point = points; point < point_limit; point++ )
1218      {
1219        point->u = point->x;
1220        point->v = point->ox;
1221      }
1222    }
1223    else
1224    {
1225      touch_flag = AF_FLAG_TOUCH_Y;
1226
1227      for ( point = points; point < point_limit; point++ )
1228      {
1229        point->u = point->y;
1230        point->v = point->oy;
1231      }
1232    }
1233
1234    point = points;
1235
1236    for ( ; contour < contour_limit; contour++ )
1237    {
1238      point       = *contour;
1239      end_point   = point->prev;
1240      first_point = point;
1241
1242      while ( point <= end_point && !( point->flags & touch_flag ) )
1243        point++;
1244
1245      if ( point <= end_point )
1246      {
1247        AF_Point  first_touched = point;
1248        AF_Point  cur_touched   = point;
1249
1250
1251        point++;
1252        while ( point <= end_point )
1253        {
1254          if ( point->flags & touch_flag )
1255          {
1256            /* we found two successive touched points; we interpolate */
1257            /* all contour points between them                        */
1258            af_iup_interp( cur_touched + 1, point - 1,
1259                           cur_touched, point );
1260            cur_touched = point;
1261          }
1262          point++;
1263        }
1264
1265        if ( cur_touched == first_touched )
1266        {
1267          /* this is a special case: only one point was touched in the */
1268          /* contour; we thus simply shift the whole contour           */
1269          af_iup_shift( first_point, end_point, cur_touched );
1270        }
1271        else
1272        {
1273          /* now interpolate after the last touched point to the end */
1274          /* of the contour                                          */
1275          af_iup_interp( cur_touched + 1, end_point,
1276                         cur_touched, first_touched );
1277
1278          /* if the first contour point isn't touched, interpolate */
1279          /* from the contour start to the first touched point     */
1280          if ( first_touched > points )
1281            af_iup_interp( first_point, first_touched - 1,
1282                           cur_touched, first_touched );
1283        }
1284      }
1285    }
1286
1287    /* now save the interpolated values back to x/y */
1288    if ( dim == AF_DIMENSION_HORZ )
1289    {
1290      for ( point = points; point < point_limit; point++ )
1291        point->x = point->u;
1292    }
1293    else
1294    {
1295      for ( point = points; point < point_limit; point++ )
1296        point->y = point->u;
1297    }
1298  }
1299
1300
1301#ifdef AF_USE_WARPER
1302
1303  FT_LOCAL_DEF( void )
1304  af_glyph_hints_scale_dim( AF_GlyphHints  hints,
1305                            AF_Dimension   dim,
1306                            FT_Fixed       scale,
1307                            FT_Pos         delta )
1308  {
1309    AF_Point  points       = hints->points;
1310    AF_Point  points_limit = points + hints->num_points;
1311    AF_Point  point;
1312
1313
1314    if ( dim == AF_DIMENSION_HORZ )
1315    {
1316      for ( point = points; point < points_limit; point++ )
1317        point->x = FT_MulFix( point->fx, scale ) + delta;
1318    }
1319    else
1320    {
1321      for ( point = points; point < points_limit; point++ )
1322        point->y = FT_MulFix( point->fy, scale ) + delta;
1323    }
1324  }
1325
1326#endif /* AF_USE_WARPER */
1327
1328/* END */
Note: See TracBrowser for help on using the repository browser.