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