1049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/***************************************************************************/
2049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
3049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  aflatin.c                                                              */
4049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
59c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod/*    Auto-fitter hinting routines for latin writing system (body).        */
6049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
79c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod/*  Copyright 2003-2014 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
19295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner#include <ft2build.h>
20295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner#include FT_ADVANCES_H
21aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#include FT_INTERNAL_DEBUG_H
22295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
23727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#include "afglobal.h"
249c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#include "afpic.h"
25049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aflatin.h"
26049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aferrors.h"
27049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
28049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
29aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
30049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "afwarp.h"
31049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
32049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
33049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
34049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
35aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*                                                                       */
36aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
37aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
38aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* messages during execution.                                            */
39aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*                                                                       */
40aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#undef  FT_COMPONENT
41aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#define FT_COMPONENT  trace_aflatin
42aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
43aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
44aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*************************************************************************/
45049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
46049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
47049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****            L A T I N   G L O B A L   M E T R I C S            *****/
48049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
49049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
50049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
51049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
52aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
53aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Find segments and links, compute all stem widths, and initialize */
54aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* standard width and height for the glyph with given charcode.     */
55aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
56049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
57049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_metrics_init_widths( AF_LatinMetrics  metrics,
58727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                FT_Face          face )
59049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
60049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* scan the array of segments in each direction */
61049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_GlyphHintsRec  hints[1];
62049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
63049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
64ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "\n"
659c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                "latin standard widths computation (style `%s')\n"
669c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                "=====================================================\n"
67ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                "\n",
689c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                af_style_names[metrics->root.style_class->style] ));
69727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
70049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_init( hints, face->memory );
71049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
72049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
73049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->axis[AF_DIMENSION_VERT].width_count = 0;
74049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
75049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
76727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      FT_Error            error;
779c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_ULong            glyph_index;
789c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_Long             y_offset;
79727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      int                 dim;
80727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      AF_LatinMetricsRec  dummy[1];
81727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      AF_Scaler           scaler = &dummy->root.scaler;
82049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
839c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#ifdef FT_CONFIG_OPTION_PIC
849c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_FaceGlobals  globals = metrics->root.globals;
859c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#endif
86049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
879c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_StyleClass   style_class  = metrics->root.style_class;
889c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
899c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                       [style_class->script];
909c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
919c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_UInt32  standard_char;
929c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
939c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
949c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      /*
959c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod       * We check more than a single standard character to catch features
969c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod       * like `c2sc' (small caps from caps) that don't contain lowercase
979c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod       * letters by definition, or other features that mainly operate on
989c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod       * numerals.
999c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod       */
1009c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
1019c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      standard_char = script_class->standard_char1;
1029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_get_char_index( &metrics->root,
1039c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                         standard_char,
1049c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                         &glyph_index,
1059c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                         &y_offset );
1069c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      if ( !glyph_index )
1079c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      {
1089c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( script_class->standard_char2 )
1099c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        {
1109c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          standard_char = script_class->standard_char2;
1119c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          af_get_char_index( &metrics->root,
1129c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                             standard_char,
1139c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                             &glyph_index,
1149c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                             &y_offset );
1159c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          if ( !glyph_index )
1169c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          {
1179c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            if ( script_class->standard_char3 )
1189c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            {
1199c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              standard_char = script_class->standard_char3;
1209c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              af_get_char_index( &metrics->root,
1219c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                 standard_char,
1229c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                 &glyph_index,
1239c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                 &y_offset );
1249c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              if ( !glyph_index )
1259c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                goto Exit;
1269c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            }
1279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            else
1289c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              goto Exit;
1299c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          }
1309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        }
1319c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        else
1329c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          goto Exit;
1339c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      }
134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
135ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
1369c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                  standard_char, glyph_index ));
137727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error || face->glyph->outline.n_points <= 0 )
140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_ZERO( dummy );
143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dummy->units_per_em = metrics->units_per_em;
145aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
146aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->x_scale = 0x10000L;
147aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->y_scale = 0x10000L;
148aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->x_delta = 0;
149aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->y_delta = 0;
150aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scaler->face        = face;
152049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scaler->render_mode = FT_RENDER_MODE_NORMAL;
153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scaler->flags       = 0;
154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1559c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy );
156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
157aacb8e1368a883fcbc9fe64fd0e460cef9c9b20cNick Kralevich      error = af_glyph_hints_reload( hints, &face->glyph->outline );
158049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
159049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
160049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
162049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_LatinAxis  axis    = &metrics->axis[dim];
164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_AxisHints  axhints = &hints->axis[dim];
165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Segment    seg, limit, link;
166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_UInt       num_widths = 0;
167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        error = af_latin_hints_compute_segments( hints,
170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                                 (AF_Dimension)dim );
171049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( error )
172049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          goto Exit;
173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1749c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /*
1759c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  We assume that the glyphs selected for the stem width
1769c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  computation are `featureless' enough so that the linking
1779c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  algorithm works fine without adjustments of its scoring
1789c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  function.
1799c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         */
180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_latin_hints_link_segments( hints,
1819c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                      0,
1829c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                      NULL,
183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                      (AF_Dimension)dim );
184049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
185049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg   = axhints->segments;
186049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        limit = seg + axhints->num_segments;
187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        for ( ; seg < limit; seg++ )
189049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
190049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          link = seg->link;
191049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
192049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* we only consider stem segments there! */
193049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( link && link->link == seg && link > seg )
194049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
195049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  dist;
196049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
197049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
198049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = seg->pos - link->pos;
199049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dist < 0 )
200049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              dist = -dist;
201049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
202049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( num_widths < AF_LATIN_MAX_WIDTHS )
203bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly              axis->widths[num_widths++].org = dist;
204049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
205049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
206049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
207727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        /* this also replaces multiple almost identical stem widths */
208ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        /* with a single one (the value 100 is heuristic)           */
209727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        af_sort_and_quantize_widths( &num_widths, axis->widths,
210727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                     dummy->units_per_em / 100 );
211049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        axis->width_count = num_widths;
212049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
213049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
214ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    Exit:
215049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
216049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
217049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_LatinAxis  axis = &metrics->axis[dim];
218049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos        stdw;
219049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
220049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
221ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
222ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                                         : AF_LATIN_CONSTANT( metrics, 50 );
223049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
224049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* let's try 20% of the smallest width */
225049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        axis->edge_distance_threshold = stdw / 5;
226049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        axis->standard_width          = stdw;
227049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        axis->extra_light             = 0;
228727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
229727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
230727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        {
231727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_UInt  i;
232727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
233727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
234727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "%s widths:\n",
235727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      dim == AF_DIMENSION_VERT ? "horizontal"
236727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                               : "vertical" ));
237727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
238727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  %d (standard)", axis->standard_width ));
239727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          for ( i = 1; i < axis->width_count; i++ )
240727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            FT_TRACE5(( " %d", axis->widths[i].org ));
241727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
242727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "\n" ));
243727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        }
244727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
245049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
246049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
247049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
248727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_TRACE5(( "\n" ));
249727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
250049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_done( hints );
251049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
252049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
253049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
254aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Find all blue zones.  Flat segments give the reference points, */
255aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* round segments the overshoot positions.                        */
256aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
257049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
258049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_metrics_init_blues( AF_LatinMetrics  metrics,
259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_Face          face )
260049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
261ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_Pos        flats [AF_BLUE_STRING_MAX_LEN];
262ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_Pos        rounds[AF_BLUE_STRING_MAX_LEN];
263ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        num_flats;
265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        num_rounds;
266ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
267049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_LatinBlue  blue;
268049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error      error;
269ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_LatinAxis  axis = &metrics->axis[AF_DIMENSION_VERT];
270727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_Outline    outline;
271049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2729c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    AF_StyleClass  sc = metrics->root.style_class;
2739c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
2749c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    AF_Blue_Stringset         bss = sc->blue_stringset;
275ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
276ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
277049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2789c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* we walk over the blue character strings as specified in the */
2799c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* style's entry in the `af_blue_stringset' array              */
280049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
281ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "latin blue zones computation\n"
282ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                "============================\n"
283ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                "\n" ));
284049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
285ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
286049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
287ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      const char*  p = &af_blue_strings[bs->string];
288049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos*      blue_ref;
289049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos*      blue_shoot;
290049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
291049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
292ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
293ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      {
294ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_Bool  have_flag = 0;
295ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
296ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
297ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_TRACE5(( "blue zone %d", axis->blue_count ));
298ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
299ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        if ( bs->properties )
300ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
301ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( " (" ));
302ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
303ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          if ( AF_LATIN_IS_TOP_BLUE( bs ) )
304ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          {
305ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_TRACE5(( "top" ));
306ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            have_flag = 1;
307ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          }
308ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
3099c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
3109c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          {
3119c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            if ( have_flag )
3129c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              FT_TRACE5(( ", " ));
3139c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            FT_TRACE5(( "neutral" ));
3149c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            have_flag = 1;
3159c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          }
3169c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
317ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
318ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          {
319ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            if ( have_flag )
320ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_TRACE5(( ", " ));
321ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_TRACE5(( "small top" ));
322ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            have_flag = 1;
323ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          }
324ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
325ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          if ( AF_LATIN_IS_LONG_BLUE( bs ) )
326ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          {
327ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            if ( have_flag )
328ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_TRACE5(( ", " ));
329ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_TRACE5(( "long" ));
330ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          }
331ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
332ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( ")" ));
333ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
334ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
335ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_TRACE5(( ":\n" ));
336ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      }
337ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif /* FT_DEBUG_LEVEL_TRACE */
338049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
339049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      num_flats  = 0;
340049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      num_rounds = 0;
341049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
342ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      while ( *p )
343049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
344ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_ULong    ch;
3459c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_ULong    glyph_index;
3469c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_Long     y_offset;
347bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        FT_Pos      best_y;                            /* same as points.y */
348727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_Int      best_point, best_contour_first, best_contour_last;
349049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Vector*  points;
350049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Bool     round = 0;
351049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
352049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
353ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        GET_UTF8_CHAR( ch, p );
354ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
355049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* load the character in the face -- skip unknown or empty ones */
3569c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset );
357049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( glyph_index == 0 )
358ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
359ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  U+%04lX unavailable\n", ch ));
360049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
361ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
362049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
363727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        error   = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
364727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        outline = face->glyph->outline;
365727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        if ( error || outline.n_points <= 0 )
366ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
367ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  U+%04lX contains no outlines\n", ch ));
368049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
369ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
370049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
371049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* now compute min or max point indices and coordinates */
372727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        points             = outline.points;
373727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        best_point         = -1;
374727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        best_y             = 0;  /* make compiler happy */
375727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        best_contour_first = 0;  /* ditto */
376727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        best_contour_last  = 0;  /* ditto */
377049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
378049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
379049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Int  nn;
380049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Int  first = 0;
381049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Int  last  = -1;
382049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
383049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
384727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
385049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
386049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Int  old_best_point = best_point;
387049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Int  pp;
388049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
389049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
390727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            last = outline.contours[nn];
391049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
392049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* Avoid single-point contours since they are never rasterized. */
393049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* In some fonts, they correspond to mark attachment points     */
394ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* that are way outside of the glyph's real outline.            */
395049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( last <= first )
396bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly              continue;
397049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
398ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            if ( AF_LATIN_IS_TOP_BLUE( bs ) )
399049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
400049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              for ( pp = first; pp <= last; pp++ )
401049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                if ( best_point < 0 || points[pp].y > best_y )
402049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                {
403049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                  best_point = pp;
404049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                  best_y     = points[pp].y;
405049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                }
406049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
407049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
408049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
409049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              for ( pp = first; pp <= last; pp++ )
410049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                if ( best_point < 0 || points[pp].y < best_y )
411049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                {
412049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                  best_point = pp;
413049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                  best_y     = points[pp].y;
414049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                }
415049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
416049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
417049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( best_point != old_best_point )
418049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
419727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              best_contour_first = first;
420727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              best_contour_last  = last;
421049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
422049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
423049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
424049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
425049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* now check whether the point belongs to a straight or round   */
426049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* segment; we first need to find in which contour the extremum */
427049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* lies, then inspect its previous and next points              */
428049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( best_point >= 0 )
429049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
430727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_Pos  best_x = points[best_point].x;
431049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Int  prev, next;
432ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_Int  best_segment_first, best_segment_last;
433727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_Int  best_on_point_first, best_on_point_last;
434049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos  dist;
435049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
436049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
437ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          best_segment_first = best_point;
438ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          best_segment_last  = best_point;
439ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
440727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
441727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          {
442727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            best_on_point_first = best_point;
443727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            best_on_point_last  = best_point;
444727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          }
445727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          else
446727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          {
447727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            best_on_point_first = -1;
448727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            best_on_point_last  = -1;
449727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          }
450727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
451ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /* look for the previous and next points on the contour  */
452ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /* that are not on the same Y coordinate, then threshold */
453ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /* the `closeness'...                                    */
454049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          prev = best_point;
455049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          next = prev;
456049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
457049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          do
458049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
459727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( prev > best_contour_first )
460049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              prev--;
461049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
462727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              prev = best_contour_last;
463049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
464727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            dist = FT_ABS( points[prev].y - best_y );
465727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            /* accept a small distance or a small angle (both values are */
466727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            /* heuristic; value 20 corresponds to approx. 2.9 degrees)   */
467727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( dist > 5 )
468727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
469727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                break;
470727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
471ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            best_segment_first = prev;
472ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
473727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
474727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            {
475727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              best_on_point_first = prev;
476727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              if ( best_on_point_last < 0 )
477727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                best_on_point_last = prev;
478727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            }
479049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
480049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          } while ( prev != best_point );
481049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
482049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          do
483049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
484727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( next < best_contour_last )
485049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              next++;
486049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
487727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              next = best_contour_first;
488049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
489727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            dist = FT_ABS( points[next].y - best_y );
490727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( dist > 5 )
491727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
492727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                break;
493727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
494ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            best_segment_last = next;
495ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
496727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
497727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            {
498727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              best_on_point_last = next;
499727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              if ( best_on_point_first < 0 )
500727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                best_on_point_first = next;
501727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            }
502049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
503049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          } while ( next != best_point );
504049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
505ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          if ( AF_LATIN_IS_LONG_BLUE( bs ) )
506ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          {
507ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* If this flag is set, we have an additional constraint to  */
508ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* get the blue zone distance: Find a segment of the topmost */
509ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* (or bottommost) contour that is longer than a heuristic   */
510ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* threshold.  This ensures that small bumps in the outline  */
511ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* are ignored (for example, the `vertical serifs' found in  */
512ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* many Hebrew glyph designs).                               */
513ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
514ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* If this segment is long enough, we are done.  Otherwise,  */
515ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* search the segment next to the extremum that is long      */
516ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* enough, has the same direction, and a not too large       */
517ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* vertical distance from the extremum.  Note that the       */
518ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* algorithm doesn't check whether the found segment is      */
519ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* actually the one (vertically) nearest to the extremum.    */
520ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
521ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* heuristic threshold value */
522ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_Pos  length_threshold = metrics->units_per_em / 25;
523ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
524ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
525ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            dist = FT_ABS( points[best_segment_last].x -
526ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                             points[best_segment_first].x );
527ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
528ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            if ( dist < length_threshold                       &&
529ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                 best_segment_last - best_segment_first + 2 <=
530ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                   best_contour_last - best_contour_first      )
531ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            {
532ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              /* heuristic threshold value */
533ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_Pos  height_threshold = metrics->units_per_em / 4;
534ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
535ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_Int   first;
536ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_Int   last;
537ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_Bool  hit;
538ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
5399c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              /* we intentionally declare these two variables        */
5409c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              /* outside of the loop since various compilers emit    */
5419c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              /* incorrect warning messages otherwise, talking about */
5429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              /* `possibly uninitialized variables'                  */
5439c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              FT_Int  p_first = 0;            /* make compiler happy */
5449c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              FT_Int  p_last  = 0;
5459c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
546ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              FT_Bool  left2right;
547ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
548ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
549ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              /* compute direction */
550ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              prev = best_point;
551ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
552ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              do
553ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              {
554ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( prev > best_contour_first )
555ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  prev--;
556ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                else
557ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  prev = best_contour_last;
558ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
559ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( points[prev].x != best_x )
560ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  break;
561ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
562ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              } while ( prev != best_point );
563ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
564ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              /* skip glyph for the degenerate case */
565ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              if ( prev == best_point )
566ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                continue;
567ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
568ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              left2right = FT_BOOL( points[prev].x < points[best_point].x );
569ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
570ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              first = best_segment_last;
571ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              last  = first;
572ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              hit   = 0;
573ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
574ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              do
575ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              {
576ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                FT_Bool  l2r;
577ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                FT_Pos   d;
578ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
579ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
580ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( !hit )
581ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                {
582ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  /* no hit; adjust first point */
583ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  first = last;
584ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
585ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  /* also adjust first and last on point */
586ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( FT_CURVE_TAG( outline.tags[first] ) ==
587ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                         FT_CURVE_TAG_ON )
588ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  {
589ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    p_first = first;
590ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    p_last  = first;
591ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  }
592ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  else
593ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  {
594ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    p_first = -1;
595ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    p_last  = -1;
596ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  }
597ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
598ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  hit = 1;
599ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                }
600ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
601ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( last < best_contour_last )
602ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  last++;
603ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                else
604ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  last = best_contour_first;
605ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
606ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( FT_ABS( best_y - points[first].y ) > height_threshold )
607ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                {
608ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  /* vertical distance too large */
609ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  hit = 0;
610ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  continue;
611ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                }
612ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
613ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                /* same test as above */
614ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                dist = FT_ABS( points[last].y - points[first].y );
615ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( dist > 5 )
616ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( FT_ABS( points[last].x - points[first].x ) <=
617ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                         20 * dist )
618ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  {
619ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    hit = 0;
620ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    continue;
621ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  }
622ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
623ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
624ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                {
625ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  p_last = last;
626ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( p_first < 0 )
627ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    p_first = last;
628ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                }
629ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
630ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                l2r = FT_BOOL( points[first].x < points[last].x );
631ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                d   = FT_ABS( points[last].x - points[first].x );
632ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
633ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                if ( l2r == left2right     &&
634ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                     d >= length_threshold )
635ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                {
636ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  /* all constraints are met; update segment after finding */
637ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  /* its end                                               */
638ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  do
639ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  {
640ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    if ( last < best_contour_last )
641ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      last++;
642ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    else
643ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      last = best_contour_first;
644ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
645ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    d = FT_ABS( points[last].y - points[first].y );
646ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    if ( d > 5 )
647ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      if ( FT_ABS( points[next].x - points[first].x ) <=
648ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                             20 * dist )
649ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      {
6509c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                        if ( last > best_contour_first )
6519c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                          last--;
6529c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                        else
6539c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                          last = best_contour_last;
654ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                        break;
655ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      }
656ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
657ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    p_last = last;
658ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
659ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    if ( FT_CURVE_TAG( outline.tags[last] ) ==
660ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                           FT_CURVE_TAG_ON )
661ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    {
662ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      p_last = last;
663ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      if ( p_first < 0 )
664ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                        p_first = last;
665ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    }
666ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
667ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  } while ( last != best_segment_first );
668ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
669ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  best_y = points[first].y;
670ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
671ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  best_segment_first = first;
672ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  best_segment_last  = last;
673ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
674ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  best_on_point_first = p_first;
675ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  best_on_point_last  = p_last;
676ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
677ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  break;
678ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                }
679ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
680ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              } while ( last != best_segment_first );
681ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            }
682ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          }
683ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
6849c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* for computing blue zones, we add the y offset as returned */
6859c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* by the currently used OpenType feature -- for example,    */
6869c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* superscript glyphs might be identical to subscript glyphs */
6879c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* with a vertical shift                                     */
6889c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          best_y += y_offset;
6899c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
690ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  U+%04lX: best_y = %5ld", ch, best_y ));
691ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
692ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /* now set the `round' flag depending on the segment's kind: */
693ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /*                                                           */
694ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /* - if the horizontal distance between the first and last   */
695ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /*   `on' point is larger than upem/8 (value 8 is heuristic) */
696ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /*   we have a flat segment                                  */
697ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /* - if either the first or the last point of the segment is */
698ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /*   an `off' point, the segment is round, otherwise it is   */
699ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          /*   flat                                                    */
700727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          if ( best_on_point_first >= 0                               &&
701727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease               best_on_point_last >= 0                                &&
702727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease               (FT_UInt)( FT_ABS( points[best_on_point_last].x -
703727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                  points[best_on_point_first].x ) ) >
704727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                 metrics->units_per_em / 8                            )
705727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            round = 0;
706727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          else
707727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            round = FT_BOOL(
708ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
709ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                        FT_CURVE_TAG_ON                                   ||
710ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      FT_CURVE_TAG( outline.tags[best_segment_last]  ) !=
711ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                        FT_CURVE_TAG_ON                                   );
712049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
7139c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          if ( round && AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
7149c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          {
7159c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            /* only use flat segments for a neutral blue zone */
7169c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            FT_TRACE5(( " (round, skipped)\n" ));
7179c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            continue;
7189c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          }
7199c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
720727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
721049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
722049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
723049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( round )
724049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          rounds[num_rounds++] = best_y;
725049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
726049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          flats[num_flats++]   = best_y;
727049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
728049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
729049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( num_flats == 0 && num_rounds == 0 )
730049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
731049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /*
732049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         *  we couldn't find a single glyph to compute this blue zone,
733049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         *  we will simply ignore it then
734049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         */
735727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_TRACE5(( "  empty\n" ));
736049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
737049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
738049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
739049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* we have computed the contents of the `rounds' and `flats' tables, */
740049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* now determine the reference and overshoot position of the blue -- */
741049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* we simply take the median value after a simple sort               */
742049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_sort_pos( num_rounds, rounds );
743049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_sort_pos( num_flats,  flats );
744049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
745bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly      blue       = &axis->blues[axis->blue_count];
746bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly      blue_ref   = &blue->ref.org;
747bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly      blue_shoot = &blue->shoot.org;
748049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
749049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      axis->blue_count++;
750049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
751049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( num_flats == 0 )
752049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
753049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        *blue_ref   =
754049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        *blue_shoot = rounds[num_rounds / 2];
755049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
756049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else if ( num_rounds == 0 )
757049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
758049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        *blue_ref   =
759049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        *blue_shoot = flats[num_flats / 2];
760049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
761049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
762049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
763ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        *blue_ref   = flats [num_flats  / 2];
764049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        *blue_shoot = rounds[num_rounds / 2];
765049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
766049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
767049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* there are sometimes problems: if the overshoot position of top     */
768049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* zones is under its reference position, or the opposite for bottom  */
769049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* zones.  We must thus check everything there and correct the errors */
770049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( *blue_shoot != *blue_ref )
771049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
772049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos   ref      = *blue_ref;
773049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos   shoot    = *blue_shoot;
774049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Bool  over_ref = FT_BOOL( shoot > ref );
775049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
776049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
777ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        if ( AF_LATIN_IS_TOP_BLUE( bs ) ^ over_ref )
778727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        {
779aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          *blue_ref   =
780aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          *blue_shoot = ( shoot + ref ) / 2;
781727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
782727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  [overshoot smaller than reference,"
783727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " taking mean value]\n" ));
784727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        }
785049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
786049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
787049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      blue->flags = 0;
788ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      if ( AF_LATIN_IS_TOP_BLUE( bs ) )
789049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->flags |= AF_LATIN_BLUE_TOP;
7909c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) )
7919c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        blue->flags |= AF_LATIN_BLUE_NEUTRAL;
792049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
793049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /*
794295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner       * The following flag is used later to adjust the y and x scales
795049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project       * in order to optimize the pixel grid alignment of the top of small
796049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project       * letters.
797049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project       */
798ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) )
799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
801727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      FT_TRACE5(( "    -> reference = %ld\n"
802727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                  "       overshoot = %ld\n",
803727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                  *blue_ref, *blue_shoot ));
804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
806aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_TRACE5(( "\n" ));
807aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return;
809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
810049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
811049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
812aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Check whether all ASCII digits have the same advance width. */
813aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
814295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  FT_LOCAL_DEF( void )
815295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
816295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner                                 FT_Face          face )
817295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  {
818295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    FT_UInt   i;
819295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    FT_Bool   started = 0, same_width = 1;
820295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    FT_Fixed  advance, old_advance = 0;
821295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
822295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
823bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    /* digit `0' is 0x30 in all supported charmaps */
824295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    for ( i = 0x30; i <= 0x39; i++ )
825295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    {
8269c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_ULong  glyph_index;
8279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_Long   y_offset;
828295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
829295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
8309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_get_char_index( &metrics->root, i, &glyph_index, &y_offset );
831295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      if ( glyph_index == 0 )
832295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        continue;
833295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
834295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      if ( FT_Get_Advance( face, glyph_index,
835295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner                           FT_LOAD_NO_SCALE         |
836295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner                           FT_LOAD_NO_HINTING       |
837295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner                           FT_LOAD_IGNORE_TRANSFORM,
838295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner                           &advance ) )
839295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        continue;
840295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
841295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      if ( started )
842295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      {
843295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        if ( advance != old_advance )
844295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        {
845295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner          same_width = 0;
846295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner          break;
847295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        }
848295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      }
849295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      else
850295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      {
851295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        old_advance = advance;
852295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner        started     = 1;
853295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      }
854295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    }
855295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
856295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    metrics->root.digits_have_same_width = same_width;
857295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  }
858295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
859295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner
860aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Initialize global metrics. */
861aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
862049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
863049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_metrics_init( AF_LatinMetrics  metrics,
864049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                         FT_Face          face )
865049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
866049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_CharMap  oldmap = face->charmap;
867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
868049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->units_per_em = face->units_per_EM;
870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
871727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
872049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
873727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      af_latin_metrics_init_widths( metrics, face );
874049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_latin_metrics_init_blues( metrics, face );
875295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner      af_latin_metrics_check_digits( metrics, face );
876049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
877049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
878049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Set_Charmap( face, oldmap );
879727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return FT_Err_Ok;
880049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
881049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
882049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
883aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Adjust scaling value, then scale and shift widths   */
884aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* and blue zones (if applicable) for given dimension. */
885aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_metrics_scale_dim( AF_LatinMetrics  metrics,
888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Scaler        scaler,
889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Dimension     dim )
890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Fixed      scale;
892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        delta;
893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_LatinAxis  axis;
894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UInt       nn;
895049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
896049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
897049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ )
898049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
899049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scale = scaler->x_scale;
900049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      delta = scaler->x_delta;
901049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
902049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
903049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
904049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scale = scaler->y_scale;
905049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      delta = scaler->y_delta;
906049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
907049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
908049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis = &metrics->axis[dim];
909049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( axis->org_scale == scale && axis->org_delta == delta )
911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return;
912049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
913049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->org_scale = scale;
914049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->org_delta = delta;
915049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
916049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
917049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     * correct X and Y scale to optimize the alignment of the top of small
918049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     * letters to the pixel grid
919049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
920049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
921049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_LatinAxis  Axis = &metrics->axis[AF_DIMENSION_VERT];
922049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_LatinBlue  blue = NULL;
923049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
924049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
925049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( nn = 0; nn < Axis->blue_count; nn++ )
926049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
927049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
928049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
929049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          blue = &Axis->blues[nn];
930049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
931049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
932049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
933049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
934049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( blue )
935049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
936727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_Pos   scaled;
937727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_Pos   threshold;
938727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_Pos   fitted;
939727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_UInt  limit;
940727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        FT_UInt  ppem;
941727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
942727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
943727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        scaled    = FT_MulFix( blue->shoot.org, scaler->y_scale );
944727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        ppem      = metrics->root.scaler.face->size->metrics.x_ppem;
945727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        limit     = metrics->root.globals->increase_x_height;
946727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        threshold = 40;
947727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
948727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        /* if the `increase-x-height' property is active, */
949727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        /* we round up much more often                    */
950727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        if ( limit                                 &&
951727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease             ppem <= limit                         &&
952727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease             ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN )
953727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          threshold = 52;
954049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
955727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        fitted = ( scaled + threshold ) & ~63;
956049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
957049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( scaled != fitted )
958049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
959049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
960049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dim == AF_DIMENSION_HORZ )
961049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
962049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( fitted < scaled )
963049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              scale -= scale / 50;  /* scale *= 0.98 */
964049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
965049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
966049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
967049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dim == AF_DIMENSION_VERT )
968ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          {
969049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            scale = FT_MulDiv( scale, fitted, scaled );
970ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
971ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_TRACE5((
972ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              "af_latin_metrics_scale_dim:"
9739c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              " x height alignment (style `%s'):\n"
974ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              "                           "
975ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              " vertical scaling changed from %.4f to %.4f (by %d%%)\n"
976ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              "\n",
9779c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              af_style_names[metrics->root.style_class->style],
978ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              axis->org_scale / 65536.0,
979ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              scale / 65536.0,
980ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              ( fitted - scaled ) * 100 / scaled ));
981ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          }
982049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
983049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
984049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
985049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
986049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->scale = scale;
987049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->delta = delta;
988049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
989049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ )
990049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
991049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.x_scale = scale;
992049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.x_delta = delta;
993049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
994049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
995049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
996049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.y_scale = scale;
997049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.y_delta = delta;
998049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
999049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
10009c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    FT_TRACE5(( "%s widths (style `%s')\n",
1001ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical",
10029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                af_style_names[metrics->root.style_class->style] ));
1003ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1004aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* scale the widths */
1005049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( nn = 0; nn < axis->width_count; nn++ )
1006049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1007049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Width  width = axis->widths + nn;
1008049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1009049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1010049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      width->cur = FT_MulFix( width->org, scale );
1011049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      width->fit = width->cur;
1012ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1013ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_TRACE5(( "  %d scaled to %.2f\n",
1014ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  width->org,
1015ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  width->cur / 64.0 ));
1016049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1017049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1018ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "\n" ));
1019ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1020049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* an extra-light axis corresponds to a standard width that is */
1021aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* smaller than 5/8 pixels                                     */
1022049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->extra_light =
1023049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1024049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1025ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
1026ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    if ( axis->extra_light )
10279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
1028ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  "\n",
10299c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                  af_style_names[metrics->root.style_class->style] ));
1030ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
1031ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1032049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_VERT )
1033049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
10349c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_TRACE5(( "blue zones (style `%s')\n",
10359c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                  af_style_names[metrics->root.style_class->style] ));
1036ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1037049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* scale the blue zones */
1038049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( nn = 0; nn < axis->blue_count; nn++ )
1039049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1040049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_LatinBlue  blue = &axis->blues[nn];
1041049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos        dist;
1042049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1043049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1044049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->ref.cur   = FT_MulFix( blue->ref.org, scale ) + delta;
1045049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->ref.fit   = blue->ref.cur;
1046049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
1047049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->shoot.fit = blue->shoot.cur;
1048049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        blue->flags    &= ~AF_LATIN_BLUE_ACTIVE;
1049049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1050049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* a blue zone is only active if it is less than 3/4 pixels tall */
1051049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
1052049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist <= 48 && dist >= -48 )
1053049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1054aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
1055aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Pos  delta1;
1056aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
1057aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Pos  delta2;
1058049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1059049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1060aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* use discrete values for blue zone widths */
1061aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1062aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
1063aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1064aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* generic, original code */
1065049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta1 = blue->shoot.org - blue->ref.org;
1066049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta2 = delta1;
1067049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 < 0 )
1068049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = -delta2;
1069049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1070049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta2 = FT_MulFix( delta2, scale );
1071049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1072049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta2 < 32 )
1073049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = 0;
1074049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else if ( delta2 < 64 )
1075049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
1076049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1077049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = FT_PIX_ROUND( delta2 );
1078049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1079049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 < 0 )
1080049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = -delta2;
1081049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1082049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          blue->ref.fit   = FT_PIX_ROUND( blue->ref.cur );
1083049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          blue->shoot.fit = blue->ref.fit + delta2;
1084049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1085aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#else
1086aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1087aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* simplified version due to abs(dist) <= 48 */
1088aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = dist;
1089aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( dist < 0 )
1090aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            delta2 = -delta2;
1091aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1092aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( delta2 < 32 )
1093aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            delta2 = 0;
1094727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          else if ( delta2 < 48 )
1095aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            delta2 = 32;
1096aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          else
1097aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            delta2 = 64;
1098aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1099aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( dist < 0 )
1100aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            delta2 = -delta2;
1101aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1102aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          blue->ref.fit   = FT_PIX_ROUND( blue->ref.cur );
1103aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          blue->shoot.fit = blue->ref.fit - delta2;
1104aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1105aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
1106aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          blue->flags |= AF_LATIN_BLUE_ACTIVE;
1108ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1109ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  reference %d: %d scaled to %.2f%s\n"
1110ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      "  overshoot %d: %d scaled to %.2f%s\n",
1111ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      nn,
1112ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      blue->ref.org,
1113ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      blue->ref.fit / 64.0,
1114ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
1115ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                                                         : " (inactive)",
1116ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      nn,
1117ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      blue->shoot.org,
1118ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      blue->shoot.fit / 64.0,
1119ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      blue->flags & AF_LATIN_BLUE_ACTIVE ? ""
1120ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                                                         : " (inactive)" ));
1121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1122049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1123049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1124049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1125049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1127aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Scale global values in both directions. */
1128aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1129049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
1130049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_metrics_scale( AF_LatinMetrics  metrics,
1131049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          AF_Scaler        scaler )
1132049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1133049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->root.scaler.render_mode = scaler->render_mode;
1134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->root.scaler.face        = scaler->face;
1135727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    metrics->root.scaler.flags       = scaler->flags;
1136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
1138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
1139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
1145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****           L A T I N   G L Y P H   A N A L Y S I S             *****/
1146049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
1147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1150aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1151aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Walk over all contours and compute its segments. */
1152aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
1154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_compute_segments( AF_GlyphHints  hints,
1155049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                   AF_Dimension   dim )
1156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1157bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_AxisHints   axis          = &hints->axis[dim];
1158bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    FT_Memory      memory        = hints->memory;
1159727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_Error       error         = FT_Err_Ok;
1160bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_Segment     segment       = NULL;
1161bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_SegmentRec  seg0;
1162bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_Point*      contour       = hints->contours;
1163bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_Point*      contour_limit = contour + hints->num_contours;
1164bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_Direction   major_dir, segment_dir;
1165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_ZERO( &seg0 );
1168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    seg0.score = 32000;
1169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    seg0.flags = AF_EDGE_NORMAL;
1170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1171049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    major_dir   = (AF_Direction)FT_ABS( axis->major_dir );
1172049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    segment_dir = major_dir;
1173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1174049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->num_segments = 0;
1175049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1176049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* set up (u,v) in each point */
1177049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ )
1178049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1179049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  point = hints->points;
1180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  limit = point + hints->num_points;
1181049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1182049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ; point < limit; point++ )
1184049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1185049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        point->u = point->fx;
1186049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        point->v = point->fy;
1187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1189049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1190049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1191049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  point = hints->points;
1192049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  limit = point + hints->num_points;
1193049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1194049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1195049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ; point < limit; point++ )
1196049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1197049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        point->u = point->fy;
1198049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        point->v = point->fx;
1199049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1200049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1201049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1202049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* do each contour separately */
1203049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( ; contour < contour_limit; contour++ )
1204049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1205049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  point   =  contour[0];
1206049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  last    =  point->prev;
1207049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      int       on_edge =  0;
1208049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos    min_pos =  32000;  /* minimum segment pos != min_coord */
1209049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos    max_pos = -32000;  /* maximum segment pos != max_coord */
1210049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Bool   passed;
1211049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1212049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1213049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( point == last )  /* skip singletons -- just in case */
1214049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1215049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1216049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( FT_ABS( last->out_dir )  == major_dir &&
1217049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           FT_ABS( point->out_dir ) == major_dir )
1218049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1219049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* we are already on an edge, try to locate its start */
1220049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        last = point;
1221049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1222049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        for (;;)
1223049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1224049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          point = point->prev;
1225049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( FT_ABS( point->out_dir ) != major_dir )
1226049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1227049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            point = point->next;
1228049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            break;
1229049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1230049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( point == last )
1231049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            break;
1232049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1233049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1234049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1235049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      last   = point;
1236049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      passed = 0;
1237049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1238049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for (;;)
1239049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1240049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  u, v;
1241049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1242049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1243049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( on_edge )
1244049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1245049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          u = point->u;
1246049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( u < min_pos )
1247049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            min_pos = u;
1248049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( u > max_pos )
1249049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            max_pos = u;
1250049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1251049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( point->out_dir != segment_dir || point == last )
1252049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1253049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* we are just leaving an edge; record a new segment! */
1254049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->last = point;
1255049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->pos  = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1256049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1257049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* a segment is round if either its first or last point */
1258049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* is a control point                                   */
1259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( ( segment->first->flags | point->flags ) &
1260bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                 AF_FLAG_CONTROL                          )
1261049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              segment->flags |= AF_EDGE_ROUND;
1262049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1263049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* compute segment size */
1264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            min_pos = max_pos = point->v;
1265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1266049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            v = segment->first->v;
1267049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( v < min_pos )
1268049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              min_pos = v;
1269049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( v > max_pos )
1270049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              max_pos = v;
1271049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1272049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->min_coord = (FT_Short)min_pos;
1273049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->max_coord = (FT_Short)max_pos;
1274049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->height    = (FT_Short)( segment->max_coord -
1275049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                             segment->min_coord );
1276049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1277049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            on_edge = 0;
1278049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment = NULL;
1279727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            /* fall through */
1280049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1281049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1282049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1283049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* now exit if we are at the start/end point */
1284049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( point == last )
1285049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1286049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( passed )
1287049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            break;
1288049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          passed = 1;
1289049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1290049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1291049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !on_edge && FT_ABS( point->out_dir ) == major_dir )
1292049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1293049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* this is the start of a new segment! */
1294049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          segment_dir = (AF_Direction)point->out_dir;
1295049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1296049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* clear all segment fields */
1297049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          error = af_axis_hints_new_segment( axis, memory, &segment );
1298049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( error )
1299049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            goto Exit;
1300049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1301049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          segment[0]        = seg0;
1302049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          segment->dir      = (FT_Char)segment_dir;
1303049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          min_pos = max_pos = point->u;
1304049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          segment->first    = point;
1305049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          segment->last     = point;
1306049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          on_edge           = 1;
1307049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1308049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1309049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        point = point->next;
1310049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1311049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1312049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    } /* contours */
1313049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1314049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1315727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /* now slightly increase the height of segments if this makes */
1316727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /* sense -- this is used to better detect and ignore serifs   */
1317049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1318049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Segment  segments     = axis->segments;
1319049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Segment  segments_end = segments + axis->num_segments;
1320049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1321049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1322049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( segment = segments; segment < segments_end; segment++ )
1323049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1324049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Point  first   = segment->first;
1325049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Point  last    = segment->last;
1326049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos    first_v = first->v;
1327049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos    last_v  = last->v;
1328049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1329049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1330049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( first == last )
1331049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
1332049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1333049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( first_v < last_v )
1334049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1335049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Point  p;
1336049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1337049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1338049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          p = first->prev;
1339049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( p->v < first_v )
1340049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->height = (FT_Short)( segment->height +
1341049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                          ( ( first_v - p->v ) >> 1 ) );
1342049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1343049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          p = last->next;
1344049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( p->v > last_v )
1345049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->height = (FT_Short)( segment->height +
1346049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                          ( ( p->v - last_v ) >> 1 ) );
1347049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1348049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1349049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1350049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Point  p;
1351049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1352049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1353049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          p = first->prev;
1354049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( p->v > first_v )
1355049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->height = (FT_Short)( segment->height +
1356049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                          ( ( p->v - first_v ) >> 1 ) );
1357049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1358049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          p = last->next;
1359049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( p->v < last_v )
1360049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            segment->height = (FT_Short)( segment->height +
1361049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                          ( ( last_v - p->v ) >> 1 ) );
1362049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1363049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1364049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1365049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1366049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
1367049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1368049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1369049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1370049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
13719c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod  /* Link segments to form stems and serifs.  If `width_count' and      */
13729c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod  /* `widths' are non-zero, use them to fine-tune the scoring function. */
1373aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1374049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
1375049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_link_segments( AF_GlyphHints  hints,
13769c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                FT_UInt        width_count,
13779c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                AF_WidthRec*   widths,
1378049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                AF_Dimension   dim )
1379049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1380049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis          = &hints->axis[dim];
1381049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
1382049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
13839c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    FT_Pos        len_threshold, len_score, dist_score, max_width;
1384049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg1, seg2;
1385049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1386049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
13879c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    if ( width_count )
13889c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      max_width = widths[width_count - 1].org;
13899c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    else
13909c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      max_width = 0;
13919c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
13929c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* a heuristic value to set up a minimum value for overlapping */
1393049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
1394049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( len_threshold == 0 )
1395049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      len_threshold = 1;
1396049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
13979c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* a heuristic value to weight lengths */
1398049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
1399049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
14009c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* a heuristic value to weight distances (no call to    */
14019c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* AF_LATIN_CONSTANT needed, since we work on multiples */
14029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* of the stem width)                                   */
14039c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    dist_score = 3000;
14049c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
1405049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* now compare each segment to the others */
1406049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg1 = segments; seg1 < segment_limit; seg1++ )
1407049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1408049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* the fake segments are introduced to hint the metrics -- */
1409049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* we must never link them to anything                     */
1410049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
1411049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1412049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1413aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* search for stems having opposite directions, */
1414aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* with seg1 to the `left' of seg2              */
1415049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( seg2 = segments; seg2 < segment_limit; seg2++ )
1416bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly      {
1417bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        FT_Pos  pos1 = seg1->pos;
1418bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        FT_Pos  pos2 = seg2->pos;
1419049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1420049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1421aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
1422aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1423aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* compute distance between the two segments */
14249c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_Pos  min = seg1->min_coord;
14259c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_Pos  max = seg1->max_coord;
14269c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_Pos  len;
1427049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1428049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1429bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          if ( min < seg2->min_coord )
1430bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            min = seg2->min_coord;
1431049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1432bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          if ( max > seg2->max_coord )
1433bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            max = seg2->max_coord;
1434049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1435aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* compute maximum coordinate difference of the two segments */
14369c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* (this is, how much they overlap)                          */
1437bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          len = max - min;
1438bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          if ( len >= len_threshold )
1439bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          {
14409c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            /*
14419c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *  The score is the sum of two demerits indicating the
14429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *  `badness' of a fit, measured along the segments' main axis
14439c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *  and orthogonal to it, respectively.
14449c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *
14459c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *  o The less overlapping along the main axis, the worse it
14469c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *    is, causing a larger demerit.
14479c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *
14489c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *  o The nearer the orthogonal distance to a stem width, the
14499c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *    better it is, causing a smaller demerit.  For simplicity,
14509c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *    however, we only increase the demerit for values that
14519c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             *    exceed the largest stem width.
14529c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod             */
14539c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14549c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            FT_Pos  dist = pos2 - pos1;
14559c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14569c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            FT_Pos  dist_demerit, score;
14579c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14589c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14599c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            if ( max_width )
14609c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            {
14619c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              /* distance demerits are based on multiples of `max_width'; */
14629c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              /* we scale by 1024 for getting more precision              */
14639c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              FT_Pos  delta = ( dist << 10 ) / max_width - ( 1 << 10 );
14649c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14659c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14669c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              if ( delta > 10000 )
14679c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                dist_demerit = 32000;
14689c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              else if ( delta > 0 )
14699c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                dist_demerit = delta * delta / dist_score;
14709c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              else
14719c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                dist_demerit = 0;
14729c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            }
14739c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            else
14749c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              dist_demerit = dist; /* default if no widths available */
14759c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
14769c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            score = dist_demerit + len_score / len;
1477049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1478aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            /* and we search for the smallest score */
1479bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            if ( score < seg1->score )
1480bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            {
1481bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly              seg1->score = score;
1482bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly              seg1->link  = seg2;
1483bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            }
1484049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1485bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            if ( score < seg2->score )
1486bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            {
1487bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly              seg2->score = score;
1488bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly              seg2->link  = seg1;
1489049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1490049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1491049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1492bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly      }
1493049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1494049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1495aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* now compute the `serif' segments, cf. explanations in `afhints.h' */
1496049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg1 = segments; seg1 < segment_limit; seg1++ )
1497049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1498049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      seg2 = seg1->link;
1499049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1500049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg2 )
1501049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1502049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg2->link != seg1 )
1503049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1504049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg1->link  = 0;
1505049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg1->serif = seg2->link;
1506049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1507049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1508049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1509049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1510049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1511049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1512aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Link segments to edges, using feature analysis for selection. */
1513aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1514049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
1515049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_compute_edges( AF_GlyphHints  hints,
1516049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                AF_Dimension   dim )
1517049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1518049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis   = &hints->axis[dim];
1519727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_Error      error  = FT_Err_Ok;
1520049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Memory     memory = hints->memory;
1521049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_LatinAxis  laxis  = &((AF_LatinMetrics)hints->metrics)->axis[dim];
1522049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1523049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
1524049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
1525049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg;
1526049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1527aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
1528049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Direction  up_dir;
1529aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
1530049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Fixed      scale;
1531049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        edge_distance_threshold;
1532049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        segment_length_threshold;
1533049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1534049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1535049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->num_edges = 0;
1536049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1537049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
1538049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         : hints->y_scale;
1539049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1540aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
1541049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
1542049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                          : AF_DIR_RIGHT;
1543aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
1544049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1545049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1546aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner     *  We ignore all segments that are less than 1 pixel in length
1547049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  to avoid many problems with serif fonts.  We compute the
1548049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  corresponding threshold in font units.
1549049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1550049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ )
1551049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        segment_length_threshold = FT_DivFix( 64, hints->y_scale );
1552049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1553049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        segment_length_threshold = 0;
1554049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1555049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
1556049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1557aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* We begin by generating a sorted table of edges for the current    */
1558aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* direction.  To do so, we simply scan each segment and try to find */
1559aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* an edge in our table that corresponds to its position.            */
1560049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1561049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* If no edge is found, we create and insert a new edge in the       */
1562049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* sorted table.  Otherwise, we simply add the segment to the edge's */
1563aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* list which gets processed in the second step to compute the       */
1564049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* edge's properties.                                                */
1565049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1566aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* Note that the table of edges is sorted along the segment/edge     */
1567049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* position.                                                         */
1568049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1569049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
1570049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1571aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* assure that edge distance threshold is at most 0.25px */
1572049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
1573049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         scale );
1574049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( edge_distance_threshold > 64 / 4 )
1575049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge_distance_threshold = 64 / 4;
1576049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1577049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    edge_distance_threshold = FT_DivFix( edge_distance_threshold,
1578049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         scale );
1579049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1580049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg = segments; seg < segment_limit; seg++ )
1581049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1582aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_Edge  found = NULL;
1583049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int   ee;
1584049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1585049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1586049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg->height < segment_length_threshold )
1587049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1588049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1589049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* A special case for serif edges: If they are smaller than */
1590049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* 1.5 pixels we ignore them.                               */
1591049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg->serif                                     &&
1592049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           2 * seg->height < 3 * segment_length_threshold )
1593049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1594049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1595049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* look for an edge corresponding to the segment */
1596049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ee = 0; ee < axis->num_edges; ee++ )
1597049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1598049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Edge  edge = axis->edges + ee;
1599049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos   dist;
1600049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1601049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1602049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = seg->pos - edge->fpos;
1603049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < 0 )
1604049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = -dist;
1605049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1606049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < edge_distance_threshold && edge->dir == seg->dir )
1607049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1608049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          found = edge;
1609049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
1610049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1611049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1612049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1613049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !found )
1614049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1615049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Edge  edge;
1616049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1617049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1618049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* insert a new edge in the list and */
1619049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* sort according to the position    */
1620049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        error = af_axis_hints_new_edge( axis, seg->pos,
1621049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                        (AF_Direction)seg->dir,
1622049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                        memory, &edge );
1623049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( error )
1624049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          goto Exit;
1625049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1626049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* add the segment to the new edge's list */
1627049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_ZERO( edge );
1628049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1629049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->first    = seg;
1630049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->last     = seg;
1631049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->dir      = seg->dir;
1632aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->fpos     = seg->pos;
1633aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->opos     = FT_MulFix( seg->pos, scale );
1634aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->pos      = edge->opos;
1635049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg->edge_next = seg;
1636049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1637049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1638049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1639049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* if an edge was found, simply add the segment to the edge's */
1640049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* list                                                       */
1641049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg->edge_next         = found->first;
1642049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        found->last->edge_next = seg;
1643049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        found->last            = seg;
1644049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1645049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1646049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1647049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1648727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /******************************************************************/
1649727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*                                                                */
1650727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /* Good, we now compute each edge's properties according to the   */
1651727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /* segments found on its position.  Basically, these are          */
1652727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*                                                                */
1653727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*  - the edge's main direction                                   */
1654727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*  - stem edge, serif edge or both (which defaults to stem then) */
1655727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*  - rounded edge, straight or both (which defaults to straight) */
1656727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*  - link for edge                                               */
1657727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /*                                                                */
1658727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    /******************************************************************/
1659049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1660049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* first of all, set the `edge' field in each segment -- this is */
1661049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* required in order to compute edge links                       */
1662049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1663049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1664049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     * Note that removing this loop and setting the `edge' field of each
1665049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     * segment directly in the code above slows down execution speed for
1666049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     * some reasons on platforms like the Sun.
1667049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1668049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1669049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edges      = axis->edges;
1670049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge_limit = edges + axis->num_edges;
1671049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge;
1672049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1673049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1674049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
1675049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1676049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg = edge->first;
1677049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg )
1678049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          do
1679049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1680049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg->edge = edge;
1681049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg       = seg->edge_next;
1682049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1683049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          } while ( seg != edge->first );
1684049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1685049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1686aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* now compute each edge properties */
1687049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
1688049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1689049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Int  is_round    = 0;  /* does it contain round segments?    */
1690049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Int  is_straight = 0;  /* does it contain straight segments? */
1691aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
1692049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  ups         = 0;  /* number of upwards segments         */
1693049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  downs       = 0;  /* number of downwards segments       */
1694aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
1695049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1696049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1697049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg = edge->first;
1698049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1699049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
1700049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1701049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Bool  is_serif;
1702049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1703049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1704049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for roundness of segment */
1705049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg->flags & AF_EDGE_ROUND )
1706049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            is_round++;
1707049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1708049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            is_straight++;
1709049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1710aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
1711049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for segment direction */
1712049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg->dir == up_dir )
1713bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            ups   += seg->max_coord - seg->min_coord;
1714049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1715bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            downs += seg->max_coord - seg->min_coord;
1716aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
1717049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1718049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for links -- if seg->serif is set, then seg->link must */
1719049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* be ignored                                                   */
1720049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          is_serif = (FT_Bool)( seg->serif               &&
1721049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                seg->serif->edge         &&
1722049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                seg->serif->edge != edge );
1723049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1724049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( ( seg->link && seg->link->edge != NULL ) || is_serif )
1725049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1726049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Edge     edge2;
1727049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  seg2;
1728049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1729049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1730049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            edge2 = edge->link;
1731049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg2  = seg->link;
1732049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1733049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_serif )
1734049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1735049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              seg2  = seg->serif;
1736049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2 = edge->serif;
1737049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1738049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1739049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( edge2 )
1740049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1741049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              FT_Pos  edge_delta;
1742049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              FT_Pos  seg_delta;
1743049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1744049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1745049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge_delta = edge->fpos - edge2->fpos;
1746049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( edge_delta < 0 )
1747049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                edge_delta = -edge_delta;
1748049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1749049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              seg_delta = seg->pos - seg2->pos;
1750049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( seg_delta < 0 )
1751049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg_delta = -seg_delta;
1752049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1753049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( seg_delta < edge_delta )
1754049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                edge2 = seg2->edge;
1755049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1756049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
1757049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2 = seg2->edge;
1758049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1759049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_serif )
1760049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1761049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge->serif   = edge2;
1762049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2->flags |= AF_EDGE_SERIF;
1763049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1764049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
1765049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge->link  = edge2;
1766049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1767049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1768049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
1769049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1770049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
1771049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1772049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* set the round/straight flags */
1773049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags = AF_EDGE_NORMAL;
1774049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1775049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( is_round > 0 && is_round >= is_straight )
1776049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->flags |= AF_EDGE_ROUND;
1777049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1778049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
1779049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* set the edge's main direction */
1780049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->dir = AF_DIR_NONE;
1781049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1782049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( ups > downs )
1783049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->dir = (FT_Char)up_dir;
1784049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1785049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( ups < downs )
1786049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->dir = (FT_Char)-up_dir;
1787049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1788049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( ups == downs )
1789049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->dir = 0;  /* both up and down! */
1790049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1791049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1792aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* get rid of serifs if link is set                 */
1793049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* XXX: This gets rid of many unpleasant artefacts! */
1794049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /*      Example: the `c' in cour.pfa at size 13     */
1795049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1796049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->serif && edge->link )
1797049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->serif = 0;
1798049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1801049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
1802049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1803049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1806aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Detect segments and edges for given dimension. */
1807aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
1809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_detect_features( AF_GlyphHints  hints,
18109c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                  FT_UInt        width_count,
18119c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                  AF_WidthRec*   widths,
1812049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                  AF_Dimension   dim )
1813049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1814049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error  error;
1815049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1816049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1817049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    error = af_latin_hints_compute_segments( hints, dim );
1818049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !error )
1819049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
18209c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_latin_hints_link_segments( hints, width_count, widths, dim );
1821049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1822049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_latin_hints_compute_edges( hints, dim );
1823049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1824aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1825049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1826049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1827049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1828049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1829aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Compute all edges which lie within blue zones. */
1830aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1831049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
1832049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_compute_blue_edges( AF_GlyphHints    hints,
1833049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                     AF_LatinMetrics  metrics )
1834049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1835bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_AxisHints  axis       = &hints->axis[AF_DIMENSION_VERT];
1836049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge       = axis->edges;
1837049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge_limit = edge + axis->num_edges;
1838bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    AF_LatinAxis  latin      = &metrics->axis[AF_DIMENSION_VERT];
1839049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Fixed      scale      = latin->scale;
1840049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1841049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1842049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* compute which blue zones are active, i.e. have their scaled */
1843049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* size < 3/4 pixels                                           */
1844049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1845049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* for each horizontal edge search the blue zone which is closest */
1846049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( ; edge < edge_limit; edge++ )
1847049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1848727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      FT_UInt   bb;
18499c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_Width  best_blue            = NULL;
18509c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_Bool   best_blue_is_neutral = 0;
18519c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_Pos    best_dist;                 /* initial threshold */
1852049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1853049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1854049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* compute the initial threshold as a fraction of the EM size */
1855aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* (the value 40 is heuristic)                                */
1856049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
1857049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1858aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* assure a minimum distance of 0.5px */
1859049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( best_dist > 64 / 2 )
1860049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        best_dist = 64 / 2;
1861049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1862727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      for ( bb = 0; bb < latin->blue_count; bb++ )
1863049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1864049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_LatinBlue  blue = latin->blues + bb;
18659c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_Bool       is_top_blue, is_neutral_blue, is_major_dir;
1866049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1868aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* skip inactive blue zones (i.e., those that are too large) */
1869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
1870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
1871049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
18729c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* if it is a top zone, check for right edges (against the major */
18739c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* direction); if it is a bottom zone, check for left edges (in  */
18749c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* the major direction) -- this assumes the TrueType convention  */
18759c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* for the orientation of contours                               */
18769c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        is_top_blue =
18779c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
18789c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        is_neutral_blue =
18799c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
18809c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        is_major_dir =
18819c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_BOOL( edge->dir == axis->major_dir );
18829c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
18839c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* neutral blue zones are handled for both directions */
18849c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( is_top_blue ^ is_major_dir || is_neutral_blue )
1885049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos  dist;
1887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* first of all, compare it to the reference position */
1890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = edge->fpos - blue->ref.org;
1891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 0 )
1892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = -dist;
1893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = FT_MulFix( dist, scale );
1895049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < best_dist )
1896049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
18979c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            best_dist            = dist;
18989c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            best_blue            = &blue->ref;
18999c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            best_blue_is_neutral = is_neutral_blue;
1900049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1901049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1902aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* now compare it to the overshoot position and check whether */
1903aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* the edge is rounded, and whether the edge is over the      */
1904aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* reference position of a top zone, or under the reference   */
19059c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* position of a bottom zone (provided we don't have a        */
19069c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          /* neutral blue zone)                                         */
19079c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          if ( edge->flags & AF_EDGE_ROUND &&
19089c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod               dist != 0                   &&
19099c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod               !is_neutral_blue            )
1910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Bool  is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
1912049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1913049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1914049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_top_blue ^ is_under_ref )
1915049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1916049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              dist = edge->fpos - blue->shoot.org;
1917049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist < 0 )
1918049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                dist = -dist;
1919049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1920049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              dist = FT_MulFix( dist, scale );
1921049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist < best_dist )
1922049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
19239c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                best_dist            = dist;
19249c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                best_blue            = &blue->shoot;
19259c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                best_blue_is_neutral = is_neutral_blue;
1926049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
1927049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1928049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1929049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1930049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1931049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1932049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( best_blue )
19339c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      {
1934049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->blue_edge = best_blue;
19359c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( best_blue_is_neutral )
19369c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          edge->flags |= AF_EDGE_NEUTRAL;
19379c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      }
1938049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1939049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1940049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1941049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1942aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Initalize hinting engine. */
1943aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1944049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
1945049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_init( AF_GlyphHints    hints,
1946049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_LatinMetrics  metrics )
1947049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1948049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Render_Mode  mode;
1949049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UInt32       scaler_flags, other_flags;
1950049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Face         face = metrics->root.scaler.face;
1951049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1952049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
19539c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics );
1954049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1955049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1956049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  correct x_scale and y_scale if needed, since they may have
1957aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner     *  been modified by `af_latin_metrics_scale_dim' above
1958049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1959049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
1960049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
1961049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
1962049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
1963049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1964049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* compute flags depending on render mode, etc. */
1965049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    mode = metrics->root.scaler.render_mode;
1966049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1967aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
1968049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
1969049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
1970049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1971049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1972049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaler_flags = hints->scaler_flags;
1973049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    other_flags  = 0;
1974049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1975049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1976049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We snap the width of vertical stems for the monochrome and
1977049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  horizontal LCD rendering targets only.
1978049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1979049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
1980049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
1981049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1982049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1983049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We snap the width of horizontal stems for the monochrome and
1984049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  vertical LCD rendering targets only.
1985049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1986049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
1987049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_VERT_SNAP;
1988049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1989049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1990049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We adjust stems to full pixels only if we don't use the `light' mode.
1991049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1992049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode != FT_RENDER_MODE_LIGHT )
1993049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
1994049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1995049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO )
1996049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_MONO;
1997049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1998049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1999049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  In `light' hinting mode we disable horizontal hinting completely.
2000049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We also do it if the face is italic.
2001049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
2002bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    if ( mode == FT_RENDER_MODE_LIGHT                      ||
2003bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly         ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
2004049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
2005049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2006049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->scaler_flags = scaler_flags;
2007049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->other_flags  = other_flags;
2008049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2009727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return FT_Err_Ok;
2010049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2011049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2012049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2013049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2014049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2015049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2016049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****        L A T I N   G L Y P H   G R I D - F I T T I N G        *****/
2017049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2018049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2019049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2020049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2021aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Snap a given width in scaled coordinates to one of the */
2022aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* current standard widths.                               */
2023049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2024049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
2025049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_snap_width( AF_Width  widths,
2026049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       FT_Int    count,
2027049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       FT_Pos    width )
2028049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2029049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    int     n;
2030049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  best      = 64 + 32 + 2;
2031049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  reference = width;
2032049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  scaled;
2033049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2034049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2035049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( n = 0; n < count; n++ )
2036049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2037049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  w;
2038049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  dist;
2039049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2040049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2041049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      w = widths[n].cur;
2042049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = width - w;
2043049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < 0 )
2044049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = -dist;
2045049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < best )
2046049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2047049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        best      = dist;
2048049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        reference = w;
2049049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2050049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2051049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2052049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaled = FT_PIX_ROUND( reference );
2053049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2054049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( width >= reference )
2055049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2056049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( width < scaled + 48 )
2057049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        width = reference;
2058049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2059049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
2060049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2061049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( width > scaled - 48 )
2062049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        width = reference;
2063049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2064049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2065049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return width;
2066049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2067049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2068049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2069aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Compute the snapped width of a given stem, ignoring very thin ones. */
2070aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* There is a lot of voodoo in this function; changing the hard-coded  */
2071aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* parameters influence the whole hinting process.                     */
2072049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2073049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
2074049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_compute_stem_width( AF_GlyphHints  hints,
2075049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               AF_Dimension   dim,
2076049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               FT_Pos         width,
2077049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               AF_Edge_Flags  base_flags,
2078049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                               AF_Edge_Flags  stem_flags )
2079049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2080ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_LatinMetrics  metrics  = (AF_LatinMetrics)hints->metrics;
2081ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_LatinAxis     axis     = &metrics->axis[dim];
2082049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos           dist     = width;
2083049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int           sign     = 0;
2084049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int           vertical = ( dim == AF_DIMENSION_VERT );
2085049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2086049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2087049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
2088bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly         axis->extra_light                       )
2089049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return width;
2090049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2091049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dist < 0 )
2092049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2093049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = -width;
2094049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      sign = 1;
2095049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2096049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2097049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
2098049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
2099049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2100049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* smooth hinting process: very lightly quantize the stem width */
2101049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2102049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* leave the widths of serifs alone */
2103aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( ( stem_flags & AF_EDGE_SERIF ) &&
2104aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner           vertical                       &&
2105aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner           ( dist < 3 * 64 )              )
2106049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Done_Width;
2107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2108aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else if ( base_flags & AF_EDGE_ROUND )
2109049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2110049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < 80 )
2111049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = 64;
2112049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2113049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else if ( dist < 56 )
2114049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = 56;
2115049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2116049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( axis->width_count > 0 )
2117049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2118049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  delta;
2119049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2120049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* compare to standard width */
2122bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        delta = dist - axis->widths[0].cur;
2123049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2124bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        if ( delta < 0 )
2125bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          delta = -delta;
2126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2127bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        if ( delta < 40 )
2128bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        {
2129bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          dist = axis->widths[0].cur;
2130bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          if ( dist < 48 )
2131bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly            dist = 48;
2132049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2133bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          goto Done_Width;
2134bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly        }
2135049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < 3 * 64 )
2137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta  = dist & 63;
2139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist  &= -64;
2140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta < 10 )
2142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist += delta;
2143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else if ( delta < 32 )
2145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist += 10;
2146049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else if ( delta < 54 )
2148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist += 54;
2149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2150049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist += delta;
2152049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = ( dist + 32 ) & ~63;
2155049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2157049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
2158049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2159049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* strong hinting process: snap the stem width to integer pixels */
2160aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  org_dist = dist;
2162049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
2165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( vertical )
2167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* in the case of vertical hinting, always round */
2169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* the stem heights to integer pixels            */
2170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2171049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist >= 64 )
2172049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = ( dist + 16 ) & ~63;
2173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2174049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = 64;
2175049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2176049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
2177049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2178049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( AF_LATIN_HINTS_DO_MONO( hints ) )
2179049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* monochrome horizontal hinting: snap widths to integer pixels */
2181049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* with a different threshold                                   */
2182049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 64 )
2184049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = 64;
2185049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2186049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 32 ) & ~63;
2187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2189049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2190049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* for horizontal anti-aliased hinting, we adopt a more subtle */
2191049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* approach: we strengthen small stems, round stems whose size */
2192049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
2193049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2194049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 48 )
2195049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 64 ) >> 1;
2196049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2197049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else if ( dist < 128 )
2198049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2199049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* We only round to an integer width if the corresponding */
2200049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* distortion is less than 1/4 pixel.  Otherwise this     */
2201049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* makes everything worse since the diagonals, which are  */
2202049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* not hinted, appear a lot bolder or thinner than the    */
2203049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* vertical stems.                                        */
2204049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2205295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner            FT_Pos  delta;
2206049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2207049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2208049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 22 ) & ~63;
2209049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta = dist - org_dist;
2210049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( delta < 0 )
2211049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              delta = -delta;
2212049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2213727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            if ( delta >= 16 )
2214049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2215049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              dist = org_dist;
2216049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist < 48 )
2217049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                dist = ( dist + 64 ) >> 1;
2218049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2219049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2220049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2221049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* round otherwise to prevent color fringes in LCD mode */
2222049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 32 ) & ~63;
2223049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2224049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2225049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2226049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2227049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Done_Width:
2228049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( sign )
2229049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = -dist;
2230049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2231049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return dist;
2232049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2233049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2234049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2235aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Align one stem edge relative to the previous stem edge. */
2236049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2237049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
2238049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_align_linked_edge( AF_GlyphHints  hints,
2239049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Dimension   dim,
2240049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Edge        base_edge,
2241049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Edge        stem_edge )
2242049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2243049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  dist = stem_edge->opos - base_edge->opos;
2244049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2245049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  fitted_width = af_latin_compute_stem_width(
2246049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             hints, dim, dist,
2247049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             (AF_Edge_Flags)base_edge->flags,
2248049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             (AF_Edge_Flags)stem_edge->flags );
2249049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2250049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2251049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    stem_edge->pos = base_edge->pos + fitted_width;
2252049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2253727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_TRACE5(( "  LINK: edge %d (opos=%.2f) linked to %.2f,"
2254bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                " dist was %.2f, now %.2f\n",
22559c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                stem_edge - hints->axis[dim].edges, stem_edge->opos / 64.0,
2256bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
2257049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2258049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2260aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Shift the coordinates of the `serif' edge by the same amount */
2261aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* as the corresponding `base' edge has been moved already.     */
2262aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2263049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
2264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_align_serif_edge( AF_GlyphHints  hints,
2265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             AF_Edge        base,
2266049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             AF_Edge        serif )
2267049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2268049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( hints );
2269049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2270bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    serif->pos = base->pos + ( serif->opos - base->opos );
2271049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2272049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2273049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2274049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2275049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2276049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2277049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                                                                 ****/
2278049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                    E D G E   H I N T I N G                      ****/
2279049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                                                                 ****/
2280049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2281049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2282049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2283049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2284049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2285aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* The main grid-fitting routine. */
2286aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2287049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
2288049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hint_edges( AF_GlyphHints  hints,
2289049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Dimension   dim )
2290049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2291049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis       = &hints->axis[dim];
2292049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edges      = axis->edges;
2293049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge_limit = edges + axis->num_edges;
2294295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    FT_PtrDist    n_edges;
2295049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge;
2296aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_Edge       anchor     = NULL;
2297049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        has_serifs = 0;
2298049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2299727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2300727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_UInt       num_actions = 0;
2301727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2302727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2303049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
23049c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
2305ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
23069c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                af_style_names[hints->metrics->style_class->style] ));
2307aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2308049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* we begin by aligning all stems relative to the blue zone */
2309049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* if needed -- that's only for horizontal edges            */
2310049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2311049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
2312049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2313049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
2314049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2315049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Width  blue;
2316aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Edge   edge1, edge2; /* these edges form the stem to check */
2317049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2318049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2319049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->flags & AF_EDGE_DONE )
2320049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
2321049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2322049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = NULL;
2323049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edge->link;
2324049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
23259c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /*
23269c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  If a stem contains both a neutral and a non-neutral blue zone,
23279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  skip the neutral one.  Otherwise, outlines with different
23289c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  directions might be incorrectly aligned at the same vertical
23299c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  position.
23309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *
23319c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *  If we have two neutral blue zones, skip one of them.
23329c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         *
23339c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod         */
23349c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( edge->blue_edge && edge2 && edge2->blue_edge )
23359c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        {
23369c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_Byte  neutral  = edge->flags  & AF_EDGE_NEUTRAL;
23379c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_Byte  neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
23389c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
23399c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
23409c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          if ( ( neutral && neutral2 ) || neutral2 )
23419c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          {
23429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            edge2->blue_edge = NULL;
23439c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            edge2->flags    &= ~AF_EDGE_NEUTRAL;
23449c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          }
23459c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          else if ( neutral )
23469c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          {
23479c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            edge->blue_edge = NULL;
23489c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            edge->flags    &= ~AF_EDGE_NEUTRAL;
23499c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          }
23509c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        }
23519c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
23529c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        blue = edge->blue_edge;
2353049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( blue )
2354049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge1 = edge;
2355aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
23569c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* flip edges if the other edge is aligned to a blue zone */
2357049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( edge2 && edge2->blue_edge )
2358049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2359049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          blue  = edge2->blue_edge;
2360049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge1 = edge2;
2361049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge2 = edge;
2362049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2363049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2364049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !edge1 )
2365049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
2366049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2367727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2368727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        if ( !anchor )
2369727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f,"
2370727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " was %.2f (anchor=edge %d)\n",
2371727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
2372727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      edge1->pos / 64.0, edge - edges ));
2373727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        else
2374727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  BLUE: edge %d (opos=%.2f) snapped to %.2f,"
2375727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " was %.2f\n",
2376727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
2377727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      edge1->pos / 64.0 ));
2378727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2379727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        num_actions++;
2380727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2381049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2382049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1->pos    = blue->fit;
2383049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1->flags |= AF_EDGE_DONE;
2384049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2385049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge2 && !edge2->blue_edge )
2386049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2387049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          af_latin_align_linked_edge( hints, dim, edge1, edge2 );
2388049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge2->flags |= AF_EDGE_DONE;
2389727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2390727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2391727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          num_actions++;
2392727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2393049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2394049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2395049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !anchor )
2396049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          anchor = edge;
2397049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2398049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2399049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2400aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* now we align all other stem edges, trying to maintain the */
2401bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly    /* relative order of stems in the glyph                      */
2402049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
2403049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2404049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge2;
2405049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2406049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2407049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
2408049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
2409049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2410049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* skip all non-stem edges */
2411049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2 = edge->link;
2412049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !edge2 )
2413049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2414049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        has_serifs++;
2415049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
2416049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2417049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2418049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* now align the stem */
2419049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2420049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* this should not happen, but it's better to be safe */
2421049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge2->blue_edge )
2422049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
24239c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_TRACE5(( "  ASSERTION FAILED for edge %d\n", edge2 - edges ));
2424049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2425049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_latin_align_linked_edge( hints, dim, edge2, edge );
2426049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags |= AF_EDGE_DONE;
2427727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2428727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2429727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        num_actions++;
2430727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2431049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
2432049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2433049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2434049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !anchor )
2435049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2436aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* if we reach this if clause, no stem has been aligned yet */
2437aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2438049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  org_len, org_center, cur_len;
2439049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  cur_pos1, error1, error2, u_off, d_off;
2440049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2441049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2442049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        org_len = edge2->opos - edge->opos;
2443049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        cur_len = af_latin_compute_stem_width(
2444049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                    hints, dim, org_len,
2445049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                    (AF_Edge_Flags)edge->flags,
2446049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                    (AF_Edge_Flags)edge2->flags );
2447aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2448aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* some voodoo to specially round edges for small stem widths; */
2449aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* the idea is to align the center of a stem, then shifting    */
2450aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* the stem edges to suitable positions                        */
2451049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( cur_len <= 64 )
2452aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
2453aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* width <= 1px */
2454aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          u_off = 32;
2455aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          d_off = 32;
2456aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
2457049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2458049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2459aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* 1px < width < 1.5px */
2460049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          u_off = 38;
2461049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          d_off = 26;
2462049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2463049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2464049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( cur_len < 96 )
2465049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2466049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          org_center = edge->opos + ( org_len >> 1 );
2467049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          cur_pos1   = FT_PIX_ROUND( org_center );
2468049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2469049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          error1 = org_center - ( cur_pos1 - u_off );
2470049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( error1 < 0 )
2471049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            error1 = -error1;
2472049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2473049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          error2 = org_center - ( cur_pos1 + d_off );
2474049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( error2 < 0 )
2475049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            error2 = -error2;
2476049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2477049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( error1 < error2 )
2478049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            cur_pos1 -= u_off;
2479049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2480049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            cur_pos1 += d_off;
2481049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2482049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos  = cur_pos1 - cur_len / 2;
2483049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge2->pos = edge->pos + cur_len;
2484049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2485049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2486049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos = FT_PIX_ROUND( edge->opos );
2487049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2488727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        anchor       = edge;
2489727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        edge->flags |= AF_EDGE_DONE;
2490727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2491aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "  ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)"
2492727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                    " snapped to %.2f and %.2f\n",
2493bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                    edge - edges, edge->opos / 64.0,
2494bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                    edge2 - edges, edge2->opos / 64.0,
2495bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                    edge->pos / 64.0, edge2->pos / 64.0 ));
2496049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2497049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_latin_align_linked_edge( hints, dim, edge, edge2 );
2498727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2499727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2500727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        num_actions += 2;
2501727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2502049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2503049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
2504049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2505049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  org_pos, org_len, org_center, cur_len;
2506049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  cur_pos1, cur_pos2, delta1, delta2;
2507049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2508049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2509049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        org_pos    = anchor->pos + ( edge->opos - anchor->opos );
2510049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        org_len    = edge2->opos - edge->opos;
2511049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        org_center = org_pos + ( org_len >> 1 );
2512049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2513049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        cur_len = af_latin_compute_stem_width(
2514bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                    hints, dim, org_len,
2515bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                    (AF_Edge_Flags)edge->flags,
2516bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                    (AF_Edge_Flags)edge2->flags );
2517049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2518049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge2->flags & AF_EDGE_DONE )
2519aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
2520aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_TRACE5(( "  ADJUST: edge %d (pos=%.2f) moved to %.2f\n",
2521aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      edge - edges, edge->pos / 64.0,
2522aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      ( edge2->pos - cur_len ) / 64.0 ));
2523aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2524049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos = edge2->pos - cur_len;
2525aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
2526049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2527049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( cur_len < 96 )
2528049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2529049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos  u_off, d_off;
2530049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2531049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2532049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          cur_pos1 = FT_PIX_ROUND( org_center );
2533049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2534727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          if ( cur_len <= 64 )
2535aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
2536aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            u_off = 32;
2537aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            d_off = 32;
2538aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
2539049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2540049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2541049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            u_off = 38;
2542049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            d_off = 26;
2543049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2544049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2545049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta1 = org_center - ( cur_pos1 - u_off );
2546049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 < 0 )
2547049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta1 = -delta1;
2548049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2549049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta2 = org_center - ( cur_pos1 + d_off );
2550049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta2 < 0 )
2551049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = -delta2;
2552049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2553049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 < delta2 )
2554049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            cur_pos1 -= u_off;
2555049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2556049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            cur_pos1 += d_off;
2557049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2558049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos  = cur_pos1 - cur_len / 2;
2559049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge2->pos = cur_pos1 + cur_len / 2;
2560049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2561727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
2562727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " snapped to %.2f and %.2f\n",
2563bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge - edges, edge->opos / 64.0,
2564bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge2 - edges, edge2->opos / 64.0,
2565bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge->pos / 64.0, edge2->pos / 64.0 ));
2566049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2567727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2568049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2569049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2570049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          org_pos    = anchor->pos + ( edge->opos - anchor->opos );
2571049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          org_len    = edge2->opos - edge->opos;
2572049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          org_center = org_pos + ( org_len >> 1 );
2573049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2574049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          cur_len    = af_latin_compute_stem_width(
2575049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                         hints, dim, org_len,
2576049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                         (AF_Edge_Flags)edge->flags,
2577049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                         (AF_Edge_Flags)edge2->flags );
2578049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2579bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          cur_pos1 = FT_PIX_ROUND( org_pos );
2580bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          delta1   = cur_pos1 + ( cur_len >> 1 ) - org_center;
2581049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 < 0 )
2582049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta1 = -delta1;
2583049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2584bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
2585bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly          delta2   = cur_pos2 + ( cur_len >> 1 ) - org_center;
2586049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta2 < 0 )
2587049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = -delta2;
2588049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2589049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos  = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
2590049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge2->pos = edge->pos + cur_len;
2591049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2592727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)"
2593727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " snapped to %.2f and %.2f\n",
2594bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge - edges, edge->opos / 64.0,
2595bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge2 - edges, edge2->opos / 64.0,
2596bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge->pos / 64.0, edge2->pos / 64.0 ));
2597049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2598049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2599727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2600727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        num_actions++;
2601727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2602727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2603049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags  |= AF_EDGE_DONE;
2604049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2->flags |= AF_EDGE_DONE;
2605049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2606049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge > edges && edge->pos < edge[-1].pos )
2607049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2608727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2609727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  BOUND: edge %d (pos=%.2f) moved to %.2f\n",
2610bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
2611727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2612727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          num_actions++;
2613727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2614727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2615049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos = edge[-1].pos;
2616049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2617049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2618049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2619049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2620049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* make sure that lowercase m's maintain their symmetry */
2621049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2622049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* In general, lowercase m's have six vertical edges if they are sans */
2623049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* serif, or twelve if they are with serifs.  This implementation is  */
2624049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* based on that assumption, and seems to work very well with most    */
2625049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* faces.  However, if for a certain face this assumption is not      */
2626049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* true, the m is just rendered like before.  In addition, any stem   */
2627049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* correction will only be applied to symmetrical glyphs (even if the */
2628049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* glyph is not an m), so the potential for unwanted distortion is    */
2629049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* relatively low.                                                    */
2630049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2631049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* We don't handle horizontal edges since we can't easily assure that */
2632049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* the third (lowest) stem aligns with the base line; it might end up */
2633049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* one pixel higher or lower.                                         */
2634049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2635049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    n_edges = edge_limit - edges;
2636049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
2637049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2638049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge1, edge2, edge3;
2639049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos   dist1, dist2, span, delta;
2640049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2641049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2642049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( n_edges == 6 )
2643049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2644049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = edges;
2645049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edges + 2;
2646049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3 = edges + 4;
2647049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2648049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
2649049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2650049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = edges + 1;
2651049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edges + 5;
2652049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3 = edges + 9;
2653049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2654049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2655049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist1 = edge2->opos - edge1->opos;
2656049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist2 = edge3->opos - edge2->opos;
2657049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2658049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      span = dist1 - dist2;
2659049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( span < 0 )
2660049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        span = -span;
2661049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2662049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( span < 8 )
2663049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2664049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
2665049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3->pos -= delta;
2666049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge3->link )
2667049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge3->link->pos -= delta;
2668049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2669049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* move the serifs along with the stem */
2670049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( n_edges == 12 )
2671049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2672049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          ( edges + 8 )->pos -= delta;
2673049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          ( edges + 11 )->pos -= delta;
2674049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2675049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2676049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3->flags |= AF_EDGE_DONE;
2677049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge3->link )
2678049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge3->link->flags |= AF_EDGE_DONE;
2679049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2680049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2681049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2682049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( has_serifs || !anchor )
2683049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2684049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /*
2685049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project       *  now hint the remaining edges (serifs and single) in order
2686049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project       *  to complete our processing
2687049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project       */
2688049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
2689049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2690049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  delta;
2691049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2692049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2693049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->flags & AF_EDGE_DONE )
2694049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
2695049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2696049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = 1000;
2697049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2698049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->serif )
2699049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2700049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta = edge->serif->opos - edge->opos;
2701049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta < 0 )
2702049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta = -delta;
2703049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2704049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2705049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( delta < 64 + 16 )
2706049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2707049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          af_latin_align_serif_edge( hints, edge->serif, edge );
2708aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_TRACE5(( "  SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)"
2709727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " aligned to %.2f\n",
2710bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge - edges, edge->opos / 64.0,
2711bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge->serif - edges, edge->serif->opos / 64.0,
2712bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                      edge->pos / 64.0 ));
2713049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2714049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( !anchor )
2715049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2716049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos = FT_PIX_ROUND( edge->opos );
2717049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          anchor    = edge;
2718aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_TRACE5(( "  SERIF_ANCHOR: edge %d (opos=%.2f)"
2719727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      " snapped to %.2f\n",
2720aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
2721049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2722049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
2723049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2724049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Edge  before, after;
2725049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2726049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2727049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          for ( before = edge - 1; before >= edges; before-- )
2728049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( before->flags & AF_EDGE_DONE )
2729049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              break;
2730049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2731049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          for ( after = edge + 1; after < edge_limit; after++ )
2732049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( after->flags & AF_EDGE_DONE )
2733049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              break;
2734049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2735049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( before >= edges && before < edge   &&
2736049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               after < edge_limit && after > edge )
2737049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
27380a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project            if ( after->opos == before->opos )
27390a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project              edge->pos = before->pos;
27400a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project            else
27410a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project              edge->pos = before->pos +
2742049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          FT_MulDiv( edge->opos - before->opos,
2743049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                     after->pos - before->pos,
2744049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                     after->opos - before->opos );
2745aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2746727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            FT_TRACE5(( "  SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f"
2747bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                        " from %d (opos=%.2f)\n",
2748bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                        edge - edges, edge->opos / 64.0,
2749aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                        edge->pos / 64.0,
2750aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                        before - edges, before->opos / 64.0 ));
2751049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2752049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
2753049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2754049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            edge->pos = anchor->pos +
2755049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                        ( ( edge->opos - anchor->opos + 16 ) & ~31 );
2756aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_TRACE5(( "  SERIF_LINK2: edge %d (opos=%.2f)"
2757727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                        " snapped to %.2f\n",
2758bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly                        edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
2759049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2760049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2761049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2762727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2763727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        num_actions++;
2764727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2765049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags |= AF_EDGE_DONE;
2766049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2767049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge > edges && edge->pos < edge[-1].pos )
2768727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        {
2769727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2770727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  BOUND: edge %d (pos=%.2f) moved to %.2f\n",
2771727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
2772727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2773727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          num_actions++;
2774727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2775049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos = edge[-1].pos;
2776727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        }
2777049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2778049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge + 1 < edge_limit        &&
2779049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project             edge[1].flags & AF_EDGE_DONE &&
2780049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project             edge->pos > edge[1].pos      )
2781727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        {
2782727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2783727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          FT_TRACE5(( "  BOUND: edge %d (pos=%.2f) moved to %.2f\n",
2784727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                      edge - edges, edge->pos / 64.0, edge[1].pos / 64.0 ));
2785727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2786727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease          num_actions++;
2787727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2788727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
2789049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->pos = edge[1].pos;
2790727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        }
2791049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2792049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2793aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2794727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2795727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    if ( !num_actions )
2796727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      FT_TRACE5(( "  (none)\n" ));
2797aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_TRACE5(( "\n" ));
2798727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease#endif
2799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2801049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2802aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Apply the complete hinting algorithm to a latin glyph. */
2803aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
2805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_latin_hints_apply( AF_GlyphHints    hints,
2806049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                        FT_Outline*      outline,
2807049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                        AF_LatinMetrics  metrics )
2808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error  error;
2810049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    int       dim;
2811049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
28129c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    AF_LatinAxis  axis;
28139c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
2814049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2815aacb8e1368a883fcbc9fe64fd0e460cef9c9b20cNick Kralevich    error = af_glyph_hints_reload( hints, outline );
2816049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( error )
2817049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
2818049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2819049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* analyze glyph outline */
2820aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
2821049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ||
2822bff90fb5ec88ad7fdfb6d1d2f5a5719c20a2c5dcOlivier Bailly         AF_HINTS_DO_HORIZONTAL( hints )                          )
2823049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#else
2824049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( AF_HINTS_DO_HORIZONTAL( hints ) )
2825049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
2826049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
28279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      axis  = &metrics->axis[AF_DIMENSION_HORZ];
28289c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      error = af_latin_hints_detect_features( hints,
28299c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                              axis->width_count,
28309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                              axis->widths,
28319c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                              AF_DIMENSION_HORZ );
2832049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
2833049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
2834049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2835049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2836049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( AF_HINTS_DO_VERTICAL( hints ) )
2837049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
28389c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      axis  = &metrics->axis[AF_DIMENSION_VERT];
28399c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      error = af_latin_hints_detect_features( hints,
28409c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                              axis->width_count,
28419c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                              axis->widths,
28429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                              AF_DIMENSION_VERT );
2843049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
2844049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
2845049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2846049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_latin_hints_compute_blue_edges( hints, metrics );
2847049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2848049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2849049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* grid-fit the outline */
2850049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
2851049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2852aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
2853aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( dim == AF_DIMENSION_HORZ                                 &&
2854aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner           metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT )
2855049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2856049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_WarperRec  warper;
2857049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Fixed      scale;
2858049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos        delta;
2859049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2860049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2861aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        af_warper_compute( &warper, hints, (AF_Dimension)dim,
2862aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           &scale, &delta );
2863aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
2864aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                  scale, delta );
2865049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
2866049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
2868049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
2870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) )   )
2871049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2872049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_latin_hint_edges( hints, (AF_Dimension)dim );
2873049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
2874049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
2875049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
2876049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2877049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2878ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2879049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_save( hints, outline );
2880049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2881049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
2882049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
2883049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2884049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2885049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****              L A T I N   S C R I P T   C L A S S              *****/
2890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2895ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  AF_DEFINE_WRITING_SYSTEM_CLASS(
2896ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    af_latin_writing_system_class,
2897ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2898ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_WRITING_SYSTEM_LATIN,
2899ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2900ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    sizeof ( AF_LatinMetricsRec ),
2901ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
29029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,
29039c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,
29049c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_DoneMetricsFunc) NULL,
2905ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
29069c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_InitHintsFunc)   af_latin_hints_init,
29079c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_ApplyHintsFunc)  af_latin_hints_apply
2908295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  )
2909049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/* END */
2912