Consider the smooth renderer completed ! It will probably
be moved to "freetype2/src/base" soon and become part of the library. changes include: - fixed a bug which prevented large spans being drawn correctly. - now renders large glyphs that overflow the render pool. - various performance enhancements. the renderer now renders large glyphs with much greater speed :-) - also faster with small glyphs .. future plans: - fix a vertical-dropout bug in the standard raster (b&w) - write a demonstration program to demonstrate direct composition..
This commit is contained in:
parent
82942cc279
commit
ea10fbf91f
|
@ -38,15 +38,19 @@
|
||||||
/* - can easily be modified to render to _any_ number of gray levels */
|
/* - can easily be modified to render to _any_ number of gray levels */
|
||||||
/* cheaply.. */
|
/* cheaply.. */
|
||||||
/* */
|
/* */
|
||||||
|
/* - faster than the standard renderer for small (< 20) pixel sizes */
|
||||||
|
/* */
|
||||||
/* It has the following disadvantages (for now): */
|
/* It has the following disadvantages (for now): */
|
||||||
/* */
|
/* */
|
||||||
/* - need more memory than the standard scan-converter to render */
|
/* - need more memory than the standard scan-converter to render */
|
||||||
/* a single outline. Note that this may be changed in a near */
|
/* a single outline. Note that this may be changed in a near */
|
||||||
/* future (we might be able to pack the data in the TCell structure) */
|
/* future (we might be able to pack the data in the TCell structure) */
|
||||||
/* */
|
/* */
|
||||||
/* - apparently, glyphs rendered with this module are a bit more */
|
/* - a bit slower than the standard renderer for large glyphs (whose */
|
||||||
/* "fuzzy" than those produced with the standard renderer. I hope */
|
/* size is typically > 100 pixels), but faster for smaller sizes.. */
|
||||||
/* to fix this using a gamma table somewhere.. */
|
/* */
|
||||||
|
/* - apparently, glyphs rendered with this module are very slightly */
|
||||||
|
/* more "fuzzy" than those produced with the standard renderer. */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
|
@ -61,8 +65,10 @@
|
||||||
#include <freetype.h> /* to link to FT_Outline_Decompose */
|
#include <freetype.h> /* to link to FT_Outline_Decompose */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* define this to dump debugging information */
|
||||||
#define xxxDEBUG_GRAYS
|
#define xxxDEBUG_GRAYS
|
||||||
|
|
||||||
|
/* as usual, for the speed hungry :-) */
|
||||||
#ifndef FT_STATIC_RASTER
|
#ifndef FT_STATIC_RASTER
|
||||||
|
|
||||||
#define RAS_ARG PRaster raster
|
#define RAS_ARG PRaster raster
|
||||||
|
@ -84,7 +90,9 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* must be at least 6 bits !! */
|
||||||
#define PIXEL_BITS 8
|
#define PIXEL_BITS 8
|
||||||
|
|
||||||
#define ONE_PIXEL (1L << PIXEL_BITS)
|
#define ONE_PIXEL (1L << PIXEL_BITS)
|
||||||
#define PIXEL_MASK (-1L << PIXEL_BITS)
|
#define PIXEL_MASK (-1L << PIXEL_BITS)
|
||||||
#define TRUNC(x) ((x) >> PIXEL_BITS)
|
#define TRUNC(x) ((x) >> PIXEL_BITS)
|
||||||
|
@ -96,6 +104,10 @@
|
||||||
#define UPSCALE(x) (PIXEL_BITS >= 6 ? (x) << (PIXEL_BITS-6) : (x) >> (6-PIXEL_BITS))
|
#define UPSCALE(x) (PIXEL_BITS >= 6 ? (x) << (PIXEL_BITS-6) : (x) >> (6-PIXEL_BITS))
|
||||||
#define DOWNSCALE(x) (PIXEL_BITS >= 6 ? (x) >> (PIXEL_BITS-6) : (x) << (6-PIXEL_BITS))
|
#define DOWNSCALE(x) (PIXEL_BITS >= 6 ? (x) >> (PIXEL_BITS-6) : (x) << (6-PIXEL_BITS))
|
||||||
|
|
||||||
|
/* define if you want to use more compact storage, this increases the number */
|
||||||
|
/* of cells available in the render pool but slows down the rendering a bit */
|
||||||
|
/* useful when you have a really tiny render pool */
|
||||||
|
#define xxxGRAYS_COMPACT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,21 +116,32 @@
|
||||||
/* TYPE DEFINITIONS */
|
/* TYPE DEFINITIONS */
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
typedef int TScan;
|
typedef int TScan; /* integer scanline/pixel coordinate */
|
||||||
typedef long TPos;
|
typedef long TPos; /* sub-pixel coordinate */
|
||||||
typedef float TDist;
|
|
||||||
|
|
||||||
|
/* maximum number of gray spans in a call to the span callback */
|
||||||
#define FT_MAX_GRAY_SPANS 32
|
#define FT_MAX_GRAY_SPANS 32
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GRAYS_COMPACT
|
||||||
|
typedef struct TCell_
|
||||||
|
{
|
||||||
|
short x : 14;
|
||||||
|
short y : 14;
|
||||||
|
int cover : PIXEL_BITS+2;
|
||||||
|
int area : PIXEL_BITS*2+2;
|
||||||
|
|
||||||
|
} TCell, *PCell;
|
||||||
|
#else
|
||||||
typedef struct TCell_
|
typedef struct TCell_
|
||||||
{
|
{
|
||||||
TScan x;
|
TScan x;
|
||||||
TScan y;
|
TScan y;
|
||||||
int area;
|
|
||||||
int cover;
|
int cover;
|
||||||
|
int area;
|
||||||
|
|
||||||
} TCell, *PCell;
|
} TCell, *PCell;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct TRaster_
|
typedef struct TRaster_
|
||||||
|
@ -153,6 +176,11 @@ typedef struct TRaster_
|
||||||
void* render_span_data;
|
void* render_span_data;
|
||||||
int span_y;
|
int span_y;
|
||||||
|
|
||||||
|
int band_size;
|
||||||
|
int band_shoot;
|
||||||
|
int conic_level;
|
||||||
|
int cubic_level;
|
||||||
|
|
||||||
void* memory;
|
void* memory;
|
||||||
|
|
||||||
} TRaster, *PRaster;
|
} TRaster, *PRaster;
|
||||||
|
@ -231,8 +259,8 @@ int record_cell( RAS_ARG )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
cell = ras.cells + ras.num_cells++;
|
cell = ras.cells + ras.num_cells++;
|
||||||
cell->x = ras.ex - ras.min_ex;
|
cell->x = (ras.ex - ras.min_ex);
|
||||||
cell->y = ras.ey - ras.min_ey;
|
cell->y = (ras.ey - ras.min_ey);
|
||||||
cell->area = ras.area;
|
cell->area = ras.area;
|
||||||
cell->cover = ras.cover;
|
cell->cover = ras.cover;
|
||||||
}
|
}
|
||||||
|
@ -441,6 +469,20 @@ int render_line( RAS_ARG_ TPos to_x, TPos to_y )
|
||||||
/* we should do something about the trivial case where dx == 0, */
|
/* we should do something about the trivial case where dx == 0, */
|
||||||
/* as it happens very often !! ... XXXXX */
|
/* as it happens very often !! ... XXXXX */
|
||||||
|
|
||||||
|
/* perform vertical clipping */
|
||||||
|
{
|
||||||
|
TScan min, max;
|
||||||
|
min = ey1;
|
||||||
|
max = ey2;
|
||||||
|
if (ey1 > ey2)
|
||||||
|
{
|
||||||
|
min = ey2;
|
||||||
|
max = ey1;
|
||||||
|
}
|
||||||
|
if (min >= ras.max_ey || max < ras.min_ey)
|
||||||
|
goto Fin;
|
||||||
|
}
|
||||||
|
|
||||||
/* everything is on a single scanline */
|
/* everything is on a single scanline */
|
||||||
if ( ey1 == ey2 )
|
if ( ey1 == ey2 )
|
||||||
{
|
{
|
||||||
|
@ -448,9 +490,7 @@ int render_line( RAS_ARG_ TPos to_x, TPos to_y )
|
||||||
goto Fin;
|
goto Fin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ok, we'll have to render a run of adjacent cells on the same */
|
/* ok, we'll have to render several scanlines */
|
||||||
/* scanline.. */
|
|
||||||
/* */
|
|
||||||
p = (ONE_PIXEL-fy1)*dx;
|
p = (ONE_PIXEL-fy1)*dx;
|
||||||
first = ONE_PIXEL;
|
first = ONE_PIXEL;
|
||||||
incr = 1;
|
incr = 1;
|
||||||
|
@ -535,6 +575,7 @@ void split_conic( FT_Vector* base )
|
||||||
base[2].y = ( a + b ) / 2;
|
base[2].y = ( a + b ) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int render_conic( RAS_ARG_ FT_Vector* control, FT_Vector* to )
|
int render_conic( RAS_ARG_ FT_Vector* control, FT_Vector* to )
|
||||||
{
|
{
|
||||||
|
@ -548,50 +589,80 @@ int render_conic( RAS_ARG_ FT_Vector* control, FT_Vector* to )
|
||||||
if (dx < dy) dx = dy;
|
if (dx < dy) dx = dy;
|
||||||
|
|
||||||
level = 1;
|
level = 1;
|
||||||
dx = dx/16;
|
dx = dx/ras.conic_level;
|
||||||
while ( dx > 0 )
|
while ( dx > 0 )
|
||||||
{
|
{
|
||||||
dx >>= 1;
|
dx >>= 1;
|
||||||
level++;
|
level++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* a shortcut to speed things up */
|
||||||
if (level <= 1)
|
if (level <= 1)
|
||||||
return render_line( RAS_VAR_ UPSCALE(to->x), UPSCALE(to->y) );
|
{
|
||||||
|
/* we compute the mid-point directly in order to avoid */
|
||||||
|
/* calling split_conic().. */
|
||||||
|
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 + 2*UPSCALE(control->x))/4;
|
||||||
|
mid_y = (ras.y + to_y + 2*UPSCALE(control->y))/4;
|
||||||
|
|
||||||
|
return render_line( RAS_VAR_ mid_x, mid_y ) ||
|
||||||
|
render_line( RAS_VAR_ to_x, to_y );
|
||||||
|
}
|
||||||
|
|
||||||
arc = ras.bez_stack;
|
arc = ras.bez_stack;
|
||||||
arc[0] = *to;
|
|
||||||
arc[1] = *control;
|
|
||||||
arc[2].x = ras.x;
|
|
||||||
arc[2].y = ras.y;
|
|
||||||
|
|
||||||
arc[0].x = UPSCALE(arc[0].x);
|
|
||||||
arc[0].y = UPSCALE(arc[0].y);
|
|
||||||
arc[1].x = UPSCALE(arc[1].x);
|
|
||||||
arc[1].y = UPSCALE(arc[1].y);
|
|
||||||
|
|
||||||
levels = ras.lev_stack;
|
levels = ras.lev_stack;
|
||||||
top = 0;
|
top = 0;
|
||||||
levels[0] = level;
|
levels[0] = level;
|
||||||
|
|
||||||
for (;;)
|
arc[0].x = UPSCALE(to->x);
|
||||||
|
arc[0].y = UPSCALE(to->y);
|
||||||
|
arc[1].x = UPSCALE(control->x);
|
||||||
|
arc[1].y = UPSCALE(control->y);
|
||||||
|
arc[2].x = ras.x;
|
||||||
|
arc[2].y = ras.y;
|
||||||
|
|
||||||
|
while (top >= 0)
|
||||||
{
|
{
|
||||||
level = levels[top];
|
level = levels[top];
|
||||||
if (level > 1)
|
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;
|
||||||
|
if ( TRUNC(min) >= ras.max_ey || TRUNC(max) < 0 )
|
||||||
|
goto Draw;
|
||||||
|
|
||||||
split_conic(arc);
|
split_conic(arc);
|
||||||
arc += 2;
|
arc += 2;
|
||||||
top ++;
|
top ++;
|
||||||
levels[top] = levels[top-1] = level-1;
|
levels[top] = levels[top-1] = level-1;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
Draw:
|
||||||
{
|
{
|
||||||
if (render_line( RAS_VAR_ arc[0].x, arc[0].y )) return 1;
|
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 + 2*arc[1].x)/4;
|
||||||
|
mid_y = (ras.y + to_y + 2*arc[1].y)/4;
|
||||||
|
|
||||||
|
if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
|
||||||
|
render_line( RAS_VAR_ to_x, to_y ) ) return 1;
|
||||||
top--;
|
top--;
|
||||||
arc-=2;
|
arc -= 2;
|
||||||
if (top < 0)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -621,6 +692,7 @@ void split_cubic( FT_Vector* base )
|
||||||
base[3].y = ( a + b ) / 2;
|
base[3].y = ( a + b ) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int render_cubic( RAS_ARG_ FT_Vector* control1,
|
int render_cubic( RAS_ARG_ FT_Vector* control1,
|
||||||
FT_Vector* control2,
|
FT_Vector* control2,
|
||||||
|
@ -642,8 +714,8 @@ int render_cubic( RAS_ARG_ FT_Vector* control1,
|
||||||
db = dx;
|
db = dx;
|
||||||
|
|
||||||
level = 1;
|
level = 1;
|
||||||
da = da/16;
|
da = da/ras.cubic_level;
|
||||||
db = db/32;
|
db = db/ras.conic_level;
|
||||||
while ( da > 0 || db > 0 )
|
while ( da > 0 || db > 0 )
|
||||||
{
|
{
|
||||||
da >>= 1;
|
da >>= 1;
|
||||||
|
@ -652,50 +724,84 @@ int render_cubic( RAS_ARG_ FT_Vector* control1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level <= 1)
|
if (level <= 1)
|
||||||
return render_line( RAS_VAR_ UPSCALE(to->x), UPSCALE(to->y) );
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
return render_line( RAS_VAR_ mid_x, mid_y ) ||
|
||||||
|
render_line( RAS_VAR_ to_x, to_y );
|
||||||
|
}
|
||||||
|
|
||||||
arc = ras.bez_stack;
|
arc = ras.bez_stack;
|
||||||
arc[0] = *to;
|
arc[0].x = UPSCALE(to->x);
|
||||||
arc[1] = *control2;
|
arc[0].y = UPSCALE(to->y);
|
||||||
arc[2] = *control1;
|
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].x = ras.x;
|
||||||
arc[3].y = ras.y;
|
arc[3].y = ras.y;
|
||||||
|
|
||||||
arc[0].x = UPSCALE(arc[0].x);
|
|
||||||
arc[0].y = UPSCALE(arc[0].y);
|
|
||||||
arc[1].x = UPSCALE(arc[1].x);
|
|
||||||
arc[1].y = UPSCALE(arc[1].y);
|
|
||||||
arc[2].x = UPSCALE(arc[2].x);
|
|
||||||
arc[2].y = UPSCALE(arc[2].y);
|
|
||||||
|
|
||||||
levels = ras.lev_stack;
|
levels = ras.lev_stack;
|
||||||
top = 0;
|
top = 0;
|
||||||
levels[0] = level;
|
levels[0] = level;
|
||||||
|
|
||||||
for (;;)
|
while (top >= 0)
|
||||||
{
|
{
|
||||||
level = levels[top];
|
level = levels[top];
|
||||||
if (level > 1)
|
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;
|
||||||
split_cubic(arc);
|
split_cubic(arc);
|
||||||
arc += 3;
|
arc += 3;
|
||||||
top ++;
|
top ++;
|
||||||
levels[top] = levels[top-1] = level-1;
|
levels[top] = levels[top-1] = level-1;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
Draw:
|
||||||
{
|
{
|
||||||
if (render_line( RAS_VAR_ arc[0].x, arc[0].y )) return 1;
|
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;
|
||||||
|
|
||||||
|
if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
|
||||||
|
render_line( RAS_VAR_ to_x, to_y ) ) return 1;
|
||||||
top --;
|
top --;
|
||||||
arc -= 3;
|
arc -= 3;
|
||||||
if (top < 0)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* a macro comparing two cell pointers. returns true if a <= b */
|
/* a macro comparing two cell pointers. returns true if a <= b */
|
||||||
|
#if 1
|
||||||
|
#define PACK(a) ( ((long)(a)->y << 16) | (a)->x )
|
||||||
|
#define LESS_THAN(a,b) ( PACK(a) < PACK(b) )
|
||||||
|
#else
|
||||||
#define LESS_THAN(a,b) ( (a)->y<(b)->y || ((a)->y==(b)->y && (a)->x < (b)->x) )
|
#define LESS_THAN(a,b) ( (a)->y<(b)->y || ((a)->y==(b)->y && (a)->x < (b)->x) )
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SWAP_CELLS(a,b,temp) { temp = *(a); *(a) = *(b); *(b) = temp; }
|
#define SWAP_CELLS(a,b,temp) { temp = *(a); *(a) = *(b); *(b) = temp; }
|
||||||
#define DEBUG_SORT
|
#define DEBUG_SORT
|
||||||
#define QUICK_SORT
|
#define QUICK_SORT
|
||||||
|
@ -740,7 +846,7 @@ void shell_sort ( PCell cells,
|
||||||
/* it should be faster than calling the stdlib qsort(), and we can even */
|
/* it should be faster than calling the stdlib qsort(), and we can even */
|
||||||
/* tailor our insertion threshold... */
|
/* tailor our insertion threshold... */
|
||||||
|
|
||||||
#define QSORT_THRESHOLD 7 /* below this size, a sub-array will be sorted */
|
#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */
|
||||||
/* through a normal insertion sort.. */
|
/* through a normal insertion sort.. */
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -902,7 +1008,7 @@ int check_sort( PCell cells, int count )
|
||||||
static
|
static
|
||||||
void grays_render_span( int y, int count, FT_Span* spans, PRaster raster )
|
void grays_render_span( int y, int count, FT_Span* spans, PRaster raster )
|
||||||
{
|
{
|
||||||
unsigned char *p, *q, *limit;
|
unsigned char *p;
|
||||||
FT_Bitmap* map = &raster->target;
|
FT_Bitmap* map = &raster->target;
|
||||||
/* first of all, compute the scanline offset */
|
/* first of all, compute the scanline offset */
|
||||||
p = (unsigned char*)map->buffer - y*map->pitch;
|
p = (unsigned char*)map->buffer - y*map->pitch;
|
||||||
|
@ -912,12 +1018,16 @@ int check_sort( PCell cells, int count )
|
||||||
for ( ; count > 0; count--, spans++ )
|
for ( ; count > 0; count--, spans++ )
|
||||||
{
|
{
|
||||||
if (spans->coverage)
|
if (spans->coverage)
|
||||||
|
#if 1
|
||||||
|
memset( p + spans->x, (spans->coverage+1) >> 1, spans->len );
|
||||||
|
#else
|
||||||
{
|
{
|
||||||
q = p + spans->x;
|
q = p + spans->x;
|
||||||
limit = q + spans->len;
|
limit = q + spans->len;
|
||||||
for ( ; q < limit; q++ )
|
for ( ; q < limit; q++ )
|
||||||
q[0] = (spans->coverage+1) >> 1;
|
q[0] = (spans->coverage+1) >> 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,6 +1093,8 @@ int check_sort( PCell cells, int count )
|
||||||
coverage = 255;
|
coverage = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
y += ras.min_ey;
|
||||||
|
|
||||||
if (coverage)
|
if (coverage)
|
||||||
{
|
{
|
||||||
/* see if we can add this span to the current list */
|
/* see if we can add this span to the current list */
|
||||||
|
@ -1026,7 +1138,7 @@ int check_sort( PCell cells, int count )
|
||||||
|
|
||||||
/* add a gray span to the current list */
|
/* add a gray span to the current list */
|
||||||
span->x = (short)x;
|
span->x = (short)x;
|
||||||
span->len = (unsigned char)acount;
|
span->len = (unsigned short)acount;
|
||||||
span->coverage = (unsigned char)coverage;
|
span->coverage = (unsigned char)coverage;
|
||||||
ras.num_gray_spans++;
|
ras.num_gray_spans++;
|
||||||
}
|
}
|
||||||
|
@ -1036,7 +1148,7 @@ int check_sort( PCell cells, int count )
|
||||||
static
|
static
|
||||||
void grays_sweep( RAS_ARG_ FT_Bitmap* target )
|
void grays_sweep( RAS_ARG_ FT_Bitmap* target )
|
||||||
{
|
{
|
||||||
TScan x, y, cover;
|
TScan x, y, cover, area;
|
||||||
PCell start, cur, limit;
|
PCell start, cur, limit;
|
||||||
|
|
||||||
cur = ras.cells;
|
cur = ras.cells;
|
||||||
|
@ -1048,9 +1160,12 @@ int check_sort( PCell cells, int count )
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
start = cur;
|
start = cur;
|
||||||
y = start->y;
|
y = start->y;
|
||||||
x = start->x;
|
x = start->x;
|
||||||
|
|
||||||
|
area = start->area;
|
||||||
|
cover += start->cover;
|
||||||
|
|
||||||
/* accumulate all start cells */
|
/* accumulate all start cells */
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -1058,18 +1173,16 @@ int check_sort( PCell cells, int count )
|
||||||
++cur;
|
++cur;
|
||||||
if (cur >= limit || cur->y != start->y || cur->x != start->x)
|
if (cur >= limit || cur->y != start->y || cur->x != start->x)
|
||||||
break;
|
break;
|
||||||
start->area += cur->area;
|
|
||||||
start->cover += cur->cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compute next cover */
|
area += cur->area;
|
||||||
cover += start->cover;
|
cover += cur->cover;
|
||||||
|
}
|
||||||
|
|
||||||
/* if the start cell has a non-null area, we must draw an */
|
/* if the start cell has a non-null area, we must draw an */
|
||||||
/* individual gray pixel there.. */
|
/* individual gray pixel there.. */
|
||||||
if (start->area && x >= 0)
|
if (area && x >= 0)
|
||||||
{
|
{
|
||||||
grays_hline( RAS_VAR_ x, y, cover*(ONE_PIXEL*2)-start->area, 1 );
|
grays_hline( RAS_VAR_ x, y, cover*(ONE_PIXEL*2)-area, 1 );
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,8 +1212,8 @@ int check_sort( PCell cells, int count )
|
||||||
ras.gray_spans, ras.render_span_data );
|
ras.gray_spans, ras.render_span_data );
|
||||||
#ifdef DEBUG_GRAYS
|
#ifdef DEBUG_GRAYS
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
FT_GraySpan* span;
|
FT_Span* span;
|
||||||
|
|
||||||
fprintf( stderr, "y=%3d ", ras.span_y );
|
fprintf( stderr, "y=%3d ", ras.span_y );
|
||||||
span = ras.gray_spans;
|
span = ras.gray_spans;
|
||||||
|
@ -1111,8 +1224,14 @@ int check_sort( PCell cells, int count )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct TBand_
|
||||||
|
{
|
||||||
|
FT_Pos min, max;
|
||||||
|
|
||||||
|
} TBand;
|
||||||
|
|
||||||
static
|
static
|
||||||
int Convert_Glyph( RAS_ARG_ FT_Outline* outline )
|
int grays_convert_glyph( RAS_ARG_ FT_Outline* outline )
|
||||||
{
|
{
|
||||||
static
|
static
|
||||||
FT_Outline_Funcs interface =
|
FT_Outline_Funcs interface =
|
||||||
|
@ -1123,23 +1242,119 @@ int check_sort( PCell cells, int count )
|
||||||
(FT_Outline_CubicTo_Func)Cubic_To
|
(FT_Outline_CubicTo_Func)Cubic_To
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TBand bands[40], *band;
|
||||||
|
int n, num_bands;
|
||||||
|
TPos min, max, max_y;
|
||||||
|
|
||||||
/* Set up state in the raster object */
|
/* Set up state in the raster object */
|
||||||
compute_cbox( RAS_VAR_ outline );
|
compute_cbox( RAS_VAR_ outline );
|
||||||
|
|
||||||
|
/* clip to target bitmap, exit if nothing to do */
|
||||||
|
if ( ras.max_ex <= 0 || ras.min_ex >= ras.target.width ||
|
||||||
|
ras.max_ey <= 0 || ras.min_ey >= ras.target.rows )
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (ras.min_ex < 0) ras.min_ex = 0;
|
if (ras.min_ex < 0) ras.min_ex = 0;
|
||||||
if (ras.min_ey < 0) ras.min_ey = 0;
|
if (ras.min_ey < 0) ras.min_ey = 0;
|
||||||
|
|
||||||
if (ras.max_ex > ras.target.width) ras.max_ex = ras.target.width;
|
if (ras.max_ex > ras.target.width) ras.max_ex = ras.target.width;
|
||||||
if (ras.max_ey > ras.target.rows) ras.max_ey = ras.target.rows;
|
if (ras.max_ey > ras.target.rows) ras.max_ey = ras.target.rows;
|
||||||
|
|
||||||
ras.num_cells = 0;
|
/* simple heuristic used to speed-up the bezier decomposition */
|
||||||
|
/* see the code in render_conic and render_cubic for more details */
|
||||||
|
ras.conic_level = 32;
|
||||||
|
ras.cubic_level = 16;
|
||||||
|
{
|
||||||
|
int level = 0;
|
||||||
|
if (ras.max_ex > 24 || ras.max_ey > 24)
|
||||||
|
level++;
|
||||||
|
if (ras.max_ex > 120 || ras.max_ey > 120)
|
||||||
|
level+=2;
|
||||||
|
|
||||||
/* Now decompose curve */
|
ras.conic_level <<= level;
|
||||||
if ( FT_Outline_Decompose( outline, &interface, &ras ) )
|
ras.cubic_level <<= level;
|
||||||
return 1;
|
}
|
||||||
/* XXX: the error condition is in ras.error */
|
|
||||||
|
|
||||||
/* record the last cell */
|
/* setup vertical bands */
|
||||||
return record_cell( RAS_VAR );
|
num_bands = (ras.max_ey - ras.min_ey)/ras.band_size;
|
||||||
|
if (num_bands == 0) num_bands = 1;
|
||||||
|
if (num_bands >= 39) num_bands = 39;
|
||||||
|
|
||||||
|
ras.band_shoot = 0;
|
||||||
|
|
||||||
|
min = ras.min_ey;
|
||||||
|
max_y = ras.max_ey;
|
||||||
|
for ( n = 0; n < num_bands; n++, min = max )
|
||||||
|
{
|
||||||
|
max = min + ras.band_size;
|
||||||
|
if (n == num_bands-1 || max > max_y)
|
||||||
|
max = max_y;
|
||||||
|
|
||||||
|
bands[0].min = min;
|
||||||
|
bands[0].max = max;
|
||||||
|
band = bands;
|
||||||
|
|
||||||
|
while (band >= bands)
|
||||||
|
{
|
||||||
|
FT_Pos bottom, top, middle;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
ras.num_cells = 0;
|
||||||
|
ras.invalid = 1;
|
||||||
|
ras.min_ey = band->min;
|
||||||
|
ras.max_ey = band->max;
|
||||||
|
|
||||||
|
error = FT_Outline_Decompose( outline, &interface, &ras ) ||
|
||||||
|
record_cell( RAS_VAR );
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
#ifdef SHELL_SORT
|
||||||
|
shell_sort( ras.cells, ras.num_cells );
|
||||||
|
#else
|
||||||
|
quick_sort( ras.cells, ras.num_cells );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_GRAYS
|
||||||
|
check_sort( ras.cells, ras.num_cells );
|
||||||
|
dump_cells( RAS_VAR );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
grays_sweep( RAS_VAR_ &ras.target );
|
||||||
|
band--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* render pool overflow, we will reduce the render band by half */
|
||||||
|
bottom = band->min;
|
||||||
|
top = band->max;
|
||||||
|
middle = bottom + ((top-bottom) >> 1);
|
||||||
|
|
||||||
|
/* waoow !! this is too complex for a single scanline, something */
|
||||||
|
/* must be really rotten here !! */
|
||||||
|
if (middle == bottom)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_GRAYS
|
||||||
|
fprintf( stderr, "Rotten glyph !!\n" );
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottom-top >= ras.band_size)
|
||||||
|
ras.band_shoot++;
|
||||||
|
|
||||||
|
band[1].min = bottom;
|
||||||
|
band[1].max = middle;
|
||||||
|
band[0].min = middle;
|
||||||
|
band[0].max = top;
|
||||||
|
band++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ras.band_shoot > 8 && ras.band_size > 16)
|
||||||
|
ras.band_size = ras.band_size/2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1175,20 +1390,6 @@ int check_sort( PCell cells, int count )
|
||||||
ras.num_cells = 0;
|
ras.num_cells = 0;
|
||||||
ras.invalid = 1;
|
ras.invalid = 1;
|
||||||
|
|
||||||
if (Convert_Glyph( (PRaster)raster, outline ))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
#ifdef SHELL_SORT
|
|
||||||
shell_sort( ras.cells, ras.num_cells );
|
|
||||||
#else
|
|
||||||
quick_sort( ras.cells, ras.num_cells );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_GRAYS
|
|
||||||
check_sort( ras.cells, ras.num_cells );
|
|
||||||
dump_cells( RAS_VAR );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ras.render_span = (FT_Raster_Span_Func)grays_render_span;
|
ras.render_span = (FT_Raster_Span_Func)grays_render_span;
|
||||||
ras.render_span_data = &ras;
|
ras.render_span_data = &ras;
|
||||||
if ( params->flags & ft_raster_flag_direct )
|
if ( params->flags & ft_raster_flag_direct )
|
||||||
|
@ -1197,8 +1398,7 @@ int check_sort( PCell cells, int count )
|
||||||
ras.render_span_data = params->user;
|
ras.render_span_data = params->user;
|
||||||
}
|
}
|
||||||
|
|
||||||
grays_sweep( (PRaster)raster, target_map );
|
return grays_convert_glyph( (PRaster)raster, outline );
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1259,8 +1459,12 @@ int check_sort( PCell cells, int count )
|
||||||
const char* pool_base,
|
const char* pool_base,
|
||||||
long pool_size )
|
long pool_size )
|
||||||
{
|
{
|
||||||
|
PRaster rast = (PRaster)raster;
|
||||||
|
|
||||||
if (raster && pool_base && pool_size >= 4096)
|
if (raster && pool_base && pool_size >= 4096)
|
||||||
init_cells( (PRaster)raster, (char*)pool_base, pool_size );
|
init_cells( rast, (char*)pool_base, pool_size );
|
||||||
|
|
||||||
|
rast->band_size = (pool_size / sizeof(TCell))/8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue