1049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/***************************************************************************/
2049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
3049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*  afcjk.c                                                                */
4049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
59c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod/*    Auto-fitter hinting routines for CJK writing system (body).          */
6049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/*                                                                         */
7fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki/*  Copyright 2006-2015 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
29ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#include "afglobal.h"
309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#include "afpic.h"
31049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aflatin.h"
32049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
33049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
34049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#ifdef AF_CONFIG_OPTION_CJK
35049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
36aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
37aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
38049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "afcjk.h"
39049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "aferrors.h"
40049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
41049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
42aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
43049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#include "afwarp.h"
44049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
45049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
46049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
47049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
48aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*                                                                       */
49aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
50aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
51aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* messages during execution.                                            */
52aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*                                                                       */
53aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#undef  FT_COMPONENT
54aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#define FT_COMPONENT  trace_afcjk
55aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
56aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
57aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /*************************************************************************/
58049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
59049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
60049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****              C J K   G L O B A L   M E T R I C S              *****/
61049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
62049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
63049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
64049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
65aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
66aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Basically the Latin version with AF_CJKMetrics */
67aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* to replace AF_LatinMetrics.                    */
68aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
69aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  FT_LOCAL_DEF( void )
70aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_init_widths( AF_CJKMetrics  metrics,
71727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                              FT_Face        face )
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
77ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "\n"
789c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                "cjk standard widths computation (style `%s')\n"
799c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                "===================================================\n"
80ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                "\n",
819c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                af_style_names[metrics->root.style_class->style] ));
82ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
83aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    af_glyph_hints_init( hints, face->memory );
84aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
85aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
86aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    metrics->axis[AF_DIMENSION_VERT].width_count = 0;
87aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
88aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
89aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Error          error;
909c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_ULong          glyph_index;
919c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_Long           y_offset;
92aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      int               dim;
93aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_CJKMetricsRec  dummy[1];
94aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_Scaler         scaler = &dummy->root.scaler;
95aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
969c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#ifdef FT_CONFIG_OPTION_PIC
979c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_FaceGlobals  globals = metrics->root.globals;
989c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#endif
99aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1009c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_StyleClass   style_class  = metrics->root.style_class;
1019c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
1029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                       [style_class->script];
1039c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
1049c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_UInt32  standard_char;
1059c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
1069c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
1079c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      standard_char = script_class->standard_char1;
1089c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_get_char_index( &metrics->root,
1099c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                         standard_char,
1109c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                         &glyph_index,
1119c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                         &y_offset );
1129c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      if ( !glyph_index )
1139c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      {
1149c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( script_class->standard_char2 )
1159c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        {
1169c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          standard_char = script_class->standard_char2;
1179c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          af_get_char_index( &metrics->root,
1189c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                             standard_char,
1199c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                             &glyph_index,
1209c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                             &y_offset );
1219c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          if ( !glyph_index )
1229c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          {
1239c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            if ( script_class->standard_char3 )
1249c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            {
1259c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              standard_char = script_class->standard_char3;
1269c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              af_get_char_index( &metrics->root,
1279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                 standard_char,
1289c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                 &glyph_index,
1299c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                 &y_offset );
1309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              if ( !glyph_index )
1319c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                goto Exit;
1329c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            }
1339c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod            else
1349c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod              goto Exit;
1359c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          }
1369c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        }
1379c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        else
1389c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          goto Exit;
1399c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      }
140aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
141ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n",
1429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                  standard_char, glyph_index ));
143ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
144aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
145aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( error || face->glyph->outline.n_points <= 0 )
146aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        goto Exit;
147aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
148aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_ZERO( dummy );
149aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
150aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      dummy->units_per_em = metrics->units_per_em;
151aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
152aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->x_scale = 0x10000L;
153aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->y_scale = 0x10000L;
154aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->x_delta = 0;
155aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->y_delta = 0;
156aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
157aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->face        = face;
158aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->render_mode = FT_RENDER_MODE_NORMAL;
159aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scaler->flags       = 0;
160aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1619c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_glyph_hints_rescale( hints, (AF_StyleMetrics)dummy );
162aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
163aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      error = af_glyph_hints_reload( hints, &face->glyph->outline );
164aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( error )
165aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        goto Exit;
166aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
167aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
168aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
169aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_CJKAxis    axis    = &metrics->axis[dim];
170aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_AxisHints  axhints = &hints->axis[dim];
171aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Segment    seg, limit, link;
172aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_UInt       num_widths = 0;
173aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
174aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
175ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        error = af_latin_hints_compute_segments( hints,
176ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                                                 (AF_Dimension)dim );
177aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( error )
178aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          goto Exit;
179aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
180ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        af_latin_hints_link_segments( hints,
1819c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                      0,
1829c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                      NULL,
183ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                                      (AF_Dimension)dim );
184aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
185aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        seg   = axhints->segments;
186aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        limit = seg + axhints->num_segments;
187aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
188aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        for ( ; seg < limit; seg++ )
189aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
190aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          link = seg->link;
191aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
192aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* we only consider stem segments there! */
193aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( link && link->link == seg && link > seg )
194aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
195aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            FT_Pos  dist;
196aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
197aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
198aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            dist = seg->pos - link->pos;
199aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            if ( dist < 0 )
200aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              dist = -dist;
201aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
202aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            if ( num_widths < AF_CJK_MAX_WIDTHS )
203aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              axis->widths[num_widths++].org = dist;
204aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
205aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
206aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
207727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        /* this also replaces multiple almost identical stem widths */
208ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        /* with a single one (the value 100 is heuristic)           */
209727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease        af_sort_and_quantize_widths( &num_widths, axis->widths,
210727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease                                     dummy->units_per_em / 100 );
211aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->width_count = num_widths;
212aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
213aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
214aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    Exit:
215aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
216aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
217aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_CJKAxis  axis = &metrics->axis[dim];
218aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos      stdw;
219aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
220aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
221aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
222aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                         : AF_LATIN_CONSTANT( metrics, 50 );
223aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
224aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* let's try 20% of the smallest width */
225aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->edge_distance_threshold = stdw / 5;
226aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->standard_width          = stdw;
227aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        axis->extra_light             = 0;
228aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
229ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
230ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
231ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_UInt  i;
232aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
233aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
234ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "%s widths:\n",
235ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      dim == AF_DIMENSION_VERT ? "horizontal"
236ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                                               : "vertical" ));
237aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
238ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  %d (standard)", axis->standard_width ));
239ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          for ( i = 1; i < axis->width_count; i++ )
240ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_TRACE5(( " %d", axis->widths[i].org ));
241aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
242ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "\n" ));
243ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
244ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
245aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
246aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
247aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
248ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "\n" ));
249ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
250ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    af_glyph_hints_done( hints );
251ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  }
252aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
253ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
254ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Find all blue zones. */
255aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
256aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  static void
257ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  af_cjk_metrics_init_blues( AF_CJKMetrics  metrics,
258ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                             FT_Face        face )
259aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
260ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_Pos      fills[AF_BLUE_STRING_MAX_LEN];
261ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_Pos      flats[AF_BLUE_STRING_MAX_LEN];
262aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
263fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_UInt     num_fills;
264fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_UInt     num_flats;
265aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2669c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    FT_Bool     fill;
2679c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
268ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_CJKBlue  blue;
269ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_Error    error;
270ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_CJKAxis  axis;
271ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_Outline  outline;
272ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2739c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    AF_StyleClass  sc = metrics->root.style_class;
274aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2759c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    AF_Blue_Stringset         bss = sc->blue_stringset;
2769c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
277aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
278aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2799c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* we walk over the blue character strings as specified in the   */
2809c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* style's entry in the `af_blue_stringset' array, computing its */
2819c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    /* extremum points (depending on the string properties)          */
282aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
283ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "cjk blue zones computation\n"
284ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                "==========================\n"
285ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                "\n" ));
286aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
287ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
288aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
289ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      const char*  p = &af_blue_strings[bs->string];
290ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_Pos*      blue_ref;
291ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_Pos*      blue_shoot;
292ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
293ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
294ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      if ( AF_CJK_IS_HORIZ_BLUE( bs ) )
295ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        axis = &metrics->axis[AF_DIMENSION_HORZ];
296ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      else
297ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        axis = &metrics->axis[AF_DIMENSION_VERT];
298aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2999c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#ifdef FT_DEBUG_LEVEL_TRACE
3009c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      {
3019c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_String*  cjk_blue_name[4] =
3029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        {
3039c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_String*)"bottom",    /* --   , --  */
3049c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_String*)"top",       /* --   , TOP */
3059c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_String*)"left",      /* HORIZ, --  */
3069c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_String*)"right"      /* HORIZ, TOP */
3079c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        };
3089c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
3099c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
3109c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_TRACE5(( "blue zone %d (%s):\n",
3119c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                    axis->blue_count,
3129c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                    cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) |
3139c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                                  AF_CJK_IS_TOP_BLUE( bs )   ] ));
3149c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      }
3159c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod#endif /* FT_DEBUG_LEVEL_TRACE */
316aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
317aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      num_fills = 0;
318aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      num_flats = 0;
319aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
3209c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      fill = 1;  /* start with characters that define fill values */
3219c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_TRACE5(( "  [overshoot values]\n" ));
322ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
323ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      while ( *p )
324aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
325ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_ULong    ch;
3269c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_ULong    glyph_index;
3279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_Long     y_offset;
328ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_Pos      best_pos;       /* same as points.y or points.x, resp. */
329ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_Int      best_point;
330ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_Vector*  points;
331aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
332aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
333ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        GET_UTF8_CHAR( ch, p );
334aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
3359c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        /* switch to characters that define flat values */
3369c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( ch == '|' )
3379c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        {
3389c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          fill = 0;
3399c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_TRACE5(( "  [reference values]\n" ));
3409c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          continue;
3419c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        }
3429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
343ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        /* load the character in the face -- skip unknown or empty ones */
3449c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        af_get_char_index( &metrics->root, ch, &glyph_index, &y_offset );
345ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        if ( glyph_index == 0 )
346ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
347ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  U+%04lX unavailable\n", ch ));
348ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          continue;
349ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
350aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
351ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        error   = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
352ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        outline = face->glyph->outline;
353ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        if ( error || outline.n_points <= 0 )
354aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
355ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  U+%04lX contains no outlines\n", ch ));
356ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          continue;
357ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
358aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
359ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        /* now compute min or max point indices and coordinates */
360ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        points     = outline.points;
361ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        best_point = -1;
362ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        best_pos   = 0;  /* make compiler happy */
363aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
364ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
365ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_Int  nn;
366ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_Int  first = 0;
367ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_Int  last  = -1;
368aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
369aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
370ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
371aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
372ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            FT_Int  pp;
373aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
374aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
375ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            last = outline.contours[nn];
376aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
377ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* Avoid single-point contours since they are never rasterized. */
378ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* In some fonts, they correspond to mark attachment points     */
379ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            /* which are way outside of the glyph's real outline.           */
380ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            if ( last <= first )
381ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              continue;
382aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
383ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            if ( AF_CJK_IS_HORIZ_BLUE( bs ) )
384aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            {
385ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              if ( AF_CJK_IS_RIGHT_BLUE( bs ) )
386aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              {
387aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
388ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( best_point < 0 || points[pp].x > best_pos )
389aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
390aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
391ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    best_pos   = points[pp].x;
392aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
393ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              }
394ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              else
395ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              {
396aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
397ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( best_point < 0 || points[pp].x < best_pos )
398aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
399aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
400ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    best_pos   = points[pp].x;
401aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
402ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              }
403ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            }
404ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            else
405ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease            {
406ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              if ( AF_CJK_IS_TOP_BLUE( bs ) )
407ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              {
408aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
409ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( best_point < 0 || points[pp].y > best_pos )
410aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
411aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
412ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    best_pos   = points[pp].y;
413aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
414ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              }
415ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              else
416ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease              {
417aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                for ( pp = first; pp <= last; pp++ )
418ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  if ( best_point < 0 || points[pp].y < best_pos )
419aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  {
420aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                    best_point = pp;
421ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    best_pos   = points[pp].y;
422aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                  }
423aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner              }
424aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            }
425aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
426aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
427ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          FT_TRACE5(( "  U+%04lX: best_pos = %5ld\n", ch, best_pos ));
428aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
429ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
4309c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        if ( fill )
431ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          fills[num_fills++] = best_pos;
432ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        else
433ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          flats[num_flats++] = best_pos;
434aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
435aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
436aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( num_flats == 0 && num_fills == 0 )
437aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
438aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /*
439aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         *  we couldn't find a single glyph to compute this blue zone,
440aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         *  we will simply ignore it then
441aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         */
4429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        FT_TRACE5(( "  empty\n" ));
443aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
444aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
445aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
4469c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      /* we have computed the contents of the `fill' and `flats' tables,   */
4479c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      /* now determine the reference and overshoot position of the blue -- */
4489c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      /* we simply take the median value after a simple sort               */
449aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_sort_pos( num_fills, fills );
4509c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_sort_pos( num_flats, flats );
451aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
452ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      blue       = &axis->blues[axis->blue_count];
453ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      blue_ref   = &blue->ref.org;
454ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      blue_shoot = &blue->shoot.org;
455aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
456aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      axis->blue_count++;
457ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
458aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( num_flats == 0 )
459aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
460ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        *blue_ref   =
461aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_shoot = fills[num_fills / 2];
462aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
463aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else if ( num_fills == 0 )
464aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
465ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        *blue_ref   =
466aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_shoot = flats[num_flats / 2];
467aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
468aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else
469aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
470aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_ref   = fills[num_fills / 2];
471aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        *blue_shoot = flats[num_flats / 2];
472aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
473aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
474aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* make sure blue_ref >= blue_shoot for top/right or */
475aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* vice versa for bottom/left                        */
476aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( *blue_shoot != *blue_ref )
477aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
478aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos   ref       = *blue_ref;
479aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos   shoot     = *blue_shoot;
480aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Bool  under_ref = FT_BOOL( shoot < ref );
481aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
482aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
483ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        /* AF_CJK_IS_TOP_BLUE covers `right' and `top' */
484ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        if ( AF_CJK_IS_TOP_BLUE( bs ) ^ under_ref )
485ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        {
486ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          *blue_ref   =
487ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          *blue_shoot = ( shoot + ref ) / 2;
488ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
4899c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_TRACE5(( "  [reference smaller than overshoot,"
490ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                      " taking mean value]\n" ));
491ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        }
492aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
493aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
494aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->flags = 0;
495ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      if ( AF_CJK_IS_TOP_BLUE( bs ) )
496ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        blue->flags |= AF_CJK_BLUE_TOP;
497aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
498ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_TRACE5(( "    -> reference = %ld\n"
499ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  "       overshoot = %ld\n",
500ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                  *blue_ref, *blue_shoot ));
501aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
502aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
503ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "\n" ));
504ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
505aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    return;
506aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
507aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
508aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
509aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  /* Basically the Latin version with type AF_CJKMetrics for metrics. */
510ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
511aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  FT_LOCAL_DEF( void )
512aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_check_digits( AF_CJKMetrics  metrics,
513aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                               FT_Face        face )
514aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
515aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_UInt   i;
516aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Bool   started = 0, same_width = 1;
517aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Fixed  advance, old_advance = 0;
518aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
519aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
520ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* digit `0' is 0x30 in all supported charmaps */
521aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( i = 0x30; i <= 0x39; i++ )
522aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
5239c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_ULong  glyph_index;
5249c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      FT_Long   y_offset;
525aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
526aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
5279c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod      af_get_char_index( &metrics->root, i, &glyph_index, &y_offset );
528aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( glyph_index == 0 )
529aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
530aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
531aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( FT_Get_Advance( face, glyph_index,
532aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           FT_LOAD_NO_SCALE         |
533aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           FT_LOAD_NO_HINTING       |
534aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           FT_LOAD_IGNORE_TRANSFORM,
535aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                           &advance ) )
536aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
537aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
538aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( started )
539aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
540aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( advance != old_advance )
541aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
542aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          same_width = 0;
543aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          break;
544aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
545aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
546aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      else
547aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
548aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        old_advance = advance;
549aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        started     = 1;
550aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
551aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
552aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
553aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    metrics->root.digits_have_same_width = same_width;
554aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
555aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
556aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
557ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Initialize global metrics. */
558ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
559049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
560aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_init( AF_CJKMetrics  metrics,
561aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                       FT_Face        face )
562049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
563049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_CharMap  oldmap = face->charmap;
564049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
565049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
566049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->units_per_em = face->units_per_EM;
567049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
568ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
569295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    {
570727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease      af_cjk_metrics_init_widths( metrics, face );
571ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      af_cjk_metrics_init_blues( metrics, face );
572aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_metrics_check_digits( metrics, face );
573295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    }
574049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
575049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Set_Charmap( face, oldmap );
576727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return FT_Err_Ok;
577049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
578049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
579049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
580ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Adjust scaling value, then scale and shift widths   */
581ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* and blue zones (if applicable) for given dimension. */
582ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
583049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
584aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_scale_dim( AF_CJKMetrics  metrics,
585aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                            AF_Scaler      scaler,
586aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                            AF_Dimension   dim )
587049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
588aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Fixed    scale;
589aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos      delta;
590aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis  axis;
591aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_UInt     nn;
592049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
593049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
594049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ )
595049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
596aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scale = scaler->x_scale;
597aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      delta = scaler->x_delta;
598049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
599049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
600049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
601aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      scale = scaler->y_scale;
602aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      delta = scaler->y_delta;
603aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
604aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
605ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    axis = &metrics->axis[dim];
606ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
607aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    if ( axis->org_scale == scale && axis->org_delta == delta )
608aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      return;
609aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
610aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->org_scale = scale;
611aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->org_delta = delta;
612aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
613aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->scale = scale;
614aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    axis->delta = delta;
615aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
616aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* scale the blue zones */
617aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( nn = 0; nn < axis->blue_count; nn++ )
618aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
619aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_CJKBlue  blue = &axis->blues[nn];
620aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Pos      dist;
621aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
622aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
623aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->ref.cur   = FT_MulFix( blue->ref.org, scale ) + delta;
624aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->ref.fit   = blue->ref.cur;
625aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
626aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->shoot.fit = blue->shoot.cur;
627aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      blue->flags    &= ~AF_CJK_BLUE_ACTIVE;
628aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
629aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* a blue zone is only active if it is less than 3/4 pixels tall */
630aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
631aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( dist <= 48 && dist >= -48 )
632aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
633aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Pos  delta1, delta2;
634aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
635aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
636aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->ref.fit  = FT_PIX_ROUND( blue->ref.cur );
637aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
638aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* shoot is under shoot for cjk */
639aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org;
640aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        delta2 = delta1;
641aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( delta1 < 0 )
642aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = -delta2;
643aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
644aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        delta2 = FT_MulFix( delta2, scale );
645aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
646aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "delta: %d", delta1 ));
647aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( delta2 < 32 )
648aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = 0;
649aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#if 0
650aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        else if ( delta2 < 64 )
651aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
652aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif
653aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        else
654aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = FT_PIX_ROUND( delta2 );
655aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "/%d\n", delta2 ));
656aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
657aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( delta1 < 0 )
658aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          delta2 = -delta2;
659aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
660aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->shoot.fit = blue->ref.fit - delta2;
661aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
662ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n"
663ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    "     ref:   cur=%.2f fit=%.2f\n"
664ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    "     shoot: cur=%.2f fit=%.2f\n",
665ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V',
666ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    nn, blue->ref.org, blue->shoot.org,
667ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    blue->ref.cur / 64.0, blue->ref.fit / 64.0,
668ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 ));
669aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
670aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue->flags |= AF_CJK_BLUE_ACTIVE;
671aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
672049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
673049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
674049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
675049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
676ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Scale global values in both directions. */
677ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
678049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( void )
679aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_metrics_scale( AF_CJKMetrics  metrics,
680aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                        AF_Scaler      scaler )
681049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
682ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* we copy the whole structure since the x and y scaling values */
683ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* are not modified, contrary to e.g. the `latin' auto-hinter   */
684049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    metrics->root.scaler = *scaler;
685049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
686049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
687049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
688049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
689049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
690049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
691049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
692049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
693049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
694049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****              C J K   G L Y P H   A N A L Y S I S              *****/
695049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
696049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
697049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
698049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
699ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
700ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Walk over all contours and compute its segments. */
701ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
702049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
703049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_compute_segments( AF_GlyphHints  hints,
704049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                 AF_Dimension   dim )
705049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
706049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis          = &hints->axis[dim];
707049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
708049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
709049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error      error;
710049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg;
711049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
712049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
713049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    error = af_latin_hints_compute_segments( hints, dim );
714049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( error )
715049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return error;
716049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
717049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* a segment is round if it doesn't have successive */
718049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* on-curve points.                                 */
719049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg = segments; seg < segment_limit; seg++ )
720049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
721049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  pt   = seg->first;
722049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Point  last = seg->last;
723fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki      FT_UInt   f0   = pt->flags & AF_FLAG_CONTROL;
724fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki      FT_UInt   f1;
725049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
726049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
727049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      seg->flags &= ~AF_EDGE_ROUND;
728049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
729049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ; pt != last; f0 = f1 )
730049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
731049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        pt = pt->next;
732fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki        f1 = pt->flags & AF_FLAG_CONTROL;
733049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
734049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !f0 && !f1 )
735049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
736049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
737049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( pt == last )
738049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg->flags |= AF_EDGE_ROUND;
739049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
740049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
741049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
742727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    return FT_Err_Ok;
743049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
744049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
745049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
746049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
747049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_link_segments( AF_GlyphHints  hints,
748049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Dimension   dim )
749049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
750049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis          = &hints->axis[dim];
751049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
752049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
753049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Direction  major_dir     = axis->major_dir;
754049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg1, seg2;
755049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        len_threshold;
756049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        dist_threshold;
757049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
758049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
759049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
760049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
761049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
762049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                                  : hints->y_scale;
763049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    dist_threshold = FT_DivFix( 64 * 3, dist_threshold );
764049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
765049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* now compare each segment to the others */
766049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg1 = segments; seg1 < segment_limit; seg1++ )
767049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
768049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg1->dir != major_dir )
769049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
770049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
771049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( seg2 = segments; seg2 < segment_limit; seg2++ )
772049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 )
773049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
774049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos  dist = seg2->pos - seg1->pos;
775049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
776049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
777049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 0 )
778049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
779049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
780049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
781049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  min = seg1->min_coord;
782049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  max = seg1->max_coord;
783049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos  len;
784049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
785049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
786049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( min < seg2->min_coord )
787049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              min = seg2->min_coord;
788049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
789049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( max > seg2->max_coord )
790049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              max = seg2->max_coord;
791049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
792049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            len = max - min;
793049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( len >= len_threshold )
794049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
795049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist * 8 < seg1->score * 9                        &&
796049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                   ( dist * 8 < seg1->score * 7 || seg1->len < len ) )
797049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
798049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg1->score = dist;
799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg1->len   = len;
800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg1->link  = seg2;
801049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
802049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
803049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( dist * 8 < seg2->score * 9                        &&
804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                   ( dist * 8 < seg2->score * 7 || seg2->len < len ) )
805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
806049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg2->score = dist;
807049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg2->len   = len;
808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg2->link  = seg1;
809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
810049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
811049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
812049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
813049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
814049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
815049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
816049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  now compute the `serif' segments
817049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *
818049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  In Hanzi, some strokes are wider on one or both of the ends.
819049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We either identify the stems on the ends as serifs or remove
820049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  the linkage, depending on the length of the stems.
821049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *
822049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
823049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
824049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
825049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Segment  link1, link2;
826049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
827049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
828049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( seg1 = segments; seg1 < segment_limit; seg1++ )
829049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
830049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        link1 = seg1->link;
831049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos )
832049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
833049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
834049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg1->score >= dist_threshold )
835049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
836049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
837049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        for ( seg2 = segments; seg2 < segment_limit; seg2++ )
838049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
839049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg2->pos > seg1->pos || seg1 == seg2 )
840049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
841049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
842049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          link2 = seg2->link;
843049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( !link2 || link2->link != seg2 || link2->pos < link1->pos )
844049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
845049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
846049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg1->pos == seg2->pos && link1->pos == link2->pos )
847049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
848049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
849049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score )
850049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            continue;
851049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
852049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* seg2 < seg1 < link1 < link2 */
853049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
854049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg1->len >= seg2->len * 3 )
855049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
856049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  seg;
857049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
858049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
859049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            for ( seg = segments; seg < segment_limit; seg++ )
860049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
861049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              AF_Segment  link = seg->link;
862049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
863049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
864049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( link == seg2 )
865049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
866fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                seg->link  = NULL;
867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg->serif = link1;
868049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              else if ( link == link2 )
870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
871fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                seg->link  = NULL;
872049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                seg->serif = seg1;
873049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
874049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
875049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
876049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
877049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
878fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki            seg1->link = link1->link = NULL;
879049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
880049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            break;
881049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
882049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
883049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
884049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
885049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg1 = segments; seg1 < segment_limit; seg1++ )
887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      seg2 = seg1->link;
889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( seg2 )
891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg2->num_linked++;
893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg2->link != seg1 )
894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
895fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki          seg1->link = NULL;
896049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
897049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 )
898049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg1->serif = seg2->link;
899049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
900049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg2->num_linked--;
901049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
902049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
903049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
904049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
905049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
906049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
907049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
908049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_compute_edges( AF_GlyphHints  hints,
909049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                              AF_Dimension   dim )
910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis   = &hints->axis[dim];
912727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease    FT_Error      error  = FT_Err_Ok;
913049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Memory     memory = hints->memory;
914aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis    laxis  = &((AF_CJKMetrics)hints->metrics)->axis[dim];
915049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
916049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segments      = axis->segments;
917049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    segment_limit = segments + axis->num_segments;
918049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Segment    seg;
919049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
920049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Fixed      scale;
921049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        edge_distance_threshold;
922049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
923049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
924049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    axis->num_edges = 0;
925049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
926049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
927049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         : hints->y_scale;
928049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
929049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
930049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
931049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* We begin by generating a sorted table of edges for the current    */
932049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* direction.  To do so, we simply scan each segment and try to find */
933049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* an edge in our table that corresponds to its position.            */
934049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
935049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* If no edge is found, we create and insert a new edge in the       */
936049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* sorted table.  Otherwise, we simply add the segment to the edge's */
937049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* list which is then processed in the second step to compute the    */
938049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* edge's properties.                                                */
939049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
940049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* Note that the edges table is sorted along the segment/edge        */
941049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* position.                                                         */
942049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*                                                                   */
943049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*********************************************************************/
944049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
945049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
946049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         scale );
947049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( edge_distance_threshold > 64 / 4 )
948049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge_distance_threshold = FT_DivFix( 64 / 4, scale );
949049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
950049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge_distance_threshold = laxis->edge_distance_threshold;
951049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
952049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( seg = segments; seg < segment_limit; seg++ )
953049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
954ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      AF_Edge  found = NULL;
955049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos   best  = 0xFFFFU;
956049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Int   ee;
957049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
958049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
959049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* look for an edge corresponding to the segment */
960049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( ee = 0; ee < axis->num_edges; ee++ )
961049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
962049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Edge  edge = axis->edges + ee;
963049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos   dist;
964049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
965049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
966049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->dir != seg->dir )
967049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
968049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
969049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = seg->pos - edge->fpos;
970049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < 0 )
971049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = -dist;
972049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
973049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist < edge_distance_threshold && dist < best )
974049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
975049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Segment  link = seg->link;
976049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
977049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
978049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check whether all linked segments of the candidate edge */
979049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* can make a single edge.                                 */
980049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( link )
981049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
982727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease            AF_Segment  seg1  = edge->first;
983049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            FT_Pos      dist2 = 0;
984049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
985049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
986049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            do
987049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
988727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease              AF_Segment  link1 = seg1->link;
989727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
990727dee178a392d20eb050d0c446f2fcc29058fa1Victoria Lease
991049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( link1 )
992049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
993049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                dist2 = AF_SEGMENT_DIST( link, link1 );
994049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                if ( dist2 >= edge_distance_threshold )
995049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                  break;
996049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
997049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
998049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            } while ( ( seg1 = seg1->edge_next ) != edge->first );
999049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1000049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dist2 >= edge_distance_threshold )
1001049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              continue;
1002049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1003049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1004049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          best  = dist;
1005049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          found = edge;
1006049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1007049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1008049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1009049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !found )
1010049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1011049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        AF_Edge  edge;
1012049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1013049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1014049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* insert a new edge in the list and */
1015049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* sort according to the position    */
1016049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        error = af_axis_hints_new_edge( axis, seg->pos,
1017049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                        (AF_Direction)seg->dir,
1018049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                        memory, &edge );
1019049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( error )
1020049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          goto Exit;
1021049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1022049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* add the segment to the new edge's list */
1023049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_ZERO( edge );
1024049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1025049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->first    = seg;
1026049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->last     = seg;
1027fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki        edge->dir      = seg->dir;
1028049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->fpos     = seg->pos;
1029fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki        edge->opos     = FT_MulFix( seg->pos, scale );
1030fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki        edge->pos      = edge->opos;
1031049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg->edge_next = seg;
1032049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1033049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1034049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1035049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* if an edge was found, simply add the segment to the edge's */
1036049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* list                                                       */
1037049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg->edge_next         = found->first;
1038049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        found->last->edge_next = seg;
1039049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        found->last            = seg;
1040049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1041049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1042049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1043ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /******************************************************************/
1044ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*                                                                */
1045ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* Good, we now compute each edge's properties according to the   */
1046ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* segments found on its position.  Basically, these are          */
1047ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*                                                                */
1048ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*  - the edge's main direction                                   */
1049ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*  - stem edge, serif edge or both (which defaults to stem then) */
1050ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*  - rounded edge, straight or both (which defaults to straight) */
1051ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*  - link for edge                                               */
1052ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*                                                                */
1053ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /******************************************************************/
1054ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1055ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* first of all, set the `edge' field in each segment -- this is */
1056ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /* required in order to compute edge links                       */
1057049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1058ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    /*
1059ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease     * Note that removing this loop and setting the `edge' field of each
1060ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease     * segment directly in the code above slows down execution speed for
1061ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease     * some reasons on platforms like the Sun.
1062ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease     */
1063049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1064049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edges      = axis->edges;
1065049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge_limit = edges + axis->num_edges;
1066049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge;
1067049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1068049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1069049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
1070049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1071049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg = edge->first;
1072049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( seg )
1073049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          do
1074049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1075049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg->edge = edge;
1076049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg       = seg->edge_next;
1077049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1078049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          } while ( seg != edge->first );
1079049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1080049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1081049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* now compute each edge properties */
1082049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      for ( edge = edges; edge < edge_limit; edge++ )
1083049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1084049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Int  is_round    = 0;  /* does it contain round segments?    */
1085049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Int  is_straight = 0;  /* does it contain straight segments? */
1086049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1087049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1088049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        seg = edge->first;
1089049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1090049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
1091049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1092049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Bool  is_serif;
1093049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1094049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1095049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for roundness of segment */
1096049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg->flags & AF_EDGE_ROUND )
1097049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            is_round++;
1098049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1099049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            is_straight++;
1100049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1101049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* check for links -- if seg->serif is set, then seg->link must */
1102049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* be ignored                                                   */
1103049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
1104049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1105049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( seg->link || is_serif )
1106049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Edge     edge2;
1108049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            AF_Segment  seg2;
1109049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1110049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1111049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            edge2 = edge->link;
1112049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            seg2  = seg->link;
1113049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1114049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_serif )
1115049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1116049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              seg2  = seg->serif;
1117049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2 = edge->serif;
1118049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1119049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1120049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( edge2 )
1121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1122049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              FT_Pos  edge_delta;
1123049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              FT_Pos  seg_delta;
1124049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1125049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge_delta = edge->fpos - edge2->fpos;
1127049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( edge_delta < 0 )
1128049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                edge_delta = -edge_delta;
1129049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1130049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              seg_delta = AF_SEGMENT_DIST( seg, seg2 );
1131049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1132049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( seg_delta < edge_delta )
1133049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                edge2 = seg2->edge;
1134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1135049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
1136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2 = seg2->edge;
1137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( is_serif )
1139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge->serif   = edge2;
1141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge2->flags |= AF_EDGE_SERIF;
1142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
1144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              edge->link  = edge2;
1145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1146049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
1148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
1150049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* set the round/straight flags */
1152049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags = AF_EDGE_NORMAL;
1153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( is_round > 0 && is_round >= is_straight )
1155049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge->flags |= AF_EDGE_ROUND;
1156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1157049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* get rid of serifs if link is set                 */
1158049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* XXX: This gets rid of many unpleasant artefacts! */
1159049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /*      Example: the `c' in cour.pfa at size 13     */
1160049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge->serif && edge->link )
1162fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki          edge->serif = NULL;
1163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
1167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1171ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Detect segments and edges for given dimension. */
1172ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Error
1174049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hints_detect_features( AF_GlyphHints  hints,
1175049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                AF_Dimension   dim )
1176049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1177049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error  error;
1178049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1179049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    error = af_cjk_hints_compute_segments( hints, dim );
1181049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !error )
1182049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      af_cjk_hints_link_segments( hints, dim );
1184049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1185049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_cjk_hints_compute_edges( hints, dim );
1186049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
1188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1189049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1190049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1191ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Compute all edges which lie within blue zones. */
1192ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1193fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki  static void
1194aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_hints_compute_blue_edges( AF_GlyphHints  hints,
1195aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                   AF_CJKMetrics  metrics,
1196aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                   AF_Dimension   dim )
1197aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  {
1198aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_AxisHints  axis       = &hints->axis[dim];
1199aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_Edge       edge       = axis->edges;
1200aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_Edge       edge_limit = edge + axis->num_edges;
1201aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    AF_CJKAxis    cjk        = &metrics->axis[dim];
1202aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Fixed      scale      = cjk->scale;
1203aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos        best_dist0;  /* initial threshold */
1204aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1205aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1206aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* compute the initial threshold as a fraction of the EM size */
1207aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale );
1208aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1209aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    if ( best_dist0 > 64 / 2 ) /* maximum 1/2 pixel */
1210aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      best_dist0 = 64 / 2;
1211aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1212aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* compute which blue zones are active, i.e. have their scaled */
1213aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* size < 3/4 pixels                                           */
1214aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1215aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* If the distant between an edge and a blue zone is shorter than */
1216aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* best_dist0, set the blue zone for the edge.  Then search for   */
1217aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* the blue zone with the smallest best_dist to the edge.         */
1218aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1219aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    for ( ; edge < edge_limit; edge++ )
1220aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
1221aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_UInt   bb;
1222aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      AF_Width  best_blue = NULL;
1223aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      FT_Pos    best_dist = best_dist0;
1224aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1225aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1226aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( bb = 0; bb < cjk->blue_count; bb++ )
1227aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1228aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_CJKBlue  blue = cjk->blues + bb;
1229aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_Bool     is_top_right_blue, is_major_dir;
1230aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1231aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1232aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* skip inactive blue zones (i.e., those that are too small) */
1233aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) )
1234aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          continue;
1235aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1236aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* if it is a top zone, check for right edges -- if it is a bottom */
1237aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* zone, check for left edges                                      */
1238aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /*                                                                 */
1239aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* of course, that's for TrueType                                  */
12409c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        is_top_right_blue =
12419c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          (FT_Byte)( ( blue->flags & AF_CJK_BLUE_TOP ) != 0 );
12429c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod        is_major_dir =
12439c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod          FT_BOOL( edge->dir == axis->major_dir );
1244aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1245aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* if it is a top zone, the edge must be against the major    */
1246aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* direction; if it is a bottom zone, it must be in the major */
1247aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* direction                                                  */
1248aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( is_top_right_blue ^ is_major_dir )
1249aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1250aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          FT_Pos    dist;
1251aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          AF_Width  compare;
1252aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1253aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1254aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          /* Compare the edge to the closest blue zone type */
1255aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( FT_ABS( edge->fpos - blue->ref.org ) >
1256aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner               FT_ABS( edge->fpos - blue->shoot.org ) )
1257aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            compare = &blue->shoot;
1258aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          else
1259aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            compare = &blue->ref;
1260aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1261aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          dist = edge->fpos - compare->org;
1262aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( dist < 0 )
1263aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            dist = -dist;
1264aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1265aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          dist = FT_MulFix( dist, scale );
1266aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          if ( dist < best_dist )
1267aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          {
1268aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            best_dist = dist;
1269aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner            best_blue = compare;
1270aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          }
1271aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1272aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1273aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1274aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( best_blue )
1275aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->blue_edge = best_blue;
1276aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
1277aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  }
1278aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1279aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1280ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Initalize hinting engine. */
1281ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1282049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
1283aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_hints_init( AF_GlyphHints  hints,
1284aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                     AF_CJKMetrics  metrics )
1285049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1286049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Render_Mode  mode;
1287049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UInt32       scaler_flags, other_flags;
1288049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1289049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
12909c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics );
1291049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1292049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1293049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  correct x_scale and y_scale when needed, since they may have
1294049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  been modified af_cjk_scale_dim above
1295049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1296049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
1297049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
1298049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
1299049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
1300049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1301049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* compute flags depending on render mode, etc. */
1302049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    mode = metrics->root.scaler.render_mode;
1303049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1304fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki#if 0 /* AF_CONFIG_OPTION_USE_WARPER */
1305049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
1306049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
1307049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1308049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1309049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaler_flags = hints->scaler_flags;
1310049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    other_flags  = 0;
1311049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1312049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1313049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We snap the width of vertical stems for the monochrome and
1314049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  horizontal LCD rendering targets only.
1315049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1316049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
1317049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
1318049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1319049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1320049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We snap the width of horizontal stems for the monochrome and
1321049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  vertical LCD rendering targets only.
1322049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1323049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
1324049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_VERT_SNAP;
1325049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1326049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
1327049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  We adjust stems to full pixels only if we don't use the `light' mode.
1328049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
1329049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode != FT_RENDER_MODE_LIGHT )
1330049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
1331049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1332049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( mode == FT_RENDER_MODE_MONO )
1333049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      other_flags |= AF_LATIN_HINTS_MONO;
1334049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1335049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE;
1336049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1337fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki#ifdef AF_CONFIG_OPTION_USE_WARPER
1338fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    /* get (global) warper flag */
1339fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    if ( !metrics->root.globals->module->warping )
1340fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki      scaler_flags |= AF_SCALER_FLAG_NO_WARPER;
1341fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki#endif
1342fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki
1343049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->scaler_flags = scaler_flags;
1344049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    hints->other_flags  = other_flags;
1345049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1346ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    return FT_Err_Ok;
1347049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1348049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1349049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1350049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1351049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1352049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
1353049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****          C J K   G L Y P H   G R I D - F I T T I N G          *****/
1354049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
1355049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1356049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1357049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1358ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Snap a given width in scaled coordinates to one of the */
1359ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* current standard widths.                               */
1360049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1361049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
1362049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_snap_width( AF_Width  widths,
1363fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                     FT_UInt   count,
1364049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     FT_Pos    width )
1365049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1366fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_UInt  n;
1367fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_Pos   best      = 64 + 32 + 2;
1368fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_Pos   reference = width;
1369fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_Pos   scaled;
1370049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1371049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1372049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( n = 0; n < count; n++ )
1373049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1374049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  w;
1375049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos  dist;
1376049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1377049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1378049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      w = widths[n].cur;
1379049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = width - w;
1380049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < 0 )
1381049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist = -dist;
1382049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < best )
1383049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1384049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        best      = dist;
1385049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        reference = w;
1386049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1387049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1388049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1389049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    scaled = FT_PIX_ROUND( reference );
1390049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1391049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( width >= reference )
1392049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1393049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( width < scaled + 48 )
1394049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        width = reference;
1395049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1396049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1397049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1398049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( width > scaled - 48 )
1399049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        width = reference;
1400049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1401049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1402049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return width;
1403049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1404049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1405049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1406ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Compute the snapped width of a given stem.                          */
1407ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* There is a lot of voodoo in this function; changing the hard-coded  */
1408ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* parameters influence the whole hinting process.                     */
1409049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1410049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
1411049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_compute_stem_width( AF_GlyphHints  hints,
1412049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             AF_Dimension   dim,
1413049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                             FT_Pos         width,
1414fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                             FT_UInt        base_flags,
1415fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                             FT_UInt        stem_flags )
1416049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1417ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_CJKMetrics  metrics  = (AF_CJKMetrics)hints->metrics;
1418ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_CJKAxis     axis     = &metrics->axis[dim];
1419aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos         dist     = width;
1420aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Int         sign     = 0;
1421aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Bool        vertical = FT_BOOL( dim == AF_DIMENSION_VERT );
1422049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1423049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( base_flags );
1424049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( stem_flags );
1425049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1426049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1427049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1428049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      return width;
1429049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1430049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dist < 0 )
1431049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1432049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = -width;
1433049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      sign = 1;
1434049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1435049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1436049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
1437049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project         ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
1438049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1439049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* smooth hinting process: very lightly quantize the stem width */
1440049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1441049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( axis->width_count > 0 )
1442049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1443049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( FT_ABS( dist - axis->widths[0].cur ) < 40 )
1444049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1445049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = axis->widths[0].cur;
1446049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 48 )
1447049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = 48;
1448049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1449049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          goto Done_Width;
1450049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1451049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1452049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1453049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dist < 54 )
1454049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist += ( 54 - dist ) / 2 ;
1455049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else if ( dist < 3 * 64 )
1456049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1457049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  delta;
1458049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1459049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1460049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta  = dist & 63;
1461049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        dist  &= -64;
1462049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1463049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( delta < 10 )
1464049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += delta;
1465049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( delta < 22 )
1466049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += 10;
1467049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( delta < 42 )
1468049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += delta;
1469049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( delta < 54 )
1470049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += 54;
1471049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1472049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist += delta;
1473049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1474049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1475049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1476049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1477049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* strong hinting process: snap the stem width to integer pixels */
1478049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1479049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
1480049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1481049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( vertical )
1482049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1483049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* in the case of vertical hinting, always round */
1484049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* the stem heights to integer pixels            */
1485049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1486049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dist >= 64 )
1487049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = ( dist + 16 ) & ~63;
1488049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1489049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          dist = 64;
1490049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1491049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1492049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1493049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( AF_LATIN_HINTS_DO_MONO( hints ) )
1494049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1495049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* monochrome horizontal hinting: snap widths to integer pixels */
1496049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* with a different threshold                                   */
1497049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1498049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 64 )
1499049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = 64;
1500049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1501049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 32 ) & ~63;
1502049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1503049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1504049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1505049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* for horizontal anti-aliased hinting, we adopt a more subtle */
1506049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* approach: we strengthen small stems, round stems whose size */
1507049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
1508049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1509049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( dist < 48 )
1510049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 64 ) >> 1;
1511049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1512049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else if ( dist < 128 )
1513049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 22 ) & ~63;
1514049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1515049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            /* round otherwise to prevent color fringes in LCD mode */
1516049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            dist = ( dist + 32 ) & ~63;
1517049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1518049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1519049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1520049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1521049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Done_Width:
1522049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( sign )
1523049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist = -dist;
1524049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1525049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return dist;
1526049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1527049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1528049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1529ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Align one stem edge relative to the previous stem edge. */
1530049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1531049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
1532049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_align_linked_edge( AF_GlyphHints  hints,
1533049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Dimension   dim,
1534049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Edge        base_edge,
1535049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Edge        stem_edge )
1536049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1537049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  dist = stem_edge->opos - base_edge->opos;
1538049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1539fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    FT_Pos  fitted_width = af_cjk_compute_stem_width( hints, dim, dist,
1540fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                                                      base_edge->flags,
1541fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                                                      stem_edge->flags );
1542049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1543049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1544049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    stem_edge->pos = base_edge->pos + fitted_width;
15459c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
15469c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    FT_TRACE5(( "  CJKLINK: edge %d @%d (opos=%.2f) linked to %.2f,"
15479c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                " dist was %.2f, now %.2f\n",
15489c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                stem_edge - hints->axis[dim].edges, stem_edge->fpos,
15499c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                stem_edge->opos / 64.0, stem_edge->pos / 64.0,
15509c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                dist / 64.0, fitted_width / 64.0 ));
1551049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1552049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1553049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1554ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Shift the coordinates of the `serif' edge by the same amount */
1555ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* as the corresponding `base' edge has been moved already.     */
1556ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1557049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
1558049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_align_serif_edge( AF_GlyphHints  hints,
1559049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                           AF_Edge        base,
1560049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                           AF_Edge        serif )
1561049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1562049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( hints );
1563049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1564049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    serif->pos = base->pos + ( serif->opos - base->opos );
1565049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1566049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1567049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1568049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1569049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1570049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1571049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                                                                 ****/
1572049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                    E D G E   H I N T I N G                      ****/
1573049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /****                                                                 ****/
1574049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1575049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1576049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
1577049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1578049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1579049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#define AF_LIGHT_MODE_MAX_HORZ_GAP    9
1580049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#define AF_LIGHT_MODE_MAX_VERT_GAP   15
1581049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#define AF_LIGHT_MODE_MAX_DELTA_ABS  14
1582049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1583049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1584049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static FT_Pos
1585049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_hint_normal_stem( AF_GlyphHints  hints,
1586049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Edge        edge,
1587049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Edge        edge2,
1588049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       FT_Pos         anchor,
1589049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                       AF_Dimension   dim )
1590049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1591049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  org_len, cur_len, org_center;
1592049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  cur_pos1, cur_pos2;
1593049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  d_off1, u_off1, d_off2, u_off2, delta;
1594049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  offset;
1595049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos  threshold = 64;
1596049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1597049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1598049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1599049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1600049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( ( edge->flags  & AF_EDGE_ROUND ) &&
1601049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           ( edge2->flags & AF_EDGE_ROUND ) )
1602049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1603049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dim == AF_DIMENSION_VERT )
1604049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
1605049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1606049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
1607049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1608049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1609049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1610049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( dim == AF_DIMENSION_VERT )
1611049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
1612049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1613049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
1614049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1615049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1616049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1617049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    org_len    = edge2->opos - edge->opos;
1618049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_len    = af_cjk_compute_stem_width( hints, dim, org_len,
1619fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                                            edge->flags,
1620fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki                                            edge2->flags );
1621049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1622049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
1623049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_pos1   = org_center - cur_len / 2;
1624049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_pos2   = cur_pos1 + cur_len;
1625049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off1     = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
1626049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off2     = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
1627049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off1     = 64 - d_off1;
1628049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off2     = 64 - d_off2;
1629049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    delta      = 0;
1630049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1631049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1632049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( d_off1 == 0 || d_off2 == 0 )
1633049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
1634049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1635049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( cur_len <= threshold )
1636049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1637049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( d_off2 < cur_len )
1638049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1639049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( u_off1 <= d_off2 )
1640049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta =  u_off1;
1641049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1642049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta = -d_off2;
1643049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1644049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1645049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
1646049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1647049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1648049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( threshold < 64 )
1649049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1650049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( d_off1 >= threshold || u_off1 >= threshold ||
1651049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           d_off2 >= threshold || u_off2 >= threshold )
1652049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
1653049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1654049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
165541371e1e39c8528eb0c4bc40683c736e6683e60cEric Vannier    offset = cur_len & 63;
1656049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1657049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( offset < 32 )
1658049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1659049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( u_off1 <= offset || d_off2 <= offset )
1660049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
1661049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1662049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1663049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      offset = 64 - threshold;
1664049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1665049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off1 = threshold - u_off1;
1666049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off1 = u_off1    - offset;
1667049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    u_off2 = threshold - d_off2;
1668049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    d_off2 = d_off2    - offset;
1669049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1670049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( d_off1 <= u_off1 )
1671049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      u_off1 = -d_off1;
1672049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1673049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( d_off2 <= u_off2 )
1674049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      u_off2 = -d_off2;
1675049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1676049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
1677049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      delta = u_off1;
1678049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1679049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      delta = u_off2;
1680049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1681049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
1682049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1683049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 1
1684049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
1685049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1686049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
1687049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
1688049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
1689049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
1690049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1691049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1692049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1693049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    cur_pos1 += delta;
1694049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1695049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( edge->opos < edge2->opos )
1696049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1697049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge->pos  = cur_pos1;
1698049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2->pos = cur_pos1 + cur_len;
1699049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1700049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    else
1701049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1702049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge->pos  = cur_pos1 + cur_len;
1703049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2->pos = cur_pos1;
1704049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1705049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1706049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return delta;
1707049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
1708049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1709049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1710ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* The main grid-fitting routine. */
1711ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1712049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
1713049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_hint_edges( AF_GlyphHints  hints,
1714049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                     AF_Dimension   dim )
1715049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
1716049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis       = &hints->axis[dim];
1717049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edges      = axis->edges;
1718049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge_limit = edges + axis->num_edges;
1719295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner    FT_PtrDist    n_edges;
1720049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge;
1721fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    AF_Edge       anchor   = NULL;
1722049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Pos        delta    = 0;
1723049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Int        skipped  = 0;
1724aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Bool       has_last_stem = FALSE;
1725aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    FT_Pos        last_stem_pos = 0;
1726aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1727ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
1728ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_UInt       num_actions = 0;
1729ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
1730ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1731ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
17329c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    FT_TRACE5(( "cjk %s edge hinting (style `%s')\n",
1733ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
17349c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod                af_style_names[hints->metrics->style_class->style] ));
1735049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1736aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    /* we begin by aligning all stems relative to the blue zone */
1737aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1738aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    if ( AF_HINTS_DO_BLUES( hints ) )
1739aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    {
1740aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      for ( edge = edges; edge < edge_limit; edge++ )
1741aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1742aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Width  blue;
1743aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        AF_Edge   edge1, edge2;
1744aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1745aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1746aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( edge->flags & AF_EDGE_DONE )
1747aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          continue;
1748aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1749aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        blue  = edge->blue_edge;
1750aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge1 = NULL;
1751aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge2 = edge->link;
1752aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1753aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( blue )
1754aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1755aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge1 = edge;
1756aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1757aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        else if ( edge2 && edge2->blue_edge )
1758aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1759aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          blue  = edge2->blue_edge;
1760aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge1 = edge2;
1761aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge2 = edge;
1762aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1763aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1764aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( !edge1 )
1765aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          continue;
1766aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1767ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
1768ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        FT_TRACE5(( "  CJKBLUE: edge %d @%d (opos=%.2f) snapped to %.2f,"
1769ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    " was %.2f\n",
1770ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    edge1 - edges, edge1->fpos, edge1->opos / 64.0,
1771ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease                    blue->fit / 64.0, edge1->pos / 64.0 ));
1772ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1773ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        num_actions++;
1774ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
1775aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1776aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge1->pos    = blue->fit;
1777aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge1->flags |= AF_EDGE_DONE;
1778aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1779aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( edge2 && !edge2->blue_edge )
1780aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        {
1781aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          af_cjk_align_linked_edge( hints, dim, edge1, edge2 );
1782aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          edge2->flags |= AF_EDGE_DONE;
1783ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1784ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
1785ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease          num_actions++;
1786ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
1787aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        }
1788aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1789aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        if ( !anchor )
1790aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          anchor = edge;
1791aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1792aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner    }
1793049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1794049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* now we align all stem edges. */
1795049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
1796049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1797049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge2;
1798049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1799049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1800049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
1801049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1802049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1803049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* skip all non-stem edges */
1804049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2 = edge->link;
1805049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( !edge2 )
1806049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1807049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        skipped++;
1808049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1809049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1810049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1811aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* Some CJK characters have so many stems that
1812aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * the hinter is likely to merge two adjacent ones.
1813aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * To solve this problem, if either edge of a stem
1814aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * is too close to the previous one, we avoid
1815aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * aligning the two edges, but rather interpolate
1816aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * their locations at the end of this function in
1817aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       * order to preserve the space between the stems.
1818aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner       */
1819aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( has_last_stem                       &&
1820aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner           ( edge->pos  < last_stem_pos + 64 ||
1821aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner             edge2->pos < last_stem_pos + 64 ) )
1822aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1823aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        skipped++;
1824aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
1825aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1826aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1827049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* now align the stem */
1828ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1829aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      /* this should not happen, but it's better to be safe */
1830aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      if ( edge2->blue_edge )
1831aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      {
1832aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
1833aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
1834aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        af_cjk_align_linked_edge( hints, dim, edge2, edge );
1835aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        edge->flags |= AF_EDGE_DONE;
1836ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1837ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
1838ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        num_actions++;
1839ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
1840ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1841aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        continue;
1842aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      }
1843049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1844049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge2 < edge )
1845049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1846049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_align_linked_edge( hints, dim, edge2, edge );
1847049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags |= AF_EDGE_DONE;
1848ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1849ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
1850ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease        num_actions++;
1851ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
1852ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
1853aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        /* We rarely reaches here it seems;
1854aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         * usually the two edges belonging
1855aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         * to one stem are marked as DONE together
1856aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner         */
1857aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        has_last_stem = TRUE;
1858aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner        last_stem_pos = edge->pos;
1859049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
1860049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1861049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1862049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( dim != AF_DIMENSION_VERT && !anchor )
1863049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1864049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1865049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
1866049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( fixedpitch )
1867049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
1868049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Edge     left  = edge;
1869049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Edge     right = edge_limit - 1;
1870049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_EdgeRec  left1, left2, right1, right2;
1871049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos      target, center1, center2;
1872049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos      delta1, delta2, d1, d2;
1873049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1874049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1875049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          while ( right > left && !right->link )
1876049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            right--;
1877049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1878049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          left1  = *left;
1879049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          left2  = *left->link;
1880049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right1 = *right->link;
1881049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right2 = *right;
1882049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1883049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta  = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2;
1884049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16;
1885049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1886049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta1  = delta;
1887049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta1 += af_hint_normal_stem( hints, left, left->link,
1888049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                         delta1, 0 );
1889049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1890049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( left->link != right )
1891049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            af_hint_normal_stem( hints, right->link, right, delta1, 0 );
1892049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1893049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          center1 = left->pos + ( right->pos - left->pos ) / 2;
1894049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1895049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( center1 >= target )
1896049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = delta - 32;
1897049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          else
1898049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            delta2 = delta + 32;
1899049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1900049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 );
1901049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1902049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          if ( delta1 != delta2 )
1903049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
1904049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( left->link != right )
1905049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              af_hint_normal_stem( hints, &right1, &right2, delta2, 0 );
1906049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1907049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            center2 = left1.pos + ( right2.pos - left1.pos ) / 2;
1908049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1909049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            d1 = center1 - target;
1910049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            d2 = center2 - target;
1911049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1912049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( FT_ABS( d2 ) < FT_ABS( d1 ) )
1913049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
1914049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              left->pos       = left1.pos;
1915049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              left->link->pos = left2.pos;
1916049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1917049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              if ( left->link != right )
1918049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              {
1919049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                right->link->pos = right1.pos;
1920049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                right->pos       = right2.pos;
1921049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              }
1922049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1923049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              delta1 = delta2;
1924049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
1925049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
1926049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1927049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta               = delta1;
1928049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right->link->flags |= AF_EDGE_DONE;
1929049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          right->flags       |= AF_EDGE_DONE;
1930049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
1931049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
1932049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1933049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif /* 0 */
1934049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1935049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          delta = af_hint_normal_stem( hints, edge, edge2, 0,
1936049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                                       AF_DIMENSION_HORZ );
1937049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1938049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1939049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_hint_normal_stem( hints, edge, edge2, delta, dim );
1940049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1941049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#if 0
1942049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n",
1943049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               edge - edges, edge2 - edges,
1944049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               ( edge->pos - edge->opos ) / 64.0,
1945049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project               ( edge2->pos - edge2->opos ) / 64.0 );
1946049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project#endif
1947049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1948049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      anchor = edge;
1949049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge->flags  |= AF_EDGE_DONE;
1950049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      edge2->flags |= AF_EDGE_DONE;
1951aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      has_last_stem = TRUE;
1952aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      last_stem_pos = edge2->pos;
1953049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
1954049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1955049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* make sure that lowercase m's maintain their symmetry */
1956049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1957049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* In general, lowercase m's have six vertical edges if they are sans */
1958049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* serif, or twelve if they are with serifs.  This implementation is  */
1959049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* based on that assumption, and seems to work very well with most    */
1960049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* faces.  However, if for a certain face this assumption is not      */
1961049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* true, the m is just rendered like before.  In addition, any stem   */
1962049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* correction will only be applied to symmetrical glyphs (even if the */
1963049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* glyph is not an m), so the potential for unwanted distortion is    */
1964049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* relatively low.                                                    */
1965049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1966049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* We don't handle horizontal edges since we can't easily assure that */
1967049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* the third (lowest) stem aligns with the base line; it might end up */
1968049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* one pixel higher or lower.                                         */
1969049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1970049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    n_edges = edge_limit - edges;
1971049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
1972049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
1973049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  edge1, edge2, edge3;
1974049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      FT_Pos   dist1, dist2, span;
1975049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1976049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1977049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( n_edges == 6 )
1978049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1979049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = edges;
1980049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edges + 2;
1981049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3 = edges + 4;
1982049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1983049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
1984049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
1985049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge1 = edges + 1;
1986049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge2 = edges + 5;
1987049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3 = edges + 9;
1988049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
1989049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1990049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist1 = edge2->opos - edge1->opos;
1991049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      dist2 = edge3->opos - edge2->opos;
1992049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1993049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      span = dist1 - dist2;
1994049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( span < 0 )
1995049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        span = -span;
1996049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
1997049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge1->link == edge1 + 1 &&
1998049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           edge2->link == edge2 + 1 &&
1999049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           edge3->link == edge3 + 1 && span < 8 )
2000049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2001049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
2002049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3->pos -= delta;
2003049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge3->link )
2004049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge3->link->pos -= delta;
2005049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2006049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        /* move the serifs along with the stem */
2007049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( n_edges == 12 )
2008049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2009049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          ( edges + 8 )->pos -= delta;
2010049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          ( edges + 11 )->pos -= delta;
2011049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2012049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2013049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge3->flags |= AF_EDGE_DONE;
2014049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( edge3->link )
2015049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          edge3->link->flags |= AF_EDGE_DONE;
2016049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2017049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2018049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2019049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !skipped )
2020ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      goto Exit;
2021049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2022049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /*
2023049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  now hint the remaining edges (serifs and single) in order
2024049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     *  to complete our processing
2025049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project     */
2026049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
2027049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2028049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
2029049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
2030049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2031049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->serif )
2032049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2033049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_align_serif_edge( hints, edge->serif, edge );
2034049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        edge->flags |= AF_EDGE_DONE;
2035049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        skipped--;
2036049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2037049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2038049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2039049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( !skipped )
2040ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      goto Exit;
2041049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2042049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
2043049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2044049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Edge  before, after;
2045049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2046049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2047049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( edge->flags & AF_EDGE_DONE )
2048049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        continue;
2049049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2050049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      before = after = edge;
2051049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2052049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      while ( --before >= edges )
2053049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( before->flags & AF_EDGE_DONE )
2054049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
2055049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2056049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      while ( ++after < edge_limit )
2057049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( after->flags & AF_EDGE_DONE )
2058049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          break;
2059049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2060049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( before >= edges || after < edge_limit )
2061049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2062049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        if ( before < edges )
2063049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          af_cjk_align_serif_edge( hints, after, edge );
2064049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else if ( after >= edge_limit )
2065049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          af_cjk_align_serif_edge( hints, before, edge );
2066049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        else
20670a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project        {
20680a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project          if ( after->fpos == before->fpos )
20690a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project            edge->pos = before->pos;
20700a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project          else
20710a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project            edge->pos = before->pos +
20720a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project                        FT_MulDiv( edge->fpos - before->fpos,
20730a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project                                   after->pos - before->pos,
20740a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project                                   after->fpos - before->fpos );
20750a9d06e2b5cf75c3d6ba958026bfdf4745f576d6The Android Open Source Project        }
2076049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2077049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2078ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2079ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  Exit:
2080ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2081ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#ifdef FT_DEBUG_LEVEL_TRACE
2082ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    if ( !num_actions )
2083ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease      FT_TRACE5(( "  (none)\n" ));
2084ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    FT_TRACE5(( "\n" ));
2085ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif
2086ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2087ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    return;
2088049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2089049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2090049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2091049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  static void
2092049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  af_cjk_align_edge_points( AF_GlyphHints  hints,
2093049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                            AF_Dimension   dim )
2094049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2095049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_AxisHints  axis       = & hints->axis[dim];
2096049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edges      = axis->edges;
2097049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge_limit = edges + axis->num_edges;
2098049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    AF_Edge       edge;
2099049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Bool       snapping;
2100049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2101049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2102049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ             &&
2103049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) )  ||
2104049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                        ( dim == AF_DIMENSION_VERT             &&
2105049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project                          AF_LATIN_HINTS_DO_VERT_SNAP( hints ) )  );
2106049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2107049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( edge = edges; edge < edge_limit; edge++ )
2108049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2109049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* move the points of each segment     */
2110049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      /* in each edge to the edge's position */
2111049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      AF_Segment  seg = edge->first;
2112049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2113049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2114049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( snapping )
2115049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2116049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
2117049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2118049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Point  point = seg->first;
2119049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2120049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2121049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          for (;;)
2122049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2123049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dim == AF_DIMENSION_HORZ )
2124049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2125049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->x      = edge->pos;
2126049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_X;
2127049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2128049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
2129049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2130049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->y      = edge->pos;
2131049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_Y;
2132049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2133049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2134049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( point == seg->last )
2135049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              break;
2136049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2137049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            point = point->next;
2138049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2139049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2140049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
2141049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2142049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
2143049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2144049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      else
2145049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2146049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        FT_Pos  delta = edge->pos - edge->opos;
2147049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2148049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2149049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        do
2150049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2151049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_Point  point = seg->first;
2152049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2153049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2154049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          for (;;)
2155049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          {
2156049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( dim == AF_DIMENSION_HORZ )
2157049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2158049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->x     += delta;
2159049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_X;
2160049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2161049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            else
2162049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            {
2163049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->y     += delta;
2164049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              point->flags |= AF_FLAG_TOUCH_Y;
2165049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            }
2166049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2167049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            if ( point == seg->last )
2168049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project              break;
2169049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2170049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project            point = point->next;
2171049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          }
2172049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2173049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          seg = seg->edge_next;
2174049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2175049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        } while ( seg != edge->first );
2176049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2177049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2178049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2179049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2180049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2181ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  /* Apply the complete hinting algorithm to a CJK glyph. */
2182ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2183049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  FT_LOCAL_DEF( FT_Error )
2184aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner  af_cjk_hints_apply( AF_GlyphHints  hints,
2185aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      FT_Outline*    outline,
2186aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                      AF_CJKMetrics  metrics )
2187049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  {
2188049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_Error  error;
2189049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    int       dim;
2190049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2191049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    FT_UNUSED( metrics );
2192049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2193049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2194aacb8e1368a883fcbc9fe64fd0e460cef9c9b20cNick Kralevich    error = af_glyph_hints_reload( hints, outline );
2195049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( error )
2196049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      goto Exit;
2197049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2198049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* analyze glyph outline */
2199fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki#ifdef AF_CONFIG_OPTION_USE_WARPER
2200fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki    if ( ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT &&
2201fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki           AF_HINTS_DO_WARP( hints )                                ) ||
2202fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki         AF_HINTS_DO_HORIZONTAL( hints )                              )
2203fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki#else
2204049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( AF_HINTS_DO_HORIZONTAL( hints ) )
2205fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki#endif
2206049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2207049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ );
2208049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
2209049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
2210aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2211aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ );
2212049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2213049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2214049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    if ( AF_HINTS_DO_VERTICAL( hints ) )
2215049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2216049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT );
2217049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( error )
2218049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        goto Exit;
2219aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner
2220aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner      af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT );
2221049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2222049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2223049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    /* grid-fit the outline */
2224049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
2225049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    {
2226049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
2227049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project           ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) )   )
2228049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      {
2229049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2230aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#ifdef AF_CONFIG_OPTION_USE_WARPER
2231fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki        if ( dim == AF_DIMENSION_HORZ                                 &&
2232fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki             metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT &&
2233fb6b5b10aaa74b8c8974714b41bac35bdd1c772dMakoto Onuki             AF_HINTS_DO_WARP( hints )                                )
2234049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        {
2235049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          AF_WarperRec  warper;
2236049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Fixed      scale;
2237049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          FT_Pos        delta;
2238049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2239049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2240aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          af_warper_compute( &warper, hints, (AF_Dimension)dim,
2241aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                             &scale, &delta );
2242aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner          af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
2243aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner                                    scale, delta );
2244049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project          continue;
2245049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        }
2246aeb407daf3711a10a27f3bc2223c5eb05158076eDavid 'Digit' Turner#endif /* AF_CONFIG_OPTION_USE_WARPER */
2247049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2248049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_hint_edges( hints, (AF_Dimension)dim );
2249049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_cjk_align_edge_points( hints, (AF_Dimension)dim );
2250049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
2251049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project        af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
2252049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project      }
2253049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    }
2254049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2255049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    af_glyph_hints_save( hints, outline );
2256049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2257049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  Exit:
2258049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project    return error;
2259049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  }
2260049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2261049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2262049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2263049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2264049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2265049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                C J K   S C R I P T   C L A S S                *****/
2266049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*****                                                               *****/
2267049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2268049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project  /*************************************************************************/
2269049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2270049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2271ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  AF_DEFINE_WRITING_SYSTEM_CLASS(
2272ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    af_cjk_writing_system_class,
2273ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2274ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_WRITING_SYSTEM_CJK,
2275ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2276ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    sizeof ( AF_CJKMetricsRec ),
2277ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
22789c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_InitMetricsFunc) af_cjk_metrics_init,
22799c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_ScaleMetricsFunc)af_cjk_metrics_scale,
22809c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_DoneMetricsFunc) NULL,
2281ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
22829c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_InitHintsFunc)   af_cjk_hints_init,
22839c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_ApplyHintsFunc)  af_cjk_hints_apply
2284ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  )
2285ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2286ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2287ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#else /* !AF_CONFIG_OPTION_CJK */
2288ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
22899c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod
2290ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease  AF_DEFINE_WRITING_SYSTEM_CLASS(
2291ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    af_cjk_writing_system_class,
2292ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease
2293ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease    AF_WRITING_SYSTEM_CJK,
2294049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
229541371e1e39c8528eb0c4bc40683c736e6683e60cEric Vannier    sizeof ( AF_CJKMetricsRec ),
2296049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
22979c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_InitMetricsFunc) NULL,
22989c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_ScaleMetricsFunc)NULL,
22999c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_DoneMetricsFunc) NULL,
2300049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
23019c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_InitHintsFunc)   NULL,
23029c745321260bb728ab1cd1c8fd5f075854b2ad49Behdad Esfahbod    (AF_WritingSystem_ApplyHintsFunc)  NULL
2303295ffce55e0198e7a9f7d46b33f5c2b4147bf821David 'Digit' Turner  )
2304049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2305049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2306ec0bab5697bb31ba980810145f62e3799946ec60Victoria Lease#endif /* !AF_CONFIG_OPTION_CJK */
2307049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2308049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project
2309049d6fea481044fcc000e7782e5bc7046fc70844The Android Open Source Project/* END */
2310