godot/thirdparty/freetype/src/autofit/afhints.c

/****************************************************************************
 *
 * afhints.c
 *
 *   Auto-fitter hinting routines (body).
 *
 * Copyright (C) 2003-2023 by
 * David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 * This file is part of the FreeType project, and may only be used,
 * modified, and distributed under the terms of the FreeType project
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
 * this file you indicate that you have read the license and
 * understand and accept it fully.
 *
 */


#include "afhints.h"
#include "aferrors.h"
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/ftdebug.h>


  /**************************************************************************
   *
   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
   * messages during execution.
   */
#undef  FT_COMPONENT
#define FT_COMPONENT


  FT_LOCAL_DEF( void )
  af_sort_pos( FT_UInt  count,
               FT_Pos*  table )
  {}


  FT_LOCAL_DEF( void )
  af_sort_and_quantize_widths( FT_UInt*  count,
                               AF_Width  table,
                               FT_Pos    threshold )
  {}

  /* Get new segment for given axis. */

  FT_LOCAL_DEF( FT_Error )
  af_axis_hints_new_segment( AF_AxisHints  axis,
                             FT_Memory     memory,
                             AF_Segment   *asegment )
  {}


  /* Get new edge for given axis, direction, and position, */
  /* without initializing the edge itself.                 */

  FT_LOCAL_DEF( FT_Error )
  af_axis_hints_new_edge( AF_AxisHints  axis,
                          FT_Int        fpos,
                          AF_Direction  dir,
                          FT_Bool       top_to_bottom_hinting,
                          FT_Memory     memory,
                          AF_Edge      *anedge )
  {}


#ifdef FT_DEBUG_AUTOFIT

#include FT_CONFIG_STANDARD_LIBRARY_H

  /* The dump functions are used in the `ftgrid' demo program, too. */
#define AF_DUMP


  static const char*
  af_dir_str( AF_Direction  dir )
  {
    const char*  result;


    switch ( dir )
    {
    case AF_DIR_UP:
      result = "up";
      break;
    case AF_DIR_DOWN:
      result = "down";
      break;
    case AF_DIR_LEFT:
      result = "left";
      break;
    case AF_DIR_RIGHT:
      result = "right";
      break;
    default:
      result = "none";
    }

    return result;
  }


#define AF_INDEX_NUM


  static char*
  af_print_idx( char*   p,
                size_t  n,
                int     idx )
  {
    if ( idx == -1 )
    {
      p[0] = '-';
      p[1] = '-';
      p[2] = '\0';
    }
    else
      ft_snprintf( p, n, "%d", idx );

    return p;
  }


  static int
  af_get_segment_index( AF_GlyphHints  hints,
                        int            point_idx,
                        int            dimension )
  {
    AF_AxisHints  axis     = &hints->axis[dimension];
    AF_Point      point    = hints->points + point_idx;
    AF_Segment    segments = axis->segments;
    AF_Segment    limit    = segments + axis->num_segments;
    AF_Segment    segment;


    for ( segment = segments; segment < limit; segment++ )
    {
      if ( segment->first <= segment->last )
      {
        if ( point >= segment->first && point <= segment->last )
          break;
      }
      else
      {
        AF_Point  p = segment->first;


        for (;;)
        {
          if ( point == p )
            goto Exit;

          if ( p == segment->last )
            break;

          p = p->next;
        }
      }
    }

  Exit:
    if ( segment == limit )
      return -1;

    return (int)( segment - segments );
  }


  static int
  af_get_edge_index( AF_GlyphHints  hints,
                     int            segment_idx,
                     int            dimension )
  {
    AF_AxisHints  axis    = &hints->axis[dimension];
    AF_Edge       edges   = axis->edges;
    AF_Segment    segment = axis->segments + segment_idx;


    return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
  }


  static int
  af_get_strong_edge_index( AF_GlyphHints  hints,
                            AF_Edge*       strong_edges,
                            int            dimension )
  {
    AF_AxisHints  axis  = &hints->axis[dimension];
    AF_Edge       edges = axis->edges;


    return AF_INDEX_NUM( strong_edges[dimension], edges );
  }


#ifdef __cplusplus
  extern "C" {
#endif
  void
  af_glyph_hints_dump_points( AF_GlyphHints  hints,
                              FT_Bool        to_stdout )
  {
    AF_Point   points  = hints->points;
    AF_Point   limit   = points + hints->num_points;
    AF_Point*  contour = hints->contours;
    AF_Point*  climit  = contour + hints->num_contours;
    AF_Point   point;


    AF_DUMP(( "Table of points:\n" ));

    if ( hints->num_points )
    {
      AF_DUMP(( "  index  hedge  hseg  vedge  vseg  flags "
             /* "  XXXXX  XXXXX XXXXX  XXXXX XXXXX  XXXXXX" */
                "  xorg  yorg  xscale  yscale   xfit    yfit "
             /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
                "  hbef  haft  vbef  vaft" ));
             /* " XXXXX XXXXX XXXXX XXXXX" */
    }
    else
      AF_DUMP(( "  (none)\n" ));

    for ( point = points; point < limit; point++ )
    {
      int  point_idx     = AF_INDEX_NUM( point, points );
      int  segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
      int  segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );

      char  buf1[16], buf2[16], buf3[16], buf4[16];
      char  buf5[16], buf6[16], buf7[16], buf8[16];


      /* insert extra newline at the beginning of a contour */
      if ( contour < climit && *contour == point )
      {
        AF_DUMP(( "\n" ));
        contour++;
      }

      AF_DUMP(( "  %5d  %5s %5s  %5s %5s  %s"
                " %5d %5d %7.2f %7.2f %7.2f %7.2f"
                " %5s %5s %5s %5s\n",
                point_idx,
                af_print_idx( buf1, 16,
                              af_get_edge_index( hints, segment_idx_1, 1 ) ),
                af_print_idx( buf2, 16, segment_idx_1 ),
                af_print_idx( buf3, 16,
                              af_get_edge_index( hints, segment_idx_0, 0 ) ),
                af_print_idx( buf4, 16, segment_idx_0 ),
                ( point->flags & AF_FLAG_NEAR )
                  ? " near "
                  : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
                    ? " weak "
                    : "strong",

                point->fx,
                point->fy,
                (double)point->ox / 64,
                (double)point->oy / 64,
                (double)point->x / 64,
                (double)point->y / 64,

                af_print_idx( buf5, 16,
                              af_get_strong_edge_index( hints,
                                                        point->before,
                                                        1 ) ),
                af_print_idx( buf6, 16,
                              af_get_strong_edge_index( hints,
                                                        point->after,
                                                        1 ) ),
                af_print_idx( buf7, 16,
                              af_get_strong_edge_index( hints,
                                                        point->before,
                                                        0 ) ),
                af_print_idx( buf8, 16,
                              af_get_strong_edge_index( hints,
                                                        point->after,
                                                        0 ) ) ));
    }
    AF_DUMP(( "\n" ));
  }
#ifdef __cplusplus
  }
#endif


  static const char*
  af_edge_flags_to_string( FT_UInt  flags )
  {
    static char  temp[32];
    int          pos = 0;


    if ( flags & AF_EDGE_ROUND )
    {
      ft_memcpy( temp + pos, "round", 5 );
      pos += 5;
    }
    if ( flags & AF_EDGE_SERIF )
    {
      if ( pos > 0 )
        temp[pos++] = ' ';
      ft_memcpy( temp + pos, "serif", 5 );
      pos += 5;
    }
    if ( pos == 0 )
      return "normal";

    temp[pos] = '\0';

    return temp;
  }


  /* Dump the array of linked segments. */

#ifdef __cplusplus
  extern "C" {
#endif
  void
  af_glyph_hints_dump_segments( AF_GlyphHints  hints,
                                FT_Bool        to_stdout )
  {
    FT_Int  dimension;


    for ( dimension = 1; dimension >= 0; dimension-- )
    {
      AF_AxisHints  axis     = &hints->axis[dimension];
      AF_Point      points   = hints->points;
      AF_Edge       edges    = axis->edges;
      AF_Segment    segments = axis->segments;
      AF_Segment    limit    = segments + axis->num_segments;
      AF_Segment    seg;

      char  buf1[16], buf2[16], buf3[16];


      AF_DUMP(( "Table of %s segments:\n",
                dimension == AF_DIMENSION_HORZ ? "vertical"
                                               : "horizontal" ));
      if ( axis->num_segments )
      {
        AF_DUMP(( "  index   pos   delta   dir   from   to "
               /* "  XXXXX  XXXXX  XXXXX  XXXXX  XXXX  XXXX" */
                  "  link  serif  edge"
               /* "  XXXX  XXXXX  XXXX" */
                  "  height  extra     flags\n" ));
               /* "  XXXXXX  XXXXX  XXXXXXXXXXX" */
      }
      else
        AF_DUMP(( "  (none)\n" ));

      for ( seg = segments; seg < limit; seg++ )
        AF_DUMP(( "  %5d  %5d  %5d  %5s  %4d  %4d"
                  "  %4s  %5s  %4s"
                  "  %6d  %5d  %11s\n",
                  AF_INDEX_NUM( seg, segments ),
                  seg->pos,
                  seg->delta,
                  af_dir_str( (AF_Direction)seg->dir ),
                  AF_INDEX_NUM( seg->first, points ),
                  AF_INDEX_NUM( seg->last, points ),

                  af_print_idx( buf1, 16,
                                AF_INDEX_NUM( seg->link, segments ) ),
                  af_print_idx( buf2, 16,
                                AF_INDEX_NUM( seg->serif, segments ) ),
                  af_print_idx( buf3, 16,
                                AF_INDEX_NUM( seg->edge, edges ) ),

                  seg->height,
                  seg->height - ( seg->max_coord - seg->min_coord ),
                  af_edge_flags_to_string( seg->flags ) ));
      AF_DUMP(( "\n" ));
    }
  }
#ifdef __cplusplus
  }
#endif


  /* Fetch number of segments. */

#ifdef __cplusplus
  extern "C" {
#endif
  FT_Error
  af_glyph_hints_get_num_segments( AF_GlyphHints  hints,
                                   FT_Int         dimension,
                                   FT_UInt*       num_segments )
  {
    AF_Dimension  dim;
    AF_AxisHints  axis;


    dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;

    axis          = &hints->axis[dim];
    *num_segments = axis->num_segments;

    return FT_Err_Ok;
  }
#ifdef __cplusplus
  }
#endif


  /* Fetch offset of segments into user supplied offset array. */

#ifdef __cplusplus
  extern "C" {
#endif
  FT_Error
  af_glyph_hints_get_segment_offset( AF_GlyphHints  hints,
                                     FT_Int         dimension,
                                     FT_UInt        idx,
                                     FT_Pos        *offset,
                                     FT_Bool       *is_blue,
                                     FT_Pos        *blue_offset )
  {
    AF_Dimension  dim;
    AF_AxisHints  axis;
    AF_Segment    seg;


    if ( !offset )
      return FT_THROW( Invalid_Argument );

    dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;

    axis = &hints->axis[dim];

    if ( idx >= axis->num_segments )
      return FT_THROW( Invalid_Argument );

    seg      = &axis->segments[idx];
    *offset  = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
                                            : seg->first->fy;
    if ( seg->edge )
      *is_blue = FT_BOOL( seg->edge->blue_edge );
    else
      *is_blue = FALSE;

    if ( *is_blue )
      *blue_offset = seg->edge->blue_edge->org;
    else
      *blue_offset = 0;

    return FT_Err_Ok;
  }
#ifdef __cplusplus
  }
#endif


  /* Dump the array of linked edges. */

#ifdef __cplusplus
  extern "C" {
#endif
  void
  af_glyph_hints_dump_edges( AF_GlyphHints  hints,
                             FT_Bool        to_stdout )
  {
    FT_Int  dimension;


    for ( dimension = 1; dimension >= 0; dimension-- )
    {
      AF_AxisHints  axis  = &hints->axis[dimension];
      AF_Edge       edges = axis->edges;
      AF_Edge       limit = edges + axis->num_edges;
      AF_Edge       edge;

      char  buf1[16], buf2[16];


      /*
       * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
       *       since they have a constant X coordinate.
       */
      if ( dimension == AF_DIMENSION_HORZ )
        AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
                  "vertical",
                  65536 * 64 / (double)hints->x_scale,
                  10 * (double)hints->x_scale / 65536 / 64 ));
      else
        AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
                  "horizontal",
                  65536 * 64 / (double)hints->y_scale,
                  10 * (double)hints->y_scale / 65536 / 64 ));

      if ( axis->num_edges )
      {
        AF_DUMP(( "  index    pos     dir   link  serif"
               /* "  XXXXX  XXXX.XX  XXXXX  XXXX  XXXXX" */
                  "  blue    opos     pos       flags\n" ));
               /* "    X   XXXX.XX  XXXX.XX  XXXXXXXXXXX" */
      }
      else
        AF_DUMP(( "  (none)\n" ));

      for ( edge = edges; edge < limit; edge++ )
        AF_DUMP(( "  %5d  %7.2f  %5s  %4s  %5s"
                  "    %c   %7.2f  %7.2f  %11s\n",
                  AF_INDEX_NUM( edge, edges ),
                  (double)(int)edge->opos / 64,
                  af_dir_str( (AF_Direction)edge->dir ),
                  af_print_idx( buf1, 16,
                                AF_INDEX_NUM( edge->link, edges ) ),
                  af_print_idx( buf2, 16,
                                AF_INDEX_NUM( edge->serif, edges ) ),

                  edge->blue_edge ? 'y' : 'n',
                  (double)edge->opos / 64,
                  (double)edge->pos / 64,
                  af_edge_flags_to_string( edge->flags ) ));
      AF_DUMP(( "\n" ));
    }
  }
#ifdef __cplusplus
  }
#endif

#undef AF_DUMP

#endif /* !FT_DEBUG_AUTOFIT */


  /* Compute the direction value of a given vector. */

  FT_LOCAL_DEF( AF_Direction )
  af_direction_compute( FT_Pos  dx,
                        FT_Pos  dy )
  {}


  FT_LOCAL_DEF( void )
  af_glyph_hints_init( AF_GlyphHints  hints,
                       FT_Memory      memory )
  {}


  FT_LOCAL_DEF( void )
  af_glyph_hints_done( AF_GlyphHints  hints )
  {}


  /* Reset metrics. */

  FT_LOCAL_DEF( void )
  af_glyph_hints_rescale( AF_GlyphHints    hints,
                          AF_StyleMetrics  metrics )
  {}


  /* Recompute all AF_Point in AF_GlyphHints from the definitions */
  /* in a source outline.                                         */

  FT_LOCAL_DEF( FT_Error )
  af_glyph_hints_reload( AF_GlyphHints  hints,
                         FT_Outline*    outline )
  {}


  /* Store the hinted outline in an FT_Outline structure. */

  FT_LOCAL_DEF( void )
  af_glyph_hints_save( AF_GlyphHints  hints,
                       FT_Outline*    outline )
  {}


  /****************************************************************
   *
   *                     EDGE POINT GRID-FITTING
   *
   ****************************************************************/


  /* Align all points of an edge to the same coordinate value, */
  /* either horizontally or vertically.                        */

  FT_LOCAL_DEF( void )
  af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
                                    AF_Dimension   dim )
  {}


  /****************************************************************
   *
   *                    STRONG POINT INTERPOLATION
   *
   ****************************************************************/


  /* Hint the strong points -- this is equivalent to the TrueType `IP' */
  /* hinting instruction.                                              */

  FT_LOCAL_DEF( void )
  af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
                                      AF_Dimension   dim )
  {}


  /****************************************************************
   *
   *                    WEAK POINT INTERPOLATION
   *
   ****************************************************************/


  /* Shift the original coordinates of all points between `p1' and */
  /* `p2' to get hinted coordinates, using the same difference as  */
  /* given by `ref'.                                               */

  static void
  af_iup_shift( AF_Point  p1,
                AF_Point  p2,
                AF_Point  ref )
  {}


  /* Interpolate the original coordinates of all points between `p1' and  */
  /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the       */
  /* reference points.  The `u' and `v' members are the current and       */
  /* original coordinate values, respectively.                            */
  /*                                                                      */
  /* Details can be found in the TrueType bytecode specification.         */

  static void
  af_iup_interp( AF_Point  p1,
                 AF_Point  p2,
                 AF_Point  ref1,
                 AF_Point  ref2 )
  {}


  /* Hint the weak points -- this is equivalent to the TrueType `IUP' */
  /* hinting instruction.                                             */

  FT_LOCAL_DEF( void )
  af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
                                    AF_Dimension   dim )
  {}


/* END */