Alexei,

Since there are two changes, (the value of FT_MAX_CURVE_DEVIATION and the 
algorithm), each must be tested independently.

Which has broken the rendering?

We need trace info: Does the new algorithm actually do what it claims. I.e. is 
the actual deviation really limited to the FT_MAX_CURVE_DEVIATION value, or has 
the code change broken this?

I've attached a(n old) version of the trace code I used. It'll probably need 
some modifying, but it includes what is required to calculate the *actual* 
maximum deviation.

David %^>


> -----Original Message-----
> From: [email protected]
> [mailto:[email protected]] On Behalf Of
> ??????? ?????????????
> Sent: 14 October 2010 02:03
> To: Werner LEMBERG
> Cc: [email protected]
> Subject: Re: [ft-devel] FT_MAX_CURVE_DEVIATION vs ONE_PIXEL
> 
> Hi all,
> 
> On Wed, Oct 13, 2010 at 9:41 AM, Werner LEMBERG <[email protected]> wrote:
> >
> >> I guess my version has PIXEL_BITS = 6. Sorry, didn't notice the
> >> discrepancy.  Yes, FT_MAX_CURVE_DEVIATIO ought to be defined so that
> >> it's always 1/4 of a pixel.
> >
> > Alexej, can you provide a patch to fix that?
> 
> The patch is below. As was intended in the original code, it aims at the
> max
> deviation of ONE_PIXEL / 4. Remember that the original code actually used
> ONE_PIXEL / 16. The speed-up is nice:
> 
> ftbench -b c -s 36 /usr/share/fonts/default/Type1/p052003l.pfb
> Render                    : 29.216 us/op   (before, see 243.png)
> Render                    : 25.480 us/op   (after, see 244.png)
> 
> Frankly, I think I am starting to notice the quality down a bit.
> Please judge for yourself.
> One quater is probably too close to the size of "subpixels", so I
> would consider
> ONE_PIXEL / 8 instead. Would I make it tunable? No way, I don't want
> people
> to ever curse at freetype because someone misjudged his eyesight. It's too
> subjective for one person to decide.
> 
> 
> 
> diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c
> index 17d172f..4828013 100644
> --- a/src/smooth/ftgrays.c
> +++ b/src/smooth/ftgrays.c
> @@ -91,11 +91,6 @@
>  #define FT_COMPONENT  trace_smooth
> 
> 
> -  /* The maximum distance of a curve from the chord, in 64ths of a pixel;
> */
> -  /* used when flattening curves.
> */
> -#define FT_MAX_CURVE_DEVIATION  16
> -
> -
>  #ifdef _STANDALONE_
> 
> 
> @@ -891,14 +886,14 @@ typedef ptrdiff_t  FT_PtrDist;
>      if ( dx < dy )
>        dx = dy;
> 
> -    if ( dx <= FT_MAX_CURVE_DEVIATION )
> +    if ( dx <= ONE_PIXEL / 4 )
>      {
>        gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
>        return;
>      }
> 
>      level = 1;
> -    dx /= FT_MAX_CURVE_DEVIATION;
> +    dx /= ONE_PIXEL / 4;
>      while ( dx > 1 )
>      {
>        dx >>= 2;
> @@ -1074,7 +1069,7 @@ typedef ptrdiff_t  FT_PtrDist;
>            goto Split;
> 
>          /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1).
> */
> -        s_limit = L * (TPos)( FT_MAX_CURVE_DEVIATION / 0.75 );
> +        s_limit = L * (TPos)( ONE_PIXEL / 3 );
> 
>          /* s is L * the perpendicular distance from P1 to the line P0-P3.
> */
>          dx1 = arc[1].x - arc[0].x;

#define TRACE_CUBIC

#ifdef TRACE_CUBIC
#include <math.h>
#endif

#ifdef TRACE_CUBIC
/*************************************************************************/
/*                                                                       */
/* Returns the one-dimensional position of the Bezier point with         */
/* parametric value t and control point values s0 .. s3.                 */
/*                                                                       */
static double bez_param(double s0, double s1, double s2, double s3, double t)
{
   double u = 1 - t;

   return   u * u * u * s0
          + 3 * t * u * (u * s1 + t * s2)
          + t * t * t * s3;
}


/*************************************************************************/
/*                                                                       */
/* Returns the unnormalised s-coordinate of the point p in the r-s       */
/* coordinate system for the Bezier curve defined by the points          */
/* arc[0..3].                                                            */
/*                                                                       */
static FT_Pos s_dist(FT_Vector* arc, FT_Vector* p)
{
   return   (arc[0].y - p->y) * (arc[3].x - arc[0].x) 
          - (arc[0].x - p->x) * (arc[3].y - arc[0].y);
}


/*************************************************************************/
/*                                                                       */
/* Returns the distance between points p and q.                          */
/*                                                                       */
static double dist(FT_Vector* p, FT_Vector* q)
{
   FT_Pos dx = q->x - p->x;
   FT_Pos dy = q->y - p->y;

   return sqrt(dx * dx + dy * dy);
}


/*************************************************************************/
/*                                                                       */
/* Returns the exact maximum lateral deviation of the Bezier curve       */
/* defined by the points arc[0..3].                                      */
/*                                                                       */
static double max_dev(FT_Vector* arc)
{
   FT_Pos s1 = s_dist(arc, &arc[1]);
   FT_Pos s2 = s_dist(arc, &arc[2]);

   double v, t_max, s_max;

   if (s1 == 0 && s2 == 0)
      return 0;

   v = abs(s1) < abs(s2) ? (double)s1 / s2 : (double)s2 / s1;

   t_max = v == 1 ? 0.5 : (2 - v - sqrt(v * v - v + 1)) / (3 * (1 - v));

   s_max = bez_param(0, 1, v, 0, t_max);

   return (abs(s1) < abs(s2) ? abs(s2) : abs(s1)) * s_max / dist(&arc[0], 
&arc[3]);
}
#endif /* TRACE_CUBIC */


  static void
  gray_render_cubic( RAS_ARG_ const FT_Vector*  control1,
                              const FT_Vector*  control2,
                              const FT_Vector*  to )
  {
#ifdef TRACE_CUBIC
    static int    tot_arcs = 0;
    static int    tot_segs = 0;
    static double tot_dev = 0;
#endif

    TPos        dx, dy, da, db;
    int         top, level;
    int*        levels;
    FT_Vector*  arc;


    dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
    if ( dx < 0 )
      dx = -dx;
    dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
    if ( dy < 0 )
      dy = -dy;
    if ( dx < dy )
      dx = dy;
    da = dx;

    dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
    if ( dx < 0 )
      dx = -dx;
    dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
    if ( dy < 0 )
      dy = -dy;
    if ( dx < dy )
      dx = dy;
    db = dx;

    level = 1;
    da    = da / ras.cubic_level;
    db    = db / ras.conic_level;
    while ( da > 0 || db > 0 )
    {
      da >>= 2;
      db >>= 3;
      level++;
    }

#ifdef TRACE_CUBIC
    arc      = ras.bez_stack;
    arc[0].x = UPSCALE( to->x );
    arc[0].y = UPSCALE( to->y );
    arc[1].x = UPSCALE( control2->x );
    arc[1].y = UPSCALE( control2->y );
    arc[2].x = UPSCALE( control1->x );
    arc[2].y = UPSCALE( control1->y );
    arc[3].x = ras.x;
    arc[3].y = ras.y;
#endif

    if ( level <= 1 )
    {
      TPos   to_x, to_y, mid_x, mid_y;

      to_x  = UPSCALE( to->x );
      to_y  = UPSCALE( to->y );
      mid_x = ( ras.x + to_x +
                3 * UPSCALE( control1->x + control2->x ) ) / 8;
      mid_y = ( ras.y + to_y +
                3 * UPSCALE( control1->y + control2->y ) ) / 8;

#ifdef TRACE_CUBIC
      gray_split_cubic( arc );
      tot_dev += max_dev(arc);
      tot_dev += max_dev(arc + 3);
      tot_segs+=2;
#endif

      gray_render_line( RAS_VAR_ mid_x, mid_y );
      gray_render_line( RAS_VAR_ to_x, to_y );
      goto Cubic_Done;
    }

#ifndef TRACE_CUBIC
    arc      = ras.bez_stack;
    arc[0].x = UPSCALE( to->x );
    arc[0].y = UPSCALE( to->y );
    arc[1].x = UPSCALE( control2->x );
    arc[1].y = UPSCALE( control2->y );
    arc[2].x = UPSCALE( control1->x );
    arc[2].y = UPSCALE( control1->y );
    arc[3].x = ras.x;
    arc[3].y = ras.y;
#endif

    levels    = ras.lev_stack;
    top       = 0;
    levels[0] = level;

    while ( top >= 0 )
    {
      level = levels[top];
      if ( level > 1 )
      {
        /* check that the arc crosses the current band */
        TPos  min, max, y;

        min = max = arc[0].y;
        y = arc[1].y;
        if ( y < min ) min = y;
        if ( y > max ) max = y;
        y = arc[2].y;
        if ( y < min ) min = y;
        if ( y > max ) max = y;
        y = arc[3].y;
        if ( y < min ) min = y;
        if ( y > max ) max = y;
        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
          goto Draw;

        gray_split_cubic( arc );
        arc += 3;
        top ++;
        levels[top] = levels[top - 1] = level - 1;
        continue;
      }

    Draw:
      {
        TPos  to_x, to_y, mid_x, mid_y;

        to_x  = arc[0].x;
        to_y  = arc[0].y;
        mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
        mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;

#ifdef TRACE_CUBIC
        gray_split_cubic( arc );
        tot_dev += max_dev(arc);
        tot_dev += max_dev(arc + 3);
        tot_segs += 2;
#endif

        gray_render_line( RAS_VAR_ mid_x, mid_y );
        gray_render_line( RAS_VAR_ to_x, to_y );
        top --;
        arc -= 3;
      }
    }

Cubic_Done:

#ifdef TRACE_CUBIC
    tot_arcs++;
    printf("%d source arcs: %d segs, avg segs/arc = %f, avg dev/seg = %f\n", 
               tot_arcs, tot_segs, (float)tot_segs / tot_arcs, tot_dev / 
tot_segs);
#endif

    return;
  }

_______________________________________________
Freetype-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/freetype-devel

Reply via email to