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