summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/src/autofit/afhints.c
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/3rdparty/freetype/src/autofit/afhints.c
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/3rdparty/freetype/src/autofit/afhints.c')
-rw-r--r--src/3rdparty/freetype/src/autofit/afhints.c1264
1 files changed, 1264 insertions, 0 deletions
diff --git a/src/3rdparty/freetype/src/autofit/afhints.c b/src/3rdparty/freetype/src/autofit/afhints.c
new file mode 100644
index 0000000000..8ab1761488
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afhints.c
@@ -0,0 +1,1264 @@
+/***************************************************************************/
+/* */
+/* afhints.c */
+/* */
+/* Auto-fitter hinting routines (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afhints.h"
+#include "aferrors.h"
+#include FT_INTERNAL_CALC_H
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_axis_hints_new_segment( AF_AxisHints axis,
+ FT_Memory memory,
+ AF_Segment *asegment )
+ {
+ FT_Error error = AF_Err_Ok;
+ AF_Segment segment = NULL;
+
+
+ if ( axis->num_segments >= axis->max_segments )
+ {
+ FT_Int old_max = axis->max_segments;
+ FT_Int new_max = old_max;
+ FT_Int big_max = FT_INT_MAX / sizeof ( *segment );
+
+
+ if ( old_max >= big_max )
+ {
+ error = AF_Err_Out_Of_Memory;
+ goto Exit;
+ }
+
+ new_max += ( new_max >> 2 ) + 4;
+ if ( new_max < old_max || new_max > big_max )
+ new_max = big_max;
+
+ if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
+ goto Exit;
+
+ axis->max_segments = new_max;
+ }
+
+ segment = axis->segments + axis->num_segments++;
+
+ Exit:
+ *asegment = segment;
+ return error;
+ }
+
+
+ FT_LOCAL( FT_Error )
+ af_axis_hints_new_edge( AF_AxisHints axis,
+ FT_Int fpos,
+ AF_Direction dir,
+ FT_Memory memory,
+ AF_Edge *aedge )
+ {
+ FT_Error error = AF_Err_Ok;
+ AF_Edge edge = NULL;
+ AF_Edge edges;
+
+
+ if ( axis->num_edges >= axis->max_edges )
+ {
+ FT_Int old_max = axis->max_edges;
+ FT_Int new_max = old_max;
+ FT_Int big_max = FT_INT_MAX / sizeof ( *edge );
+
+
+ if ( old_max >= big_max )
+ {
+ error = AF_Err_Out_Of_Memory;
+ goto Exit;
+ }
+
+ new_max += ( new_max >> 2 ) + 4;
+ if ( new_max < old_max || new_max > big_max )
+ new_max = big_max;
+
+ if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
+ goto Exit;
+
+ axis->max_edges = new_max;
+ }
+
+ edges = axis->edges;
+ edge = edges + axis->num_edges;
+
+ while ( edge > edges )
+ {
+ if ( edge[-1].fpos < fpos )
+ break;
+
+ /* we want the edge with same position and minor direction */
+ /* to appear before those in the major one in the list */
+ if ( edge[-1].fpos == fpos && dir == axis->major_dir )
+ break;
+
+ edge[0] = edge[-1];
+ edge--;
+ }
+
+ axis->num_edges++;
+
+ FT_ZERO( edge );
+ edge->fpos = (FT_Short)fpos;
+ edge->dir = (FT_Char)dir;
+
+ Exit:
+ *aedge = edge;
+ return error;
+ }
+
+
+#ifdef AF_DEBUG
+
+#include FT_CONFIG_STANDARD_LIBRARY_H
+
+ static const char*
+ af_dir_str( AF_Direction dir )
+ {
+ const char* result;
+
+
+ switch ( dir )
+ {
+ case AF_DIR_UP:
+ result = "up";
+ break;
+ case AF_DIR_DOWN:
+ result = "down";
+ break;
+ case AF_DIR_LEFT:
+ result = "left";
+ break;
+ case AF_DIR_RIGHT:
+ result = "right";
+ break;
+ default:
+ result = "none";
+ }
+
+ return result;
+ }
+
+
+#define AF_INDEX_NUM( ptr, base ) ( (ptr) ? ( (ptr) - (base) ) : -1 )
+
+
+ void
+ af_glyph_hints_dump_points( AF_GlyphHints hints )
+ {
+ AF_Point points = hints->points;
+ AF_Point limit = points + hints->num_points;
+ AF_Point point;
+
+
+ printf( "Table of points:\n" );
+ printf( " [ index | xorg | yorg | xscale | yscale "
+ "| xfit | yfit | flags ]\n" );
+
+ for ( point = points; point < limit; point++ )
+ {
+ printf( " [ %5d | %5d | %5d | %-5.2f | %-5.2f "
+ "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n",
+ point - points,
+ point->fx,
+ point->fy,
+ point->ox/64.0,
+ point->oy/64.0,
+ point->x/64.0,
+ point->y/64.0,
+ ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
+ ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ',
+ ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ',
+ ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ',
+ ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ',
+ ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' ');
+ }
+ printf( "\n" );
+ }
+
+
+ static const char*
+ af_edge_flags_to_string( AF_Edge_Flags flags )
+ {
+ static char temp[32];
+ int pos = 0;
+
+
+ if ( flags & AF_EDGE_ROUND )
+ {
+ ft_memcpy( temp + pos, "round", 5 );
+ pos += 5;
+ }
+ if ( flags & AF_EDGE_SERIF )
+ {
+ if ( pos > 0 )
+ temp[pos++] = ' ';
+ ft_memcpy( temp + pos, "serif", 5 );
+ pos += 5;
+ }
+ if ( pos == 0 )
+ return "normal";
+
+ temp[pos] = 0;
+
+ return temp;
+ }
+
+
+ /* A function to dump the array of linked segments. */
+ void
+ af_glyph_hints_dump_segments( AF_GlyphHints hints )
+ {
+ FT_Int dimension;
+
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AF_AxisHints axis = &hints->axis[dimension];
+ AF_Segment segments = axis->segments;
+ AF_Segment limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+
+ printf ( "Table of %s segments:\n",
+ dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link | serif |"
+ " height | extra | flags ]\n" );
+
+ for ( seg = segments; seg < limit; seg++ )
+ {
+ printf ( " [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n",
+ seg - segments,
+ dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
+ : (int)seg->first->oy / 64.0,
+ af_dir_str( (AF_Direction)seg->dir ),
+ AF_INDEX_NUM( seg->link, segments ),
+ AF_INDEX_NUM( seg->serif, segments ),
+ seg->height,
+ seg->height - ( seg->max_coord - seg->min_coord ),
+ af_edge_flags_to_string( seg->flags ) );
+ }
+ printf( "\n" );
+ }
+ }
+
+
+ void
+ af_glyph_hints_dump_edges( AF_GlyphHints hints )
+ {
+ FT_Int dimension;
+
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AF_AxisHints axis = &hints->axis[dimension];
+ AF_Edge edges = axis->edges;
+ AF_Edge limit = edges + axis->num_edges;
+ AF_Edge edge;
+
+
+ /*
+ * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
+ * since they have constant a X coordinate.
+ */
+ printf ( "Table of %s edges:\n",
+ dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link |"
+ " serif | blue | opos | pos | flags ]\n" );
+
+ for ( edge = edges; edge < limit; edge++ )
+ {
+ printf ( " [ %5d | %5.2g | %5s | %4d |"
+ " %5d | %c | %5.2f | %5.2f | %s ]\n",
+ edge - edges,
+ (int)edge->opos / 64.0,
+ af_dir_str( (AF_Direction)edge->dir ),
+ AF_INDEX_NUM( edge->link, edges ),
+ AF_INDEX_NUM( edge->serif, edges ),
+ edge->blue_edge ? 'y' : 'n',
+ edge->opos / 64.0,
+ edge->pos / 64.0,
+ af_edge_flags_to_string( edge->flags ) );
+ }
+ printf( "\n" );
+ }
+ }
+
+#else /* !AF_DEBUG */
+
+ /* these empty stubs are only used to link the `ftgrid' test program */
+ /* when debugging is disabled */
+
+ void
+ af_glyph_hints_dump_points( AF_GlyphHints hints )
+ {
+ FT_UNUSED( hints );
+ }
+
+
+ void
+ af_glyph_hints_dump_segments( AF_GlyphHints hints )
+ {
+ FT_UNUSED( hints );
+ }
+
+
+ void
+ af_glyph_hints_dump_edges( AF_GlyphHints hints )
+ {
+ FT_UNUSED( hints );
+ }
+
+#endif /* !AF_DEBUG */
+
+
+ /* compute the direction value of a given vector */
+ FT_LOCAL_DEF( AF_Direction )
+ af_direction_compute( FT_Pos dx,
+ FT_Pos dy )
+ {
+ FT_Pos ll, ss; /* long and short arm lengths */
+ AF_Direction dir; /* candidate direction */
+
+
+ if ( dy >= dx )
+ {
+ if ( dy >= -dx )
+ {
+ dir = AF_DIR_UP;
+ ll = dy;
+ ss = dx;
+ }
+ else
+ {
+ dir = AF_DIR_LEFT;
+ ll = -dx;
+ ss = dy;
+ }
+ }
+ else /* dy < dx */
+ {
+ if ( dy >= -dx )
+ {
+ dir = AF_DIR_RIGHT;
+ ll = dx;
+ ss = dy;
+ }
+ else
+ {
+ dir = AF_DIR_DOWN;
+ ll = dy;
+ ss = dx;
+ }
+ }
+
+ ss *= 14;
+ if ( FT_ABS( ll ) <= FT_ABS( ss ) )
+ dir = AF_DIR_NONE;
+
+ return dir;
+ }
+
+
+ /* compute all inflex points in a given glyph */
+
+ static void
+ af_glyph_hints_compute_inflections( AF_GlyphHints hints )
+ {
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point point = contour[0];
+ AF_Point first = point;
+ AF_Point start = point;
+ AF_Point end = point;
+ AF_Point before;
+ AF_Point after;
+ FT_Pos in_x, in_y, out_x, out_y;
+ AF_Angle orient_prev, orient_cur;
+ FT_Int finished = 0;
+
+
+ /* compute first segment in contour */
+ first = point;
+
+ start = end = first;
+ do
+ {
+ end = end->next;
+ if ( end == first )
+ goto Skip;
+
+ in_x = end->fx - start->fx;
+ in_y = end->fy - start->fy;
+
+ } while ( in_x == 0 && in_y == 0 );
+
+ /* extend the segment start whenever possible */
+ before = start;
+ do
+ {
+ do
+ {
+ start = before;
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ out_x = start->fx - before->fx;
+ out_y = start->fy - before->fy;
+
+ } while ( out_x == 0 && out_y == 0 );
+
+ orient_prev = ft_corner_orientation( in_x, in_y, out_x, out_y );
+
+ } while ( orient_prev == 0 );
+
+ first = start;
+
+ in_x = out_x;
+ in_y = out_y;
+
+ /* now process all segments in the contour */
+ do
+ {
+ /* first, extend current segment's end whenever possible */
+ after = end;
+ do
+ {
+ do
+ {
+ end = after;
+ after = after->next;
+ if ( after == first )
+ finished = 1;
+
+ out_x = after->fx - end->fx;
+ out_y = after->fy - end->fy;
+
+ } while ( out_x == 0 && out_y == 0 );
+
+ orient_cur = ft_corner_orientation( in_x, in_y, out_x, out_y );
+
+ } while ( orient_cur == 0 );
+
+ if ( ( orient_prev + orient_cur ) == 0 )
+ {
+ /* we have an inflection point here */
+ do
+ {
+ start->flags |= AF_FLAG_INFLECTION;
+ start = start->next;
+
+ } while ( start != end );
+
+ start->flags |= AF_FLAG_INFLECTION;
+ }
+
+ start = end;
+ end = after;
+
+ orient_prev = orient_cur;
+ in_x = out_x;
+ in_y = out_y;
+
+ } while ( !finished );
+
+ Skip:
+ ;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_init( AF_GlyphHints hints,
+ FT_Memory memory )
+ {
+ FT_ZERO( hints );
+ hints->memory = memory;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_done( AF_GlyphHints hints )
+ {
+ if ( hints && hints->memory )
+ {
+ FT_Memory memory = hints->memory;
+ int dim;
+
+
+ /*
+ * note that we don't need to free the segment and edge
+ * buffers, since they are really within the hints->points array
+ */
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+
+
+ axis->num_segments = 0;
+ axis->max_segments = 0;
+ FT_FREE( axis->segments );
+
+ axis->num_edges = 0;
+ axis->max_edges = 0;
+ FT_FREE( axis->edges );
+ }
+
+ FT_FREE( hints->contours );
+ hints->max_contours = 0;
+ hints->num_contours = 0;
+
+ FT_FREE( hints->points );
+ hints->num_points = 0;
+ hints->max_points = 0;
+
+ hints->memory = NULL;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_rescale( AF_GlyphHints hints,
+ AF_ScriptMetrics metrics )
+ {
+ hints->metrics = metrics;
+ hints->scaler_flags = metrics->scaler.flags;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_glyph_hints_reload( AF_GlyphHints hints,
+ FT_Outline* outline,
+ FT_Bool get_inflections )
+ {
+ FT_Error error = AF_Err_Ok;
+ AF_Point points;
+ FT_UInt old_max, new_max;
+ FT_Fixed x_scale = hints->x_scale;
+ FT_Fixed y_scale = hints->y_scale;
+ FT_Pos x_delta = hints->x_delta;
+ FT_Pos y_delta = hints->y_delta;
+ FT_Memory memory = hints->memory;
+
+
+ hints->num_points = 0;
+ hints->num_contours = 0;
+
+ hints->axis[0].num_segments = 0;
+ hints->axis[0].num_edges = 0;
+ hints->axis[1].num_segments = 0;
+ hints->axis[1].num_edges = 0;
+
+ /* first of all, reallocate the contours array when necessary */
+ new_max = (FT_UInt)outline->n_contours;
+ old_max = hints->max_contours;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 3 ) & ~3;
+
+ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
+ goto Exit;
+
+ hints->max_contours = new_max;
+ }
+
+ /*
+ * then reallocate the points arrays if necessary --
+ * note that we reserve two additional point positions, used to
+ * hint metrics appropriately
+ */
+ new_max = (FT_UInt)( outline->n_points + 2 );
+ old_max = hints->max_points;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 2 + 7 ) & ~7;
+
+ if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
+ goto Exit;
+
+ hints->max_points = new_max;
+ }
+
+ hints->num_points = outline->n_points;
+ hints->num_contours = outline->n_contours;
+
+ /* We can't rely on the value of `FT_Outline.flags' to know the fill */
+ /* direction used for a glyph, given that some fonts are broken (e.g., */
+ /* the Arphic ones). We thus recompute it each time we need to. */
+ /* */
+ hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
+ hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
+
+ if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
+ {
+ hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
+ hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
+ }
+
+ hints->x_scale = x_scale;
+ hints->y_scale = y_scale;
+ hints->x_delta = x_delta;
+ hints->y_delta = y_delta;
+
+ hints->xmin_delta = 0;
+ hints->xmax_delta = 0;
+
+ points = hints->points;
+ if ( hints->num_points == 0 )
+ goto Exit;
+
+ {
+ AF_Point point;
+ AF_Point point_limit = points + hints->num_points;
+
+
+ /* compute coordinates & Bezier flags, next and prev */
+ {
+ FT_Vector* vec = outline->points;
+ char* tag = outline->tags;
+ AF_Point first = points;
+ AF_Point end = points + outline->contours[0];
+ AF_Point prev = end;
+ FT_Int contour_index = 0;
+
+
+ for ( point = points; point < point_limit; point++, vec++, tag++ )
+ {
+ point->fx = (FT_Short)vec->x;
+ point->fy = (FT_Short)vec->y;
+ point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
+ point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
+
+ switch ( FT_CURVE_TAG( *tag ) )
+ {
+ case FT_CURVE_TAG_CONIC:
+ point->flags = AF_FLAG_CONIC;
+ break;
+ case FT_CURVE_TAG_CUBIC:
+ point->flags = AF_FLAG_CUBIC;
+ break;
+ default:
+ point->flags = 0;
+ }
+
+ point->prev = prev;
+ prev->next = point;
+ prev = point;
+
+ if ( point == end )
+ {
+ if ( ++contour_index < outline->n_contours )
+ {
+ first = point + 1;
+ end = points + outline->contours[contour_index];
+ prev = end;
+ }
+ }
+ }
+ }
+
+ /* set-up the contours array */
+ {
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ short* end = outline->contours;
+ short idx = 0;
+
+
+ for ( ; contour < contour_limit; contour++, end++ )
+ {
+ contour[0] = points + idx;
+ idx = (short)( end[0] + 1 );
+ }
+ }
+
+ /* compute directions of in & out vectors */
+ {
+ AF_Point first = points;
+ AF_Point prev = NULL;
+ FT_Pos in_x = 0;
+ FT_Pos in_y = 0;
+ AF_Direction in_dir = AF_DIR_NONE;
+
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ AF_Point next;
+ FT_Pos out_x, out_y;
+
+
+ if ( point == first )
+ {
+ prev = first->prev;
+ in_x = first->fx - prev->fx;
+ in_y = first->fy - prev->fy;
+ in_dir = af_direction_compute( in_x, in_y );
+ first = prev + 1;
+ }
+
+ point->in_dir = (FT_Char)in_dir;
+
+ next = point->next;
+ out_x = next->fx - point->fx;
+ out_y = next->fy - point->fy;
+
+ in_dir = af_direction_compute( out_x, out_y );
+ point->out_dir = (FT_Char)in_dir;
+
+ if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
+ {
+ Is_Weak_Point:
+ point->flags |= AF_FLAG_WEAK_INTERPOLATION;
+ }
+ else if ( point->out_dir == point->in_dir )
+ {
+ if ( point->out_dir != AF_DIR_NONE )
+ goto Is_Weak_Point;
+
+ if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
+ goto Is_Weak_Point;
+ }
+ else if ( point->in_dir == -point->out_dir )
+ goto Is_Weak_Point;
+
+ in_x = out_x;
+ in_y = out_y;
+ prev = point;
+ }
+ }
+ }
+
+ /* compute inflection points -- */
+ /* disabled due to no longer perceived benefits */
+ if ( 0 && get_inflections )
+ af_glyph_hints_compute_inflections( hints );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_save( AF_GlyphHints hints,
+ FT_Outline* outline )
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+ FT_Vector* vec = outline->points;
+ char* tag = outline->tags;
+
+
+ for ( ; point < limit; point++, vec++, tag++ )
+ {
+ vec->x = point->x;
+ vec->y = point->y;
+
+ if ( point->flags & AF_FLAG_CONIC )
+ tag[0] = FT_CURVE_TAG_CONIC;
+ else if ( point->flags & AF_FLAG_CUBIC )
+ tag[0] = FT_CURVE_TAG_CUBIC;
+ else
+ tag[0] = FT_CURVE_TAG_ON;
+ }
+ }
+
+
+ /****************************************************************
+ *
+ * EDGE POINT GRID-FITTING
+ *
+ ****************************************************************/
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_edge_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = & hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge edge = seg->edge;
+ AF_Point point, first, last;
+
+
+ if ( edge == NULL )
+ continue;
+
+ first = seg->first;
+ last = seg->last;
+ point = first;
+ for (;;)
+ {
+ point->x = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_X;
+
+ if ( point == last )
+ break;
+
+ point = point->next;
+
+ }
+ }
+ }
+ else
+ {
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge edge = seg->edge;
+ AF_Point point, first, last;
+
+
+ if ( edge == NULL )
+ continue;
+
+ first = seg->first;
+ last = seg->last;
+ point = first;
+ for (;;)
+ {
+ point->y = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_Y;
+
+ if ( point == last )
+ break;
+
+ point = point->next;
+ }
+ }
+ }
+ }
+
+
+ /****************************************************************
+ *
+ * STRONG POINT INTERPOLATION
+ *
+ ****************************************************************/
+
+
+ /* hint the strong points -- this is equivalent to the TrueType `IP' */
+ /* hinting instruction */
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_strong_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_Point points = hints->points;
+ AF_Point point_limit = points + hints->num_points;
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Flags touch_flag;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ touch_flag = AF_FLAG_TOUCH_X;
+ else
+ touch_flag = AF_FLAG_TOUCH_Y;
+
+ if ( edges < edge_limit )
+ {
+ AF_Point point;
+ AF_Edge edge;
+
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ FT_Pos u, ou, fu; /* point position */
+ FT_Pos delta;
+
+
+ if ( point->flags & touch_flag )
+ continue;
+
+ /* if this point is candidate to weak interpolation, we */
+ /* interpolate it after all strong points have been processed */
+
+ if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
+ !( point->flags & AF_FLAG_INFLECTION ) )
+ continue;
+
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ u = point->fy;
+ ou = point->oy;
+ }
+ else
+ {
+ u = point->fx;
+ ou = point->ox;
+ }
+
+ fu = u;
+
+ /* is the point before the first edge? */
+ edge = edges;
+ delta = edge->fpos - u;
+ if ( delta >= 0 )
+ {
+ u = edge->pos - ( edge->opos - ou );
+ goto Store_Point;
+ }
+
+ /* is the point after the last edge? */
+ edge = edge_limit - 1;
+ delta = u - edge->fpos;
+ if ( delta >= 0 )
+ {
+ u = edge->pos + ( ou - edge->opos );
+ goto Store_Point;
+ }
+
+ {
+ FT_UInt min, max, mid;
+ FT_Pos fpos;
+
+
+ /* find enclosing edges */
+ min = 0;
+ max = edge_limit - edges;
+
+#if 1
+ /* for small edge counts, a linear search is better */
+ if ( max <= 8 )
+ {
+ FT_UInt nn;
+
+ for ( nn = 0; nn < max; nn++ )
+ if ( edges[nn].fpos >= u )
+ break;
+
+ if ( edges[nn].fpos == u )
+ {
+ u = edges[nn].pos;
+ goto Store_Point;
+ }
+ min = nn;
+ }
+ else
+#endif
+ while ( min < max )
+ {
+ mid = ( max + min ) >> 1;
+ edge = edges + mid;
+ fpos = edge->fpos;
+
+ if ( u < fpos )
+ max = mid;
+ else if ( u > fpos )
+ min = mid + 1;
+ else
+ {
+ /* we are on the edge */
+ u = edge->pos;
+ goto Store_Point;
+ }
+ }
+
+ {
+ AF_Edge before = edges + min - 1;
+ AF_Edge after = edges + min + 0;
+
+
+ /* assert( before && after && before != after ) */
+ if ( before->scale == 0 )
+ before->scale = FT_DivFix( after->pos - before->pos,
+ after->fpos - before->fpos );
+
+ u = before->pos + FT_MulFix( fu - before->fpos,
+ before->scale );
+ }
+ }
+
+ Store_Point:
+ /* save the point position */
+ if ( dim == AF_DIMENSION_HORZ )
+ point->x = u;
+ else
+ point->y = u;
+
+ point->flags |= touch_flag;
+ }
+ }
+ }
+
+
+ /****************************************************************
+ *
+ * WEAK POINT INTERPOLATION
+ *
+ ****************************************************************/
+
+
+ static void
+ af_iup_shift( AF_Point p1,
+ AF_Point p2,
+ AF_Point ref )
+ {
+ AF_Point p;
+ FT_Pos delta = ref->u - ref->v;
+
+ if ( delta == 0 )
+ return;
+
+ for ( p = p1; p < ref; p++ )
+ p->u = p->v + delta;
+
+ for ( p = ref + 1; p <= p2; p++ )
+ p->u = p->v + delta;
+ }
+
+
+ static void
+ af_iup_interp( AF_Point p1,
+ AF_Point p2,
+ AF_Point ref1,
+ AF_Point ref2 )
+ {
+ AF_Point p;
+ FT_Pos u;
+ FT_Pos v1 = ref1->v;
+ FT_Pos v2 = ref2->v;
+ FT_Pos d1 = ref1->u - v1;
+ FT_Pos d2 = ref2->u - v2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ if ( v1 == v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else
+ u += d2;
+
+ p->u = u;
+ }
+ return;
+ }
+
+ if ( v1 < v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else if ( u >= v2 )
+ u += d2;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ else
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v2 )
+ u += d2;
+ else if ( u >= v1 )
+ u += d1;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_weak_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_Point points = hints->points;
+ AF_Point point_limit = points + hints->num_points;
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ AF_Flags touch_flag;
+ AF_Point point;
+ AF_Point end_point;
+ AF_Point first_point;
+
+
+ /* PASS 1: Move segment points to edge positions */
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ touch_flag = AF_FLAG_TOUCH_X;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->u = point->x;
+ point->v = point->ox;
+ }
+ }
+ else
+ {
+ touch_flag = AF_FLAG_TOUCH_Y;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->u = point->y;
+ point->v = point->oy;
+ }
+ }
+
+ point = points;
+
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point first_touched, last_touched;
+
+
+ point = *contour;
+ end_point = point->prev;
+ first_point = point;
+
+ /* find first touched point */
+ for (;;)
+ {
+ if ( point > end_point ) /* no touched point in contour */
+ goto NextContour;
+
+ if ( point->flags & touch_flag )
+ break;
+
+ point++;
+ }
+
+ first_touched = point;
+ last_touched = point;
+
+ for (;;)
+ {
+ FT_ASSERT( point <= end_point &&
+ ( point->flags & touch_flag ) != 0 );
+
+ /* skip any touched neighbhours */
+ while ( point < end_point && ( point[1].flags & touch_flag ) != 0 )
+ point++;
+
+ last_touched = point;
+
+ /* find the next touched point, if any */
+ point ++;
+ for (;;)
+ {
+ if ( point > end_point )
+ goto EndContour;
+
+ if ( ( point->flags & touch_flag ) != 0 )
+ break;
+
+ point++;
+ }
+
+ /* interpolate between last_touched and point */
+ af_iup_interp( last_touched + 1, point - 1,
+ last_touched, point );
+ }
+
+ EndContour:
+ /* special case: only one point was touched */
+ if ( last_touched == first_touched )
+ {
+ af_iup_shift( first_point, end_point, first_touched );
+ }
+ else /* interpolate the last part */
+ {
+ if ( last_touched < end_point )
+ af_iup_interp( last_touched + 1, end_point,
+ last_touched, first_touched );
+
+ if ( first_touched > points )
+ af_iup_interp( first_point, first_touched - 1,
+ last_touched, first_touched );
+ }
+
+ NextContour:
+ ;
+ }
+
+ /* now save the interpolated values back to x/y */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->x = point->u;
+ }
+ else
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->y = point->u;
+ }
+ }
+
+
+#ifdef AF_USE_WARPER
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_scale_dim( AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Fixed scale,
+ FT_Pos delta )
+ {
+ AF_Point points = hints->points;
+ AF_Point points_limit = points + hints->num_points;
+ AF_Point point;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( point = points; point < points_limit; point++ )
+ point->x = FT_MulFix( point->fx, scale ) + delta;
+ }
+ else
+ {
+ for ( point = points; point < points_limit; point++ )
+ point->y = FT_MulFix( point->fy, scale ) + delta;
+ }
+ }
+
+#endif /* AF_USE_WARPER */
+
+/* END */