1049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/***************************************************************************/
2049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
3049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  afwarp.c                                                               */
4049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
5049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*    Auto-fitter warping algorithm (body).                                */
6049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
7c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner/*  Copyright 2006, 2007, 2011 by                                          */
8049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
10049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  This file is part of the FreeType project, and may only be used,       */
11049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  modified, and distributed under the terms of the FreeType project      */
12049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  this file you indicate that you have read the license and              */
14049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  understand and accept it fully.                                        */
15049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
16049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/***************************************************************************/
17049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
18049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
19c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /*
20c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner   *  The idea of the warping code is to slightly scale and shift a glyph
21c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner   *  within a single dimension so that as much of its segments are aligned
22c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner   *  (more or less) on the grid.  To find out the optimal scaling and
23c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner   *  shifting value, various parameter combinations are tried and scored.
24c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner   */
25c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner
26049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "afwarp.h"
27049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
28c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
29c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner
30c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /*************************************************************************/
31c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /*                                                                       */
32c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
33c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
34c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* messages during execution.                                            */
35c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /*                                                                       */
36c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner#undef  FT_COMPONENT
37c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner#define FT_COMPONENT  trace_afwarp
38c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner
39049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
40c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* The weights cover the range 0/64 - 63/64 of a pixel.  Obviously, */
41c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* values around a half pixel (which means exactly between two grid */
42c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* lines) gets the worst weight.                                    */
43049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 1
44049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static const AF_WarpScore
45049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_warper_weights[64] =
46049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
47049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    35, 32, 30, 25, 20, 15, 12, 10,  5,  1,  0,  0,  0,  0,  0,  0,
48049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     0,  0,  0,  0,  0,  0, -1, -2, -5, -8,-10,-10,-20,-20,-30,-30,
49049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
50049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   -30,-30,-20,-20,-10,-10, -8, -5, -2, -1,  0,  0,  0,  0,  0,  0,
51049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     0,  0,  0,  0,  0,  0,  0,  1,  5, 10, 12, 15, 20, 25, 30, 32,
52049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  };
53049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#else
54049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static const AF_WarpScore
55049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_warper_weights[64] =
56049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
57049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    30, 20, 10,  5,  4,  4,  3,  2,  1,  0,  0,  0,  0,  0,  0,  0,
58049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     0,  0,  0,  0,  0,  0,  0, -1, -2, -2, -5, -5,-10,-10,-15,-20,
59049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
60049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   -20,-15,-15,-10,-10, -5, -5, -2, -2, -1,  0,  0,  0,  0,  0,  0,
61049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  4,  5, 10, 20,
62049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  };
63049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
64049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
65049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
66c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* Score segments for a given `scale' and `delta' in the range */
67c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* `xx1' to `xx2', and store the best result in `warper'.  If  */
68c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* the new best score is equal to the old one, prefer the      */
69c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* value with a smaller distortion (around `base_distort').    */
70c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner
71049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
72049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_warper_compute_line_best( AF_Warper     warper,
73049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_Fixed      scale,
74049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_Pos        delta,
75049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_Pos        xx1,
76049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_Pos        xx2,
77049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               AF_WarpScore  base_distort,
78049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               AF_Segment    segments,
79049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_UInt       num_segments )
80049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
81049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        idx_min, idx_max, idx0;
82049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UInt       nn;
83049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_WarpScore  scores[65];
84049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
85049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
86049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( nn = 0; nn < 65; nn++ )
87049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scores[nn] = 0;
88049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
89049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    idx0 = xx1 - warper->t1;
90049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
91049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* compute minimum and maximum indices */
92049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
93049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  xx1min = warper->x1min;
94049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  xx1max = warper->x1max;
95049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  w      = xx2 - xx1;
96049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
97049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
98049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( xx1min + w < warper->x2min )
99049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        xx1min = warper->x2min - w;
100049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
101049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      xx1max = warper->x1max;
102049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( xx1max + w > warper->x2max )
103049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        xx1max = warper->x2max - w;
104049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
105049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      idx_min = xx1min - warper->t1;
106049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      idx_max = xx1max - warper->t1;
107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
108049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( idx_min < 0 || idx_min > idx_max || idx_max > 64 )
109049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
110c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner        FT_TRACE5(( "invalid indices:\n"
111c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner                    "  min=%d max=%d, xx1=%ld xx2=%ld,\n"
112c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner                    "  x1min=%ld x1max=%ld, x2min=%ld x2max=%ld\n",
113c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner                    idx_min, idx_max, xx1, xx2,
114c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner                    warper->x1min, warper->x1max,
115c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner                    warper->x2min, warper->x2max ));
116049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        return;
117049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
118049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
119049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
120049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( nn = 0; nn < num_segments; nn++ )
121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
122049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  len = segments[nn].max_coord - segments[nn].min_coord;
123049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  y0  = FT_MulFix( segments[nn].pos, scale ) + delta;
124049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  y   = y0 + ( idx_min - idx0 );
125049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int  idx;
126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
127049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
128c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner      /* score the length of the segments for the given range */
129049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( idx = idx_min; idx <= idx_max; idx++, y++ )
130049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        scores[idx] += af_warper_weights[y & 63] * len;
131049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
132049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
133049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* find best score */
134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
135049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int  idx;
136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( idx = idx_min; idx <= idx_max; idx++ )
139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_WarpScore  score = scores[idx];
141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_WarpScore  distort = base_distort + ( idx - idx0 );
142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
144c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner        if ( score > warper->best_score         ||
145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project             ( score == warper->best_score    &&
146c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner               distort < warper->best_distort ) )
147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          warper->best_score   = score;
149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          warper->best_distort = distort;
150049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          warper->best_scale   = scale;
151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          warper->best_delta   = delta + ( idx - idx0 );
152049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
155049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
157049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
158c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* Compute optimal scaling and delta values for a given glyph and */
159c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* dimension.                                                     */
160c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner
161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
162049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_warper_compute( AF_Warper      warper,
163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     AF_GlyphHints  hints,
164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     AF_Dimension   dim,
165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     FT_Fixed      *a_scale,
166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     FT_Pos        *a_delta )
167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis;
169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Point      points;
170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
171049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Fixed      org_scale;
172049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        org_delta;
173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
174049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UInt       nn, num_points, num_segments;
175049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        X1, X2;
176049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        w;
177049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
178049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_WarpScore  base_distort;
179049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments;
180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
181049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
182049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* get original scaling transformation */
183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_VERT )
184049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
185049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      org_scale = hints->y_scale;
186049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      org_delta = hints->y_delta;
187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
189049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
190049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      org_scale = hints->x_scale;
191049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      org_delta = hints->x_delta;
192049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
193049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
194049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->best_scale   = org_scale;
195049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->best_delta   = org_delta;
196049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->best_score   = INT_MIN;
197049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->best_distort = 0;
198049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
199049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis         = &hints->axis[dim];
200049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    segments     = axis->segments;
201049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    num_segments = axis->num_segments;
202049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    points       = hints->points;
203049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    num_points   = hints->num_points;
204049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
205049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    *a_scale = org_scale;
206049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    *a_delta = org_delta;
207049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
208049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* get X1 and X2, minimum and maximum in original coordinates */
209049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( num_segments < 1 )
210049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return;
211049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
212049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 1
213049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    X1 = X2 = points[0].fx;
214049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( nn = 1; nn < num_points; nn++ )
215049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
216049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int  X = points[nn].fx;
217049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
218049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
219049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( X < X1 )
220049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        X1 = X;
221049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( X > X2 )
222049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        X2 = X;
223049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
224049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#else
225049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    X1 = X2 = segments[0].pos;
226049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( nn = 1; nn < num_segments; nn++ )
227049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
228049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int  X = segments[nn].pos;
229049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
230049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
231049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( X < X1 )
232049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        X1 = X;
233049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( X > X2 )
234049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        X2 = X;
235049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
236049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
237049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
238049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( X1 >= X2 )
239049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return;
240049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
241049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->x1 = FT_MulFix( X1, org_scale ) + org_delta;
242049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->x2 = FT_MulFix( X2, org_scale ) + org_delta;
243049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
244049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->t1 = AF_WARPER_FLOOR( warper->x1 );
245049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->t2 = AF_WARPER_CEIL( warper->x2 );
246049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
247c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner    /* examine a half pixel wide range around the maximum coordinates */
248049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->x1min = warper->x1 & ~31;
249049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->x1max = warper->x1min + 32;
250049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->x2min = warper->x2 & ~31;
251049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->x2max = warper->x2min + 32;
252049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
253049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( warper->x1max > warper->x2 )
254049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      warper->x1max = warper->x2;
255049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
256049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( warper->x2min < warper->x1 )
257049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      warper->x2min = warper->x1;
258049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->w0 = warper->x2 - warper->x1;
260049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
261049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( warper->w0 <= 64 )
262049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
263049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      warper->x1max = warper->x1;
264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      warper->x2min = warper->x2;
265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
266049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
267c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner    /* examine (at most) a pixel wide range around the natural width */
268049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->wmin = warper->x2min - warper->x1max;
269049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->wmax = warper->x2max - warper->x1min;
270049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
271049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 1
272c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner    /* some heuristics to reduce the number of widths to be examined */
273049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
274049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      int  margin = 16;
275049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
276049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
277049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( warper->w0 <= 128 )
278049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
279049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         margin = 8;
280049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         if ( warper->w0 <= 96 )
281049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           margin = 4;
282049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
283049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
284049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( warper->wmin < warper->w0 - margin )
285049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        warper->wmin = warper->w0 - margin;
286049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
287049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( warper->wmax > warper->w0 + margin )
288049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        warper->wmax = warper->w0 + margin;
289049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
290049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
291049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( warper->wmin < warper->w0 * 3 / 4 )
292049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      warper->wmin = warper->w0 * 3 / 4;
293049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
294049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( warper->wmax > warper->w0 * 5 / 4 )
295049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      warper->wmax = warper->w0 * 5 / 4;
296049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#else
297049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* no scaling, just translation */
298049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    warper->wmin = warper->wmax = warper->w0;
299049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
300049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
301049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( w = warper->wmin; w <= warper->wmax; w++ )
302049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
303049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Fixed  new_scale;
304049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos    new_delta;
305049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos    xx1, xx2;
306049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
307049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
308c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner      /* compute min and max positions for given width,       */
309c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner      /* assuring that they stay within the coordinate ranges */
310049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      xx1 = warper->x1;
311049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      xx2 = warper->x2;
312049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( w >= warper->w0 )
313049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
314049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        xx1 -= w - warper->w0;
315049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( xx1 < warper->x1min )
316049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
317049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          xx2 += warper->x1min - xx1;
318049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          xx1  = warper->x1min;
319049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
320049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
321049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
322049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
323049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        xx1 -= w - warper->w0;
324049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( xx1 > warper->x1max )
325049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
326049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          xx2 -= xx1 - warper->x1max;
327049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          xx1  = warper->x1max;
328049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
329049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
330049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
331049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( xx1 < warper->x1 )
332049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        base_distort = warper->x1 - xx1;
333049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
334049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        base_distort = xx1 - warper->x1;
335049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
336049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( xx2 < warper->x2 )
337049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        base_distort += warper->x2 - xx2;
338049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
339049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        base_distort += xx2 - warper->x2;
340049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
341c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner      /* give base distortion a greater weight while scoring */
342049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      base_distort *= 10;
343049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
344049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      new_scale = org_scale + FT_DivFix( w - warper->w0, X2 - X1 );
345049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      new_delta = xx1 - FT_MulFix( X1, new_scale );
346049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
347049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_warper_compute_line_best( warper, new_scale, new_delta, xx1, xx2,
348049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                   base_distort,
349049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                   segments, num_segments );
350049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
351049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
352049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
353049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Fixed  best_scale = warper->best_scale;
354049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos    best_delta = warper->best_delta;
355049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
356049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
357049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      hints->xmin_delta = FT_MulFix( X1, best_scale - org_scale )
358049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          + best_delta;
359049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      hints->xmax_delta = FT_MulFix( X2, best_scale - org_scale )
360049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          + best_delta;
361049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
362049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      *a_scale = best_scale;
363049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      *a_delta = best_delta;
364049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
365049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
366049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
367c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner#else /* !AF_CONFIG_OPTION_USE_WARPER */
368049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
369c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  /* ANSI C doesn't like empty source files */
370c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner  typedef int  _af_warp_dummy;
371049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
372c3ee10bfa1f76a18500b487de9c85757375b48f3David 'Digit' Turner#endif /* !AF_CONFIG_OPTION_USE_WARPER */
373049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
374049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/* END */
375