⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pshalgo.c

📁 一个类似windows
💻 C
📖 第 1 页 / 共 4 页
字号:
      {
        point->org_u = vec->x;
        point->org_v = vec->y;
      }
      else
      {
        point->org_u = vec->y;
        point->org_v = vec->x;
      }

#ifdef DEBUG_HINTER
      point->org_x = vec->x;
      point->org_y = vec->y;
#endif

    }
  }


  /* save hinted point coordinates back to outline */
  static void
  psh_glyph_save_points( PSH_Glyph  glyph,
                         FT_Int     dimension )
  {
    FT_UInt     n;
    PSH_Point   point = glyph->points;
    FT_Vector*  vec   = glyph->outline->points;
    char*       tags  = glyph->outline->tags;


    for ( n = 0; n < glyph->num_points; n++ )
    {
      if ( dimension == 0 )
        vec[n].x = point->cur_u;
      else
        vec[n].y = point->cur_u;

      if ( psh_point_is_strong( point ) )
        tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );

#ifdef DEBUG_HINTER

      if ( dimension == 0 )
      {
        point->cur_x   = point->cur_u;
        point->flags_x = point->flags2 | point->flags;
      }
      else
      {
        point->cur_y   = point->cur_u;
        point->flags_y = point->flags2 | point->flags;
      }

#endif

      point++;
    }
  }


  static FT_Error
  psh_glyph_init( PSH_Glyph    glyph,
                  FT_Outline*  outline,
                  PS_Hints     ps_hints,
                  PSH_Globals  globals )
  {
    FT_Error   error;
    FT_Memory  memory;


    /* clear all fields */
    FT_MEM_ZERO( glyph, sizeof ( *glyph ) );

    memory = glyph->memory = globals->memory;

    /* allocate and setup points + contours arrays */
    if ( FT_NEW_ARRAY( glyph->points,   outline->n_points   ) ||
         FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
      goto Exit;

    glyph->num_points   = outline->n_points;
    glyph->num_contours = outline->n_contours;

    {
      FT_UInt      first = 0, next, n;
      PSH_Point    points  = glyph->points;
      PSH_Contour  contour = glyph->contours;


      for ( n = 0; n < glyph->num_contours; n++ )
      {
        FT_Int     count;
        PSH_Point  point;


        next  = outline->contours[n] + 1;
        count = next - first;

        contour->start = points + first;
        contour->count = (FT_UInt)count;

        if ( count > 0 )
        {
          point = points + first;

          point->prev    = points + next - 1;
          point->contour = contour;

          for ( ; count > 1; count-- )
          {
            point[0].next = point + 1;
            point[1].prev = point;
            point++;
            point->contour = contour;
          }
          point->next = points + first;
        }

        contour++;
        first = next;
      }
    }

    {
      PSH_Point   points = glyph->points;
      PSH_Point   point  = points;
      FT_Vector*  vec    = outline->points;
      FT_UInt     n;


      for ( n = 0; n < glyph->num_points; n++, point++ )
      {
        FT_Int  n_prev = (FT_Int)( point->prev - points );
        FT_Int  n_next = (FT_Int)( point->next - points );
        FT_Pos  dxi, dyi, dxo, dyo;


        if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
          point->flags = PSH_POINT_OFF;

        dxi = vec[n].x - vec[n_prev].x;
        dyi = vec[n].y - vec[n_prev].y;

        point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi );

        dxo = vec[n_next].x - vec[n].x;
        dyo = vec[n_next].y - vec[n].y;

        point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo );

        /* detect smooth points */
        if ( point->flags & PSH_POINT_OFF )
          point->flags |= PSH_POINT_SMOOTH;
        else if ( point->dir_in  != PSH_DIR_NONE ||
                  point->dir_out != PSH_DIR_NONE )
        {
          if ( point->dir_in == point->dir_out )
            point->flags |= PSH_POINT_SMOOTH;
        }
        else
        {
          FT_Angle  angle_in, angle_out, diff;


          angle_in  = FT_Atan2( dxi, dyi );
          angle_out = FT_Atan2( dxo, dyo );

          diff = angle_in - angle_out;
          if ( diff < 0 )
            diff = -diff;

          if ( diff > FT_ANGLE_PI )
            diff = FT_ANGLE_2PI - diff;

          if ( diff < FT_ANGLE_PI / 16 )
            point->flags |= PSH_POINT_SMOOTH;
        }
      }
    }

    glyph->outline = outline;
    glyph->globals = globals;

#ifdef COMPUTE_INFLEXS
    psh_glyph_load_points( glyph, 0 );
    psh_glyph_compute_inflections( glyph );
#endif /* COMPUTE_INFLEXS */

    /* now deal with hints tables */
    error = psh_hint_table_init( &glyph->hint_tables [0],
                                 &ps_hints->dimension[0].hints,
                                 &ps_hints->dimension[0].masks,
                                 &ps_hints->dimension[0].counters,
                                 memory );
    if ( error )
      goto Exit;

    error = psh_hint_table_init( &glyph->hint_tables [1],
                                 &ps_hints->dimension[1].hints,
                                 &ps_hints->dimension[1].masks,
                                 &ps_hints->dimension[1].counters,
                                 memory );
    if ( error )
      goto Exit;

  Exit:
    return error;
  }


  /* compute all extrema in a glyph for a given dimension */
  static void
  psh_glyph_compute_extrema( PSH_Glyph  glyph )
  {
    FT_UInt  n;


    /* first of all, compute all local extrema */
    for ( n = 0; n < glyph->num_contours; n++ )
    {
      PSH_Point  first = glyph->contours[n].start;
      PSH_Point  point, before, after;


      if ( glyph->contours[n].count == 0 )
        continue;

      point  = first;
      before = point;
      after  = point;

      do
      {
        before = before->prev;
        if ( before == first )
          goto Skip;

      } while ( before->org_u == point->org_u );

      first = point = before->next;

      for (;;)
      {
        after = point;
        do
        {
          after = after->next;
          if ( after == first )
            goto Next;

        } while ( after->org_u == point->org_u );

        if ( before->org_u < point->org_u )
        {
          if ( after->org_u < point->org_u )
          {
            /* local maximum */
            goto Extremum;
          }
        }
        else /* before->org_u > point->org_u */
        {
          if ( after->org_u > point->org_u )
          {
            /* local minimum */
          Extremum:
            do
            {
              psh_point_set_extremum( point );
              point = point->next;

            } while ( point != after );
          }
        }

        before = after->prev;
        point  = after;

      } /* for  */

    Next:
      ;
    }

    /* for each extremum, determine its direction along the */
    /* orthogonal axis                                      */
    for ( n = 0; n < glyph->num_points; n++ )
    {
      PSH_Point  point, before, after;


      point  = &glyph->points[n];
      before = point;
      after  = point;

      if ( psh_point_is_extremum( point ) )
      {
        do
        {
          before = before->prev;
          if ( before == point )
            goto Skip;

        } while ( before->org_v == point->org_v );

        do
        {
          after = after->next;
          if ( after == point )
            goto Skip;

        } while ( after->org_v == point->org_v );
      }

      if ( before->org_v < point->org_v &&
           after->org_v  > point->org_v )
      {
        psh_point_set_positive( point );
      }
      else if ( before->org_v > point->org_v &&
                after->org_v  < point->org_v )
      {
        psh_point_set_negative( point );
      }

    Skip:
      ;
    }
  }


  /* major_dir is the direction for points on the bottom/left of the stem; */
  /* Points on the top/right of the stem will have a direction of          */
  /* -major_dir.                                                           */

  static void
  psh_hint_table_find_strong_point( PSH_Hint_Table  table,
                                    PSH_Point       point,
                                    FT_Int          threshold,
                                    FT_Int          major_dir )
  {
    PSH_Hint*  sort      = table->sort;
    FT_UInt    num_hints = table->num_hints;
    FT_Int     point_dir = 0;


    if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) )
      point_dir = point->dir_in;

    else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) )
      point_dir = point->dir_out;

    if ( point_dir )
    {
      FT_UInt  flag;


      for ( ; num_hints > 0; num_hints--, sort++ )
      {
        PSH_Hint  hint = sort[0];
        FT_Pos    d;


        if ( point_dir == major_dir )
        {
          flag = PSH_POINT_EDGE_MIN;
          d    = point->org_u - hint->org_pos;

          if ( FT_ABS( d ) < threshold )
          {
          Is_Strong:
            psh_point_set_strong( point );
            point->flags2 |= flag;
            point->hint    = hint;
            break;
          }
        }
        else if ( point_dir == -major_dir )
        {
          flag = PSH_POINT_EDGE_MAX;
          d    = point->org_u - hint->org_pos - hint->org_len;

          if ( FT_ABS( d ) < threshold )
            goto Is_Strong;
        }
      }
    }

#if 1
    else if ( psh_point_is_extremum( point ) )
    {
      /* treat extrema as special cases for stem edge alignment */
      FT_UInt  min_flag, max_flag;


      if ( major_dir == PSH_DIR_HORIZONTAL )
      {
        min_flag = PSH_POINT_POSITIVE;
        max_flag = PSH_POINT_NEGATIVE;
      }
      else
      {
        min_flag = PSH_POINT_NEGATIVE;
        max_flag = PSH_POINT_POSITIVE;
      }

      for ( ; num_hints > 0; num_hints--, sort++ )
      {
        PSH_Hint  hint = sort[0];
        FT_Pos    d;
        FT_Int    flag;


        if ( point->flags2 & min_flag )
        {
          flag = PSH_POINT_EDGE_MIN;
          d    = point->org_u - hint->org_pos;

          if ( FT_ABS( d ) < threshold )
          {
          Is_Strong2:
            point->flags2 |= flag;
            point->hint    = hint;
            psh_point_set_strong( point );
            break;
          }
        }
        else if ( point->flags2 & max_flag )
        {
          flag = PSH_POINT_EDGE_MAX;
          d    = point->org_u - hint->org_pos - hint->org_len;

          if ( FT_ABS( d ) < threshold )
            goto Is_Strong2;
        }

        if ( point->org_u >= hint->org_pos                 &&
             point->org_u <= hint->org_pos + hint->org_len )
        {
          point->hint = hint;
        }
      }
    }

#endif /* 1 */
  }


  /* the accepted shift for strong points in fractional pixels */
#define PSH_STRONG_THRESHOLD  32

  /* the maximum shift value in font units */
#define PSH_STRONG_THRESHOLD_MAXIMUM  30


  /* find strong points in a glyph */
  static void
  psh_glyph_find_strong_points( PSH_Glyph  glyph,
                                FT_Int     dimension )
  {
    /* a point is `strong' if it is located on a stem edge and       */
    /* has an `in' or `out' tangent parallel to the hint's direction */

    PSH_Hint_Table  table     = &glyph->hint_tables[dimension];
    PS_Mask         mask      = table->hint_masks->masks;
    FT_UInt         num_masks = table->hint_masks->num_masks;
    FT_UInt         first     = 0;
    FT_Int          major_dir = dimension == 0 ? PSH_DIR_VERTICAL
                                               : PSH_DIR_HORIZONTAL;
    PSH_Dimension   dim       = &glyph->globals->dimension[dimension];
    FT_Fixed        scale     = dim->scale_mult;
    FT_Int          threshold;


    threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale );
    if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM )
      threshold = PSH_STRONG_THRESHOLD_MAXIMUM;

    /* process secondary hints to `selected' points */
    if ( num_masks > 1 && glyph->num_points > 0 )
    {
      first = mask->end_point;
      mask++;
      for ( ; num_masks > 1; num_masks--, mask++ )
      {
        FT_UInt  next;
        FT_Int   count;


        next  = mask->end_point;
        count = next - first;
        if ( count > 0 )
        {
          PSH_Point  point = glyph->points + first;


          psh_hint_table_activate_mask( table, mask );

          for ( ; count > 0; count--, point++ )
            psh_hint_table_find_strong_point( table, point,
                                              threshold, major_dir );
        }
        first = next;
      }
    }

    /* process primary hints for all points */
    if ( num_masks == 1 )
    {
      FT_UInt    count = glyph->num_points;
      PSH_Point  point = glyph->points;


      psh_hint_table_activate_mask( table, table->hint_masks->masks );
      for ( ; count > 0; count--, point++ )
      {
        if ( !psh_point_is_strong( point ) )
          psh_hint_table_find_strong_point( table, point,
                                            threshold, major_dir );
      }
    }

    /* now, certain points may have been attached to a hint and */
    /* not marked as strong; update their flags then            */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -