1f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/***************************************************************************/
2f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*                                                                         */
3f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  afhints.c                                                              */
4f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*                                                                         */
5f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*    Auto-fitter hinting routines (body).                                 */
6f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*                                                                         */
70a0c22569deab933df21127e75db5c81f724f292Werner Lemberg/*  Copyright 2003-2018 by                                                 */
8f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*                                                                         */
10f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  This file is part of the FreeType project, and may only be used,       */
11f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  modified, and distributed under the terms of the FreeType project      */
12f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  this file you indicate that you have read the license and              */
14f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*  understand and accept it fully.                                        */
15f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/*                                                                         */
16f13516c8321b386227414be01e707563e852fc0dWerner Lemberg/***************************************************************************/
17f13516c8321b386227414be01e707563e852fc0dWerner Lemberg
18f13516c8321b386227414be01e707563e852fc0dWerner Lemberg
198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg#include "afhints.h"
20a37745bad4e46c5ad0e690150b0ec8081ff81c90Werner Lemberg#include "aferrors.h"
21effd15de89b8c11f933609888c8370dc1d6fe948David Turner#include FT_INTERNAL_CALC_H
22b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg#include FT_INTERNAL_DEBUG_H
23b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg
24b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg
25b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg  /*************************************************************************/
26b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg  /*                                                                       */
27b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
28b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
29b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg  /* messages during execution.                                            */
30b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg  /*                                                                       */
31b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg#undef  FT_COMPONENT
32b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg#define FT_COMPONENT  trace_afhints
33b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
34111b5aefcaf1156fe4f25b3f0f166f3cbc644ac3Werner Lemberg
35c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Get new segment for given axis. */
36c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
37b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  FT_LOCAL_DEF( FT_Error )
38b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  af_axis_hints_new_segment( AF_AxisHints  axis,
39b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner                             FT_Memory     memory,
40b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner                             AF_Segment   *asegment )
41b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  {
42e3c9301581a450fae5db73a3b94b10ed6a0aeb5eWerner Lemberg    FT_Error    error   = FT_Err_Ok;
43b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    AF_Segment  segment = NULL;
44b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
45b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
4656ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
4756ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    {
484441f7b24675fbd7d91f794f5d54e6c1ff168439Werner Lemberg      if ( !axis->segments )
4956ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      {
5056ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        axis->segments     = axis->embedded.segments;
5156ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        axis->max_segments = AF_SEGMENTS_EMBEDDED;
5256ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      }
5356ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    }
5456ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    else if ( axis->num_segments >= axis->max_segments )
55b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    {
56b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      FT_Int  old_max = axis->max_segments;
57b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      FT_Int  new_max = old_max;
5887054758fb1a416a045690d38dcd3d2b05ab1ac1Suzuki, Toshiya (鈴木俊哉)      FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
59b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
60b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
61b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      if ( old_max >= big_max )
62b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      {
63059bc335ce42220b222763379e89d0cbf2b949ebWerner Lemberg        error = FT_THROW( Out_Of_Memory );
64b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner        goto Exit;
65b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      }
66b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
670529ba8d2579dcff1c287c40ea491ebc39fa24f5David Turner      new_max += ( new_max >> 2 ) + 4;
68b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      if ( new_max < old_max || new_max > big_max )
69b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner        new_max = big_max;
70b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
7156ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      if ( axis->segments == axis->embedded.segments )
7256ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      {
7356ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        if ( FT_NEW_ARRAY( axis->segments, new_max ) )
7456ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod          goto Exit;
7556ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        ft_memcpy( axis->segments, axis->embedded.segments,
7656ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod                   sizeof ( axis->embedded.segments ) );
7756ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      }
7856ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      else
7956ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      {
8056ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
8156ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod          goto Exit;
8256ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      }
83b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
84b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      axis->max_segments = new_max;
85b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    }
86b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
87b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    segment = axis->segments + axis->num_segments++;
88b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
89b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  Exit:
90b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    *asegment = segment;
91b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    return error;
92b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  }
93b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
94b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
95387a9fe73dabcac45a11a55bb27fa0e8e7d81437Werner Lemberg  /* Get new edge for given axis, direction, and position, */
96387a9fe73dabcac45a11a55bb27fa0e8e7d81437Werner Lemberg  /* without initializing the edge itself.                 */
97c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
98f13516c8321b386227414be01e707563e852fc0dWerner Lemberg  FT_LOCAL( FT_Error )
99b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  af_axis_hints_new_edge( AF_AxisHints  axis,
100b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner                          FT_Int        fpos,
101b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner                          AF_Direction  dir,
1022e09812c5121413fa29692a46b310983cb3de3e8Werner Lemberg                          FT_Bool       top_to_bottom_hinting,
103b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner                          FT_Memory     memory,
104b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg                          AF_Edge      *anedge )
105b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  {
106e3c9301581a450fae5db73a3b94b10ed6a0aeb5eWerner Lemberg    FT_Error  error = FT_Err_Ok;
107b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    AF_Edge   edge  = NULL;
108b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    AF_Edge   edges;
109b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
110b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
11156ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    if ( axis->num_edges < AF_EDGES_EMBEDDED )
11256ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    {
1134441f7b24675fbd7d91f794f5d54e6c1ff168439Werner Lemberg      if ( !axis->edges )
11456ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      {
11556ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        axis->edges     = axis->embedded.edges;
11656ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        axis->max_edges = AF_EDGES_EMBEDDED;
11756ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      }
11856ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    }
11956ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod    else if ( axis->num_edges >= axis->max_edges )
120b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    {
121b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      FT_Int  old_max = axis->max_edges;
122b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      FT_Int  new_max = old_max;
12387054758fb1a416a045690d38dcd3d2b05ab1ac1Suzuki, Toshiya (鈴木俊哉)      FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
124b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
125b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
126b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      if ( old_max >= big_max )
127b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      {
128059bc335ce42220b222763379e89d0cbf2b949ebWerner Lemberg        error = FT_THROW( Out_Of_Memory );
129b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner        goto Exit;
130b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      }
131b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
1320529ba8d2579dcff1c287c40ea491ebc39fa24f5David Turner      new_max += ( new_max >> 2 ) + 4;
133b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      if ( new_max < old_max || new_max > big_max )
134b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner        new_max = big_max;
135b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
13656ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      if ( axis->edges == axis->embedded.edges )
13756ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      {
13856ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        if ( FT_NEW_ARRAY( axis->edges, new_max ) )
13956ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod          goto Exit;
14056ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        ft_memcpy( axis->edges, axis->embedded.edges,
14156ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod                   sizeof ( axis->embedded.edges ) );
14256ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      }
14356ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      else
14456ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      {
14556ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
14656ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod          goto Exit;
14756ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      }
148b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
149b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      axis->max_edges = new_max;
150b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    }
151b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
152b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    edges = axis->edges;
153b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    edge  = edges + axis->num_edges;
154b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
155b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    while ( edge > edges )
156b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    {
1572e09812c5121413fa29692a46b310983cb3de3e8Werner Lemberg      if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos )
1582e09812c5121413fa29692a46b310983cb3de3e8Werner Lemberg                                 : ( edge[-1].fpos < fpos ) )
159b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        break;
160b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
16149e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg      /* we want the edge with same position and minor direction */
16249e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg      /* to appear before those in the major one in the list     */
16349e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg      if ( edge[-1].fpos == fpos && dir == axis->major_dir )
164b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        break;
165b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
166b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      edge[0] = edge[-1];
167b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      edge--;
168b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    }
169b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
170b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    axis->num_edges++;
171b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
172b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  Exit:
173b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    *anedge = edge;
174b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner    return error;
175b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner  }
176b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
177b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
178d503b1bce25d61a7ed6c262e013b6ceb3b627045Werner Lemberg#ifdef FT_DEBUG_AUTOFIT
1798bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
18024d72a1b0b3d7227000a8b9a54f3513f99c7fe4eWerner Lemberg#include FT_CONFIG_STANDARD_LIBRARY_H
1818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
18252166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg  /* The dump functions are used in the `ftgrid' demo program, too. */
18352166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg#define AF_DUMP( varformat )          \
18452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg          do                          \
18552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg          {                           \
18652166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg            if ( to_stdout )          \
18752166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg              printf varformat;       \
18852166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg            else                      \
18952166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg              FT_TRACE7( varformat ); \
19052166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg          } while ( 0 )
19152166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg
19252166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg
193b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  static const char*
194b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  af_dir_str( AF_Direction  dir )
1958bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
1968bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    const char*  result;
1978bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
198b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
199b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    switch ( dir )
2008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
201b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    case AF_DIR_UP:
202b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      result = "up";
203b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      break;
204b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    case AF_DIR_DOWN:
205b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      result = "down";
206b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      break;
207b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    case AF_DIR_LEFT:
208b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      result = "left";
209b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      break;
210b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    case AF_DIR_RIGHT:
211b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      result = "right";
212b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      break;
213b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    default:
214b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      result = "none";
2158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
216b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
2178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    return result;
2188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
2198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
220b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
221a632b5f4064873ab7f21b749f93332387bc47f76Werner Lemberg#define AF_INDEX_NUM( ptr, base )  (int)( (ptr) ? ( (ptr) - (base) ) : -1 )
222b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
2238bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
2247f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  static char*
2257f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  af_print_idx( char* p,
2267f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                int   idx )
2277f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  {
2287f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    if ( idx == -1 )
2297f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    {
2307f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      p[0] = '-';
2317f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      p[1] = '-';
2327f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      p[2] = '\0';
2337f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    }
2347f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    else
2357f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      ft_sprintf( p, "%d", idx );
2367f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2377f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    return p;
2387f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  }
2397f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2407f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2417f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  static int
2427f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  af_get_segment_index( AF_GlyphHints  hints,
2437f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                        int            point_idx,
2447f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                        int            dimension )
2457f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  {
2467f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_AxisHints  axis     = &hints->axis[dimension];
2477f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_Point      point    = hints->points + point_idx;
2487f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_Segment    segments = axis->segments;
2497f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_Segment    limit    = segments + axis->num_segments;
2507f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_Segment    segment;
2517f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2527f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2537f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    for ( segment = segments; segment < limit; segment++ )
2547f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    {
2557f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      if ( segment->first <= segment->last )
2567f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      {
2577f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg        if ( point >= segment->first && point <= segment->last )
2587f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg          break;
2597f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      }
2607f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      else
2617f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      {
26268fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg        AF_Point  p = segment->first;
26368fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg
26468fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg
26568fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg        for (;;)
26668fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg        {
26768fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg          if ( point == p )
26868fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg            goto Exit;
26968fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg
27068fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg          if ( p == segment->last )
27168fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg            break;
27268fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg
27368fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg          p = p->next;
27468fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg        }
2757f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      }
2767f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    }
2777f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
27868fb4789a582561606fafbe51e7a217598bb35ecWerner Lemberg  Exit:
2797f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    if ( segment == limit )
2807f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      return -1;
2817f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2827f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    return (int)( segment - segments );
2837f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  }
2847f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2857f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2867f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  static int
2877f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  af_get_edge_index( AF_GlyphHints  hints,
2887f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                     int            segment_idx,
2897f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                     int            dimension )
2907f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  {
2917f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_AxisHints  axis    = &hints->axis[dimension];
2927f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_Edge       edges   = axis->edges;
2937f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    AF_Segment    segment = axis->segments + segment_idx;
2947f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2957f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2967f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
2977f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg  }
2987f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
2997f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
3008bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#ifdef __cplusplus
3018bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg  extern "C" {
3028bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#endif
3038bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  void
30452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg  af_glyph_hints_dump_points( AF_GlyphHints  hints,
30552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                              FT_Bool        to_stdout )
3068bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
307baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg    AF_Point   points  = hints->points;
308baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg    AF_Point   limit   = points + hints->num_points;
309baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg    AF_Point*  contour = hints->contours;
310baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg    AF_Point*  climit  = contour + hints->num_contours;
311baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg    AF_Point   point;
3128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
313b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
314a2fa657a03f17ef9cd79b4ad529f08cfe676aa1cWerner Lemberg    AF_DUMP(( "Table of points:\n" ));
315a2fa657a03f17ef9cd79b4ad529f08cfe676aa1cWerner Lemberg
316a2fa657a03f17ef9cd79b4ad529f08cfe676aa1cWerner Lemberg    if ( hints->num_points )
3178768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg    {
318709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg      AF_DUMP(( "  index  hedge  hseg  vedge  vseg  flags "
3198768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg             /* "  XXXXX  XXXXX XXXXX  XXXXX XXXXX  XXXXXX" */
320baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg                "  xorg  yorg  xscale  yscale   xfit    yfit" ));
3218768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg             /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
3228768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg    }
323a2fa657a03f17ef9cd79b4ad529f08cfe676aa1cWerner Lemberg    else
324a2fa657a03f17ef9cd79b4ad529f08cfe676aa1cWerner Lemberg      AF_DUMP(( "  (none)\n" ));
325b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
3268bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( point = points; point < limit; point++ )
3277f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    {
3287f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      int  point_idx     = AF_INDEX_NUM( point, points );
3297f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      int  segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
3307f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      int  segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
3317f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
3327f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      char  buf1[16], buf2[16], buf3[16], buf4[16];
3337f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
3347f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
335baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg      /* insert extra newline at the beginning of a contour */
336baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg      if ( contour < climit && *contour == point )
337baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg      {
338baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg        AF_DUMP(( "\n" ));
339baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg        contour++;
340baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg      }
341baa41ff204e581fee745d0a2badbe62b35509e58Werner Lemberg
342709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg      AF_DUMP(( "  %5d  %5s %5s  %5s %5s  %s"
3437f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                " %5d %5d %7.2f %7.2f %7.2f %7.2f\n",
3447f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                point_idx,
3457f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                af_print_idx( buf1,
3467f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                              af_get_edge_index( hints, segment_idx_1, 1 ) ),
3477f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                af_print_idx( buf2, segment_idx_1 ),
3487f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                af_print_idx( buf3,
3497f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                              af_get_edge_index( hints, segment_idx_0, 0 ) ),
3507f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                af_print_idx( buf4, segment_idx_0 ),
351709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg                ( point->flags & AF_FLAG_NEAR )
352709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg                  ? " near "
353709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg                  : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
354709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg                    ? " weak "
355709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg                    : "strong",
3567f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
35752166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                point->fx,
35852166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                point->fy,
35952166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                point->ox / 64.0,
36052166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                point->oy / 64.0,
36152166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                point->x / 64.0,
3627f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                point->y / 64.0 ));
3637f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg    }
36452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg    AF_DUMP(( "\n" ));
3658bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
3668bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#ifdef __cplusplus
3678bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg  }
3688bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#endif
3698bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
3708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
371b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner  static const char*
37281e5ff53a89b454a3984a7181516dfb4cb22187aWerner Lemberg  af_edge_flags_to_string( FT_UInt  flags )
373b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner  {
37449e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg    static char  temp[32];
37549e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg    int          pos = 0;
37649e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
377b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
378b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    if ( flags & AF_EDGE_ROUND )
379b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    {
380e85baf4f8e9ba09fd16d31808b6a5d31735b13bfWerner Lemberg      ft_memcpy( temp + pos, "round", 5 );
381b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      pos += 5;
382b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    }
383b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    if ( flags & AF_EDGE_SERIF )
384b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    {
38549e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg      if ( pos > 0 )
386b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        temp[pos++] = ' ';
387e85baf4f8e9ba09fd16d31808b6a5d31735b13bfWerner Lemberg      ft_memcpy( temp + pos, "serif", 5 );
388b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      pos += 5;
389b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    }
39049e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg    if ( pos == 0 )
391b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      return "normal";
392b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
393b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    temp[pos] = '\0';
39449e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
395b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    return temp;
396b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner  }
397b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
39849e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
399c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Dump the array of linked segments. */
400c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
4018bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#ifdef __cplusplus
4028bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg  extern "C" {
4038bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#endif
4048bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  void
40552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg  af_glyph_hints_dump_segments( AF_GlyphHints  hints,
40652166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                                FT_Bool        to_stdout )
4078bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
40823df31adcc598c4da75ea6ed3cf11bd95a6e3ba9Werner Lemberg    FT_Int  dimension;
409b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
4108bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
4118bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( dimension = 1; dimension >= 0; dimension-- )
4128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
413b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      AF_AxisHints  axis     = &hints->axis[dimension];
414fd5ae9599ad674db14a3730f2a07e11e0407b182Werner Lemberg      AF_Point      points   = hints->points;
415fd5ae9599ad674db14a3730f2a07e11e0407b182Werner Lemberg      AF_Edge       edges    = axis->edges;
4168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Segment    segments = axis->segments;
4178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Segment    limit    = segments + axis->num_segments;
4188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Segment    seg;
4198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
4207f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      char  buf1[16], buf2[16], buf3[16];
4217f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
4228bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
42352166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg      AF_DUMP(( "Table of %s segments:\n",
42452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                dimension == AF_DIMENSION_HORZ ? "vertical"
42552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                                               : "horizontal" ));
426eed830614f280406f4c4784d4b22429b8c199cb8Werner Lemberg      if ( axis->num_segments )
4278768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg      {
4281831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg        AF_DUMP(( "  index   pos   delta   dir   from   to "
4298768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg               /* "  XXXXX  XXXXX  XXXXX  XXXXX  XXXX  XXXX" */
4301831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  "  link  serif  edge"
4318768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg               /* "  XXXX  XXXXX  XXXX" */
4327f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  "  height  extra     flags\n" ));
4338768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg               /* "  XXXXXX  XXXXX  XXXXXXXXXXX" */
4348768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg      }
435fd5ae9599ad674db14a3730f2a07e11e0407b182Werner Lemberg      else
43652166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg        AF_DUMP(( "  (none)\n" ));
4378bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
4388bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( seg = segments; seg < limit; seg++ )
4391831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg        AF_DUMP(( "  %5d  %5d  %5d  %5s  %4d  %4d"
4407f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  "  %4s  %5s  %4s"
4417f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  "  %6d  %5d  %11s\n",
442a632b5f4064873ab7f21b749f93332387bc47f76Werner Lemberg                  AF_INDEX_NUM( seg, segments ),
4431831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  seg->pos,
4441831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  seg->delta,
44552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  af_dir_str( (AF_Direction)seg->dir ),
44652166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  AF_INDEX_NUM( seg->first, points ),
44752166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  AF_INDEX_NUM( seg->last, points ),
4487f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
4497f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
4507f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
4517f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
4527f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
45352166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  seg->height,
45452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  seg->height - ( seg->max_coord - seg->min_coord ),
45581e5ff53a89b454a3984a7181516dfb4cb22187aWerner Lemberg                  af_edge_flags_to_string( seg->flags ) ));
45652166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg      AF_DUMP(( "\n" ));
4578bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
4588bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
4598bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#ifdef __cplusplus
4608bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg  }
4618bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#endif
4628bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
4638bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
4643a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  /* Fetch number of segments. */
4653a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4663a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#ifdef __cplusplus
4673a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  extern "C" {
4683a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#endif
4693a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  FT_Error
4703a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  af_glyph_hints_get_num_segments( AF_GlyphHints  hints,
4713a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg                                   FT_Int         dimension,
4723a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg                                   FT_Int*        num_segments )
4733a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  {
4743a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    AF_Dimension  dim;
4753a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    AF_AxisHints  axis;
4763a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4773a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4783a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
4793a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4803a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    axis          = &hints->axis[dim];
4813a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    *num_segments = axis->num_segments;
4823a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
483e3c9301581a450fae5db73a3b94b10ed6a0aeb5eWerner Lemberg    return FT_Err_Ok;
4843a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  }
4853a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#ifdef __cplusplus
4863a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  }
4873a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#endif
4883a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4893a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4903a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  /* Fetch offset of segments into user supplied offset array. */
4913a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
4923a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#ifdef __cplusplus
4933a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  extern "C" {
4943a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#endif
4953a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  FT_Error
4963a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  af_glyph_hints_get_segment_offset( AF_GlyphHints  hints,
4973a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg                                     FT_Int         dimension,
4983a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg                                     FT_Int         idx,
4995c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg                                     FT_Pos        *offset,
5005c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg                                     FT_Bool       *is_blue,
5015c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg                                     FT_Pos        *blue_offset )
5023a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  {
5033a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    AF_Dimension  dim;
5043a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    AF_AxisHints  axis;
5053a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    AF_Segment    seg;
5063a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5073a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5083a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    if ( !offset )
509059bc335ce42220b222763379e89d0cbf2b949ebWerner Lemberg      return FT_THROW( Invalid_Argument );
5103a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5113a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
5123a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5133a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    axis = &hints->axis[dim];
5143a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5153a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg    if ( idx < 0 || idx >= axis->num_segments )
516059bc335ce42220b222763379e89d0cbf2b949ebWerner Lemberg      return FT_THROW( Invalid_Argument );
5173a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5185c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg    seg      = &axis->segments[idx];
5190ab2b62d3fa6b3c5a50ece8b322bf21cc0e38d52Werner Lemberg    *offset  = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
5200ab2b62d3fa6b3c5a50ece8b322bf21cc0e38d52Werner Lemberg                                            : seg->first->fy;
5215c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg    if ( seg->edge )
5225c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg      *is_blue = (FT_Bool)( seg->edge->blue_edge != 0 );
5235c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg    else
5245c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg      *is_blue = FALSE;
5255c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg
5265c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg    if ( *is_blue )
5270ab2b62d3fa6b3c5a50ece8b322bf21cc0e38d52Werner Lemberg      *blue_offset = seg->edge->blue_edge->org;
5285c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg    else
5295c7f5500e89824dad3888a02cd9770e58c44230eWerner Lemberg      *blue_offset = 0;
5303a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
531e3c9301581a450fae5db73a3b94b10ed6a0aeb5eWerner Lemberg    return FT_Err_Ok;
5323a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  }
5333a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#ifdef __cplusplus
5343a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg  }
5353a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg#endif
5363a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
5373a0844c8ef274a1dff8594164579a093435fb286Werner Lemberg
538c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Dump the array of linked edges. */
539c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
5408bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#ifdef __cplusplus
5418bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg  extern "C" {
5428bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#endif
5438bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  void
54452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg  af_glyph_hints_dump_edges( AF_GlyphHints  hints,
54552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                             FT_Bool        to_stdout )
5468bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
547b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_Int  dimension;
548b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
5498bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
5508bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( dimension = 1; dimension >= 0; dimension-- )
5518bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
552b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      AF_AxisHints  axis  = &hints->axis[dimension];
5538bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Edge       edges = axis->edges;
5548bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Edge       limit = edges + axis->num_edges;
5558bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Edge       edge;
5568bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
5577f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg      char  buf1[16], buf2[16];
5587f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
559b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
560b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      /*
561b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg       *  note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
562c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg       *        since they have a constant X coordinate.
563b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg       */
5641831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg      if ( dimension == AF_DIMENSION_HORZ )
5651831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg        AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
5661831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  "vertical",
5671831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  65536.0 * 64.0 / hints->x_scale,
5681831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  10.0 * hints->x_scale / 65536.0 / 64.0 ));
5691831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg      else
5701831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg        AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
5711831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  "horizontal",
5721831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  65536.0 * 64.0 / hints->y_scale,
5731831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  10.0 * hints->y_scale / 65536.0 / 64.0 ));
5741831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg
575fd5ae9599ad674db14a3730f2a07e11e0407b182Werner Lemberg      if ( axis->num_edges )
5768768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg      {
5771831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg        AF_DUMP(( "  index    pos     dir   link  serif"
5788768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg               /* "  XXXXX  XXXX.XX  XXXXX  XXXX  XXXXX" */
5791831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  "  blue    opos     pos       flags\n" ));
5808768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg               /* "    X   XXXX.XX  XXXX.XX  XXXXXXXXXXX" */
5818768536c89d6bb3e747bc69a7c2c1e58d2ed4aa9Werner Lemberg      }
582fd5ae9599ad674db14a3730f2a07e11e0407b182Werner Lemberg      else
58352166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg        AF_DUMP(( "  (none)\n" ));
5848bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
5858bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( edge = edges; edge < limit; edge++ )
5861831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg        AF_DUMP(( "  %5d  %7.2f  %5s  %4s  %5s"
5871831e6f0689c8de6340774de1ad00fd3bb6ff924Werner Lemberg                  "    %c   %7.2f  %7.2f  %11s\n",
588a632b5f4064873ab7f21b749f93332387bc47f76Werner Lemberg                  AF_INDEX_NUM( edge, edges ),
58952166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  (int)edge->opos / 64.0,
59052166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  af_dir_str( (AF_Direction)edge->dir ),
5917f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
5927f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg                  af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
5937f00fa64627bb57042ec62aa2ec938f679e097c1Werner Lemberg
59452166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  edge->blue_edge ? 'y' : 'n',
59552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  edge->opos / 64.0,
59652166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg                  edge->pos / 64.0,
59781e5ff53a89b454a3984a7181516dfb4cb22187aWerner Lemberg                  af_edge_flags_to_string( edge->flags ) ));
59852166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg      AF_DUMP(( "\n" ));
5998bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
6008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
6018bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#ifdef __cplusplus
6028bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg  }
6038bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg#endif
6048bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
60552166ab0a7e51ebedd144e8cac546a3f732c77b1Werner Lemberg#undef AF_DUMP
6068bd77f9030a718daf6526ce631e9e79fd62a95bdWerner Lemberg
607d503b1bce25d61a7ed6c262e013b6ceb3b627045Werner Lemberg#endif /* !FT_DEBUG_AUTOFIT */
6088bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
6098bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
610c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Compute the direction value of a given vector. */
611c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
6128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( AF_Direction )
6138bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_direction_compute( FT_Pos  dx,
6148bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                        FT_Pos  dy )
6158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
616281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner    FT_Pos        ll, ss;  /* long and short arm lengths */
617281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner    AF_Direction  dir;     /* candidate direction        */
6189fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner
619545c4e566e9785ba3c84062e211d21aeb5be989aWerner Lemberg
620281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner    if ( dy >= dx )
6219fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner    {
622281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner      if ( dy >= -dx )
6239fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      {
624281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        dir = AF_DIR_UP;
625281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ll  = dy;
626281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ss  = dx;
6279fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      }
628281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner      else
6299fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      {
630281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        dir = AF_DIR_LEFT;
631281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ll  = -dx;
632281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ss  = dy;
6339fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      }
6349fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner    }
635281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner    else /* dy < dx */
6369fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner    {
637281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner      if ( dy >= -dx )
6389fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      {
639281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        dir = AF_DIR_RIGHT;
640281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ll  = dx;
641281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ss  = dy;
6429fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      }
643281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner      else
6449fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      {
645281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        dir = AF_DIR_DOWN;
646886f4d049391993197b409a9038138a8208dd5feAlexei Podtelezhnikov (Алексей Подтележников)        ll  = -dy;
647281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner        ss  = dx;
6489fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner      }
6499fbd2ab8849d2517f2e7f4ce1af3c5a77893cbe5David Turner    }
650cee37a3b0a34c88caa981f9ef8cd3080d1fe0defWerner Lemberg
651886f4d049391993197b409a9038138a8208dd5feAlexei Podtelezhnikov (Алексей Подтележников)    /* return no direction if arm lengths do not differ enough       */
652e8da532d2a87a2210dc8ddc07966dcf01dd07bd7Werner Lemberg    /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
653886f4d049391993197b409a9038138a8208dd5feAlexei Podtelezhnikov (Алексей Подтележников)    /* the long arm is never negative                                */
654886f4d049391993197b409a9038138a8208dd5feAlexei Podtelezhnikov (Алексей Подтележников)    if ( ll <= 14 * FT_ABS( ss ) )
655281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner      dir = AF_DIR_NONE;
656cee37a3b0a34c88caa981f9ef8cd3080d1fe0defWerner Lemberg
657281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner    return dir;
6588bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
6598bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
6608bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
6618bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( void )
6628bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_glyph_hints_init( AF_GlyphHints  hints,
6638bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                       FT_Memory      memory )
6648bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
6656f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    /* no need to initialize the embedded items */
6666f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) );
6678bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->memory = memory;
6688bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
6698bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
6708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
6718bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( void )
6728bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_glyph_hints_done( AF_GlyphHints  hints )
6738bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
67416217e5f22127cbe3aed6375b446629228098b90Werner Lemberg    FT_Memory  memory;
675b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    int        dim;
6768bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
677b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
678b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    if ( !( hints && hints->memory ) )
679b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg      return;
680b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg
68116217e5f22127cbe3aed6375b446629228098b90Werner Lemberg    memory = hints->memory;
68216217e5f22127cbe3aed6375b446629228098b90Werner Lemberg
683b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    /*
684b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg     *  note that we don't need to free the segment and edge
685b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg     *  buffers since they are really within the hints->points array
686b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg     */
687b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
688b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    {
689b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg      AF_AxisHints  axis = &hints->axis[dim];
690b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
6918bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
692b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg      axis->num_segments = 0;
693b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg      axis->max_segments = 0;
69456ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      if ( axis->segments != axis->embedded.segments )
69556ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        FT_FREE( axis->segments );
696b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner
697b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg      axis->num_edges = 0;
698b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg      axis->max_edges = 0;
69956ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod      if ( axis->edges != axis->embedded.edges )
70056ddafa01ce251d2f1f3adde3b0f72dd8ff7a405Behdad Esfahbod        FT_FREE( axis->edges );
701b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    }
7028bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
7036f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    if ( hints->contours != hints->embedded.contours )
7046f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod      FT_FREE( hints->contours );
705b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    hints->max_contours = 0;
706b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    hints->num_contours = 0;
7078bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
7086f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    if ( hints->points != hints->embedded.points )
7096f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod      FT_FREE( hints->points );
710b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    hints->max_points = 0;
7116f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    hints->num_points = 0;
7128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
713b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg    hints->memory = NULL;
7148bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
7158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
7168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
717c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Reset metrics. */
718c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
719e664efadddc49bee32b337571e329f150006a84bDavid Turner  FT_LOCAL_DEF( void )
7203f91cb338b860307b4db874e703bbdf96a8750c6Werner Lemberg  af_glyph_hints_rescale( AF_GlyphHints    hints,
7213f91cb338b860307b4db874e703bbdf96a8750c6Werner Lemberg                          AF_StyleMetrics  metrics )
722e664efadddc49bee32b337571e329f150006a84bDavid Turner  {
7235b5f382b7d093e085d41be95cd73075acb5cd1a2David Turner    hints->metrics      = metrics;
7245b5f382b7d093e085d41be95cd73075acb5cd1a2David Turner    hints->scaler_flags = metrics->scaler.flags;
725e664efadddc49bee32b337571e329f150006a84bDavid Turner  }
726e664efadddc49bee32b337571e329f150006a84bDavid Turner
727e664efadddc49bee32b337571e329f150006a84bDavid Turner
728c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Recompute all AF_Point in AF_GlyphHints from the definitions */
729c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* in a source outline.                                         */
730c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
7318bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( FT_Error )
732b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  af_glyph_hints_reload( AF_GlyphHints  hints,
73309344385ee652cb8df33d35f07627c93e827f10dWerner Lemberg                         FT_Outline*    outline )
7348bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
735e3c9301581a450fae5db73a3b94b10ed6a0aeb5eWerner Lemberg    FT_Error   error   = FT_Err_Ok;
736b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    AF_Point   points;
737b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_UInt    old_max, new_max;
738b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_Fixed   x_scale = hints->x_scale;
739b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_Fixed   y_scale = hints->y_scale;
740b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_Pos     x_delta = hints->x_delta;
741b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_Pos     y_delta = hints->y_delta;
742b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    FT_Memory  memory  = hints->memory;
743b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
7448bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
745f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    hints->num_points   = 0;
746f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    hints->num_contours = 0;
7478bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
7488bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->axis[0].num_segments = 0;
7498bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->axis[0].num_edges    = 0;
7508bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->axis[1].num_segments = 0;
7518bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->axis[1].num_edges    = 0;
7528bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
753c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg    /* first of all, reallocate the contours array if necessary */
754b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    new_max = (FT_UInt)outline->n_contours;
755b57bb11ad015e2d41426d435d6e5ba692afba207Werner Lemberg    old_max = (FT_UInt)hints->max_contours;
7566f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod
7576f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    if ( new_max <= AF_CONTOURS_EMBEDDED )
758b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg    {
7594441f7b24675fbd7d91f794f5d54e6c1ff168439Werner Lemberg      if ( !hints->contours )
760b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg      {
761b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg        hints->contours     = hints->embedded.contours;
762b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg        hints->max_contours = AF_CONTOURS_EMBEDDED;
763b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg      }
764b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg    }
7656f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    else if ( new_max > old_max )
7668bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
7676f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod      if ( hints->contours == hints->embedded.contours )
7686f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod        hints->contours = NULL;
7696f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod
770b57bb11ad015e2d41426d435d6e5ba692afba207Werner Lemberg      new_max = ( new_max + 3 ) & ~3U; /* round up to a multiple of 4 */
7718bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
7728bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
7738bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        goto Exit;
7748bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
775b57bb11ad015e2d41426d435d6e5ba692afba207Werner Lemberg      hints->max_contours = (FT_Int)new_max;
7768bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
7778bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
778b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    /*
779f13516c8321b386227414be01e707563e852fc0dWerner Lemberg     *  then reallocate the points arrays if necessary --
780b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg     *  note that we reserve two additional point positions, used to
781b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg     *  hint metrics appropriately
782b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg     */
7838bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    new_max = (FT_UInt)( outline->n_points + 2 );
784b57bb11ad015e2d41426d435d6e5ba692afba207Werner Lemberg    old_max = (FT_UInt)hints->max_points;
7856f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod
7866f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    if ( new_max <= AF_POINTS_EMBEDDED )
787b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg    {
7884441f7b24675fbd7d91f794f5d54e6c1ff168439Werner Lemberg      if ( !hints->points )
789b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg      {
790b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg        hints->points     = hints->embedded.points;
791b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg        hints->max_points = AF_POINTS_EMBEDDED;
792b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg      }
793b6cb4997e8f0accd98b9589f29e4654e8002501fWerner Lemberg    }
7946f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod    else if ( new_max > old_max )
7958bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
7966f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod      if ( hints->points == hints->embedded.points )
7976f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod        hints->points = NULL;
7986f16b10019d7699aff4d5bbc64999a5fd1ce7457Behdad Esfahbod
799b57bb11ad015e2d41426d435d6e5ba692afba207Werner Lemberg      new_max = ( new_max + 2 + 7 ) & ~7U; /* round up to a multiple of 8 */
8008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
801b9c22aff61a90a17d8ace2dfda5094df31ac860cDavid Turner      if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
8028bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        goto Exit;
8038bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
804b57bb11ad015e2d41426d435d6e5ba692afba207Werner Lemberg      hints->max_points = (FT_Int)new_max;
8058bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
8068bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
8078bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->num_points   = outline->n_points;
8088bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->num_contours = outline->n_contours;
8098bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
810b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    /* We can't rely on the value of `FT_Outline.flags' to know the fill   */
811b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    /* direction used for a glyph, given that some fonts are broken (e.g., */
812b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    /* the Arphic ones).  We thus recompute it each time we need to.       */
813b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    /*                                                                     */
814b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
815b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg    hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
8168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
8178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
8188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
819b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
820b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg      hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
8218bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
8228bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
8238bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->x_scale = x_scale;
8248bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->y_scale = y_scale;
8258bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->x_delta = x_delta;
8268bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    hints->y_delta = y_delta;
8278bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
828d91eebda1c2eb722eeb63fce27fbbf243a701cf0David Turner    hints->xmin_delta = 0;
829d91eebda1c2eb722eeb63fce27fbbf243a701cf0David Turner    hints->xmax_delta = 0;
830d91eebda1c2eb722eeb63fce27fbbf243a701cf0David Turner
8318bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    points = hints->points;
8328bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( hints->num_points == 0 )
8338bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      goto Exit;
8348bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
8358bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
8368bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Point  point;
8378bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Point  point_limit = points + hints->num_points;
8388bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
839709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg      /* value 20 in `near_limit' is heuristic */
840709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg      FT_UInt  units_per_em = hints->metrics->scaler.face->units_per_EM;
841709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg      FT_Int   near_limit   = 20 * units_per_em / 2048;
842709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg
8438bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
844b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      /* compute coordinates & Bezier flags, next and prev */
8458bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
84649e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg        FT_Vector*  vec           = outline->points;
84749e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg        char*       tag           = outline->tags;
848709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg        FT_Short    endpoint      = outline->contours[0];
849709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg        AF_Point    end           = points + endpoint;
85049e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg        AF_Point    prev          = end;
851b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        FT_Int      contour_index = 0;
8528bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
85349e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
8548bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        for ( point = points; point < point_limit; point++, vec++, tag++ )
8558bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
856709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg          FT_Pos  out_x, out_y;
857709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg
858709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg
859faa21472b795eff3a5254b17ca10d0333d7d03feWerner Lemberg          point->in_dir  = (FT_Char)AF_DIR_NONE;
860faa21472b795eff3a5254b17ca10d0333d7d03feWerner Lemberg          point->out_dir = (FT_Char)AF_DIR_NONE;
861faa21472b795eff3a5254b17ca10d0333d7d03feWerner Lemberg
862750fa961c63e35913583c0d78e9bfa5bb3dfda59David Turner          point->fx = (FT_Short)vec->x;
863750fa961c63e35913583c0d78e9bfa5bb3dfda59David Turner          point->fy = (FT_Short)vec->y;
8648bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
8658bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
8668bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
867614a8f17c7bd931e99ebbf70308fe75ee27eb8e7Werner Lemberg          end->fx = (FT_Short)outline->points[endpoint].x;
868614a8f17c7bd931e99ebbf70308fe75ee27eb8e7Werner Lemberg          end->fy = (FT_Short)outline->points[endpoint].y;
869614a8f17c7bd931e99ebbf70308fe75ee27eb8e7Werner Lemberg
8708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          switch ( FT_CURVE_TAG( *tag ) )
8718bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          {
8728bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          case FT_CURVE_TAG_CONIC:
8738bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            point->flags = AF_FLAG_CONIC;
8748bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            break;
8758bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          case FT_CURVE_TAG_CUBIC:
8768bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            point->flags = AF_FLAG_CUBIC;
8778bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            break;
8788bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          default:
879c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg            point->flags = AF_FLAG_NONE;
8808bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          }
8818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
882709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg          out_x = point->fx - prev->fx;
883709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg          out_y = point->fy - prev->fy;
884709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg
885709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg          if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
886709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg            prev->flags |= AF_FLAG_NEAR;
887709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg
8888bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point->prev = prev;
889b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          prev->next  = point;
890b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          prev        = point;
891b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
89249e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg          if ( point == end )
8938bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          {
894b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            if ( ++contour_index < outline->n_contours )
8958bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            {
896709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg              endpoint = outline->contours[contour_index];
897614a8f17c7bd931e99ebbf70308fe75ee27eb8e7Werner Lemberg              end      = points + endpoint;
898614a8f17c7bd931e99ebbf70308fe75ee27eb8e7Werner Lemberg              prev     = end;
8998bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            }
9008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          }
9018bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
9028bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
9038bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
904c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg      /* set up the contours array */
9058bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
9068bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        AF_Point*  contour       = hints->contours;
9078bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        AF_Point*  contour_limit = contour + hints->num_contours;
9088bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        short*     end           = outline->contours;
9098bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        short      idx           = 0;
9108bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
9118bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
9128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        for ( ; contour < contour_limit; contour++, end++ )
9138bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
9148bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          contour[0] = points + idx;
9158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          idx        = (short)( end[0] + 1 );
9168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
9178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
9188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
9198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
9208a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        /*
9218a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  Compute directions of `in' and `out' vectors.
9228a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *
9238a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  Note that distances between points that are very near to each
924709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg         *  other are accumulated.  In other words, the auto-hinter either
9258a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  prepends the small vectors between near points to the first
926709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg         *  non-near vector, or the sum of small vector lengths exceeds a
927709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg         *  threshold, thus `grouping' the small vectors.  All intermediate
928709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg         *  points are tagged as weak; the directions are adjusted also to
929709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg         *  be equal to the accumulated one.
9308a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         */
9318a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
932709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg        FT_Int  near_limit2 = 2 * near_limit - 1;
933cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
9348a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        AF_Point*  contour;
9358a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        AF_Point*  contour_limit = hints->contours + hints->num_contours;
93649e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
9378a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
9388a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        for ( contour = hints->contours; contour < contour_limit; contour++ )
9398bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
9408a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          AF_Point  first = *contour;
9418a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          AF_Point  next, prev, curr;
9428a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
9438a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          FT_Pos  out_x, out_y;
9448a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
94549e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
9468a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          /* since the first point of a contour could be part of a */
9478a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          /* series of near points, go backwards to find the first */
9488a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          /* non-near point and adjust `first'                     */
9498a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
9508a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          point = first;
9518a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          prev  = first->prev;
9528a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
9538a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          while ( prev != first )
954b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          {
9558a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_x = point->fx - prev->fx;
9568a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_y = point->fy - prev->fy;
957cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
95807e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg            /*
95907e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             *  We use Taxicab metrics to measure the vector length.
96007e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             *
96107e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             *  Note that the accumulated distances so far could have the
96207e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             *  opposite direction of the distance measured here.  For this
96307e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             *  reason we use `near_limit2' for the comparison to get a
96407e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             *  non-near point even in the worst case.
96507e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg             */
96607e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg            if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 )
9678a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              break;
968cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
9698a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            point = prev;
9708a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            prev  = prev->prev;
9718a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          }
972cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
9738a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          /* adjust first point */
9748a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          first = point;
975cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
9768a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          /* now loop over all points of the contour to get */
9778a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          /* `in' and `out' vector directions               */
978cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
979709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg          curr = first;
98007e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg
98107e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg          /*
98207e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           *  We abuse the `u' and `v' fields to store index deltas to the
98307e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           *  next and previous non-near point, respectively.
98407e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           *
98507e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           *  To avoid problems with not having non-near points, we point to
98607e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           *  `first' by default as the next non-near point.
98707e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           *
98807e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg           */
98907e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg          curr->u  = (FT_Pos)( first - curr );
99007e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg          first->v = -curr->u;
99107e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg
9928a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          out_x = 0;
9938a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          out_y = 0;
994cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
99567b912d2fa17caa921f513cae180c7aae28b1bc6Alexei Podtelezhnikov (Алексей Подтележников)          next = first;
99667b912d2fa17caa921f513cae180c7aae28b1bc6Alexei Podtelezhnikov (Алексей Подтележников)          do
9978a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          {
9988a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            AF_Direction  out_dir;
999cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
1000cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
100167b912d2fa17caa921f513cae180c7aae28b1bc6Alexei Podtelezhnikov (Алексей Подтележников)            point = next;
1002709486db7f5684329bdf39156fadf6bdff6d8fddWerner Lemberg            next  = point->next;
1003cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
10048a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_x += next->fx - point->fx;
10058a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_y += next->fy - point->fy;
10068a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10078a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
10088a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            {
10098a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              next->flags |= AF_FLAG_WEAK_INTERPOLATION;
10108a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              continue;
1011cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            }
1012cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
10138a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            curr->u = (FT_Pos)( next - curr );
10148a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            next->v = -curr->u;
10158a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10168a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_dir = af_direction_compute( out_x, out_y );
10178a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10188a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            /* adjust directions for all points inbetween; */
10198a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            /* the loop also updates position of `curr'    */
10208a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            curr->out_dir = (FT_Char)out_dir;
10218a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            for ( curr = curr->next; curr != next; curr = curr->next )
10228a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            {
10238a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              curr->in_dir  = (FT_Char)out_dir;
10248a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              curr->out_dir = (FT_Char)out_dir;
10258a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            }
10268a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            next->in_dir = (FT_Char)out_dir;
10278a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
102807e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg            curr->u  = (FT_Pos)( first - curr );
102907e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg            first->v = -curr->u;
103007e7b8affeef35383fdef09ebe817b568f71249aWerner Lemberg
10318a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_x = 0;
10328a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_y = 0;
103367b912d2fa17caa921f513cae180c7aae28b1bc6Alexei Podtelezhnikov (Алексей Подтележников)
103467b912d2fa17caa921f513cae180c7aae28b1bc6Alexei Podtelezhnikov (Алексей Подтележников)          } while ( next != first );
10358a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        }
10368bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
10378a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        /*
10388a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  The next step is to `simplify' an outline's topology so that we
10398a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  can identify local extrema more reliably: A series of
10408a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  non-horizontal or non-vertical vectors pointing into the same
10418a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  quadrant are handled as a single, long vector.  From a
10428a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  topological point of the view, the intermediate points are of no
10438a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  interest and thus tagged as weak.
10448a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         */
10458bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
10468a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        for ( point = points; point < point_limit; point++ )
10478a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        {
10488a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
10498a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            continue;
1050cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
10518a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          if ( point->in_dir  == AF_DIR_NONE &&
10528a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg               point->out_dir == AF_DIR_NONE )
1053cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg          {
10548a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            /* check whether both vectors point into the same quadrant */
10558a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10568a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            FT_Pos  in_x, in_y;
10578a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            FT_Pos  out_x, out_y;
10588a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10598a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            AF_Point  next_u = point + point->u;
10608a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            AF_Point  prev_v = point + point->v;
10618a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10628a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10638a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            in_x = point->fx - prev_v->fx;
10648a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            in_y = point->fy - prev_v->fy;
10658a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10668a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_x = next_u->fx - point->fx;
10678a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            out_y = next_u->fy - point->fy;
1068cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg
10698a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 )
10708a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            {
10718a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              /* yes, so tag current point as weak */
10728a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              /* and update index deltas           */
10738a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10748a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              point->flags |= AF_FLAG_WEAK_INTERPOLATION;
10758a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
10768a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              prev_v->u = (FT_Pos)( next_u - prev_v );
10778a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              next_u->v = -prev_v->u;
10788a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            }
10798a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          }
10808a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        }
10818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
10828a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        /*
10838a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  Finally, check for remaining weak points.  Everything else not
10848a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  collected in edges so far is then implicitly classified as strong
10858a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         *  points.
10868a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg         */
10878bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
10888a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        for ( point = points; point < point_limit; point++ )
10898a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg        {
10908a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg          if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
10918a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg            continue;
1092c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
1093b6978dd0c949aedbaa1773724e19fec47a34a29cWerner Lemberg          if ( point->flags & AF_FLAG_CONTROL )
10948bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          {
1095cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            /* control points are always weak */
10968bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          Is_Weak_Point:
10978bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            point->flags |= AF_FLAG_WEAK_INTERPOLATION;
10988bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          }
10998bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          else if ( point->out_dir == point->in_dir )
11008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          {
1101281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner            if ( point->out_dir != AF_DIR_NONE )
1102cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            {
1103df41fe57917df4ac239fdbc0877c24049aaf8c90Werner Lemberg              /* current point lies on a horizontal or          */
1104df41fe57917df4ac239fdbc0877c24049aaf8c90Werner Lemberg              /* vertical segment (but doesn't start or end it) */
1105281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner              goto Is_Weak_Point;
1106cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            }
1107281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner
1108cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            {
11098a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              AF_Point  next_u = point + point->u;
11108a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              AF_Point  prev_v = point + point->v;
11118a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
11128a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
11138a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              if ( ft_corner_is_flat( point->fx  - prev_v->fx,
11148a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                                      point->fy  - prev_v->fy,
11158a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                                      next_u->fx - point->fx,
11168a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                                      next_u->fy - point->fy ) )
11178a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              {
11188a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                /* either the `in' or the `out' vector is much more  */
11198a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                /* dominant than the other one, so tag current point */
11208a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                /* as weak and update index deltas                   */
11218a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
11228a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                prev_v->u = (FT_Pos)( next_u - prev_v );
11238a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                next_u->v = -prev_v->u;
11248a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg
11258a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg                goto Is_Weak_Point;
11268a94b1efd6cfe76ffbd66e9315542c9438a34722Werner Lemberg              }
1127cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            }
11288bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          }
11298bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          else if ( point->in_dir == -point->out_dir )
1130cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg          {
1131cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg            /* current point forms a spike */
11328bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            goto Is_Weak_Point;
1133cc25e3ae12216380179506b9d5d9c25293966708Werner Lemberg          }
11348bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
11358bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
11368bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
11378bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
11388bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  Exit:
11398bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    return error;
11408bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
11418bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
11428bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1143c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Store the hinted outline in an FT_Outline structure. */
1144c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
11458bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( void )
1146b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  af_glyph_hints_save( AF_GlyphHints  hints,
1147b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg                       FT_Outline*    outline )
11488bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
11498bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Point    point = hints->points;
11508bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Point    limit = point + hints->num_points;
11518bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    FT_Vector*  vec   = outline->points;
11528bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    char*       tag   = outline->tags;
11538bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1154b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
11558bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( ; point < limit; point++, vec++, tag++ )
11568bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
1157750fa961c63e35913583c0d78e9bfa5bb3dfda59David Turner      vec->x = point->x;
1158750fa961c63e35913583c0d78e9bfa5bb3dfda59David Turner      vec->y = point->y;
11598bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
11608bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      if ( point->flags & AF_FLAG_CONIC )
11618bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        tag[0] = FT_CURVE_TAG_CONIC;
11628bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      else if ( point->flags & AF_FLAG_CUBIC )
11638bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        tag[0] = FT_CURVE_TAG_CUBIC;
11648bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      else
11658bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        tag[0] = FT_CURVE_TAG_ON;
11668bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
11678bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
11688bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
11698bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1170b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  /****************************************************************
1171b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *
1172b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *                     EDGE POINT GRID-FITTING
1173b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *
1174b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   ****************************************************************/
11758bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
11768bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1177c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Align all points of an edge to the same coordinate value, */
1178c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* either horizontally or vertically.                        */
1179c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
11808bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( void )
11818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
11828bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                                    AF_Dimension   dim )
11838bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
1184b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    AF_AxisHints  axis          = & hints->axis[dim];
1185b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    AF_Segment    segments      = axis->segments;
1186b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    AF_Segment    segment_limit = segments + axis->num_segments;
1187b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    AF_Segment    seg;
11888bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1189b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
1190b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    if ( dim == AF_DIMENSION_HORZ )
11918bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
1192b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      for ( seg = segments; seg < segment_limit; seg++ )
11938bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
1194b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        AF_Edge   edge = seg->edge;
1195b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        AF_Point  point, first, last;
1196b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
11978bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
11984441f7b24675fbd7d91f794f5d54e6c1ff168439Werner Lemberg        if ( !edge )
1199b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          continue;
12008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1201b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        first = seg->first;
1202b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        last  = seg->last;
1203b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        point = first;
12048bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        for (;;)
12058bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
1206b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          point->x      = edge->pos;
1207b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          point->flags |= AF_FLAG_TOUCH_X;
12088bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1209b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          if ( point == last )
12108bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            break;
12118bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point = point->next;
12138bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
1214b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      }
1215b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    }
1216b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    else
1217b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    {
1218b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      for ( seg = segments; seg < segment_limit; seg++ )
1219b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      {
1220b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        AF_Edge   edge = seg->edge;
1221b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        AF_Point  point, first, last;
1222b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1223b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
12244441f7b24675fbd7d91f794f5d54e6c1ff168439Werner Lemberg        if ( !edge )
1225b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          continue;
12268bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1227b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        first = seg->first;
1228b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        last  = seg->last;
1229b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        point = first;
1230b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        for (;;)
1231b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        {
1232b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          point->y      = edge->pos;
1233b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          point->flags |= AF_FLAG_TOUCH_Y;
12348bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1235b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          if ( point == last )
1236b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            break;
1237b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1238b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          point = point->next;
1239b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        }
1240b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      }
12418bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
12428bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
12438bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12448bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1245b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  /****************************************************************
1246b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *
1247b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *                    STRONG POINT INTERPOLATION
1248b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *
1249b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   ****************************************************************/
12508bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12518bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1252c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Hint the strong points -- this is equivalent to the TrueType `IP' */
1253c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* hinting instruction.                                              */
1254b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
12558bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( void )
12568bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
12578bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                                      AF_Dimension   dim )
12588bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
12598bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Point      points      = hints->points;
12608bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Point      point_limit = points + hints->num_points;
12618bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_AxisHints  axis        = &hints->axis[dim];
12628bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Edge       edges       = axis->edges;
12638bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Edge       edge_limit  = edges + axis->num_edges;
126481e5ff53a89b454a3984a7181516dfb4cb22187aWerner Lemberg    FT_UInt       touch_flag;
12658bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12668bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12678bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( dim == AF_DIMENSION_HORZ )
12688bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      touch_flag = AF_FLAG_TOUCH_X;
12698bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    else
12708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      touch_flag  = AF_FLAG_TOUCH_Y;
12718bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12728bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( edges < edge_limit )
12738bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
12748bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Point  point;
12758bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      AF_Edge   edge;
12768bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1277b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
12788bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( point = points; point < point_limit; point++ )
12798bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
12808bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        FT_Pos  u, ou, fu;  /* point position */
12818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        FT_Pos  delta;
12828bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12838bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12848bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        if ( point->flags & touch_flag )
12858bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          continue;
12868bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1287b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg        /* if this point is candidate to weak interpolation, we       */
12888bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        /* interpolate it after all strong points have been processed */
1289b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
12905b68e4fb60421038b58cceb8ef86e27ebf8625d7Werner Lemberg        if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) )
12918bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          continue;
12928bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
12938bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        if ( dim == AF_DIMENSION_VERT )
12948bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
12958bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u  = point->fy;
12968bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          ou = point->oy;
12978bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
12988bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        else
12998bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
13008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u  = point->fx;
13018bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          ou = point->ox;
13028bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
13038bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13048bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        fu = u;
13058bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13068bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        /* is the point before the first edge? */
13078bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        edge  = edges;
13088bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        delta = edge->fpos - u;
13098bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        if ( delta >= 0 )
13108bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
13118bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u = edge->pos - ( edge->opos - ou );
13128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          goto Store_Point;
13138bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
13148bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        /* is the point after the last edge? */
13168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        edge  = edge_limit - 1;
13178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        delta = u - edge->fpos;
13188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        if ( delta >= 0 )
13198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
13208bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u = edge->pos + ( ou - edge->opos );
13218bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          goto Store_Point;
13228bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
13238bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13248bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
1325b56680240a10db7e13cf5925a61946626d269c84Suzuki, Toshiya (鈴木俊哉)          FT_PtrDist  min, max, mid;
1326b56680240a10db7e13cf5925a61946626d269c84Suzuki, Toshiya (鈴木俊哉)          FT_Pos      fpos;
13278bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13288bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13298bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          /* find enclosing edges */
13308bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          min = 0;
13318bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          max = edge_limit - edges;
13328bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1333b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner#if 1
1334c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg          /* for a small number of edges, a linear search is better */
1335b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          if ( max <= 8 )
1336b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          {
1337b56680240a10db7e13cf5925a61946626d269c84Suzuki, Toshiya (鈴木俊哉)            FT_PtrDist  nn;
1338b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1339c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
1340b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            for ( nn = 0; nn < max; nn++ )
1341b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner              if ( edges[nn].fpos >= u )
1342b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner                break;
1343b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1344b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            if ( edges[nn].fpos == u )
1345b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            {
1346b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner              u = edges[nn].pos;
1347b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner              goto Store_Point;
1348b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            }
1349b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            min = nn;
1350b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          }
1351b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          else
1352b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner#endif
13538bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          while ( min < max )
13548bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          {
13558bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            mid  = ( max + min ) >> 1;
13568bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            edge = edges + mid;
13578bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            fpos = edge->fpos;
13588bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13598bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            if ( u < fpos )
13608bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg              max = mid;
13618bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            else if ( u > fpos )
13628bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg              min = mid + 1;
13638bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            else
13648bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            {
13658bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg              /* we are on the edge */
13668bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg              u = edge->pos;
13678bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg              goto Store_Point;
13688bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            }
13698bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          }
13708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1371c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg          /* point is not on an edge */
13728bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          {
13738bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            AF_Edge  before = edges + min - 1;
13748bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            AF_Edge  after  = edges + min + 0;
13758bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13768bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13778bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            /* assert( before && after && before != after ) */
13788bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            if ( before->scale == 0 )
13798bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg              before->scale = FT_DivFix( after->pos - before->pos,
13808bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                                         after->fpos - before->fpos );
13818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13828bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg            u = before->pos + FT_MulFix( fu - before->fpos,
13838bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                                         before->scale );
13848bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          }
13858bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
13868bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13878bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      Store_Point:
13888bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        /* save the point position */
13898bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        if ( dim == AF_DIMENSION_HORZ )
13908bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point->x = u;
13918bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        else
13928bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point->y = u;
13938bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13948bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->flags |= touch_flag;
13958bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
13968bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
13978bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
13988bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
13998bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1400b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg  /****************************************************************
1401b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *
1402b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *                    WEAK POINT INTERPOLATION
1403b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   *
1404b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg   ****************************************************************/
1405b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
14068bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1407c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Shift the original coordinates of all points between `p1' and */
1408c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* `p2' to get hinted coordinates, using the same difference as  */
1409c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* given by `ref'.                                               */
1410c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
14118bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  static void
14128bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_iup_shift( AF_Point  p1,
14138bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                AF_Point  p2,
14148bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                AF_Point  ref )
14158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
14168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Point  p;
14178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    FT_Pos    delta = ref->u - ref->v;
14188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1419c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
142049e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg    if ( delta == 0 )
1421b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      return;
14228bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14238bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( p = p1; p < ref; p++ )
14248bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      p->u = p->v + delta;
14258bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14268bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( p = ref + 1; p <= p2; p++ )
14278bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      p->u = p->v + delta;
14288bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
14298bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14308bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1431c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Interpolate the original coordinates of all points between `p1' and  */
1432c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the       */
1433c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* reference points.  The `u' and `v' members are the current and       */
1434c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* original coordinate values, respectively.                            */
1435c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /*                                                                      */
1436c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Details can be found in the TrueType bytecode specification.         */
1437c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
14388bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  static void
14398bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_iup_interp( AF_Point  p1,
14408bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                 AF_Point  p2,
14418bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                 AF_Point  ref1,
14428bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                 AF_Point  ref2 )
14438bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
14448bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    AF_Point  p;
1445409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    FT_Pos    u, v1, v2, u1, u2, d1, d2;
14468bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14478bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14488bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( p1 > p2 )
14498bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      return;
14508bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1451409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    if ( ref1->v > ref2->v )
14528bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
1453409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)      p    = ref1;
1454409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)      ref1 = ref2;
1455409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)      ref2 = p;
14568bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
14578bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1458409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    v1 = ref1->v;
1459409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    v2 = ref2->v;
1460409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    u1 = ref1->u;
1461409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    u2 = ref2->u;
1462409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    d1 = u1 - v1;
1463409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    d2 = u2 - v2;
1464409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)
1465409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)    if ( u1 == u2 || v1 == v2 )
14668bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
14678bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( p = p1; p <= p2; p++ )
14688bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
14698bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        u = p->v;
14708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14718bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        if ( u <= v1 )
14728bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u += d1;
14738bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        else if ( u >= v2 )
14748bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u += d2;
14758bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        else
1476409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)          u = u1;
14778bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14788bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        p->u = u;
14798bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
14808bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
14818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    else
14828bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
1483409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)      FT_Fixed  scale = FT_DivFix( u2 - u1, v2 - v1 );
1484409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)
1485a678560dc23f7dfa6d6cda8d0d35be37c04713e2Werner Lemberg
14868bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( p = p1; p <= p2; p++ )
14878bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
14888bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        u = p->v;
14898bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1490409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)        if ( u <= v1 )
14918bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          u += d1;
1492409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)        else if ( u >= v2 )
1493409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)          u += d2;
14948bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        else
1495409149527173a089278fd6d1b84a2a8dc911c9a6Alexei Podtelezhnikov (Алексей Подтележников)          u = u1 + FT_MulFix( u - v1, scale );
14968bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
14978bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        p->u = u;
14988bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
14998bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
15008bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
15018bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15028bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1503c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* Hint the weak points -- this is equivalent to the TrueType `IUP' */
1504c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg  /* hinting instruction.                                             */
1505c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
15068bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  FT_LOCAL_DEF( void )
15078bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
15088bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg                                    AF_Dimension   dim )
15098bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  {
1510f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point   points        = hints->points;
1511f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point   point_limit   = points + hints->num_points;
1512f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point*  contour       = hints->contours;
1513f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point*  contour_limit = contour + hints->num_contours;
151481e5ff53a89b454a3984a7181516dfb4cb22187aWerner Lemberg    FT_UInt    touch_flag;
1515f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point   point;
1516f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point   end_point;
1517f13516c8321b386227414be01e707563e852fc0dWerner Lemberg    AF_Point   first_point;
15188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15208bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    /* PASS 1: Move segment points to edge positions */
15218bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15228bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( dim == AF_DIMENSION_HORZ )
15238bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
15248bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      touch_flag = AF_FLAG_TOUCH_X;
15258bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15268bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( point = points; point < point_limit; point++ )
15278bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
15288bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->u = point->x;
15298bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->v = point->ox;
15308bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
15318bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
15328bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    else
15338bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
15348bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      touch_flag = AF_FLAG_TOUCH_Y;
15358bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15368bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( point = points; point < point_limit; point++ )
15378bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
15388bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->u = point->y;
15398bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->v = point->oy;
15408bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
15418bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
15428bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
15438bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    for ( ; contour < contour_limit; contour++ )
15448bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
154549e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg      AF_Point  first_touched, last_touched;
154649e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg
1547b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
15488bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      point       = *contour;
15498bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      end_point   = point->prev;
15508bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      first_point = point;
15518bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1552b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      /* find first touched point */
1553b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      for (;;)
1554b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      {
1555b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        if ( point > end_point )  /* no touched point in contour */
1556b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          goto NextContour;
1557b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1558b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        if ( point->flags & touch_flag )
1559b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          break;
1560b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
15618bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point++;
1562b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      }
15638bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1564b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      first_touched = point;
1565b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1566b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      for (;;)
15678bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      {
1568c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg        FT_ASSERT( point <= end_point                 &&
156949e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg                   ( point->flags & touch_flag ) != 0 );
15708bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1571c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg        /* skip any touched neighbours */
1572c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg        while ( point < end_point                    &&
1573c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg                ( point[1].flags & touch_flag ) != 0 )
1574b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          point++;
15758bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1576b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        last_touched = point;
1577b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1578b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        /* find the next touched point, if any */
1579c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg        point++;
1580b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        for (;;)
15818bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        {
1582b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          if ( point > end_point )
1583b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            goto EndContour;
1584b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
158549e18b8d5f7df1c931e07f94615b375a0399162aWerner Lemberg          if ( ( point->flags & touch_flag ) != 0 )
1586b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner            break;
1587b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
15888bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg          point++;
15898bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        }
15908bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
1591b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        /* interpolate between last_touched and point */
1592b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        af_iup_interp( last_touched + 1, point - 1,
1593b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner                       last_touched, point );
15948bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      }
1595b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1596b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    EndContour:
1597b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      /* special case: only one point was touched */
1598b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      if ( last_touched == first_touched )
1599b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        af_iup_shift( first_point, end_point, first_touched );
1600c5bda503b9b15bdd042e2c9696f2b1975f49d98cWerner Lemberg
1601b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      else /* interpolate the last part */
1602b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      {
1603b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        if ( last_touched < end_point )
1604b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          af_iup_interp( last_touched + 1, end_point,
1605b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner                         last_touched, first_touched );
1606b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1607b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner        if ( first_touched > points )
1608b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner          af_iup_interp( first_point, first_touched - 1,
1609b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner                         last_touched, first_touched );
1610b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      }
1611b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner
1612b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner    NextContour:
1613b792017fafd1e99e8ca81811a58b09dc562b48c9David Turner      ;
16148bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
16158bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg
16168bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    /* now save the interpolated values back to x/y */
16178bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    if ( dim == AF_DIMENSION_HORZ )
16188bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
16198bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( point = points; point < point_limit; point++ )
16208bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->x = point->u;
16218bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
16228bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    else
16238bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    {
16248bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg      for ( point = points; point < point_limit; point++ )
16258bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg        point->y = point->u;
16268bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg    }
16278bb07e6386ef47f9f9d2bd28a36dda8784530727Werner Lemberg  }
1628b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
16291be9ebf5f909d7fc026eb185a8b5eeb6a372afe6Werner Lemberg
1630576fc2c06e9b34db235b18cc8ae20c3ce789fb65Werner Lemberg#ifdef AF_CONFIG_OPTION_USE_WARPER
16311be9ebf5f909d7fc026eb185a8b5eeb6a372afe6Werner Lemberg
16327ad15d59265410139078d835181565b771e34c05Werner Lemberg  /* Apply (small) warp scale and warp delta for given dimension. */
16337ad15d59265410139078d835181565b771e34c05Werner Lemberg
1634bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner  FT_LOCAL_DEF( void )
1635bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner  af_glyph_hints_scale_dim( AF_GlyphHints  hints,
1636bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner                            AF_Dimension   dim,
1637bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner                            FT_Fixed       scale,
1638bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner                            FT_Pos         delta )
1639bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner  {
1640bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    AF_Point  points       = hints->points;
1641bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    AF_Point  points_limit = points + hints->num_points;
1642bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    AF_Point  point;
1643281679de8591f6884ea904c9c812e520ba3cc5dcDavid Turner
16441be9ebf5f909d7fc026eb185a8b5eeb6a372afe6Werner Lemberg
1645bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    if ( dim == AF_DIMENSION_HORZ )
1646bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    {
1647bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner      for ( point = points; point < points_limit; point++ )
1648bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner        point->x = FT_MulFix( point->fx, scale ) + delta;
1649bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    }
1650bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    else
1651bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    {
1652bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner      for ( point = points; point < points_limit; point++ )
1653bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner        point->y = FT_MulFix( point->fy, scale ) + delta;
1654bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner    }
1655bb4edc923597aa48da0d0ac217e7a80d41e77f0dDavid Turner  }
16561be9ebf5f909d7fc026eb185a8b5eeb6a372afe6Werner Lemberg
1657576fc2c06e9b34db235b18cc8ae20c3ce789fb65Werner Lemberg#endif /* AF_CONFIG_OPTION_USE_WARPER */
1658b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg
1659b19b0810cd887a4c1036121b0d3e9bb93278a0a9Werner Lemberg/* END */
1660