source: trunk/poppler/freetype-2.1.10/src/autofit/afhints.c @ 2

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

First import

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