afcjk.c revision aeb407daf3711a10a27f3bc2223c5eb05158076e
1049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/***************************************************************************/
2049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
3049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  afcjk.c                                                                */
4049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
5049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*    Auto-fitter hinting routines for CJK script (body).                  */
6049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
7aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner/*  Copyright 2006-2011 by                                                 */
8049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
10049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  This file is part of the FreeType project, and may only be used,       */
11049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  modified, and distributed under the terms of the FreeType project      */
12049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  this file you indicate that you have read the license and              */
14049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  understand and accept it fully.                                        */
15049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
16049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/***************************************************************************/
17049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
18049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*
19049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   *  The algorithm is based on akito's autohint patch, available here:
20049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   *
21049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   *  http://www.kde.gr.jp/~akito/patch/freetype2/
22049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   *
23049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project   */
24049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
25aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#include <ft2build.h>
26aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#include FT_ADVANCES_H
27aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#include FT_INTERNAL_DEBUG_H
28aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
29049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aftypes.h"
30049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aflatin.h"
31049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
32049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
33049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#ifdef AF_CONFIG_OPTION_CJK
34049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
35aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
36aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
37049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "afcjk.h"
38049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aferrors.h"
39049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
40049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
41aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
42049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "afwarp.h"
43049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
44049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
45049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
46049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
47aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*                                                                       */
48aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
49aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
50aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* messages during execution.                                            */
51aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*                                                                       */
52aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#undef  FT_COMPONENT
53aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#define FT_COMPONENT  trace_afcjk
54aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
55aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
56aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*************************************************************************/
57049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
58049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
59049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****              C J K   G L O B A L   M E T R I C S              *****/
60049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
61049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
62049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
63049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
64aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
65aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Basically the Latin version with AF_CJKMetrics */
66aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* to replace AF_LatinMetrics.                    */
67aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
68aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  FT_LOCAL_DEF( void )
69aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_init_widths( AF_CJKMetrics  metrics,
70aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                              FT_Face        face,
71aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                              FT_ULong       charcode )
72aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
73aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* scan the array of segments in each direction */
74aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_GlyphHintsRec  hints[1];
75aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
76aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
77aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    af_glyph_hints_init( hints, face->memory );
78aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
79aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
80aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    metrics->axis[AF_DIMENSION_VERT].width_count = 0;
81aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
82aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
83aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Error          error;
84aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_UInt           glyph_index;
85aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      int               dim;
86aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_CJKMetricsRec  dummy[1];
87aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_Scaler         scaler = &dummy->root.scaler;
88aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
89aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
90aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      glyph_index = FT_Get_Char_Index( face, charcode );
91aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( glyph_index == 0 )
92aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        goto Exit;
93aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
94aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
95aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( error || face->glyph->outline.n_points <= 0 )
96aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        goto Exit;
97aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
98aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_ZERO( dummy );
99aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
100aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      dummy->units_per_em = metrics->units_per_em;
101aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
102aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->x_scale = 0x10000L;
103aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->y_scale = 0x10000L;
104aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->x_delta = 0;
105aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->y_delta = 0;
106aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
107aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->face        = face;
108aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->render_mode = FT_RENDER_MODE_NORMAL;
109aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->flags       = 0;
110aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
111aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy );
112aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
113aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      error = af_glyph_hints_reload( hints, &face->glyph->outline );
114aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( error )
115aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        goto Exit;
116aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
117aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
118aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
119aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_CJKAxis    axis    = &metrics->axis[dim];
120aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_AxisHints  axhints = &hints->axis[dim];
121aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Segment    seg, limit, link;
122aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_UInt       num_widths = 0;
123aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
124aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
125aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim );
126aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( error )
127aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          goto Exit;
128aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
129aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        af_latin_hints_link_segments( hints, (AF_Dimension)dim );
130aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
131aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        seg   = axhints->segments;
132aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        limit = seg + axhints->num_segments;
133aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
134aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        for ( ; seg < limit; seg++ )
135aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
136aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          link = seg->link;
137aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
138aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* we only consider stem segments there! */
139aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( link && link->link == seg && link > seg )
140aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
141aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_Pos  dist;
142aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
143aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
144aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            dist = seg->pos - link->pos;
145aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            if ( dist < 0 )
146aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              dist = -dist;
147aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
148aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            if ( num_widths < AF_CJK_MAX_WIDTHS )
149aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              axis->widths[num_widths++].org = dist;
150aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
151aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
152aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
153aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        af_sort_widths( num_widths, axis->widths );
154aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->width_count = num_widths;
155aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
156aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
157aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    Exit:
158aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
159aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
160aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_CJKAxis  axis = &metrics->axis[dim];
161aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos      stdw;
162aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
163aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
164aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
165aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                         : AF_LATIN_CONSTANT( metrics, 50 );
166aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
167aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* let's try 20% of the smallest width */
168aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->edge_distance_threshold = stdw / 5;
169aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->standard_width          = stdw;
170aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->extra_light             = 0;
171aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
172aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
173aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
174aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    af_glyph_hints_done( hints );
175aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
176aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
177aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
178aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#define AF_CJK_MAX_TEST_CHARACTERS  32
179aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
180aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
181aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Each blue zone has two types of fill and unfill, this is, */
182aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* filling the entire glyph square or not.                   */
183aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
184aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  enum
185aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
186aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJK_BLUE_TYPE_FILL,
187aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJK_BLUE_TYPE_UNFILL,
188aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJK_BLUE_TYPE_MAX
189aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  };
190aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
191aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
192aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Put some common and representative Han Ideographs characters here. */
193aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  static const FT_ULong af_cjk_hani_blue_chars[AF_CJK_BLUE_MAX]
194aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                              [AF_CJK_BLUE_TYPE_MAX]
195aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                              [AF_CJK_MAX_TEST_CHARACTERS] =
196aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
197aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
198aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
199aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x4ED6, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730,
200aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x5BF9, 0x5C0D, 0x5C31, 0x5E2D, 0x6211, 0x65F6, 0x6642, 0x6703,
201aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x6765, 0x70BA, 0x80FD, 0x8230, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019,
202aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x9F4A /* top fill */
203aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      },
204aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
205aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x519B, 0x540C, 0x5DF2, 0x613F, 0x65E2, 0x661F, 0x662F, 0x666F,
206aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x6C11, 0x7167, 0x73B0, 0x73FE, 0x7406, 0x7528, 0x7F6E, 0x8981,
207aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x8ECD, 0x90A3, 0x914D, 0x91CC, 0x958B, 0x96F7, 0x9732, 0x9762,
208aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x987E /* top unfill */
209aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
210aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    },
211aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
212aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
213aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x4E2A, 0x4E3A, 0x4EBA, 0x4ED6, 0x4EE5, 0x4EEC, 0x4F60, 0x4F86,
214aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x500B, 0x5011, 0x5230, 0x548C, 0x5927, 0x5BF9, 0x5C0D, 0x5C31,
215aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x6211, 0x65F6, 0x6642, 0x6709, 0x6765, 0x70BA, 0x8981, 0x8AAA,
216aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x8BF4 /* bottom fill */
217aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      },
218aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
219aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x4E3B, 0x4E9B, 0x56E0, 0x5B83, 0x60F3, 0x610F, 0x7406, 0x751F,
220aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x7576, 0x770B, 0x7740, 0x7F6E, 0x8005, 0x81EA, 0x8457, 0x88E1,
221aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x8FC7, 0x8FD8, 0x8FDB, 0x9032, 0x904E, 0x9053, 0x9084, 0x91CC,
222aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x9762 /* bottom unfill */
223aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
224aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    },
225aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifndef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
226aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      { {0x0000}, {0x0000} },
227aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      { {0x0000}, {0x0000} }
228aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#else
229aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
230aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
231aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x4E9B, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730,
232aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x5979, 0x5C06, 0x5C07, 0x5C31, 0x5E74, 0x5F97, 0x60C5, 0x6700,
233aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x6837, 0x6A23, 0x7406, 0x80FD, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019,
234aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x901A /* left fill */
235aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      },
236aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
237aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x5373, 0x5417, 0x5427, 0x542C, 0x5462, 0x54C1, 0x54CD, 0x55CE,
238aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x5E08, 0x5E2B, 0x6536, 0x65AD, 0x65B7, 0x660E, 0x773C, 0x9593,
239aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x95F4, 0x9645, 0x9648, 0x9650, 0x9664, 0x9673, 0x968F, 0x969B,
240aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x96A8 /* left unfill */
241aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
242aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    },
243aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
244aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
245aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x4E8B, 0x524D, 0x5B78, 0x5C06, 0x5C07, 0x60C5, 0x60F3, 0x6216,
246aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x653F, 0x65AF, 0x65B0, 0x6837, 0x6A23, 0x6C11, 0x6C92, 0x6CA1,
247aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x7136, 0x7279, 0x73B0, 0x73FE, 0x7403, 0x7B2C, 0x7D93, 0x8C01,
248aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x8D77 /* right fill */
249aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      },
250aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
251aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x4F8B, 0x5225, 0x522B, 0x5236, 0x52A8, 0x52D5, 0x5417, 0x55CE,
252aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x589E, 0x6307, 0x660E, 0x671D, 0x671F, 0x6784, 0x7269, 0x786E,
253aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x79CD, 0x8ABF, 0x8C03, 0x8CBB, 0x8D39, 0x90A3, 0x90FD, 0x9593,
254aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        0x95F4 /* right unfill */
255aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
256aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
257aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif /* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */
258aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  };
259aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
260aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
261aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Calculate blue zones for all the CJK_BLUE_XXX's. */
262aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
263aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  static void
264aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_init_blues( AF_CJKMetrics   metrics,
265aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                             FT_Face         face,
266aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                             const FT_ULong  blue_chars
267aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                               [AF_CJK_BLUE_MAX]
268aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                               [AF_CJK_BLUE_TYPE_MAX]
269aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                               [AF_CJK_MAX_TEST_CHARACTERS] )
270aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
271aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos        fills[AF_CJK_MAX_TEST_CHARACTERS];
272aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos        flats[AF_CJK_MAX_TEST_CHARACTERS];
273aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
274aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Int        num_fills;
275aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Int        num_flats;
276aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
277aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Int        bb;
278aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKBlue    blue;
279aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Error      error;
280aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis    axis;
281aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_GlyphSlot  glyph = face->glyph;
282aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
283aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef FT_DEBUG_LEVEL_TRACE
284aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_String*  cjk_blue_name[AF_CJK_BLUE_MAX] = {
285aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      (FT_String*)"top",
286aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      (FT_String*)"bottom",
287aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      (FT_String*)"left",
288aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      (FT_String*)"right"
289aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    };
290aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_String*  cjk_blue_type_name[AF_CJK_BLUE_TYPE_MAX] = {
291aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      (FT_String*)"filled",
292aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      (FT_String*)"unfilled"
293aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    };
294aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
295aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
296aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
297aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* We compute the blues simply by loading each character from the */
298aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* `blue_chars[blues]' string, then computing its extreme points  */
299aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* (depending blue zone type etc.).                               */
300aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
301aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_TRACE5(( "cjk blue zones computation\n" ));
302aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_TRACE5(( "------------------------------------------------\n" ));
303aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
304aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( bb = 0; bb < AF_CJK_BLUE_MAX; bb++ )
305aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
306aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Int   fill_type;
307aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Pos*  blue_ref;
308aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Pos*  blue_shoot;
309aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
310aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
311aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      num_fills = 0;
312aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      num_flats = 0;
313aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
314aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( fill_type = 0; fill_type < AF_CJK_BLUE_TYPE_MAX; fill_type++ )
315aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
316aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        const FT_ULong*  p     = blue_chars[bb][fill_type];
317aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        const FT_ULong*  limit = p + AF_CJK_MAX_TEST_CHARACTERS;
318aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Bool          fill  = FT_BOOL(
319aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                   fill_type == AF_CJK_BLUE_TYPE_FILL );
320aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
321aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
322aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "cjk blue %s/%s\n", cjk_blue_name[bb],
323aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                        cjk_blue_type_name[fill_type] ));
324aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
325aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
326aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        for ( ; p < limit && *p; p++ )
327aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
328aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_UInt     glyph_index;
329aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Pos      best_pos; /* same as points.y */
330aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Int      best_point;
331aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Vector*  points;
332aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
333aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
334aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_TRACE5(( "  U+%lX...", *p ));
335aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
336aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* load the character in the face -- skip unknown or empty ones */
337aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          glyph_index = FT_Get_Char_Index( face, *p );
338aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( glyph_index == 0 )
339aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
340aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_TRACE5(( "unavailable\n" ));
341aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            continue;
342aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
343aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
344aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
345aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( error || glyph->outline.n_points <= 0 )
346aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
347aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_TRACE5(( "no outline\n" ));
348aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            continue;
349aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
350aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
351aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* now compute min or max point indices and coordinates */
352aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          points     = glyph->outline.points;
353aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          best_point = -1;
354aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          best_pos   = 0;  /* make compiler happy */
355aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
356aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
357aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_Int  nn;
358aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_Int  first = 0;
359aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_Int  last  = -1;
360aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
361aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
362aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            for ( nn = 0;
363aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  nn < glyph->outline.n_contours;
364aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  first = last + 1, nn++ )
365aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            {
366aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              FT_Int  pp;
367aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
368aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
369aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              last = glyph->outline.contours[nn];
370aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
371aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              /* Avoid single-point contours since they are never       */
372aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              /* rasterized.  In some fonts, they correspond to mark    */
373aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              /* attachment points which are way outside of the glyph's */
374aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              /* real outline.                                          */
375aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              if ( last <= first )
376aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                continue;
377aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
378aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              switch ( bb )
379aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              {
380aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              case AF_CJK_BLUE_TOP:
381aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
382aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  if ( best_point < 0 || points[pp].y > best_pos )
383aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
384aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
385aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_pos   = points[pp].y;
386aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
387aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                break;
388aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
389aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              case AF_CJK_BLUE_BOTTOM:
390aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
391aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  if ( best_point < 0 || points[pp].y < best_pos )
392aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
393aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
394aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_pos   = points[pp].y;
395aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
396aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                break;
397aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
398aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              case AF_CJK_BLUE_LEFT:
399aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
400aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  if ( best_point < 0 || points[pp].x < best_pos )
401aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
402aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
403aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_pos   = points[pp].x;
404aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
405aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                break;
406aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
407aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              case AF_CJK_BLUE_RIGHT:
408aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
409aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  if ( best_point < 0 || points[pp].x > best_pos )
410aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
411aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
412aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_pos   = points[pp].x;
413aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
414aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                break;
415aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
416aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              default:
417aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                ;
418aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              }
419aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            }
420aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_TRACE5(( "best_pos=%5ld\n", best_pos ));
421aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
422aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
423aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( fill )
424aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            fills[num_fills++] = best_pos;
425aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          else
426aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            flats[num_flats++] = best_pos;
427aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
428aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
429aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
430aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( num_flats == 0 && num_fills == 0 )
431aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
432aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /*
433aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         *  we couldn't find a single glyph to compute this blue zone,
434aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         *  we will simply ignore it then
435aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         */
436aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "empty\n" ));
437aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
438aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
439aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
440aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* we have computed the contents of the `fill' and `flats' tables, */
441aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* now determine the reference position of the blue --             */
442aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* we simply take the median value after a simple sort             */
443aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_sort_pos( num_flats, flats );
444aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_sort_pos( num_fills, fills );
445aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
446aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( AF_CJK_BLUE_TOP == bb || AF_CJK_BLUE_BOTTOM == bb )
447aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis = &metrics->axis[AF_DIMENSION_VERT];
448aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else
449aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis = &metrics->axis[AF_DIMENSION_HORZ];
450aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
451aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue       = & axis->blues[axis->blue_count];
452aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue_ref   = & blue->ref.org;
453aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue_shoot = & blue->shoot.org;
454aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
455aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      axis->blue_count++;
456aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( num_flats == 0 )
457aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
458aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_ref   = fills[num_fills / 2];
459aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_shoot = fills[num_fills / 2];
460aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
461aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else if ( num_fills == 0 )
462aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
463aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_ref   = flats[num_flats / 2];
464aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_shoot = flats[num_flats / 2];
465aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
466aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else
467aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
468aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_ref   = fills[num_fills / 2];
469aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_shoot = flats[num_flats / 2];
470aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
471aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
472aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* make sure blue_ref >= blue_shoot for top/right or */
473aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* vice versa for bottom/left                        */
474aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( *blue_shoot != *blue_ref )
475aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
476aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos   ref       = *blue_ref;
477aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos   shoot     = *blue_shoot;
478aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Bool  under_ref = FT_BOOL( shoot < ref );
479aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
480aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
481aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( (AF_CJK_BLUE_TOP == bb || AF_CJK_BLUE_RIGHT == bb) ^ under_ref )
482aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
483aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
484aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
485aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->flags = 0;
486aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( AF_CJK_BLUE_TOP == bb )
487aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->flags |= AF_CJK_BLUE_IS_TOP;
488aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else if ( AF_CJK_BLUE_RIGHT == bb )
489aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->flags |= AF_CJK_BLUE_IS_RIGHT;
490aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
491aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_TRACE5(( "-- cjk %s bluezone ref = %ld shoot = %ld\n",
492aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  cjk_blue_name[bb], *blue_ref, *blue_shoot ));
493aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
494aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
495aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    return;
496aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
497aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
498aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
499aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Basically the Latin version with type AF_CJKMetrics for metrics. */
500aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  FT_LOCAL_DEF( void )
501aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_check_digits( AF_CJKMetrics  metrics,
502aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                               FT_Face        face )
503aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
504aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_UInt   i;
505aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Bool   started = 0, same_width = 1;
506aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Fixed  advance, old_advance = 0;
507aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
508aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
509aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* check whether all ASCII digits have the same advance width; */
510aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* digit `0' is 0x30 in all supported charmaps                 */
511aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( i = 0x30; i <= 0x39; i++ )
512aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
513aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_UInt  glyph_index;
514aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
515aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
516aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      glyph_index = FT_Get_Char_Index( face, i );
517aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( glyph_index == 0 )
518aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
519aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
520aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( FT_Get_Advance( face, glyph_index,
521aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           FT_LOAD_NO_SCALE         |
522aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           FT_LOAD_NO_HINTING       |
523aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           FT_LOAD_IGNORE_TRANSFORM,
524aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           &advance ) )
525aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
526aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
527aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( started )
528aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
529aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( advance != old_advance )
530aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
531aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          same_width = 0;
532aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          break;
533aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
534aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
535aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else
536aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
537aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        old_advance = advance;
538aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        started     = 1;
539aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
540aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
541aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
542aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    metrics->root.digits_have_same_width = same_width;
543aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
544aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
545aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
546049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
547aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_init( AF_CJKMetrics  metrics,
548aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                       FT_Face        face )
549049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
550049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_CharMap  oldmap = face->charmap;
551049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
552049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
553049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->units_per_em = face->units_per_EM;
554049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
555049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
556049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      face->charmap = NULL;
557295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    else
558295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    {
559aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_metrics_init_widths( metrics, face, 0x7530 );
560aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_metrics_init_blues( metrics, face, af_cjk_hani_blue_chars );
561aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_metrics_check_digits( metrics, face );
562295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    }
563049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
564049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Set_Charmap( face, oldmap );
565049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
566049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return AF_Err_Ok;
567049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
568049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
569049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
570049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
571aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_scale_dim( AF_CJKMetrics  metrics,
572aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                            AF_Scaler      scaler,
573aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                            AF_Dimension   dim )
574049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
575aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Fixed    scale;
576aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos      delta;
577aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis  axis;
578aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_UInt     nn;
579049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
580049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
581049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis = &metrics->axis[dim];
582049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
583049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ )
584049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
585aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scale = scaler->x_scale;
586aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      delta = scaler->x_delta;
587049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
588049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
589049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
590aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scale = scaler->y_scale;
591aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      delta = scaler->y_delta;
592aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
593aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
594aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    if ( axis->org_scale == scale && axis->org_delta == delta )
595aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      return;
596aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
597aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->org_scale = scale;
598aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->org_delta = delta;
599aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
600aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->scale = scale;
601aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->delta = delta;
602aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
603aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* scale the blue zones */
604aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( nn = 0; nn < axis->blue_count; nn++ )
605aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
606aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_CJKBlue  blue = &axis->blues[nn];
607aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Pos      dist;
608aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
609aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
610aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->ref.cur   = FT_MulFix( blue->ref.org, scale ) + delta;
611aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->ref.fit   = blue->ref.cur;
612aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
613aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->shoot.fit = blue->shoot.cur;
614aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->flags    &= ~AF_CJK_BLUE_ACTIVE;
615aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
616aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* a blue zone is only active if it is less than 3/4 pixels tall */
617aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
618aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( dist <= 48 && dist >= -48 )
619aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
620aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos  delta1, delta2;
621aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
622aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
623aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->ref.fit  = FT_PIX_ROUND( blue->ref.cur );
624aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
625aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* shoot is under shoot for cjk */
626aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org;
627aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        delta2 = delta1;
628aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( delta1 < 0 )
629aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = -delta2;
630aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
631aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        delta2 = FT_MulFix( delta2, scale );
632aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
633aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "delta: %d", delta1 ));
634aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( delta2 < 32 )
635aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = 0;
636aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
637aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        else if ( delta2 < 64 )
638aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
639aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
640aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        else
641aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = FT_PIX_ROUND( delta2 );
642aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "/%d\n", delta2 ));
643aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
644aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( delta1 < 0 )
645aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = -delta2;
646aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
647aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->shoot.fit = blue->ref.fit - delta2;
648aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
649aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]: "
650aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                     "ref: cur=%.2f fit=%.2f shoot: cur=%.2f fit=%.2f\n",
651aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                       ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V',
652aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                       nn, blue->ref.org, blue->shoot.org,
653aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                       blue->ref.cur / 64.0, blue->ref.fit / 64.0,
654aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                       blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 ));
655aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
656aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->flags |= AF_CJK_BLUE_ACTIVE;
657aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
658049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
659049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
660049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
661049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
662049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
663aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_scale( AF_CJKMetrics  metrics,
664aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                        AF_Scaler      scaler )
665049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
666049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->root.scaler = *scaler;
667049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
668049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
669049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
670049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
671049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
672049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
673049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
674049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
675049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
676049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****              C J K   G L Y P H   A N A L Y S I S              *****/
677049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
678049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
679049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
680049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
681049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
682049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_compute_segments( AF_GlyphHints  hints,
683049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                 AF_Dimension   dim )
684049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
685049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis          = &hints->axis[dim];
686049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
687049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
688049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error      error;
689049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg;
690049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
691049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
692049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    error = af_latin_hints_compute_segments( hints, dim );
693049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( error )
694049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return error;
695049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
696049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* a segment is round if it doesn't have successive */
697049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* on-curve points.                                 */
698049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg = segments; seg < segment_limit; seg++ )
699049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
700049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  pt   = seg->first;
701049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  last = seg->last;
702049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Flags  f0   = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
703049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Flags  f1;
704049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
705049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
706049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      seg->flags &= ~AF_EDGE_ROUND;
707049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
708049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ; pt != last; f0 = f1 )
709049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
710049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        pt = pt->next;
711049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
712049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
713049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !f0 && !f1 )
714049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
715049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
716049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( pt == last )
717049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg->flags |= AF_EDGE_ROUND;
718049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
719049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
720049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
721049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return AF_Err_Ok;
722049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
723049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
724049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
725049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
726049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_link_segments( AF_GlyphHints  hints,
727049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Dimension   dim )
728049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
729049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis          = &hints->axis[dim];
730049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
731049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
732049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Direction  major_dir     = axis->major_dir;
733049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg1, seg2;
734049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        len_threshold;
735049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        dist_threshold;
736049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
737049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
738049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
739049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
740049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
741049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                                  : hints->y_scale;
742049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    dist_threshold = FT_DivFix( 64 * 3, dist_threshold );
743049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
744049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* now compare each segment to the others */
745049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg1 = segments; seg1 < segment_limit; seg1++ )
746049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
747049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* the fake segments are for metrics hinting only */
748049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg1->first == seg1->last )
749049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
750049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
751049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg1->dir != major_dir )
752049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
753049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
754049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( seg2 = segments; seg2 < segment_limit; seg2++ )
755049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 )
756049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
757049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos  dist = seg2->pos - seg1->pos;
758049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
759049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
760049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 0 )
761049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
762049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
763049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
764049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  min = seg1->min_coord;
765049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  max = seg1->max_coord;
766049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  len;
767049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
768049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
769049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( min < seg2->min_coord )
770049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              min = seg2->min_coord;
771049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
772049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( max > seg2->max_coord )
773049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              max = seg2->max_coord;
774049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
775049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            len = max - min;
776049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( len >= len_threshold )
777049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
778049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist * 8 < seg1->score * 9                        &&
779049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                   ( dist * 8 < seg1->score * 7 || seg1->len < len ) )
780049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
781049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg1->score = dist;
782049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg1->len   = len;
783049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg1->link  = seg2;
784049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
785049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
786049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist * 8 < seg2->score * 9                        &&
787049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                   ( dist * 8 < seg2->score * 7 || seg2->len < len ) )
788049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
789049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg2->score = dist;
790049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg2->len   = len;
791049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg2->link  = seg1;
792049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
793049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
794049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
795049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
796049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
797049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
798049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  now compute the `serif' segments
800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *
801049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  In Hanzi, some strokes are wider on one or both of the ends.
802049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We either identify the stems on the ends as serifs or remove
803049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  the linkage, depending on the length of the stems.
804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *
805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
806049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
807049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Segment  link1, link2;
809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
810049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
811049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( seg1 = segments; seg1 < segment_limit; seg1++ )
812049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
813049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        link1 = seg1->link;
814049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos )
815049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
816049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
817049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg1->score >= dist_threshold )
818049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
819049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
820049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        for ( seg2 = segments; seg2 < segment_limit; seg2++ )
821049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
822049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg2->pos > seg1->pos || seg1 == seg2 )
823049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
824049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
825049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          link2 = seg2->link;
826049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( !link2 || link2->link != seg2 || link2->pos < link1->pos )
827049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
828049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
829049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg1->pos == seg2->pos && link1->pos == link2->pos )
830049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
831049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
832049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score )
833049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
834049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
835049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* seg2 < seg1 < link1 < link2 */
836049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
837049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg1->len >= seg2->len * 3 )
838049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
839049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  seg;
840049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
841049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
842049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            for ( seg = segments; seg < segment_limit; seg++ )
843049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
844049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              AF_Segment  link = seg->link;
845049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
846049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
847049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( link == seg2 )
848049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
849049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg->link  = 0;
850049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg->serif = link1;
851049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
852049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              else if ( link == link2 )
853049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
854049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg->link  = 0;
855049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg->serif = seg1;
856049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
857049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
858049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
859049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
860049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
861049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg1->link = link1->link = 0;
862049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
863049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            break;
864049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
865049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
866049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
868049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg1 = segments; seg1 < segment_limit; seg1++ )
870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
871049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      seg2 = seg1->link;
872049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
873049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg2 )
874049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
875049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg2->num_linked++;
876049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg2->link != seg1 )
877049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
878049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg1->link = 0;
879049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
880049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 )
881049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg1->serif = seg2->link;
882049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
883049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg2->num_linked--;
884049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
885049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_compute_edges( AF_GlyphHints  hints,
892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Dimension   dim )
893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis   = &hints->axis[dim];
895049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error      error  = AF_Err_Ok;
896049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Memory     memory = hints->memory;
897aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis    laxis  = &((AF_CJKMetrics)hints->metrics)->axis[dim];
898049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
899049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
900049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
901049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg;
902049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
903049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Fixed      scale;
904049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        edge_distance_threshold;
905049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
906049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
907049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->num_edges = 0;
908049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
909049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         : hints->y_scale;
911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
912049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
913049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
914049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* We begin by generating a sorted table of edges for the current    */
915049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* direction.  To do so, we simply scan each segment and try to find */
916049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* an edge in our table that corresponds to its position.            */
917049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
918049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* If no edge is found, we create and insert a new edge in the       */
919049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* sorted table.  Otherwise, we simply add the segment to the edge's */
920049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* list which is then processed in the second step to compute the    */
921049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* edge's properties.                                                */
922049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
923049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* Note that the edges table is sorted along the segment/edge        */
924049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* position.                                                         */
925049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
926049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
927049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
928049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
929049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         scale );
930049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( edge_distance_threshold > 64 / 4 )
931049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge_distance_threshold = FT_DivFix( 64 / 4, scale );
932049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
933049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge_distance_threshold = laxis->edge_distance_threshold;
934049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
935049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg = segments; seg < segment_limit; seg++ )
936049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
937049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  found = 0;
938049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos   best  = 0xFFFFU;
939049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int   ee;
940049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
941049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
942049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* look for an edge corresponding to the segment */
943049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ee = 0; ee < axis->num_edges; ee++ )
944049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
945049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Edge  edge = axis->edges + ee;
946049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos   dist;
947049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
948049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
949049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->dir != seg->dir )
950049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
951049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
952049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = seg->pos - edge->fpos;
953049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < 0 )
954049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = -dist;
955049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
956049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < edge_distance_threshold && dist < best )
957049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
958049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Segment  link = seg->link;
959049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
960049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
961049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check whether all linked segments of the candidate edge */
962049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* can make a single edge.                                 */
963049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( link )
964049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
965049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  seg1 = edge->first;
966049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  link1;
967049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos      dist2 = 0;
968049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
969049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
970049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            do
971049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
972049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              link1 = seg1->link;
973049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( link1 )
974049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
975049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                dist2 = AF_SEGMENT_DIST( link, link1 );
976049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                if ( dist2 >= edge_distance_threshold )
977049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                  break;
978049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
979049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
980049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            } while ( ( seg1 = seg1->edge_next ) != edge->first );
981049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
982049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dist2 >= edge_distance_threshold )
983049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              continue;
984049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
985049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
986049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          best  = dist;
987049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          found = edge;
988049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
989049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
990049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
991049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !found )
992049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
993049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Edge  edge;
994049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
995049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
996049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* insert a new edge in the list and */
997049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* sort according to the position    */
998049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        error = af_axis_hints_new_edge( axis, seg->pos,
999049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                        (AF_Direction)seg->dir,
1000049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                        memory, &edge );
1001049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( error )
1002049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          goto Exit;
1003049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1004049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* add the segment to the new edge's list */
1005049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_ZERO( edge );
1006049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1007049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->first    = seg;
1008049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->last     = seg;
1009049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->fpos     = seg->pos;
1010049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->opos     = edge->pos = FT_MulFix( seg->pos, scale );
1011049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg->edge_next = seg;
1012049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->dir      = seg->dir;
1013049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1014049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1015049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1016049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* if an edge was found, simply add the segment to the edge's */
1017049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* list                                                       */
1018049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg->edge_next         = found->first;
1019049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        found->last->edge_next = seg;
1020049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        found->last            = seg;
1021049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1022049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1023049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1024049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
1025049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1026049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* Good, we now compute each edge's properties according to segments */
1027049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* found on its position.  Basically, these are as follows.          */
1028049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1029049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*  - edge's main direction                                          */
1030049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*  - stem edge, serif edge or both (which defaults to stem then)    */
1031049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*  - rounded edge, straight or both (which defaults to straight)    */
1032049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*  - link for edge                                                  */
1033049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1034049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
1035049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1036049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* first of all, set the `edge' field in each segment -- this is     */
1037049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* required in order to compute edge links                           */
1038049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
1039049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* Note that removing this loop and setting the `edge' field of each */
1040049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* segment directly in the code above slows down execution speed for */
1041049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* some reasons on platforms like the Sun.                           */
1042049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1043049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1044049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edges      = axis->edges;
1045049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge_limit = edges + axis->num_edges;
1046049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge;
1047049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1048049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1049049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
1050049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1051049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg = edge->first;
1052049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg )
1053049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          do
1054049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1055049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg->edge = edge;
1056049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg       = seg->edge_next;
1057049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1058049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          } while ( seg != edge->first );
1059049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1060049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1061049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* now compute each edge properties */
1062049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
1063049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1064049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Int  is_round    = 0;  /* does it contain round segments?    */
1065049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Int  is_straight = 0;  /* does it contain straight segments? */
1066049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1067049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1068049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg = edge->first;
1069049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1070049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
1071049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1072049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Bool  is_serif;
1073049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1074049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1075049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for roundness of segment */
1076049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg->flags & AF_EDGE_ROUND )
1077049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            is_round++;
1078049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1079049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            is_straight++;
1080049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1081049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for links -- if seg->serif is set, then seg->link must */
1082049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* be ignored                                                   */
1083049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
1084049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1085049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg->link || is_serif )
1086049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1087049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Edge     edge2;
1088049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  seg2;
1089049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1090049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1091049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            edge2 = edge->link;
1092049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg2  = seg->link;
1093049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1094049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_serif )
1095049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1096049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              seg2  = seg->serif;
1097049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2 = edge->serif;
1098049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1099049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1100049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( edge2 )
1101049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1102049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              FT_Pos  edge_delta;
1103049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              FT_Pos  seg_delta;
1104049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1105049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1106049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge_delta = edge->fpos - edge2->fpos;
1107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( edge_delta < 0 )
1108049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                edge_delta = -edge_delta;
1109049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1110049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              seg_delta = AF_SEGMENT_DIST( seg, seg2 );
1111049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1112049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( seg_delta < edge_delta )
1113049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                edge2 = seg2->edge;
1114049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1115049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
1116049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2 = seg2->edge;
1117049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1118049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_serif )
1119049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1120049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge->serif   = edge2;
1121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2->flags |= AF_EDGE_SERIF;
1122049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1123049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
1124049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge->link  = edge2;
1125049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1127049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
1128049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1129049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
1130049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1131049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* set the round/straight flags */
1132049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags = AF_EDGE_NORMAL;
1133049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( is_round > 0 && is_round >= is_straight )
1135049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->flags |= AF_EDGE_ROUND;
1136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* get rid of serifs if link is set                 */
1138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* XXX: This gets rid of many unpleasant artefacts! */
1139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /*      Example: the `c' in cour.pfa at size 13     */
1140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->serif && edge->link )
1142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->serif = 0;
1143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1146049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
1147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1150049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
1152049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_detect_features( AF_GlyphHints  hints,
1153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                AF_Dimension   dim )
1154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1155049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error  error;
1156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1157049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1158049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    error = af_cjk_hints_compute_segments( hints, dim );
1159049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !error )
1160049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_cjk_hints_link_segments( hints, dim );
1162049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_cjk_hints_compute_edges( hints, dim );
1164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1169aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  FT_LOCAL_DEF( void )
1170aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_hints_compute_blue_edges( AF_GlyphHints  hints,
1171aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                   AF_CJKMetrics  metrics,
1172aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                   AF_Dimension   dim )
1173aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
1174aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_AxisHints  axis       = &hints->axis[dim];
1175aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_Edge       edge       = axis->edges;
1176aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_Edge       edge_limit = edge + axis->num_edges;
1177aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis    cjk        = &metrics->axis[dim];
1178aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Fixed      scale      = cjk->scale;
1179aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos        best_dist0;  /* initial threshold */
1180aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1181aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1182aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* compute the initial threshold as a fraction of the EM size */
1183aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale );
1184aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1185aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    if ( best_dist0 > 64 / 2 ) /* maximum 1/2 pixel */
1186aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      best_dist0 = 64 / 2;
1187aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1188aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* compute which blue zones are active, i.e. have their scaled */
1189aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* size < 3/4 pixels                                           */
1190aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1191aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* If the distant between an edge and a blue zone is shorter than */
1192aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* best_dist0, set the blue zone for the edge.  Then search for   */
1193aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* the blue zone with the smallest best_dist to the edge.         */
1194aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1195aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( ; edge < edge_limit; edge++ )
1196aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
1197aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_UInt   bb;
1198aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_Width  best_blue = NULL;
1199aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Pos    best_dist = best_dist0;
1200aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1201aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1202aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( bb = 0; bb < cjk->blue_count; bb++ )
1203aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1204aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_CJKBlue  blue = cjk->blues + bb;
1205aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Bool     is_top_right_blue, is_major_dir;
1206aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1207aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1208aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* skip inactive blue zones (i.e., those that are too small) */
1209aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) )
1210aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          continue;
1211aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1212aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* if it is a top zone, check for right edges -- if it is a bottom */
1213aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* zone, check for left edges                                      */
1214aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /*                                                                 */
1215aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* of course, that's for TrueType                                  */
1216aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        is_top_right_blue  =
1217aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_BOOL( ( ( blue->flags & AF_CJK_BLUE_IS_TOP )   != 0 ) ||
1218aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                   ( ( blue->flags & AF_CJK_BLUE_IS_RIGHT ) != 0 ) );
1219aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
1220aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1221aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* if it is a top zone, the edge must be against the major    */
1222aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* direction; if it is a bottom zone, it must be in the major */
1223aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* direction                                                  */
1224aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( is_top_right_blue ^ is_major_dir )
1225aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1226aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Pos    dist;
1227aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          AF_Width  compare;
1228aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1229aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1230aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* Compare the edge to the closest blue zone type */
1231aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( FT_ABS( edge->fpos - blue->ref.org ) >
1232aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner               FT_ABS( edge->fpos - blue->shoot.org ) )
1233aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            compare = &blue->shoot;
1234aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          else
1235aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            compare = &blue->ref;
1236aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1237aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          dist = edge->fpos - compare->org;
1238aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( dist < 0 )
1239aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            dist = -dist;
1240aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1241aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          dist = FT_MulFix( dist, scale );
1242aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( dist < best_dist )
1243aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
1244aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            best_dist = dist;
1245aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            best_blue = compare;
1246aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
1247aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1248aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1249aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1250aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( best_blue )
1251aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->blue_edge = best_blue;
1252aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
1253aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
1254aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1255aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1256049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
1257aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_hints_init( AF_GlyphHints  hints,
1258aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                     AF_CJKMetrics  metrics )
1259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1260049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Render_Mode  mode;
1261049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UInt32       scaler_flags, other_flags;
1262049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1263049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
1265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1266049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1267049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  correct x_scale and y_scale when needed, since they may have
1268049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  been modified af_cjk_scale_dim above
1269049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1270049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
1271049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
1272049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
1273049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
1274049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1275049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* compute flags depending on render mode, etc. */
1276049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    mode = metrics->root.scaler.render_mode;
1277049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1278aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
1279049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
1280049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
1281049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1282049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1283049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaler_flags = hints->scaler_flags;
1284049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    other_flags  = 0;
1285049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1286049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1287049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We snap the width of vertical stems for the monochrome and
1288049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  horizontal LCD rendering targets only.
1289049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1290049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
1291049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
1292049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1293049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1294049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We snap the width of horizontal stems for the monochrome and
1295049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  vertical LCD rendering targets only.
1296049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1297049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
1298049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_VERT_SNAP;
1299049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1300049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1301049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We adjust stems to full pixels only if we don't use the `light' mode.
1302049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1303049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode != FT_RENDER_MODE_LIGHT )
1304049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
1305049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1306049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO )
1307049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_MONO;
1308049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1309049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE;
1310049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1311049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->scaler_flags = scaler_flags;
1312049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->other_flags  = other_flags;
1313049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1314049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return 0;
1315049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1316049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1317049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1318049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1319049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1320049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
1321049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****          C J K   G L Y P H   G R I D - F I T T I N G          *****/
1322049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
1323049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1324049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1325049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1326049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /* snap a given width in scaled coordinates to one of the */
1327049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /* current standard widths                                */
1328049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1329049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
1330049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_snap_width( AF_Width  widths,
1331049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     FT_Int    count,
1332049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     FT_Pos    width )
1333049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1334049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    int     n;
1335049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  best      = 64 + 32 + 2;
1336049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  reference = width;
1337049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  scaled;
1338049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1339049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1340049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( n = 0; n < count; n++ )
1341049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1342049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  w;
1343049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  dist;
1344049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1345049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1346049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      w = widths[n].cur;
1347049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = width - w;
1348049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < 0 )
1349049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = -dist;
1350049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < best )
1351049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1352049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        best      = dist;
1353049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        reference = w;
1354049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1355049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1356049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1357049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaled = FT_PIX_ROUND( reference );
1358049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1359049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( width >= reference )
1360049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1361049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( width < scaled + 48 )
1362049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        width = reference;
1363049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1364049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1365049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1366049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( width > scaled - 48 )
1367049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        width = reference;
1368049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1369049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1370049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return width;
1371049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1372049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1373049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1374049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /* compute the snapped width of a given stem */
1375049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1376049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
1377049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_compute_stem_width( AF_GlyphHints  hints,
1378049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             AF_Dimension   dim,
1379049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             FT_Pos         width,
1380049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             AF_Edge_Flags  base_flags,
1381049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             AF_Edge_Flags  stem_flags )
1382049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1383aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKMetrics  metrics  = (AF_CJKMetrics) hints->metrics;
1384aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis     axis     = & metrics->axis[dim];
1385aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos         dist     = width;
1386aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Int         sign     = 0;
1387aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Bool        vertical = FT_BOOL( dim == AF_DIMENSION_VERT );
1388049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1389049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( base_flags );
1390049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( stem_flags );
1391049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1392049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1393049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1394049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return width;
1395049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1396049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dist < 0 )
1397049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1398049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = -width;
1399049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      sign = 1;
1400049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1401049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1402049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
1403049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
1404049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1405049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* smooth hinting process: very lightly quantize the stem width */
1406049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1407049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( axis->width_count > 0 )
1408049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1409049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( FT_ABS( dist - axis->widths[0].cur ) < 40 )
1410049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1411049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = axis->widths[0].cur;
1412049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 48 )
1413049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = 48;
1414049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1415049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          goto Done_Width;
1416049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1417049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1418049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1419049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < 54 )
1420049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist += ( 54 - dist ) / 2 ;
1421049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else if ( dist < 3 * 64 )
1422049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1423049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  delta;
1424049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1425049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1426049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta  = dist & 63;
1427049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist  &= -64;
1428049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1429049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( delta < 10 )
1430049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += delta;
1431049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( delta < 22 )
1432049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += 10;
1433049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( delta < 42 )
1434049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += delta;
1435049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( delta < 54 )
1436049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += 54;
1437049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1438049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += delta;
1439049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1440049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1441049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1442049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1443049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* strong hinting process: snap the stem width to integer pixels */
1444049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1445049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
1446049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1447049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( vertical )
1448049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1449049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* in the case of vertical hinting, always round */
1450049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* the stem heights to integer pixels            */
1451049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1452049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist >= 64 )
1453049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = ( dist + 16 ) & ~63;
1454049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1455049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = 64;
1456049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1457049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1458049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1459049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( AF_LATIN_HINTS_DO_MONO( hints ) )
1460049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1461049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* monochrome horizontal hinting: snap widths to integer pixels */
1462049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* with a different threshold                                   */
1463049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1464049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 64 )
1465049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = 64;
1466049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1467049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 32 ) & ~63;
1468049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1469049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1470049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1471049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* for horizontal anti-aliased hinting, we adopt a more subtle */
1472049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* approach: we strengthen small stems, round stems whose size */
1473049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
1474049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1475049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 48 )
1476049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 64 ) >> 1;
1477049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1478049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else if ( dist < 128 )
1479049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 22 ) & ~63;
1480049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1481049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* round otherwise to prevent color fringes in LCD mode */
1482049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 32 ) & ~63;
1483049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1484049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1485049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1486049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1487049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Done_Width:
1488049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( sign )
1489049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = -dist;
1490049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1491049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return dist;
1492049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1493049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1494049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1495049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /* align one stem edge relative to the previous stem edge */
1496049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1497049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
1498049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_align_linked_edge( AF_GlyphHints  hints,
1499049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Dimension   dim,
1500049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Edge        base_edge,
1501049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Edge        stem_edge )
1502049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1503049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  dist = stem_edge->opos - base_edge->opos;
1504049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1505049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  fitted_width = af_cjk_compute_stem_width(
1506049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             hints, dim, dist,
1507049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             (AF_Edge_Flags)base_edge->flags,
1508049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             (AF_Edge_Flags)stem_edge->flags );
1509049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1510049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1511049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    stem_edge->pos = base_edge->pos + fitted_width;
1512049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1513049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1514049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1515049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
1516049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_align_serif_edge( AF_GlyphHints  hints,
1517049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                           AF_Edge        base,
1518049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                           AF_Edge        serif )
1519049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1520049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( hints );
1521049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1522049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    serif->pos = base->pos + ( serif->opos - base->opos );
1523049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1524049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1525049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1526049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1527049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1528049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1529049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                                                                 ****/
1530049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                    E D G E   H I N T I N G                      ****/
1531049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                                                                 ****/
1532049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1533049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1534049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1535049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1536049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1537049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#define AF_LIGHT_MODE_MAX_HORZ_GAP    9
1538049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#define AF_LIGHT_MODE_MAX_VERT_GAP   15
1539049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#define AF_LIGHT_MODE_MAX_DELTA_ABS  14
1540049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1541049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1542049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
1543049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_hint_normal_stem( AF_GlyphHints  hints,
1544049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Edge        edge,
1545049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Edge        edge2,
1546049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       FT_Pos         anchor,
1547049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Dimension   dim )
1548049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1549049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  org_len, cur_len, org_center;
1550049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  cur_pos1, cur_pos2;
1551049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  d_off1, u_off1, d_off2, u_off2, delta;
1552049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  offset;
1553049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  threshold = 64;
1554049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1555049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1556049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1557049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1558049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( ( edge->flags  & AF_EDGE_ROUND ) &&
1559049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           ( edge2->flags & AF_EDGE_ROUND ) )
1560049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1561049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dim == AF_DIMENSION_VERT )
1562049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
1563049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1564049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
1565049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1566049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1567049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1568049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dim == AF_DIMENSION_VERT )
1569049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
1570049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1571049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
1572049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1573049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1574049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1575049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    org_len    = edge2->opos - edge->opos;
1576049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_len    = af_cjk_compute_stem_width( hints, dim, org_len,
1577049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                            (AF_Edge_Flags)edge->flags,
1578049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                            (AF_Edge_Flags)edge2->flags );
1579049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1580049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
1581049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_pos1   = org_center - cur_len / 2;
1582049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_pos2   = cur_pos1 + cur_len;
1583049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off1     = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
1584049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off2     = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
1585049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off1     = 64 - d_off1;
1586049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off2     = 64 - d_off2;
1587049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    delta      = 0;
1588049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1589049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1590049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( d_off1 == 0 || d_off2 == 0 )
1591049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
1592049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1593049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( cur_len <= threshold )
1594049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1595049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( d_off2 < cur_len )
1596049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1597049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( u_off1 <= d_off2 )
1598049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta =  u_off1;
1599049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1600049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta = -d_off2;
1601049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1602049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1603049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
1604049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1605049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1606049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( threshold < 64 )
1607049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1608049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( d_off1 >= threshold || u_off1 >= threshold ||
1609049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           d_off2 >= threshold || u_off2 >= threshold )
1610049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
1611049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1612049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1613049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    offset = cur_len % 64;
1614049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1615049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( offset < 32 )
1616049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1617049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( u_off1 <= offset || d_off2 <= offset )
1618049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
1619049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1620049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1621049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      offset = 64 - threshold;
1622049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1623049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off1 = threshold - u_off1;
1624049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off1 = u_off1    - offset;
1625049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off2 = threshold - d_off2;
1626049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off2 = d_off2    - offset;
1627049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1628049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( d_off1 <= u_off1 )
1629049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      u_off1 = -d_off1;
1630049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1631049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( d_off2 <= u_off2 )
1632049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      u_off2 = -d_off2;
1633049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1634049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
1635049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      delta = u_off1;
1636049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1637049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      delta = u_off2;
1638049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1639049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
1640049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1641049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 1
1642049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1643049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1644049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
1645049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
1646049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
1647049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
1648049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1649049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1650049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1651049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_pos1 += delta;
1652049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1653049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( edge->opos < edge2->opos )
1654049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1655049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge->pos  = cur_pos1;
1656049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2->pos = cur_pos1 + cur_len;
1657049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1658049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1659049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1660049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge->pos  = cur_pos1 + cur_len;
1661049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2->pos = cur_pos1;
1662049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1663049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1664049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return delta;
1665049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1666049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1667049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1668049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
1669049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hint_edges( AF_GlyphHints  hints,
1670049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     AF_Dimension   dim )
1671049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1672049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis       = &hints->axis[dim];
1673049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edges      = axis->edges;
1674049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge_limit = edges + axis->num_edges;
1675295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    FT_PtrDist    n_edges;
1676049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge;
1677049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       anchor   = 0;
1678049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        delta    = 0;
1679049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        skipped  = 0;
1680aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Bool       has_last_stem = FALSE;
1681aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos        last_stem_pos = 0;
1682aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1683049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1684aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* we begin by aligning all stems relative to the blue zone */
1685aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_TRACE5(( "==== cjk hinting %s edges =====\n",
1686aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ));
1687aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1688aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    if ( AF_HINTS_DO_BLUES( hints ) )
1689aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
1690aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( edge = edges; edge < edge_limit; edge++ )
1691aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1692aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Width  blue;
1693aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Edge   edge1, edge2;
1694aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1695aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1696aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( edge->flags & AF_EDGE_DONE )
1697aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          continue;
1698aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1699aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue  = edge->blue_edge;
1700aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge1 = NULL;
1701aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge2 = edge->link;
1702aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1703aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( blue )
1704aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1705aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge1 = edge;
1706aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1707aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        else if ( edge2 && edge2->blue_edge )
1708aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1709aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          blue  = edge2->blue_edge;
1710aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge1 = edge2;
1711aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge2 = edge;
1712aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1713aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1714aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( !edge1 )
1715aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          continue;
1716aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1717aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "CJKBLUE: edge %d @%d (opos=%.2f) snapped to (%.2f), "
1718aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                 "was (%.2f)\n",
1719aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                 edge1-edges, edge1->fpos, edge1->opos / 64.0, blue->fit / 64.0,
1720aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                 edge1->pos / 64.0 ));
1721aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1722aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge1->pos    = blue->fit;
1723aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge1->flags |= AF_EDGE_DONE;
1724aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1725aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( edge2 && !edge2->blue_edge )
1726aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1727aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          af_cjk_align_linked_edge( hints, dim, edge1, edge2 );
1728aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge2->flags |= AF_EDGE_DONE;
1729aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1730aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1731aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( !anchor )
1732aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          anchor = edge;
1733aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1734aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
1735049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1736049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* now we align all stem edges. */
1737049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
1738049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1739049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge2;
1740049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1741049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1742049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
1743049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1744049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1745049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* skip all non-stem edges */
1746049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2 = edge->link;
1747049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !edge2 )
1748049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1749049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        skipped++;
1750049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1751049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1752049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1753aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* Some CJK characters have so many stems that
1754aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * the hinter is likely to merge two adjacent ones.
1755aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * To solve this problem, if either edge of a stem
1756aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * is too close to the previous one, we avoid
1757aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * aligning the two edges, but rather interpolate
1758aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * their locations at the end of this function in
1759aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * order to preserve the space between the stems.
1760aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       */
1761aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( has_last_stem                       &&
1762aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner           ( edge->pos  < last_stem_pos + 64 ||
1763aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner             edge2->pos < last_stem_pos + 64 ) )
1764aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1765aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        skipped++;
1766aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
1767aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1768aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1769049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* now align the stem */
1770aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* this should not happen, but it's better to be safe */
1771aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( edge2->blue_edge )
1772aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1773aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
1774aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1775aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        af_cjk_align_linked_edge( hints, dim, edge2, edge );
1776aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->flags |= AF_EDGE_DONE;
1777aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
1778aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1779049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1780049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge2 < edge )
1781049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1782049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_align_linked_edge( hints, dim, edge2, edge );
1783049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags |= AF_EDGE_DONE;
1784aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* We rarely reaches here it seems;
1785aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         * usually the two edges belonging
1786aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         * to one stem are marked as DONE together
1787aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         */
1788aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        has_last_stem = TRUE;
1789aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        last_stem_pos = edge->pos;
1790049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1791049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1792049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1793049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dim != AF_DIMENSION_VERT && !anchor )
1794049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1795049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1796049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
1797049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( fixedpitch )
1798049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Edge     left  = edge;
1800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Edge     right = edge_limit - 1;
1801049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_EdgeRec  left1, left2, right1, right2;
1802049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos      target, center1, center2;
1803049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos      delta1, delta2, d1, d2;
1804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1806049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          while ( right > left && !right->link )
1807049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            right--;
1808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          left1  = *left;
1810049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          left2  = *left->link;
1811049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right1 = *right->link;
1812049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right2 = *right;
1813049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1814049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta  = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2;
1815049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16;
1816049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1817049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta1  = delta;
1818049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta1 += af_hint_normal_stem( hints, left, left->link,
1819049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         delta1, 0 );
1820049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1821049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( left->link != right )
1822049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            af_hint_normal_stem( hints, right->link, right, delta1, 0 );
1823049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1824049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          center1 = left->pos + ( right->pos - left->pos ) / 2;
1825049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1826049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( center1 >= target )
1827049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = delta - 32;
1828049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1829049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = delta + 32;
1830049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1831049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 );
1832049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1833049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 != delta2 )
1834049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1835049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( left->link != right )
1836049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              af_hint_normal_stem( hints, &right1, &right2, delta2, 0 );
1837049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1838049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            center2 = left1.pos + ( right2.pos - left1.pos ) / 2;
1839049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1840049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            d1 = center1 - target;
1841049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            d2 = center2 - target;
1842049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1843049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( FT_ABS( d2 ) < FT_ABS( d1 ) )
1844049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1845049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              left->pos       = left1.pos;
1846049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              left->link->pos = left2.pos;
1847049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1848049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( left->link != right )
1849049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
1850049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                right->link->pos = right1.pos;
1851049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                right->pos       = right2.pos;
1852049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
1853049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1854049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              delta1 = delta2;
1855049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1856049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1857049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1858049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta               = delta1;
1859049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right->link->flags |= AF_EDGE_DONE;
1860049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right->flags       |= AF_EDGE_DONE;
1861049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1862049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1863049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1864049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif /* 0 */
1865049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1866049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta = af_hint_normal_stem( hints, edge, edge2, 0,
1867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                       AF_DIMENSION_HORZ );
1868049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_hint_normal_stem( hints, edge, edge2, delta, dim );
1871049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1872049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
1873049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n",
1874049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               edge - edges, edge2 - edges,
1875049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               ( edge->pos - edge->opos ) / 64.0,
1876049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               ( edge2->pos - edge2->opos ) / 64.0 );
1877049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1878049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1879049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      anchor = edge;
1880049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge->flags  |= AF_EDGE_DONE;
1881049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2->flags |= AF_EDGE_DONE;
1882aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      has_last_stem = TRUE;
1883aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      last_stem_pos = edge2->pos;
1884049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1885049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* make sure that lowercase m's maintain their symmetry */
1887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* In general, lowercase m's have six vertical edges if they are sans */
1889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* serif, or twelve if they are with serifs.  This implementation is  */
1890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* based on that assumption, and seems to work very well with most    */
1891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* faces.  However, if for a certain face this assumption is not      */
1892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* true, the m is just rendered like before.  In addition, any stem   */
1893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* correction will only be applied to symmetrical glyphs (even if the */
1894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* glyph is not an m), so the potential for unwanted distortion is    */
1895049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* relatively low.                                                    */
1896049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1897049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* We don't handle horizontal edges since we can't easily assure that */
1898049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* the third (lowest) stem aligns with the base line; it might end up */
1899049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* one pixel higher or lower.                                         */
1900049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1901049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    n_edges = edge_limit - edges;
1902049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
1903049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1904049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge1, edge2, edge3;
1905049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos   dist1, dist2, span;
1906049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1907049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1908049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( n_edges == 6 )
1909049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = edges;
1911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edges + 2;
1912049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3 = edges + 4;
1913049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1914049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1915049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1916049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = edges + 1;
1917049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edges + 5;
1918049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3 = edges + 9;
1919049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1920049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1921049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist1 = edge2->opos - edge1->opos;
1922049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist2 = edge3->opos - edge2->opos;
1923049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1924049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      span = dist1 - dist2;
1925049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( span < 0 )
1926049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        span = -span;
1927049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1928049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge1->link == edge1 + 1 &&
1929049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           edge2->link == edge2 + 1 &&
1930049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           edge3->link == edge3 + 1 && span < 8 )
1931049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1932049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
1933049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3->pos -= delta;
1934049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge3->link )
1935049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge3->link->pos -= delta;
1936049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1937049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* move the serifs along with the stem */
1938049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( n_edges == 12 )
1939049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1940049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          ( edges + 8 )->pos -= delta;
1941049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          ( edges + 11 )->pos -= delta;
1942049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1943049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1944049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3->flags |= AF_EDGE_DONE;
1945049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge3->link )
1946049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge3->link->flags |= AF_EDGE_DONE;
1947049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1948049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1949049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1950049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !skipped )
1951049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return;
1952049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1953049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1954049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  now hint the remaining edges (serifs and single) in order
1955049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  to complete our processing
1956049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1957049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
1958049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1959049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
1960049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1961049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1962049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->serif )
1963049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1964049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_align_serif_edge( hints, edge->serif, edge );
1965049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags |= AF_EDGE_DONE;
1966049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        skipped--;
1967049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1968049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1969049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1970049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !skipped )
1971049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return;
1972049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1973049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
1974049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1975049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  before, after;
1976049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1977049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1978049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
1979049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1980049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1981049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      before = after = edge;
1982049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1983049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      while ( --before >= edges )
1984049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( before->flags & AF_EDGE_DONE )
1985049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
1986049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1987049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      while ( ++after < edge_limit )
1988049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( after->flags & AF_EDGE_DONE )
1989049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
1990049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1991049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( before >= edges || after < edge_limit )
1992049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1993049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( before < edges )
1994049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          af_cjk_align_serif_edge( hints, after, edge );
1995049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( after >= edge_limit )
1996049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          af_cjk_align_serif_edge( hints, before, edge );
1997049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
19980a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project        {
19990a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project          if ( after->fpos == before->fpos )
20000a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project            edge->pos = before->pos;
20010a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project          else
20020a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project            edge->pos = before->pos +
20030a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project                        FT_MulDiv( edge->fpos - before->fpos,
20040a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project                                   after->pos - before->pos,
20050a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project                                   after->fpos - before->fpos );
20060a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project        }
2007049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2008049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2009049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2010049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2011049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2012049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
2013049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_align_edge_points( AF_GlyphHints  hints,
2014049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Dimension   dim )
2015049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2016049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis       = & hints->axis[dim];
2017049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edges      = axis->edges;
2018049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge_limit = edges + axis->num_edges;
2019049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge;
2020049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Bool       snapping;
2021049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2022049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2023049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ             &&
2024049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) )  ||
2025049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                        ( dim == AF_DIMENSION_VERT             &&
2026049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          AF_LATIN_HINTS_DO_VERT_SNAP( hints ) )  );
2027049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2028049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
2029049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2030049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* move the points of each segment     */
2031049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* in each edge to the edge's position */
2032049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Segment  seg = edge->first;
2033049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2034049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2035049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( snapping )
2036049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2037049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
2038049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2039049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Point  point = seg->first;
2040049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2041049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2042049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          for (;;)
2043049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2044049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dim == AF_DIMENSION_HORZ )
2045049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2046049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->x      = edge->pos;
2047049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_X;
2048049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2049049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
2050049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2051049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->y      = edge->pos;
2052049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_Y;
2053049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2054049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2055049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( point == seg->last )
2056049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              break;
2057049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2058049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            point = point->next;
2059049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2060049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2061049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
2062049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2063049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
2064049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2065049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
2066049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2067049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  delta = edge->pos - edge->opos;
2068049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2069049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2070049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
2071049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2072049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Point  point = seg->first;
2073049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2074049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2075049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          for (;;)
2076049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2077049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dim == AF_DIMENSION_HORZ )
2078049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2079049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->x     += delta;
2080049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_X;
2081049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2082049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
2083049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2084049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->y     += delta;
2085049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_Y;
2086049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2087049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2088049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( point == seg->last )
2089049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              break;
2090049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2091049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            point = point->next;
2092049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2093049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2094049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
2095049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2096049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
2097049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2098049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2099049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2100049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2101049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2102049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
2103aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_hints_apply( AF_GlyphHints  hints,
2104aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      FT_Outline*    outline,
2105aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      AF_CJKMetrics  metrics )
2106049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error  error;
2108049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    int       dim;
2109049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2110049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( metrics );
2111049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2112049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2113aacb8e1368a883fcbc9fe64fd0e460cef9c9b20cNick Kralevich    error = af_glyph_hints_reload( hints, outline );
2114049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( error )
2115049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
2116049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2117049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* analyze glyph outline */
2118049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( AF_HINTS_DO_HORIZONTAL( hints ) )
2119049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2120049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ );
2121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
2122049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
2123aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2124aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ );
2125049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2127049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( AF_HINTS_DO_VERTICAL( hints ) )
2128049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2129049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT );
2130049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
2131049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
2132aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2133aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT );
2134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2135049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* grid-fit the outline */
2137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
2138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
2140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) )   )
2141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2143aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
2144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dim == AF_DIMENSION_HORZ                                  &&
2145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project             metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL )
2146049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_WarperRec  warper;
2148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Fixed      scale;
2149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos        delta;
2150049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2152aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          af_warper_compute( &warper, hints, (AF_Dimension)dim,
2153aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                             &scale, &delta );
2154aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
2155aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                    scale, delta );
2156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
2157049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2158aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif /* AF_CONFIG_OPTION_USE_WARPER */
2159049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2160049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_hint_edges( hints, (AF_Dimension)dim );
2161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_align_edge_points( hints, (AF_Dimension)dim );
2162049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
2163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
2164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
2168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_dump_points( hints );
2169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_dump_segments( hints );
2170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_dump_edges( hints );
2171049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
2172049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_save( hints, outline );
2174049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2175049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
2176049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
2177049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2178049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2179049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2181049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2182049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                C J K   S C R I P T   C L A S S                *****/
2184049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2185049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2186049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2189aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* this corresponds to Unicode 6.0 */
2190aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2191049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static const AF_Script_UniRangeRec  af_cjk_uniranges[] =
2192049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2193295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x2E80UL,  0x2EFFUL ),  /* CJK Radicals Supplement                 */
2194295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x2F00UL,  0x2FDFUL ),  /* Kangxi Radicals                         */
2195aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC(  0x2FF0UL,  0x2FFFUL ),  /* Ideographic Description Characters      */
2196295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3000UL,  0x303FUL ),  /* CJK Symbols and Punctuation             */
2197295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3040UL,  0x309FUL ),  /* Hiragana                                */
2198295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x30A0UL,  0x30FFUL ),  /* Katakana                                */
2199295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3100UL,  0x312FUL ),  /* Bopomofo                                */
2200295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3130UL,  0x318FUL ),  /* Hangul Compatibility Jamo               */
2201aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC(  0x3190UL,  0x319FUL ),  /* Kanbun                                  */
2202295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x31A0UL,  0x31BFUL ),  /* Bopomofo Extended                       */
2203295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x31C0UL,  0x31EFUL ),  /* CJK Strokes                             */
2204295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x31F0UL,  0x31FFUL ),  /* Katakana Phonetic Extensions            */
2205295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3200UL,  0x32FFUL ),  /* Enclosed CJK Letters and Months         */
2206295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3300UL,  0x33FFUL ),  /* CJK Compatibility                       */
2207295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x3400UL,  0x4DBFUL ),  /* CJK Unified Ideographs Extension A      */
2208295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x4DC0UL,  0x4DFFUL ),  /* Yijing Hexagram Symbols                 */
2209295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0x4E00UL,  0x9FFFUL ),  /* CJK Unified Ideographs                  */
2210aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC(  0xA960UL,  0xA97FUL ),  /* Hangul Jamo Extended-A                  */
2211aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC(  0xAC00UL,  0xD7AFUL ),  /* Hangul Syllables                        */
2212aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC(  0xD7B0UL,  0xD7FFUL ),  /* Hangul Jamo Extended-B                  */
2213295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0xF900UL,  0xFAFFUL ),  /* CJK Compatibility Ideographs            */
2214aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC(  0xFE10UL,  0xFE1FUL ),  /* Vertical forms                          */
2215295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0xFE30UL,  0xFE4FUL ),  /* CJK Compatibility Forms                 */
2216295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(  0xFF00UL,  0xFFEFUL ),  /* Halfwidth and Fullwidth Forms           */
2217aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC( 0x1B000UL, 0x1B0FFUL ),  /* Kana Supplement                         */
2218aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC( 0x1D300UL, 0x1D35FUL ),  /* Tai Xuan Hing Symbols                   */
2219aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC( 0x1F200UL, 0x1F2FFUL ),  /* Enclosed Ideographic Supplement         */
2220295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ),  /* CJK Unified Ideographs Extension B      */
2221aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC( 0x2A700UL, 0x2B73FUL ),  /* CJK Unified Ideographs Extension C      */
2222aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_UNIRANGE_REC( 0x2B740UL, 0x2B81FUL ),  /* CJK Unified Ideographs Extension D      */
2223295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC( 0x2F800UL, 0x2FA1FUL ),  /* CJK Compatibility Ideographs Supplement */
2224295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC(       0UL,       0UL )
2225049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  };
2226049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2227049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2228295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  AF_DEFINE_SCRIPT_CLASS(af_cjk_script_class,
2229049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_SCRIPT_CJK,
2230049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_cjk_uniranges,
2231049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2232aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    sizeof( AF_CJKMetricsRec ),
2233049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2234049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_InitMetricsFunc) af_cjk_metrics_init,
2235049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale,
2236049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_DoneMetricsFunc) NULL,
2237049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2238049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_InitHintsFunc)   af_cjk_hints_init,
2239049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_ApplyHintsFunc)  af_cjk_hints_apply
2240295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  )
2241049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2242049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#else /* !AF_CONFIG_OPTION_CJK */
2243049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2244049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static const AF_Script_UniRangeRec  af_cjk_uniranges[] =
2245049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2246295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    AF_UNIRANGE_REC( 0UL, 0UL )
2247049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  };
2248049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2249049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2250295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  AF_DEFINE_SCRIPT_CLASS(af_cjk_script_class,
2251049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_SCRIPT_CJK,
2252049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_cjk_uniranges,
2253049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2254aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    sizeof( AF_CJKMetricsRec ),
2255049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2256049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_InitMetricsFunc) NULL,
2257049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_ScaleMetricsFunc)NULL,
2258049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_DoneMetricsFunc) NULL,
2259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2260049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_InitHintsFunc)   NULL,
2261049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    (AF_Script_ApplyHintsFunc)  NULL
2262295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  )
2263049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif /* !AF_CONFIG_OPTION_CJK */
2265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2266049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2267049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/* END */
2268