Edit

kc3-lang/freetype/src/base/ftsynth.c

Branch :

  • Show log

    Commit

  • Author : Werner Lemberg
    Date : 2001-07-12 22:41:08
    Hash : a4bf7d66
    Message : 2001-07-13 Werner Lemberg <wl@gnu.org> * src/base/ftsynth.c: Include ftcalc.h unconditionally.

  • src/base/ftsynth.c
  • /***************************************************************************/
    /*                                                                         */
    /*  ftsynth.c                                                              */
    /*                                                                         */
    /*    FreeType synthesizing code for emboldening and slanting (body).      */
    /*                                                                         */
    /*  Copyright 2000-2001 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 <ft2build.h>
    #include FT_INTERNAL_OBJECTS_H
    #include FT_INTERNAL_CALC_H
    #include FT_OUTLINE_H
    #include FT_SYNTHESIS_H
    
    
    #define FT_BOLD_THRESHOLD  0x0100
    
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   EXPERIMENTAL OBLIQUING SUPPORT                                ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
      FT_EXPORT_DEF( FT_Error )
      FT_Outline_Oblique( FT_GlyphSlot  original,
                          FT_Outline*   outline,
                          FT_Pos*       advance )
      {
        FT_Matrix  transform;
    
        FT_UNUSED( original );
        /* we don't touch the advance width */
        FT_UNUSED( advance );
    
    
    
        /* For italic, simply apply a shear transform, with an angle */
        /* of about 12 degrees.                                      */
    
        transform.xx = 0x10000L;
        transform.yx = 0x00000L;
    
        transform.xy = 0x06000L;
        transform.yy = 0x10000L;
    
        FT_Outline_Transform( outline, &transform );
    
        return 0;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT                    ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
    
      /* Compute the norm of a vector */
    
    #ifdef FT_CONFIG_OPTION_OLD_CALCS
    
      static FT_Pos
      ft_norm( FT_Vector*  vec )
      {
        FT_Int64  t1, t2;
    
    
        MUL_64( vec->x, vec->x, t1 );
        MUL_64( vec->y, vec->y, t2 );
        ADD_64( t1, t2, t1 );
    
        return (FT_Pos)SQRT_64( t1 );
      }
    
    #else /* FT_CONFIG_OPTION_OLD_CALCS */
    
      static FT_Pos
      ft_norm( FT_Vector*  vec )
      {
        FT_F26Dot6  u, v, d;
        FT_Int      shift;
        FT_ULong    H, L, L2, hi, lo, med;
    
    
        u = vec->x; if ( u < 0 ) u = -u;
        v = vec->y; if ( v < 0 ) v = -v;
    
        if ( u < v )
        {
          d = u;
          u = v;
          v = d;
        }
    
        /* check that we are not trying to normalize zero! */
        if ( u == 0 )
          return 0;
    
        /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */
        hi  = (FT_ULong)u >> 16;
        lo  = (FT_ULong)u & 0xFFFF;
        med = hi * lo;
    
        H     = hi * hi + ( med >> 15 );
        med <<= 17;
        L     = lo * lo + med;
        if ( L < med )
          H++;
    
        hi  = (FT_ULong)v >> 16;
        lo  = (FT_ULong)v & 0xFFFF;
        med = hi * lo;
    
        H    += hi * hi + ( med >> 15 );
        med <<= 17;
        L2    = lo * lo + med;
        if ( L2 < med )
          H++;
    
        L += L2;
        if ( L < L2 )
          H++;
    
        /* if the value is smaller than 32 bits */
        shift = 0;
        if ( H == 0 )
        {
          while ( ( L & 0xC0000000UL ) == 0 )
          {
            L <<= 2;
            shift++;
          }
          return ( FT_Sqrt32( L ) >> shift );
        }
        else
        {
          while ( H )
          {
            L   = ( L >> 2 ) | ( H << 30 );
            H >>= 2;
            shift++;
          }
          return ( FT_Sqrt32( L ) << shift );
        }
      }
    
    #endif /* FT_CONFIG_OPTION_OLD_CALCS */
    
    
      static int
      ft_test_extrema( FT_Outline*  outline,
                       int          n )
      {
        FT_Vector  *prev, *cur, *next;
        FT_Pos      product;
        FT_Int      c, first, last;
    
    
        /* we need to compute the `previous' and `next' point */
        /* for these extrema.                                 */
        cur   = outline->points + n;
        prev  = cur - 1;
        next  = cur + 1;
    
        first = 0;
        for ( c = 0; c < outline->n_contours; c++ )
        {
          last  = outline->contours[c];
    
          if ( n == first )
            prev = outline->points + last;
    
          if ( n == last )
            next = outline->points + first;
    
          first = last + 1;
        }
    
        product = FT_MulDiv( cur->x - prev->x,   /* in.x  */
                             next->y - cur->y,   /* out.y */
                             0x40 )
                  -
                  FT_MulDiv( cur->y - prev->y,   /* in.y  */
                             next->x - cur->x,   /* out.x */
                             0x40 );
    
        if ( product )
          product = product > 0 ? 1 : -1;
    
        return product;
      }
    
    
      /* Compute the orientation of path filling.  It differs between TrueType */
      /* and Type1 formats.  We could use the `ft_outline_reverse_fill' flag,  */
      /* but it is better to re-compute it directly (it seems that this flag   */
      /* isn't correctly set for some weird composite glyphs currently).       */
      /*                                                                       */
      /* We do this by computing bounding box points, and computing their      */
      /* curvature.                                                            */
      /*                                                                       */
      /* The function returns either 1 or -1.                                  */
      /*                                                                       */
      static int
      ft_get_orientation( FT_Outline*  outline )
      {
        FT_BBox  box;
        FT_BBox  indices;
        int      n, last;
    
    
        indices.xMin = -1;
        indices.yMin = -1;
        indices.xMax = -1;
        indices.yMax = -1;
    
        box.xMin = box.yMin =  32767;
        box.xMax = box.yMax = -32768;
    
        /* is it empty ? */
        if ( outline->n_contours < 1 )
          return 1;
    
        last = outline->contours[outline->n_contours - 1];
    
        for ( n = 0; n <= last; n++ )
        {
          FT_Pos  x, y;
    
    
          x = outline->points[n].x;
          if ( x < box.xMin )
          {
            box.xMin     = x;
            indices.xMin = n;
          }
          if ( x > box.xMax )
          {
            box.xMax     = x;
            indices.xMax = n;
          }
    
          y = outline->points[n].y;
          if ( y < box.yMin )
          {
            box.yMin     = y;
            indices.yMin = n;
          }
          if ( y > box.yMax )
          {
            box.yMax     = y;
            indices.yMax = n;
          }
        }
    
        /* test orientation of the xmin */
        n = ft_test_extrema( outline, indices.xMin );
        if ( n )
          goto Exit;
    
        n = ft_test_extrema( outline, indices.yMin );
        if ( n )
          goto Exit;
    
        n = ft_test_extrema( outline, indices.xMax );
        if ( n )
          goto Exit;
    
        n = ft_test_extrema( outline, indices.yMax );
        if ( !n )
          n = 1;
    
      Exit:
        return n;
      }
    
    
      FT_EXPORT_DEF( FT_Error )
      FT_Outline_Embolden( FT_GlyphSlot original,
                           FT_Outline*  outline,
                           FT_Pos*      advance )
      {
        FT_Vector   u, v;
        FT_Vector*  points;
        FT_Vector   cur, prev, next;
        FT_Pos      distance;
        FT_Face     face = FT_SLOT_FACE( original );
        int         c, n, first, orientation;
    
        FT_UNUSED( advance );
    
    
        /* compute control distance */
        distance = FT_MulFix( face->units_per_EM / 60,
                              face->size->metrics.y_scale );
    
        orientation = ft_get_orientation( &original->outline );
    
        points = original->outline.points;
    
        first = 0;
        for ( c = 0; c < outline->n_contours; c++ )
        {
          int  last = outline->contours[c];
    
    
          prev = points[last];
    
          for ( n = first; n <= last; n++ )
          {
            FT_Pos     norm, delta, d;
            FT_Vector  in, out;
    
    
            cur = points[n];
            if ( n < last ) next = points[n + 1];
            else            next = points[first];
    
            /* compute the in and out vectors */
            in.x  = cur.x - prev.x;
            in.y  = cur.y - prev.y;
    
            out.x = next.x - cur.x;
            out.y = next.y - cur.y;
    
            /* compute U and V */
            norm = ft_norm( &in );
            u.x = orientation *  FT_DivFix( in.y, norm );
            u.y = orientation * -FT_DivFix( in.x, norm );
    
            norm = ft_norm( &out );
            v.x = orientation *  FT_DivFix( out.y, norm );
            v.y = orientation * -FT_DivFix( out.x, norm );
    
            d = distance;
    
            if ( ( outline->tags[n] & FT_Curve_Tag_On ) == 0 )
              d *= 2;
    
            /* Check discriminant for parallel vectors */
            delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x );
            if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD )
            {
              /* Move point -- compute A and B */
              FT_Pos  x, y, A, B;
    
    
              A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y );
              B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y );
    
              x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y );
              y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x );
    
              outline->points[n].x = distance + FT_DivFix( x, delta );
              outline->points[n].y = distance + FT_DivFix( y, delta );
            }
            else
            {
              /* Vectors are nearly parallel */
              FT_Pos  x, y;
    
    
              x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2;
              y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2;
    
              outline->points[n].x = x;
              outline->points[n].y = y;
            }
    
            prev = cur;
          }
    
          first = last + 1;
        }
    
        if ( advance )
          *advance = ( *advance + distance * 4 ) & -64;
    
        return 0;
      }
    
    
    /* END */