diff --git a/src/renderer/ftgrays.c b/src/renderer/ftgrays.c deleted file mode 100644 index 281833292..000000000 --- a/src/renderer/ftgrays.c +++ /dev/null @@ -1,1954 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftgrays.c */ -/* */ -/* A new `perfect' anti-aliasing renderer (body). */ -/* */ -/* Copyright 2000 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. */ -/* */ -/***************************************************************************/ - - /*************************************************************************/ - /* */ - /* This file can be compiled without the rest of the FreeType engine, */ - /* by defining the _STANDALONE_ macro when compiling it. You also need */ - /* to put the files `ftgrays.h' and `ftimage.h' into the current */ - /* compilation directory. Typically, you could do something like */ - /* */ - /* - copy `src/base/ftgrays.c' to your current directory */ - /* */ - /* - copy `include/freetype/ftimage.h' and */ - /* `include/freetype/ftgrays.h' to the same directory */ - /* */ - /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ - /* */ - /* cc -c -D_STANDALONE_ ftgrays.c */ - /* */ - /* The renderer can be initialized with a call to */ - /* `ft_grays_raster.grays_raster_new'; an anti-aliased bitmap can be */ - /* generated with a call to `ft_grays_raster.grays_raster_render'. */ - /* */ - /* See the comments and documentation in the file `ftimage.h' for */ - /* more details on how the raster works. */ - /* */ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* This is a new anti-aliasing scan-converter for FreeType 2. The */ - /* algorithm used here is _very_ different from the one in the standard */ - /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ - /* coverage of the outline on each pixel cell. */ - /* */ - /* It is based on ideas that I initially found in Raph Levien's */ - /* excellent LibArt graphics library (see http://www.levien.com/libart */ - /* for more information, though the web pages do not tell anything */ - /* about the renderer; you will have to dive into the source code to */ - /* understand how it works). */ - /* */ - /* Note, however, that this is a _very_ different implementation */ - /* compared Raph's. Coverage information is stored in a very different */ - /* way, and I don't use sorted vector paths. Also, it doesn't use */ - /* floating point values. */ - /* */ - /* This renderer has the following advantages: */ - /* */ - /* - It doesn't need an intermediate bitmap. Instead, one can supply */ - /* a callback function that will be called by the renderer to draw */ - /* gray spans on any target surface. You can thus do direct */ - /* composition on any kind of bitmap, provided that you give the */ - /* renderer the right callback. */ - /* */ - /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ - /* each pixel cell */ - /* */ - /* - It performs a single pass on the outline (the `standard' FT2 */ - /* renderer makes two passes). */ - /* */ - /* - It can easily be modified to render to _any_ number of gray levels */ - /* cheaply. */ - /* */ - /* - For small (< 20) pixel sizes, it is faster than the standard */ - /* renderer. */ - /* */ - /*************************************************************************/ - - -#include /* for memcpy() */ - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_aaraster - - -#define ErrRaster_Invalid_Outline -1 - - -#ifdef _STANDALONE_ - - -#include "ftimage.h" -#include "ftgrays.h" - - - /* This macro is used to indicate that a function parameter is unused. */ - /* Its purpose is simply to reduce compiler warnings. Note also that */ - /* simply defining it as `(void)x' doesn't avoid warnings with certain */ - /* ANSI compilers (e.g. LCC). */ -#define UNUSED( x ) (x) = (x) - - /* Disable the tracing mechanism for simplicity -- developers can */ - /* activate it easily by redefining these two macros. */ -#ifndef FT_ERROR -#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ -#endif - -#ifndef FT_TRACE -#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ -#endif - - -#else /* _STANDALONE_ */ - - -#include "ftgrays.h" -#include /* for UNUSED() */ -#include /* for FT_TRACE() and FT_ERROR() */ -#include /* for FT_Outline_Decompose() */ - - -#endif /* _STANDALONE_ */ - - - /* define this to dump debugging information */ -#define xxxDEBUG_GRAYS - - - /* as usual, for the speed hungry :-) */ - -#ifndef FT_STATIC_RASTER - - -#define RAS_ARG PRaster raster -#define RAS_ARG_ PRaster raster, - -#define RAS_VAR raster -#define RAS_VAR_ raster, - -#define ras (*raster) - - -#else /* FT_STATIC_RASTER */ - - -#define RAS_ARG /* empty */ -#define RAS_ARG_ /* empty */ -#define RAS_VAR /* empty */ -#define RAS_VAR_ /* empty */ - - static TRaster ras; - - -#endif /* FT_STATIC_RASTER */ - - - /* must be at least 6 bits! */ -#define PIXEL_BITS 8 - -#define ONE_PIXEL ( 1L << PIXEL_BITS ) -#define PIXEL_MASK ( -1L << PIXEL_BITS ) -#define TRUNC( x ) ( (x) >> PIXEL_BITS ) -#define SUBPIXELS( x ) ( (x) << PIXEL_BITS ) -#define FLOOR( x ) ( (x) & -ONE_PIXEL ) -#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) -#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) - -#if PIXEL_BITS >= 6 -#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) -#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) -#else -#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) -#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) -#endif - - /* Define this if you want to use a more compact storage scheme. This */ - /* increases the number of cells available in the render pool but slows */ - /* down the rendering a bit. It is useful if you have a really tiny */ - /* render pool. */ -#define xxxGRAYS_COMPACT - - - /*************************************************************************/ - /* */ - /* TYPE DEFINITIONS */ - /* */ - typedef int TScan; /* integer scanline/pixel coordinate */ - typedef long TPos; /* sub-pixel coordinate */ - - /* maximal number of gray spans in a call to the span callback */ -#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 /* GRAYS_COMPACT */ - - typedef struct TCell_ - { - TScan x; - TScan y; - int cover; - int area; - - } TCell, *PCell; - -#endif /* GRAYS_COMPACT */ - - - typedef struct TRaster_ - { - PCell cells; - int max_cells; - int num_cells; - - TScan min_ex, max_ex; - TScan min_ey, max_ey; - - int area; - int cover; - int invalid; - - TScan ex, ey; - TScan cx, cy; - TPos x, y; - - TScan last_ey; - - FT_Vector bez_stack[32 * 3]; - int lev_stack[32]; - - FT_Outline outline; - FT_Bitmap target; - - FT_Span gray_spans[FT_MAX_GRAY_SPANS]; - int num_gray_spans; - - FT_Raster_Span_Func render_span; - void* render_span_data; - int span_y; - - int band_size; - int band_shoot; - int conic_level; - int cubic_level; - - void* memory; - - } TRaster, *PRaster; - - - /*************************************************************************/ - /* */ - /* Initialize the cells table. */ - /* */ - static - void init_cells( RAS_ARG_ void* buffer, - long byte_size ) - { - ras.cells = (PCell)buffer; - ras.max_cells = byte_size / sizeof ( TCell ); - ras.num_cells = 0; - ras.area = 0; - ras.cover = 0; - ras.invalid = 1; - } - - - /*************************************************************************/ - /* */ - /* Compute the outline bounding box. */ - /* */ - static - void compute_cbox( RAS_ARG_ FT_Outline* outline ) - { - FT_Vector* vec = outline->points; - FT_Vector* limit = vec + outline->n_points; - - - if ( outline->n_points <= 0 ) - { - ras.min_ex = ras.max_ex = 0; - ras.min_ey = ras.max_ey = 0; - return; - } - - ras.min_ex = ras.max_ex = vec->x; - ras.min_ey = ras.max_ey = vec->y; - - vec++; - - for ( ; vec < limit; vec++ ) - { - TPos x = vec->x; - TPos y = vec->y; - - - if ( x < ras.min_ex ) ras.min_ex = x; - if ( x > ras.max_ex ) ras.max_ex = x; - if ( y < ras.min_ey ) ras.min_ey = y; - if ( y > ras.max_ey ) ras.max_ey = y; - } - - /* truncate the bounding box to integer pixels */ - ras.min_ex = ras.min_ex >> 6; - ras.min_ey = ras.min_ey >> 6; - ras.max_ex = ( ras.max_ex + 63 ) >> 6; - ras.max_ey = ( ras.max_ey + 63 ) >> 6; - } - - - /*************************************************************************/ - /* */ - /* Record the current cell in the table. */ - /* */ - static - int record_cell( RAS_ARG ) - { - PCell cell; - - - if ( !ras.invalid && ( ras.area | ras.cover ) ) - { - if ( ras.num_cells >= ras.max_cells ) - return 1; - - cell = ras.cells + ras.num_cells++; - cell->x = ras.ex - ras.min_ex; - cell->y = ras.ey - ras.min_ey; - cell->area = ras.area; - cell->cover = ras.cover; - } - - return 0; - } - - - /*************************************************************************/ - /* */ - /* Set the current cell to a new position. */ - /* */ - static - int set_cell( RAS_ARG_ TScan ex, - TScan ey ) - { - int invalid, record, clean; - - - /* Move the cell pointer to a new position. We set the `invalid' */ - /* flag to indicate that the cell isn't part of those we're interested */ - /* in during the render phase. This means that: */ - /* */ - /* . the new vertical position must be within min_ey..max_ey - 1. */ - /* . the new horizontal position must be strictly less than max_ex */ - /* */ - /* Note that if a cell is to the left of the clipping region, it is */ - /* actually set to the (min_ex-1) horizontal position. */ - - record = 0; - clean = 1; - - invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex ); - if ( !invalid ) - { - /* All cells that are on the left of the clipping region go to the */ - /* min_ex - 1 horizontal position. */ - if ( ex < ras.min_ex ) - ex = ras.min_ex - 1; - - /* if our position is new, then record the previous cell */ - if ( ex != ras.ex || ey != ras.ey ) - record = 1; - else - clean = ras.invalid; /* do not clean if we didn't move from */ - /* a valid cell */ - } - - /* record the previous cell if needed (i.e., if we changed the cell */ - /* position, of changed the `invalid' flag) */ - if ( ( ras.invalid != invalid || record ) && record_cell( RAS_VAR ) ) - return 1; - - if ( clean ) - { - ras.area = 0; - ras.cover = 0; - } - - ras.invalid = invalid; - ras.ex = ex; - ras.ey = ey; - return 0; - } - - - /*************************************************************************/ - /* */ - /* Start a new contour at a given cell. */ - /* */ - static - void start_cell( RAS_ARG_ TScan ex, - TScan ey ) - { - if ( ex < ras.min_ex ) - ex = ras.min_ex - 1; - - ras.area = 0; - ras.cover = 0; - ras.ex = ex; - ras.ey = ey; - ras.last_ey = SUBPIXELS( ey ); - ras.invalid = 0; - - (void)set_cell( RAS_VAR_ ex, ey ); - } - - - /*************************************************************************/ - /* */ - /* Render a scanline as one or more cells. */ - /* */ - static - int render_scanline( RAS_ARG_ TScan ey, - TPos x1, - TScan y1, - TPos x2, - TScan y2 ) - { - TScan ex1, ex2, fx1, fx2, delta; - long p, first, dx; - int incr, lift, mod, rem; - - - dx = x2 - x1; - - ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */ - ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */ - fx1 = x1 - SUBPIXELS( ex1 ); - fx2 = x2 - SUBPIXELS( ex2 ); - - /* trivial case. Happens often */ - if ( y1 == y2 ) - return set_cell( RAS_VAR_ ex2, ey ); - - /* everything is located in a single cell. That is easy! */ - /* */ - if ( ex1 == ex2 ) - { - delta = y2 - y1; - ras.area += ( fx1 + fx2 ) * delta; - ras.cover += delta; - return 0; - } - - /* ok, we'll have to render a run of adjacent cells on the same */ - /* scanline... */ - /* */ - p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); - first = ONE_PIXEL; - incr = 1; - - if ( dx < 0 ) - { - p = fx1 * ( y2 - y1 ); - first = 0; - incr = -1; - dx = -dx; - } - - delta = p / dx; - mod = p % dx; - if ( mod < 0 ) - { - delta--; - mod += dx; - } - - ras.area += ( fx1 + first ) * delta; - ras.cover += delta; - - ex1 += incr; - if ( set_cell( RAS_VAR_ ex1, ey ) ) - goto Error; - y1 += delta; - - if ( ex1 != ex2 ) - { - p = ONE_PIXEL * ( y2 - y1 ); - lift = p / dx; - rem = p % dx; - if ( rem < 0 ) - { - lift--; - rem += dx; - } - - mod -= dx; - - while ( ex1 != ex2 ) - { - delta = lift; - mod += rem; - if ( mod >= 0 ) - { - mod -= dx; - delta++; - } - - ras.area += ONE_PIXEL * delta; - ras.cover += delta; - y1 += delta; - ex1 += incr; - if ( set_cell( RAS_VAR_ ex1, ey ) ) - goto Error; - } - } - - delta = y2 - y1; - ras.area += ( fx2 + ONE_PIXEL - first ) * delta; - ras.cover += delta; - - return 0; - - Error: - return 1; - } - - - /*************************************************************************/ - /* */ - /* Render a given line as a series of scanlines. */ - /* */ - static - int render_line( RAS_ARG_ TPos to_x, - TPos to_y ) - { - TScan ey1, ey2, fy1, fy2; - TPos dx, dy, x, x2; - int p, rem, mod, lift, delta, first, incr; - - - ey1 = TRUNC( ras.last_ey ); - ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ - fy1 = ras.y - ras.last_ey; - fy2 = to_y - SUBPIXELS( ey2 ); - - dx = to_x - ras.x; - dy = to_y - ras.y; - - /* we should do something about the trivial case where dx == 0, */ - /* 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 End; - } - - /* everything is on a single scanline */ - if ( ey1 == ey2 ) - { - if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ) ) - goto Error; - goto End; - } - - /* ok, we'll have to render several scanlines */ - p = ( ONE_PIXEL - fy1 ) * dx; - first = ONE_PIXEL; - incr = 1; - - if ( dy < 0 ) - { - p = fy1 * dx; - first = 0; - incr = -1; - dy = -dy; - } - - delta = p / dy; - mod = p % dy; - if ( mod < 0 ) - { - delta--; - mod += dy; - } - - x = ras.x + delta; - if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ) ) - goto Error; - - ey1 += incr; - if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) ) - goto Error; - - if ( ey1 != ey2 ) - { - p = ONE_PIXEL * dx; - lift = p / dy; - rem = p % dy; - if ( rem < 0 ) - { - lift--; - rem += dy; - } - mod -= dy; - - while ( ey1 != ey2 ) - { - delta = lift; - mod += rem; - if ( mod >= 0 ) - { - mod -= dy; - delta++; - } - - x2 = x + delta; - if ( render_scanline( RAS_VAR_ ey1, - x, ONE_PIXEL - first, x2, first ) ) - goto Error; - x = x2; - ey1 += incr; - if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) ) - goto Error; - } - } - - if ( render_scanline( RAS_VAR_ ey1, - x, ONE_PIXEL - first, to_x, fy2 ) ) - goto Error; - - End: - ras.x = to_x; - ras.y = to_y; - ras.last_ey = SUBPIXELS( ey2 ); - - return 0; - - Error: - return 1; - } - - - static - void split_conic( FT_Vector* base ) - { - TPos a, b; - - - base[4].x = base[2].x; - b = base[1].x; - a = base[3].x = ( base[2].x + b ) / 2; - b = base[1].x = ( base[0].x + b ) / 2; - base[2].x = ( a + b ) / 2; - - base[4].y = base[2].y; - b = base[1].y; - a = base[3].y = ( base[2].y + b ) / 2; - b = base[1].y = ( base[0].y + b ) / 2; - base[2].y = ( a + b ) / 2; - } - - - static - int render_conic( RAS_ARG_ FT_Vector* control, - FT_Vector* to ) - { - TPos dx, dy; - int top, level; - int* levels; - FT_Vector* arc; - - - dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 ); - if ( dx < 0 ) - dx = -dx; - dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 ); - if ( dy < 0 ) - dy = -dy; - if ( dx < dy ) - dx = dy; - - level = 1; - dx = dx / ras.conic_level; - while ( dx > 0 ) - { - dx >>= 1; - level++; - } - - /* a shortcut to speed things up */ - if ( level <= 1 ) - { - /* 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; - levels = ras.lev_stack; - top = 0; - levels[0] = level; - - 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]; - 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 ); - arc += 2; - 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 + 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--; - arc -= 2; - } - } - return 0; - } - - - static - void split_cubic( FT_Vector* base ) - { - TPos a, b, c, d; - - - base[6].x = base[3].x; - c = base[1].x; - d = base[2].x; - base[1].x = a = ( base[0].x + c ) / 2; - base[5].x = b = ( base[3].x + d ) / 2; - c = ( c + d ) / 2; - base[2].x = a = ( a + c ) / 2; - base[4].x = b = ( b + c ) / 2; - base[3].x = ( a + b ) / 2; - - base[6].y = base[3].y; - c = base[1].y; - d = base[2].y; - base[1].y = a = ( base[0].y + c ) / 2; - base[5].y = b = ( base[3].y + d ) / 2; - c = ( c + d ) / 2; - base[2].y = a = ( a + c ) / 2; - base[4].y = b = ( b + c ) / 2; - base[3].y = ( a + b ) / 2; - } - - - static - int render_cubic( RAS_ARG_ FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to ) - { - 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 >>= 1; - db >>= 2; - level++; - } - - 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; - - return render_line( RAS_VAR_ mid_x, mid_y ) || - render_line( RAS_VAR_ to_x, to_y ); - } - - 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; - - 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; - 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; - - if ( render_line( RAS_VAR_ mid_x, mid_y ) || - render_line( RAS_VAR_ to_x, to_y ) ) - return 1; - top --; - arc -= 3; - } - } - return 0; - } - - - /* 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 /* 1 */ -#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \ - ( (a)->y == (b)->y && (a)->x < (b)->x ) ) -#endif /* 1 */ - -#define SWAP_CELLS( a, b, temp ) do \ - { \ - temp = *(a); \ - *(a) = *(b); \ - *(b) = temp; \ - } while ( 0 ) -#define DEBUG_SORT -#define QUICK_SORT - -#ifdef SHELL_SORT - - /* a simple shell sort algorithm that works directly on our */ - /* cells table */ - static - void shell_sort ( PCell cells, - int count ) - { - PCell i, j, limit = cells + count; - TCell temp; - int gap; - - - /* compute initial gap */ - for ( gap = 0; ++gap < count; gap *= 3 ) - ; - - while ( gap /= 3 ) - { - for ( i = cells + gap; i < limit; i++ ) - { - for ( j = i - gap; ; j -= gap ) - { - PCell k = j + gap; - - - if ( LESS_THAN( j, k ) ) - break; - - SWAP_CELLS( j, k, temp ); - - if ( j < cells + gap ) - break; - } - } - } - } - -#endif /* SHELL_SORT */ - - -#ifdef QUICK_SORT - - /* This is a non-recursive quicksort that directly process our cells */ - /* array. It should be faster than calling the stdlib qsort(), and we */ - /* can even tailor our insertion threshold... */ - -#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */ - /* through a normal insertion sort.. */ - - static - void quick_sort( PCell cells, - int count ) - { - PCell stack[40]; /* should be enough ;-) */ - PCell* top; /* top of stack */ - PCell base, limit; - TCell temp; - - - limit = cells + count; - base = cells; - top = stack; - - for (;;) - { - int len = limit - base; - PCell i, j, pivot; - - - if ( len > QSORT_THRESHOLD ) - { - /* we use base + len/2 as the pivot */ - pivot = base + len / 2; - SWAP_CELLS( base, pivot, temp ); - - i = base + 1; - j = limit - 1; - - /* now ensure that *i <= *base <= *j */ - if ( LESS_THAN( j, i ) ) - SWAP_CELLS( i, j, temp ); - - if ( LESS_THAN( base, i ) ) - SWAP_CELLS( base, i, temp ); - - if ( LESS_THAN( j, base ) ) - SWAP_CELLS( base, j, temp ); - - for (;;) - { - do i++; while ( LESS_THAN( i, base ) ); - do j--; while ( LESS_THAN( base, j ) ); - - if ( i > j ) - break; - - SWAP_CELLS( i, j, temp ); - } - - SWAP_CELLS( base, j, temp ); - - /* now, push the largest sub-array */ - if ( j - base > limit - i ) - { - top[0] = base; - top[1] = j; - base = i; - } - else - { - top[0] = i; - top[1] = limit; - limit = j; - } - top += 2; - } - else - { - /* the sub-array is small, perform insertion sort */ - j = base; - i = j + 1; - - for ( ; i < limit; j = i, i++ ) - { - for ( ; LESS_THAN( j + 1, j ); j-- ) - { - SWAP_CELLS( j + 1, j, temp ); - if ( j == base ) - break; - } - } - if ( top > stack ) - { - top -= 2; - base = top[0]; - limit = top[1]; - } - else - break; - } - } - } - -#endif /* QUICK_SORT */ - - -#ifdef DEBUG_GRAYS -#ifdef DEBUG_SORT - - static - int check_sort( PCell cells, - int count ) - { - PCell p, q; - - - for ( p = cells + count - 2; p >= cells; p-- ) - { - q = p + 1; - if ( !LESS_THAN( p, q ) ) - return 0; - } - return 1; - } - -#endif /* DEBUG_SORT */ -#endif /* DEBUG_GRAYS */ - - - static - int Move_To( FT_Vector* to, - FT_Raster raster ) - { - TPos x, y; - - - /* record current cell, if any */ - record_cell( (PRaster)raster ); - - /* start to a new position */ - x = UPSCALE( to->x ); - y = UPSCALE( to->y ); - start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) ); - ((PRaster)raster)->x = x; - ((PRaster)raster)->y = y; - return 0; - } - - - static - int Line_To( FT_Vector* to, - FT_Raster raster ) - { - return render_line( (PRaster)raster, - UPSCALE( to->x ), UPSCALE( to->y ) ); - } - - - static - int Conic_To( FT_Vector* control, - FT_Vector* to, - FT_Raster raster ) - { - return render_conic( (PRaster)raster, control, to ); - } - - - static - int Cubic_To( FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to, - FT_Raster raster ) - { - return render_cubic( (PRaster)raster, control1, control2, to ); - } - - - static - void grays_render_span( int y, - int count, - FT_Span* spans, - PRaster raster ) - { - unsigned char* p; - FT_Bitmap* map = &raster->target; - - - /* first of all, compute the scanline offset */ - p = (unsigned char*)map->buffer - y * map->pitch; - if ( map->pitch >= 0 ) - p += ( map->rows - 1 ) * map->pitch; - - for ( ; count > 0; count--, spans++ ) - { - if ( spans->coverage ) -#if 1 - memset( p + spans->x, (unsigned char)spans->coverage, spans->len ); -#else /* 1 */ - { - q = p + spans->x; - limit = q + spans->len; - for ( ; q < limit; q++ ) - q[0] = (unsigned char)spans->coverage; - } -#endif /* 1 */ - } - } - - -#ifdef DEBUG_GRAYS - -#include - - static - void dump_cells( RAS_ARG ) - { - PCell cell, limit; - int y = -1; - - - cell = ras.cells; - limit = cell + ras.num_cells; - - for ( ; cell < limit; cell++ ) - { - if ( cell->y != y ) - { - fprintf( stderr, "\n%2d: ", cell->y ); - y = cell->y; - } - fprintf( stderr, "[%d %d %d]", - cell->x, cell->area, cell->cover ); - } - fprintf(stderr, "\n" ); - } - -#endif /* DEBUG_GRAYS */ - - - static - void grays_hline( RAS_ARG_ TScan x, - TScan y, - TPos area, - int acount ) - { - FT_Span* span; - int count; - int coverage; - - - /* compute the coverage line's coverage, depending on the */ - /* outline fill rule */ - /* */ - /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ - /* */ - coverage = area >> ( PIXEL_BITS * 2 + 1 - 8); /* use range 0..256 */ - - if ( ras.outline.flags & ft_outline_even_odd_fill ) - { - if ( coverage < 0 ) - coverage = -coverage; - - while ( coverage >= 512 ) - coverage -= 512; - - if ( coverage > 256 ) - coverage = 512 - coverage; - else if ( coverage == 256 ) - coverage = 255; - } - else - { - /* normal non-zero winding rule */ - if ( coverage < 0 ) - coverage = -coverage; - - if ( coverage >= 256 ) - coverage = 255; - } - - y += ras.min_ey; - x += ras.min_ex; - - if ( coverage ) - { - /* see if we can add this span to the current list */ - count = ras.num_gray_spans; - span = ras.gray_spans + count - 1; - if ( count > 0 && - ras.span_y == y && - (int)span->x + span->len == (int)x && - span->coverage == coverage ) - { - span->len += acount; - return; - } - - if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) - { - if ( ras.render_span ) - ras.render_span( ras.span_y, count, ras.gray_spans, - ras.render_span_data ); - /* ras.render_span( span->y, ras.gray_spans, count ); */ - -#ifdef DEBUG_GRAYS - - if ( ras.span_y >= 0 ) - { - int n; - - - fprintf( stderr, "y=%3d ", ras.span_y ); - span = ras.gray_spans; - for ( n = 0; n < count; n++, span++ ) - fprintf( stderr, "[%d..%d]:%02x ", - span->x, span->x + span->len - 1, span->coverage ); - fprintf( stderr, "\n" ); - } - -#endif /* DEBUG_GRAYS */ - - ras.num_gray_spans = 0; - ras.span_y = y; - - count = 0; - span = ras.gray_spans; - } - else - span++; - - /* add a gray span to the current list */ - span->x = (short)x; - span->len = (unsigned short)acount; - span->coverage = (unsigned char)coverage; - ras.num_gray_spans++; - } - } - - - static - void grays_sweep( RAS_ARG_ FT_Bitmap* target ) - { - TScan x, y, cover, area; - PCell start, cur, limit; - - UNUSED( target ); - - - cur = ras.cells; - limit = cur + ras.num_cells; - - cover = 0; - ras.span_y = -1; - ras.num_gray_spans = 0; - - for (;;) - { - start = cur; - y = start->y; - x = start->x; - - area = start->area; - cover += start->cover; - - /* accumulate all start cells */ - for (;;) - { - ++cur; - if ( cur >= limit || cur->y != start->y || cur->x != start->x ) - break; - - area += cur->area; - cover += cur->cover; - } - - /* if the start cell has a non-null area, we must draw an */ - /* individual gray pixel there */ - if ( area && x >= 0 ) - { - grays_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 ); - x++; - } - - if ( x < 0 ) - x = 0; - - if ( cur < limit && start->y == cur->y ) - { - /* draw a gray span between the start cell and the current one */ - if ( cur->x > x ) - grays_hline( RAS_VAR_ x, y, - cover * ( ONE_PIXEL * 2 ), cur->x - x ); - } - else - { - /* draw a gray span until the end of the clipping region */ - if ( cover && x < ras.max_ex - ras.min_ex ) - grays_hline( RAS_VAR_ x, y, - cover * ( ONE_PIXEL * 2 ), - ras.max_ex - x - ras.min_ex ); - cover = 0; - } - - if ( cur >= limit ) - break; - } - - if ( ras.render_span && ras.num_gray_spans > 0 ) - ras.render_span( ras.span_y, ras.num_gray_spans, - ras.gray_spans, ras.render_span_data ); - -#ifdef DEBUG_GRAYS - - { - int n; - FT_Span* span; - - - fprintf( stderr, "y=%3d ", ras.span_y ); - span = ras.gray_spans; - for ( n = 0; n < ras.num_gray_spans; n++, span++ ) - fprintf( stderr, "[%d..%d]:%02x ", - span->x, span->x + span->len - 1, span->coverage ); - fprintf( stderr, "\n" ); - } - -#endif /* DEBUG_GRAYS */ - - } - - -#ifdef _STANDALONE_ - - /*************************************************************************/ - /* */ - /* The following function should only compile in stand_alone mode, */ - /* i.e., if building this component without the rest of FreeType. */ - /* */ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* */ - /* FT_Outline_Decompose */ - /* */ - /* */ - /* Walks over an outline's structure to decompose it into individual */ - /* segments and Bezier arcs. This function is also able to emit */ - /* `move to' and `close to' operations to indicate the start and end */ - /* of new contours in the outline. */ - /* */ - /* */ - /* outline :: A pointer to the source target. */ - /* */ - /* interface :: A table of `emitters', i.e,. function pointers called */ - /* during decomposition to indicate path operations. */ - /* */ - /* user :: A typeless pointer which is passed to each emitter */ - /* during the decomposition. It can be used to store */ - /* the state during the decomposition. */ - /* */ - /* */ - /* Error code. 0 means sucess. */ - /* */ - static - int FT_Outline_Decompose( FT_Outline* outline, - FT_Outline_Funcs* interface, - void* user ) - { -#undef SCALED -#define SCALED( x ) ( ( (x) << shift ) - delta ) - - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_start; - - FT_Vector* point; - FT_Vector* limit; - char* tags; - - int n; /* index of contour in outline */ - int first; /* index of first point in contour */ - int error; - char tag; /* current point's state */ - - int shift = interface->shift; - FT_Pos delta = interface->delta; - - - first = 0; - - for ( n = 0; n < outline->n_contours; n++ ) - { - int last; /* index of last point in contour */ - - - last = outline->contours[n]; - limit = outline->points + last; - - v_start = outline->points[first]; - v_last = outline->points[last]; - - v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); - v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); - - v_control = v_start; - - point = outline->points + first; - tags = outline->tags + first; - tag = FT_CURVE_TAG( tags[0] ); - - /* A contour cannot start with a cubic control point! */ - if ( tag == FT_Curve_Tag_Cubic ) - goto Invalid_Outline; - - /* check first point to determine origin */ - if ( tag == FT_Curve_Tag_Conic ) - { - /* first point is conic control. Yes, this happens. */ - if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On ) - { - /* start at last point if it is on the curve */ - v_start = v_last; - limit--; - } - else - { - /* if both first and last points are conic, */ - /* start at their middle and record its position */ - /* for closure */ - v_start.x = ( v_start.x + v_last.x ) / 2; - v_start.y = ( v_start.y + v_last.y ) / 2; - - v_last = v_start; - } - point--; - tags--; - } - - error = interface->move_to( &v_start, user ); - if ( error ) - goto Exit; - - while ( point < limit ) - { - point++; - tags++; - - tag = FT_CURVE_TAG( tags[0] ); - switch ( tag ) - { - case FT_Curve_Tag_On: /* emit a single line_to */ - { - FT_Vector vec; - - - vec.x = SCALED( point->x ); - vec.y = SCALED( point->y ); - - error = interface->line_to( &vec, user ); - if ( error ) - goto Exit; - continue; - } - - case FT_Curve_Tag_Conic: /* consume conic arcs */ - { - v_control.x = SCALED( point->x ); - v_control.y = SCALED( point->y ); - - Do_Conic: - if ( point < limit ) - { - FT_Vector vec; - FT_Vector v_middle; - - - point++; - tags++; - tag = FT_CURVE_TAG( tags[0] ); - - vec.x = SCALED( point->x ); - vec.y = SCALED( point->y ); - - if ( tag == FT_Curve_Tag_On ) - { - error = interface->conic_to( &v_control, &vec, user ); - if ( error ) - goto Exit; - continue; - } - - if ( tag != FT_Curve_Tag_Conic ) - goto Invalid_Outline; - - v_middle.x = ( v_control.x + vec.x ) / 2; - v_middle.y = ( v_control.y + vec.y ) / 2; - - error = interface->conic_to( &v_control, &v_middle, user ); - if ( error ) - goto Exit; - - v_control = vec; - goto Do_Conic; - } - - error = interface->conic_to( &v_control, &v_start, user ); - goto Close; - } - - default: /* FT_Curve_Tag_Cubic */ - { - FT_Vector vec1, vec2; - - - if ( point + 1 > limit || - FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) - goto Invalid_Outline; - - point += 2; - tags += 2; - - vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); - vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); - - if ( point <= limit ) - { - FT_Vector vec; - - - vec.x = SCALED( point->x ); - vec.y = SCALED( point->y ); - - error = interface->cubic_to( &vec1, &vec2, &vec, user ); - if ( error ) - goto Exit; - continue; - } - - error = interface->cubic_to( &vec1, &vec2, &v_start, user ); - goto Close; - } - } - } - - /* close the contour with a line segment */ - error = interface->line_to( &v_start, user ); - - Close: - if ( error ) - goto Exit; - - first = last + 1; - } - - return 0; - - Exit: - return error; - - Invalid_Outline: - return ErrRaster_Invalid_Outline; - } - -#endif /* _STANDALONE_ */ - - - typedef struct TBand_ - { - FT_Pos min, max; - - } TBand; - - - static - int grays_convert_glyph( RAS_ARG_ FT_Outline* outline ) - { - static - FT_Outline_Funcs interface = - { - (FT_Outline_MoveTo_Func) Move_To, - (FT_Outline_LineTo_Func) Line_To, - (FT_Outline_ConicTo_Func)Conic_To, - (FT_Outline_CubicTo_Func)Cubic_To, - 0, - 0 - }; - - TBand bands[40], *band; - int n, num_bands; - TPos min, max, max_y; - - - /* Set up state in the raster object */ - 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_ey < 0 ) ras.min_ey = 0; - - 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; - - /* 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; - - ras.conic_level <<= level; - ras.cubic_level <<= level; - } - - /* setup vertical bands */ - 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; - } - - - extern - int grays_raster_render( PRaster raster, - FT_Raster_Params* params ) - { - FT_Outline* outline = (FT_Outline*)params->source; - FT_Bitmap* target_map = params->target; - - - if ( !raster || !raster->cells || !raster->max_cells ) - return -1; - - /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return 0; - - if ( !outline || !outline->contours || !outline->points ) - return ErrRaster_Invalid_Outline; - - if ( outline->n_points != - outline->contours[outline->n_contours - 1] + 1 ) - return ErrRaster_Invalid_Outline; - - if ( !target_map || !target_map->buffer ) - return -1; - - /* XXXX: this version does not support monochrome rendering yet! */ - if ( !( params->flags & ft_raster_flag_aa ) ) - return -1; - - ras.outline = *outline; - ras.target = *target_map; - ras.num_cells = 0; - ras.invalid = 1; - - ras.render_span = (FT_Raster_Span_Func)grays_render_span; - ras.render_span_data = &ras; - - if ( params->flags & ft_raster_flag_direct ) - { - ras.render_span = (FT_Raster_Span_Func)params->gray_spans; - ras.render_span_data = params->user; - } - - return grays_convert_glyph( (PRaster)raster, outline ); - } - - - /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ - /**** a static object. *****/ - -#ifdef _STANDALONE_ - - static - int grays_raster_new( void* memory, - FT_Raster* araster ) - { - static TRaster the_raster; - - UNUSED( memory ); - - - *araster = (FT_Raster)&the_raster; - memset( &the_raster, 0, sizeof ( the_raster ) ); - - return 0; - } - - - static - void grays_raster_done( FT_Raster raster ) - { - /* nothing */ - UNUSED( raster ); - } - -#else /* _STANDALONE_ */ - - static - int grays_raster_new( FT_Memory memory, - FT_Raster* araster ) - { - FT_Error error; - PRaster raster; - - - *araster = 0; - if ( !ALLOC( raster, sizeof ( TRaster ) ) ) - { - raster->memory = memory; - *araster = (FT_Raster)raster; - } - - return error; - } - - - static - void grays_raster_done( FT_Raster raster ) - { - FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; - - - FREE( raster ); - } - -#endif /* _STANDALONE_ */ - - - static - void grays_raster_reset( FT_Raster raster, - const char* pool_base, - long pool_size ) - { - PRaster rast = (PRaster)raster; - - - if ( raster && pool_base && pool_size >= 4096 ) - init_cells( rast, (char*)pool_base, pool_size ); - - rast->band_size = ( pool_size / sizeof ( TCell ) ) / 8; - } - - - FT_Raster_Funcs ft_grays_raster = - { - ft_glyph_format_outline, - - (FT_Raster_New_Func) grays_raster_new, - (FT_Raster_Reset_Func) grays_raster_reset, - (FT_Raster_Set_Mode_Func)0, - (FT_Raster_Render_Func) grays_raster_render, - (FT_Raster_Done_Func) grays_raster_done - }; - - -/* END */ diff --git a/src/renderer/ftgrays.h b/src/renderer/ftgrays.h deleted file mode 100644 index 2e6ff17eb..000000000 --- a/src/renderer/ftgrays.h +++ /dev/null @@ -1,58 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftgrays.h */ -/* */ -/* FreeType smooth renderer declaration */ -/* */ -/* Copyright 1996-2000 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. */ -/* */ -/***************************************************************************/ - - -#ifndef FTGRAYS_H -#define FTGRAYS_H - - -#ifdef __cplusplus - extern "C" { -#endif - - -#ifdef _STANDALONE_ -#include "ftimage.h" -#else -#include -#endif - - - /*************************************************************************/ - /* */ - /* To make ftgrays.h independent from configuration files we check */ - /* whether FT_EXPORT_VAR has been defined already. */ - /* */ - /* On some systems and compilers (Win32 mostly), an extra keyword is */ - /* necessary to compile the library as a DLL. */ - /* */ -#ifndef FT_EXPORT_VAR -#define FT_EXPORT_VAR( x ) extern x -#endif - - FT_EXPORT_VAR( FT_Raster_Funcs ) ft_grays_raster; - - -#ifdef __cplusplus -} -#endif - - -#endif /* FTGRAYS_H */ - - -/* END */ diff --git a/src/renderer/ftraster.c b/src/renderer/ftraster.c deleted file mode 100644 index 19beb9426..000000000 --- a/src/renderer/ftraster.c +++ /dev/null @@ -1,3267 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftraster.c */ -/* */ -/* The FreeType glyph rasterizer (body). */ -/* */ -/* Copyright 1996-2000 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. */ -/* */ -/***************************************************************************/ - - /*************************************************************************/ - /* */ - /* This is a rewrite of the FreeType 1.x scan-line converter */ - /* */ - /*************************************************************************/ - - -#include "ftraster.h" -#include /* for FT_MulDiv() only */ - - - /*************************************************************************/ - /* */ - /* A simple technical note on how the raster works: */ - /* */ - /* Converting an outline into a bitmap is achieved in several steps: */ - /* */ - /* 1 - Decomposing the outline into successive `profiles'. Each */ - /* profile is simply an array of scanline intersections on a given */ - /* dimension. A profile's main attributes are */ - /* */ - /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */ - /* */ - /* o an array of intersection coordinates for each scanline */ - /* between `Ymin' and `Ymax'. */ - /* */ - /* o a direction, indicating whether it was built going `up' or */ - /* `down', as this is very important for filling rules. */ - /* */ - /* 2 - Sweeping the target map's scanlines in order to compute segment */ - /* `spans' which are then filled. Additionally, this pass */ - /* performs drop-out control. */ - /* */ - /* The outline data is parsed during step 1 only. The profiles are */ - /* built from the bottom of the render pool, used as a stack. The */ - /* following graphics shows the profile list under construction: */ - /* */ - /* ____________________________________________________________ _ _ */ - /* | | | | | */ - /* | profile | coordinates for | profile | coordinates for |--> */ - /* | 1 | profile 1 | 2 | profile 2 |--> */ - /* |_________|___________________|_________|_________________|__ _ _ */ - /* */ - /* ^ ^ */ - /* | | */ - /* start of render pool top */ - /* */ - /* The top of the profile stack is kept in the `top' variable. */ - /* */ - /* As you can see, a profile record is pushed on top of the render */ - /* pool, which is then followed by its coordinates/intersections. If */ - /* a change of direction is detected in the outline, a new profile is */ - /* generated until the end of the outline. */ - /* */ - /* Note that when all profiles have been generated, the function */ - /* Finalize_Profile_Table() is used to record, for each profile, its */ - /* bottom-most scanline as well as the scanline above its upmost */ - /* boundary. These positions are called `y-turns' because they (sort */ - /* of) correspond to local extrema. They are stored in a sorted list */ - /* built from the top of the render pool as a downwards stack: */ - /* */ - /* _ _ _______________________________________ */ - /* | | */ - /* <--| sorted list of | */ - /* <--| extrema scanlines | */ - /* _ _ __________________|____________________| */ - /* */ - /* ^ ^ */ - /* | | */ - /* maxBuff sizeBuff = end of pool */ - /* */ - /* This list is later used during the sweep phase in order to */ - /* optimize performance (see technical note on the sweep below). */ - /* */ - /* Of course, the raster detects whether the two stacks collide and */ - /* handles the situation propertly. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /*************************************************************************/ - /** **/ - /** CONFIGURATION MACROS **/ - /** **/ - /*************************************************************************/ - /*************************************************************************/ - - /* define DEBUG_RASTER if you want to compile a debugging version */ -#define xxxDEBUG_RASTER - - /* The default render pool size in bytes */ -#define RASTER_RENDER_POOL 8192 - - /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */ - /* 5-levels anti-aliasing */ -#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS -#define FT_RASTER_OPTION_ANTI_ALIASING -#endif - - /* The size of the two-lines intermediate bitmap used */ - /* for anti-aliasing, in bytes. */ -#define RASTER_GRAY_LINES 2048 - - - /*************************************************************************/ - /*************************************************************************/ - /** **/ - /** OTHER MACROS (do not change) **/ - /** **/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_raster - - -#ifdef _STANDALONE_ - - - /* This macro is used to indicate that a function parameter is unused. */ - /* Its purpose is simply to reduce compiler warnings. Note also that */ - /* simply defining it as `(void)x' doesn't avoid warnings with certain */ - /* ANSI compilers (e.g. LCC). */ -#define UNUSED( x ) (x) = (x) - - /* Disable the tracing mechanism for simplicity -- developers can */ - /* activate it easily by redefining these two macros. */ -#ifndef FT_ERROR -#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ -#endif - -#ifndef FT_TRACE -#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ -#endif - - -#else /* _STANDALONE_ */ - - -#include -#include /* for FT_TRACE() and FT_ERROR() */ - - -#endif /* _STANDALONE_ */ - - -#define Raster_Err_None 0 -#define Raster_Err_Not_Ini -1 -#define Raster_Err_Overflow -2 -#define Raster_Err_Neg_Height -3 -#define Raster_Err_Invalid -4 -#define Raster_Err_Gray_Unsupported -5 -#define Raster_Err_Unsupported -6 - - /* FMulDiv means `Fast MulDiv', it is used in case where `b' is */ - /* typically a small value and the result of a*b is known to fit into */ - /* 32 bits. */ -#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) - - /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ - /* for clipping computations. It simply uses the FT_MulDiv() function */ - /* defined in `ftcalc.h'. */ -#define SMulDiv FT_MulDiv - - /* The rasterizer is a very general purpose component; please leave */ - /* the following redefinitions there (you never know your target */ - /* environment). */ - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef NULL -#define NULL (void*)0 -#endif - -#ifndef SUCCESS -#define SUCCESS 0 -#endif - -#ifndef FAILURE -#define FAILURE 1 -#endif - - -#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ - /* Setting this constant to more than 32 is a */ - /* pure waste of space. */ - -#define Pixel_Bits 6 /* fractional bits of *input* coordinates */ - - - /*************************************************************************/ - /*************************************************************************/ - /** **/ - /** SIMPLE TYPE DECLARATIONS **/ - /** **/ - /*************************************************************************/ - /*************************************************************************/ - - typedef int Int; - typedef unsigned int UInt; - typedef short Short; - typedef unsigned short UShort, *PUShort; - typedef long Long, *PLong; - typedef unsigned long ULong; - - typedef unsigned char Byte, *PByte; - typedef char Bool; - - - typedef struct TPoint_ - { - Long x; - Long y; - - } TPoint; - - - typedef enum TFlow_ - { - Flow_None = 0, - Flow_Up = 1, - Flow_Down = -1 - - } TFlow; - - - /* States of each line, arc, and profile */ - typedef enum TStates_ - { - Unknown, - Ascending, - Descending, - Flat - - } TStates; - - - typedef struct TProfile_ TProfile; - typedef TProfile* PProfile; - - struct TProfile_ - { - FT_F26Dot6 X; /* current coordinate during sweep */ - PProfile link; /* link to next profile - various purpose */ - PLong offset; /* start of profile's data in render pool */ - Int flow; /* Profile orientation: Asc/Descending */ - Long height; /* profile's height in scanlines */ - Long start; /* profile's starting scanline */ - - UShort countL; /* number of lines to step before this */ - /* profile becomes drawable */ - - PProfile next; /* next profile in same contour, used */ - /* during drop-out control */ - }; - - typedef PProfile TProfileList; - typedef PProfile* PProfileList; - - - /* Simple record used to implement a stack of bands, required */ - /* by the sub-banding mechanism */ - typedef struct TBand_ - { - Short y_min; /* band's minimum */ - Short y_max; /* band's maximum */ - - } TBand; - - -#define AlignProfileSize \ - ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) ) - - -#ifdef TT_STATIC_RASTER - - -#define RAS_ARGS /* void */ -#define RAS_ARG /* void */ - -#define RAS_VARS /* void */ -#define RAS_VAR /* void */ - -#define UNUSED_RASTER do ; while ( 0 ) - - -#else /* TT_STATIC_RASTER */ - - -#define RAS_ARGS TRaster_Instance* raster, -#define RAS_ARG TRaster_Instance* raster - -#define RAS_VARS raster, -#define RAS_VAR raster - -#define UNUSED_RASTER UNUSED( raster ) - - -#endif /* TT_STATIC_RASTER */ - - - typedef struct TRaster_Instance_ TRaster_Instance; - - - /* prototypes used for sweep function dispatch */ - typedef void Function_Sweep_Init( RAS_ARGS Short* min, - Short* max ); - - typedef void Function_Sweep_Span( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ); - - typedef void Function_Sweep_Step( RAS_ARG ); - - - /* NOTE: These operations are only valid on 2's complement processors */ - -#define FLOOR( x ) ( (x) & -ras.precision ) -#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) -#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) -#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) -#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) - - /* Note that I have moved the location of some fields in the */ - /* structure to ensure that the most used variables are used */ - /* at the top. Thus, their offset can be coded with less */ - /* opcodes, and it results in a smaller executable. */ - - struct TRaster_Instance_ - { - Int precision_bits; /* precision related variables */ - Int precision; - Int precision_half; - Long precision_mask; - Int precision_shift; - Int precision_step; - Int precision_jitter; - - Int scale_shift; /* == precision_shift for bitmaps */ - /* == precision_shift+1 for pixmaps */ - - PLong buff; /* The profiles buffer */ - PLong sizeBuff; /* Render pool size */ - PLong maxBuff; /* Profiles buffer size */ - PLong top; /* Current cursor in buffer */ - - FT_Error error; - - Int numTurns; /* number of Y-turns in outline */ - - TPoint* arc; /* current Bezier arc pointer */ - - UShort bWidth; /* target bitmap width */ - PByte bTarget; /* target bitmap buffer */ - PByte gTarget; /* target pixmap buffer */ - - Long lastX, lastY, minY, maxY; - - UShort num_Profs; /* current number of profiles */ - - Bool fresh; /* signals a fresh new profile which */ - /* 'start' field must be completed */ - Bool joint; /* signals that the last arc ended */ - /* exactly on a scanline. Allows */ - /* removal of doublets */ - PProfile cProfile; /* current profile */ - PProfile fProfile; /* head of linked list of profiles */ - PProfile gProfile; /* contour's first profile in case */ - /* of impact */ - TStates state; /* rendering state */ - - FT_Bitmap target; /* description of target bit/pixmap */ - FT_Outline outline; - - Long traceOfs; /* current offset in target bitmap */ - Long traceG; /* current offset in target pixmap */ - - Short traceIncr; /* sweep's increment in target bitmap */ - - Short gray_min_x; /* current min x during gray rendering */ - Short gray_max_x; /* current max x during gray rendering */ - - /* dispatch variables */ - - Function_Sweep_Init* Proc_Sweep_Init; - Function_Sweep_Span* Proc_Sweep_Span; - Function_Sweep_Span* Proc_Sweep_Drop; - Function_Sweep_Step* Proc_Sweep_Step; - - Byte dropOutControl; /* current drop_out control method */ - - Bool second_pass; /* indicates wether a horizontal pass */ - /* should be performed to control */ - /* drop-out accurately when calling */ - /* Render_Glyph. Note that there is */ - /* no horizontal pass during gray */ - /* rendering. */ - TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ - - TBand band_stack[16]; /* band stack used for sub-banding */ - Int band_top; /* band stack top */ - - Int count_table[256]; /* Look-up table used to quickly count */ - /* set bits in a gray 2x2 cell */ - - void* memory; - -#ifdef FT_RASTER_OPTION_ANTI_ALIASING - - Byte grays[5]; /* Palette of gray levels used for */ - /* render. */ - - Byte gray_lines[RASTER_GRAY_LINES]; - /* Intermediate table used to render the */ - /* graylevels pixmaps. */ - /* gray_lines is a buffer holding two */ - /* monochrome scanlines */ - Short gray_width; /* width in bytes of one monochrome */ - /* intermediate scanline of gray_lines. */ - /* Each gray pixel takes 2 bits long there */ - - /* The gray_lines must hold 2 lines, thus with size */ - /* in bytes of at least `gray_width*2'. */ - -#endif /* FT_RASTER_ANTI_ALIASING */ - -#if 0 - PByte flags; /* current flags table */ - PUShort outs; /* current outlines table */ - FT_Vector* coords; - - UShort nPoints; /* number of points in current glyph */ - Short nContours; /* number of contours in current glyph */ -#endif - - }; - - -#ifdef FT_CONFIG_OPTION_STATIC_RASTER - - static TRaster_Instance cur_ras; -#define ras cur_ras - -#else - -#define ras (*raster) - -#endif /* FT_CONFIG_OPTION_STATIC_RASTER */ - - - /*************************************************************************/ - /*************************************************************************/ - /** **/ - /** PROFILES COMPUTATION **/ - /** **/ - /*************************************************************************/ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* */ - /* Set_High_Precision */ - /* */ - /* */ - /* Sets precision variables according to param flag. */ - /* */ - /* */ - /* High :: Set to True for high precision (typically for ppem < 18), */ - /* false otherwise. */ - /* */ - static - void Set_High_Precision( RAS_ARGS Int High ) - { - if ( High ) - { - ras.precision_bits = 10; - ras.precision_step = 128; - ras.precision_jitter = 24; - } - else - { - ras.precision_bits = 6; - ras.precision_step = 32; - ras.precision_jitter = 2; - } - - FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); - - ras.precision = 1L << ras.precision_bits; - ras.precision_half = ras.precision / 2; - ras.precision_shift = ras.precision_bits - Pixel_Bits; - ras.precision_mask = -ras.precision; - } - - - /*************************************************************************/ - /* */ - /* */ - /* New_Profile */ - /* */ - /* */ - /* Creates a new profile in the render pool. */ - /* */ - /* */ - /* aState :: The state/orientation of the new profile. */ - /* */ - /* */ - /* SUCCESS on success. FAILURE in case of overflow or of incoherent */ - /* profile. */ - /* */ - static - Bool New_Profile( RAS_ARGS TStates aState ) - { - if ( !ras.fProfile ) - { - ras.cProfile = (PProfile)ras.top; - ras.fProfile = ras.cProfile; - ras.top += AlignProfileSize; - } - - if ( ras.top >= ras.maxBuff ) - { - ras.error = Raster_Err_Overflow; - return FAILURE; - } - - switch ( aState ) - { - case Ascending: - ras.cProfile->flow = Flow_Up; - FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile )); - break; - - case Descending: - ras.cProfile->flow = Flow_Down; - FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile )); - break; - - default: - FT_ERROR(( "New_Profile: invalid profile direction!\n" )); - ras.error = Raster_Err_Invalid; - return FAILURE; - } - - ras.cProfile->start = 0; - ras.cProfile->height = 0; - ras.cProfile->offset = ras.top; - ras.cProfile->link = (PProfile)0; - ras.cProfile->next = (PProfile)0; - - if ( !ras.gProfile ) - ras.gProfile = ras.cProfile; - - ras.state = aState; - ras.fresh = TRUE; - ras.joint = FALSE; - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* End_Profile */ - /* */ - /* */ - /* Finalizes the current profile. */ - /* */ - /* */ - /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ - /* */ - static - Bool End_Profile( RAS_ARG ) - { - Long h; - PProfile oldProfile; - - - h = ras.top - ras.cProfile->offset; - - if ( h < 0 ) - { - FT_ERROR(( "End_Profile: negative height encountered!\n" )); - ras.error = Raster_Err_Neg_Height; - return FAILURE; - } - - if ( h > 0 ) - { - FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n", - (long)ras.cProfile, ras.cProfile->start, h )); - - oldProfile = ras.cProfile; - ras.cProfile->height = h; - ras.cProfile = (PProfile)ras.top; - - ras.top += AlignProfileSize; - - ras.cProfile->height = 0; - ras.cProfile->offset = ras.top; - oldProfile->next = ras.cProfile; - ras.num_Profs++; - } - - if ( ras.top >= ras.maxBuff ) - { - FT_TRACE1(( "overflow in End_Profile\n" )); - ras.error = Raster_Err_Overflow; - return FAILURE; - } - - ras.joint = FALSE; - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Insert_Y_Turn */ - /* */ - /* */ - /* Inserts a salient into the sorted list placed on top of the render */ - /* pool. */ - /* */ - /* */ - /* New y scanline position. */ - /* */ - /* */ - /* SUCCESS on success. FAILURE in case of overflow. */ - /* */ - static - Bool Insert_Y_Turn( RAS_ARGS Int y ) - { - PLong y_turns; - Int y2, n; - - - n = ras.numTurns - 1; - y_turns = ras.sizeBuff - ras.numTurns; - - /* look for first y value that is <= */ - while ( n >= 0 && y < y_turns[n] ) - n--; - - /* if it is <, simply insert it, ignore if == */ - if ( n >= 0 && y > y_turns[n] ) - while ( n >= 0 ) - { - y2 = y_turns[n]; - y_turns[n] = y; - y = y2; - n--; - } - - if ( n < 0 ) - { - if ( ras.maxBuff <= ras.top ) - { - ras.error = Raster_Err_Overflow; - return FAILURE; - } - ras.maxBuff--; - ras.numTurns++; - ras.sizeBuff[-ras.numTurns] = y; - } - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Finalize_Profile_Table */ - /* */ - /* */ - /* Adjusts all links in the profiles list. */ - /* */ - /* */ - /* SUCCESS on success. FAILURE in case of overflow. */ - /* */ - static - Bool Finalize_Profile_Table( RAS_ARG ) - { - Int bottom, top; - UShort n; - PProfile p; - - - n = ras.num_Profs; - - if ( n > 1 ) - { - p = ras.fProfile; - while ( n > 0 ) - { - if ( n > 1 ) - p->link = (PProfile)( p->offset + p->height ); - else - p->link = NULL; - - switch ( p->flow ) - { - case Flow_Down: - bottom = p->start - p->height+1; - top = p->start; - p->start = bottom; - p->offset += p->height - 1; - break; - - case Flow_Up: - default: - bottom = p->start; - top = p->start + p->height - 1; - } - - if ( Insert_Y_Turn( RAS_VARS bottom ) || - Insert_Y_Turn( RAS_VARS top + 1 ) ) - return FAILURE; - - p = p->link; - n--; - } - } - else - ras.fProfile = NULL; - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Split_Conic */ - /* */ - /* */ - /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */ - /* stack. */ - /* */ - /* */ - /* None (subdivided Bezier is taken from the top of the stack). */ - /* */ - /* */ - /* This routine is the `beef' of this component. It is _the_ inner */ - /* loop that should be optimized to hell to get the best performance. */ - /* */ - static - void Split_Conic( TPoint* base ) - { - Long a, b; - - - base[4].x = base[2].x; - b = base[1].x; - a = base[3].x = ( base[2].x + b ) / 2; - b = base[1].x = ( base[0].x + b ) / 2; - base[2].x = ( a + b ) / 2; - - base[4].y = base[2].y; - b = base[1].y; - a = base[3].y = ( base[2].y + b ) / 2; - b = base[1].y = ( base[0].y + b ) / 2; - base[2].y = ( a + b ) / 2; - - /* hand optimized. gcc doesn't seem too good at common expression */ - /* substitution and instruction scheduling ;-) */ - } - - - /*************************************************************************/ - /* */ - /* */ - /* Split_Cubic */ - /* */ - /* */ - /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */ - /* Bezier stack. */ - /* */ - /* */ - /* This routine is the `beef' of the component. It is one of _the_ */ - /* inner loops that should be optimized like hell to get the best */ - /* performance. */ - /* */ - static - void Split_Cubic( TPoint* base ) - { - Long a, b, c, d; - - - base[6].x = base[3].x; - c = base[1].x; - d = base[2].x; - base[1].x = a = ( base[0].x + c + 1 ) >> 1; - base[5].x = b = ( base[3].x + d + 1 ) >> 1; - c = ( c + d + 1 ) >> 1; - base[2].x = a = ( a + c + 1 ) >> 1; - base[4].x = b = ( b + c + 1 ) >> 1; - base[3].x = ( a + b + 1 ) >> 1; - - base[6].y = base[3].y; - c = base[1].y; - d = base[2].y; - base[1].y = a = ( base[0].y + c + 1 ) >> 1; - base[5].y = b = ( base[3].y + d + 1 ) >> 1; - c = ( c + d + 1 ) >> 1; - base[2].y = a = ( a + c + 1 ) >> 1; - base[4].y = b = ( b + c + 1 ) >> 1; - base[3].y = ( a + b + 1 ) >> 1; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Line_Up */ - /* */ - /* */ - /* Computes the x-coordinates of an ascending line segment and stores */ - /* them in the render pool. */ - /* */ - /* */ - /* x1 :: The x-coordinate of the segment's start point. */ - /* */ - /* y1 :: The y-coordinate of the segment's start point. */ - /* */ - /* x2 :: The x-coordinate of the segment's end point. */ - /* */ - /* y2 :: The y-coordinate of the segment's end point. */ - /* */ - /* miny :: A lower vertical clipping bound value. */ - /* */ - /* maxy :: An upper vertical clipping bound value. */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow. */ - /* */ - static - Bool Line_Up( RAS_ARGS Long x1, Long y1, - Long x2, Long y2, - Long miny, Long maxy ) - { - Long Dx, Dy; - Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ - Long Ix, Rx, Ax; - - PLong top; - - - Dx = x2 - x1; - Dy = y2 - y1; - - if ( Dy <= 0 || y2 < miny || y1 > maxy ) - return SUCCESS; - - if ( y1 < miny ) - { - /* Take care: miny-y1 can be a very large value; we use */ - /* a slow MulDiv function to avoid clipping bugs */ - x1 += SMulDiv( Dx, miny - y1, Dy ); - e1 = TRUNC( miny ); - f1 = 0; - } - else - { - e1 = TRUNC( y1 ); - f1 = FRAC( y1 ); - } - - if ( y2 > maxy ) - { - /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ - e2 = TRUNC( maxy ); - f2 = 0; - } - else - { - e2 = TRUNC( y2 ); - f2 = FRAC( y2 ); - } - - if ( f1 > 0 ) - { - if ( e1 == e2 ) - return SUCCESS; - else - { - x1 += FMulDiv( Dx, ras.precision - f1, Dy ); - e1 += 1; - } - } - else - if ( ras.joint ) - { - ras.top--; - ras.joint = FALSE; - } - - ras.joint = ( f2 == 0 ); - - if ( ras.fresh ) - { - ras.cProfile->start = e1; - ras.fresh = FALSE; - } - - size = e2 - e1 + 1; - if ( ras.top + size >= ras.maxBuff ) - { - ras.error = Raster_Err_Overflow; - return FAILURE; - } - - if ( Dx > 0 ) - { - Ix = ( ras.precision * Dx ) / Dy; - Rx = ( ras.precision * Dx ) % Dy; - Dx = 1; - } - else - { - Ix = -( ( ras.precision * -Dx ) / Dy ); - Rx = ( ras.precision * -Dx ) % Dy; - Dx = -1; - } - - Ax = -Dy; - top = ras.top; - - while ( size > 0 ) - { - *top++ = x1; - - x1 += Ix; - Ax += Rx; - if ( Ax >= 0 ) - { - Ax -= Dy; - x1 += Dx; - } - size--; - } - - ras.top = top; - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Line_Down */ - /* */ - /* */ - /* Computes the x-coordinates of an descending line segment and */ - /* stores them in the render pool. */ - /* */ - /* */ - /* x1 :: The x-coordinate of the segment's start point. */ - /* */ - /* y1 :: The y-coordinate of the segment's start point. */ - /* */ - /* x2 :: The x-coordinate of the segment's end point. */ - /* */ - /* y2 :: The y-coordinate of the segment's end point. */ - /* */ - /* miny :: A lower vertical clipping bound value. */ - /* */ - /* maxy :: An upper vertical clipping bound value. */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow. */ - /* */ - static - Bool Line_Down( RAS_ARGS Long x1, Long y1, - Long x2, Long y2, - Long miny, Long maxy ) - { - Bool result, fresh; - - - fresh = ras.fresh; - - result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); - - if ( fresh && !ras.fresh ) - ras.cProfile->start = -ras.cProfile->start; - - return result; - } - - - /* A function type describing the functions used to split Bezier arcs */ - typedef void (*TSplitter)( TPoint* base ); - - - /*************************************************************************/ - /* */ - /* */ - /* Bezier_Up */ - /* */ - /* */ - /* Computes the x-coordinates of an ascending Bezier arc and stores */ - /* them in the render pool. */ - /* */ - /* */ - /* degree :: The degree of the Bezier arc (either 2 or 3). */ - /* */ - /* splitter :: The function to split Bezier arcs. */ - /* */ - /* miny :: A lower vertical clipping bound value. */ - /* */ - /* maxy :: An upper vertical clipping bound value. */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow. */ - /* */ - static - Bool Bezier_Up( RAS_ARGS Int degree, - TSplitter splitter, - Long miny, - Long maxy ) - { - Long y1, y2, e, e2, e0; - Short f1; - - TPoint* arc; - TPoint* start_arc; - - PLong top; - - - arc = ras.arc; - y1 = arc[degree].y; - y2 = arc[0].y; - top = ras.top; - - if ( y2 < miny || y1 > maxy ) - goto Fin; - - e2 = FLOOR( y2 ); - - if ( e2 > maxy ) - e2 = maxy; - - e0 = miny; - - if ( y1 < miny ) - e = miny; - else - { - e = CEILING( y1 ); - f1 = FRAC( y1 ); - e0 = e; - - if ( f1 == 0 ) - { - if ( ras.joint ) - { - top--; - ras.joint = FALSE; - } - - *top++ = arc[degree].x; - - e += ras.precision; - } - } - - if ( ras.fresh ) - { - ras.cProfile->start = TRUNC( e0 ); - ras.fresh = FALSE; - } - - if ( e2 < e ) - goto Fin; - - if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) - { - ras.top = top; - ras.error = Raster_Err_Overflow; - return FAILURE; - } - - start_arc = arc; - - while ( arc >= start_arc && e <= e2 ) - { - ras.joint = FALSE; - - y2 = arc[0].y; - - if ( y2 > e ) - { - y1 = arc[degree].y; - if ( y2 - y1 >= ras.precision_step ) - { - splitter( arc ); - arc += degree; - } - else - { - *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x, - e - y1, y2 - y1 ); - arc -= degree; - e += ras.precision; - } - } - else - { - if ( y2 == e ) - { - ras.joint = TRUE; - *top++ = arc[0].x; - - e += ras.precision; - } - arc -= degree; - } - } - - Fin: - ras.top = top; - ras.arc -= degree; - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Bezier_Down */ - /* */ - /* */ - /* Computes the x-coordinates of an descending Bezier arc and stores */ - /* them in the render pool. */ - /* */ - /* */ - /* degree :: The degree of the Bezier arc (either 2 or 3). */ - /* */ - /* splitter :: The function to split Bezier arcs. */ - /* */ - /* miny :: A lower vertical clipping bound value. */ - /* */ - /* maxy :: An upper vertical clipping bound value. */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow. */ - /* */ - static - Bool Bezier_Down( RAS_ARGS Int degree, - TSplitter splitter, - Long miny, - Long maxy ) - { - TPoint* arc = ras.arc; - Bool result, fresh; - - - arc[0].y = -arc[0].y; - arc[1].y = -arc[1].y; - arc[2].y = -arc[2].y; - if ( degree > 2 ) - arc[3].y = -arc[3].y; - - fresh = ras.fresh; - - result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); - - if ( fresh && !ras.fresh ) - ras.cProfile->start = -ras.cProfile->start; - - arc[0].y = -arc[0].y; - return result; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Line_To */ - /* */ - /* */ - /* Injects a new line segment and adjusts Profiles list. */ - /* */ - /* */ - /* x :: The x-coordinate of the segment's end point (its start point */ - /* is stored in `LastX'). */ - /* */ - /* y :: The y-coordinate of the segment's end point (its start point */ - /* is stored in `LastY'). */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ - /* profile. */ - /* */ - static - Bool Line_To( RAS_ARGS Long x, - Long y ) - { - /* First, detect a change of direction */ - - switch ( ras.state ) - { - case Unknown: - if ( y > ras.lastY ) - { - if ( New_Profile( RAS_VARS Ascending ) ) - return FAILURE; - } - else - { - if ( y < ras.lastY ) - if ( New_Profile( RAS_VARS Descending ) ) - return FAILURE; - } - break; - - case Ascending: - if ( y < ras.lastY ) - { - if ( End_Profile( RAS_VAR ) || - New_Profile( RAS_VARS Descending ) ) - return FAILURE; - } - break; - - case Descending: - if ( y > ras.lastY ) - { - if ( End_Profile( RAS_VAR ) || - New_Profile( RAS_VARS Ascending ) ) - return FAILURE; - } - break; - - default: - ; - } - - /* Then compute the lines */ - - switch ( ras.state ) - { - case Ascending: - if ( Line_Up ( RAS_VARS ras.lastX, ras.lastY, - x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - case Descending: - if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, - x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; - } - - ras.lastX = x; - ras.lastY = y; - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Conic_To */ - /* */ - /* */ - /* Injects a new conic arc and adjusts the profile list. */ - /* */ - /* */ - /* cx :: The x-coordinate of the arc's new control point. */ - /* */ - /* cy :: The y-coordinate of the arc's new control point. */ - /* */ - /* x :: The x-coordinate of the arc's end point (its start point is */ - /* stored in `LastX'). */ - /* */ - /* y :: The y-coordinate of the arc's end point (its start point is */ - /* stored in `LastY'). */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ - /* profile. */ - /* */ - static - Bool Conic_To( RAS_ARGS Long cx, - Long cy, - Long x, - Long y ) - { - Long y1, y2, y3, x3, ymin, ymax; - TStates state_bez; - - - ras.arc = ras.arcs; - ras.arc[2].x = ras.lastX; - ras.arc[2].y = ras.lastY; - ras.arc[1].x = cx; ras.arc[1].y = cy; - ras.arc[0].x = x; ras.arc[0].y = y; - - do - { - y1 = ras.arc[2].y; - y2 = ras.arc[1].y; - y3 = ras.arc[0].y; - x3 = ras.arc[0].x; - - /* first, categorize the Bezier arc */ - - if ( y1 <= y3 ) - { - ymin = y1; - ymax = y3; - } - else - { - ymin = y3; - ymax = y1; - } - - if ( y2 < ymin || y2 > ymax ) - { - /* this arc has no given direction, split it! */ - Split_Conic( ras.arc ); - ras.arc += 2; - } - else if ( y1 == y3 ) - { - /* this arc is flat, ignore it and pop it from the Bezier stack */ - ras.arc -= 2; - } - else - { - /* the arc is y-monotonous, either ascending or descending */ - /* detect a change of direction */ - state_bez = y1 < y3 ? Ascending : Descending; - if ( ras.state != state_bez ) - { - /* finalize current profile if any */ - if ( ras.state != Unknown && - End_Profile( RAS_VAR ) ) - goto Fail; - - /* create a new profile */ - if ( New_Profile( RAS_VARS state_bez ) ) - goto Fail; - } - - /* now call the appropriate routine */ - if ( state_bez == Ascending ) - { - if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) - goto Fail; - } - else - if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) - goto Fail; - } - - } while ( ras.arc >= ras.arcs ); - - ras.lastX = x3; - ras.lastY = y3; - - return SUCCESS; - - Fail: - return FAILURE; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Cubic_To */ - /* */ - /* */ - /* Injects a new cubic arc and adjusts the profile list. */ - /* */ - /* */ - /* cx1 :: The x-coordinate of the arc's first new control point. */ - /* */ - /* cy1 :: The y-coordinate of the arc's first new control point. */ - /* */ - /* cx2 :: The x-coordinate of the arc's second new control point. */ - /* */ - /* cy2 :: The y-coordinate of the arc's second new control point. */ - /* */ - /* x :: The x-coordinate of the arc's end point (its start point is */ - /* stored in `LastX'). */ - /* */ - /* y :: The y-coordinate of the arc's end point (its start point is */ - /* stored in `LastY'). */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ - /* profile. */ - /* */ - static - Bool Cubic_To( RAS_ARGS Long cx1, - Long cy1, - Long cx2, - Long cy2, - Long x, - Long y ) - { - Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; - TStates state_bez; - - - ras.arc = ras.arcs; - ras.arc[3].x = ras.lastX; - ras.arc[3].y = ras.lastY; - ras.arc[2].x = cx1; ras.arc[2].y = cy1; - ras.arc[1].x = cx2; ras.arc[1].y = cy2; - ras.arc[0].x = x; ras.arc[0].y = y; - - do - { - y1 = ras.arc[3].y; - y2 = ras.arc[2].y; - y3 = ras.arc[1].y; - y4 = ras.arc[0].y; - x4 = ras.arc[0].x; - - /* first, categorize the Bezier arc */ - - if ( y1 <= y4 ) - { - ymin1 = y1; - ymax1 = y4; - } - else - { - ymin1 = y4; - ymax1 = y1; - } - - if ( y2 <= y3 ) - { - ymin2 = y2; - ymax2 = y3; - } - else - { - ymin2 = y3; - ymax2 = y2; - } - - if ( ymin2 < ymin1 || ymax2 > ymax1 ) - { - /* this arc has no given direction, split it! */ - Split_Cubic( ras.arc ); - ras.arc += 3; - } - else if ( y1 == y4 ) - { - /* this arc is flat, ignore it and pop it from the Bezier stack */ - ras.arc -= 3; - } - else - { - state_bez = y1 <= y4 ? Ascending : Descending; - - /* detect a change of direction */ - if ( ras.state != state_bez ) - { - if ( ras.state != Unknown && - End_Profile( RAS_VAR ) ) - goto Fail; - - if ( New_Profile( RAS_VARS state_bez ) ) - goto Fail; - } - - /* compute intersections */ - if ( state_bez == Ascending ) - { - if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) - goto Fail; - } - else - if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) - goto Fail; - } - - } while ( ras.arc >= ras.arcs ); - - ras.lastX = x4; - ras.lastY = y4; - - return SUCCESS; - - Fail: - return FAILURE; - } - - -#undef SWAP_ -#define SWAP_( x, y ) do \ - { \ - Long swap = x; \ - \ - \ - x = y; \ - y = swap; \ - } while ( 0 ) - - - /*************************************************************************/ - /* */ - /* */ - /* Decompose_Curve */ - /* */ - /* */ - /* Scans the outline arays in order to emit individual segments and */ - /* Beziers by calling Line_To() and Bezier_To(). It handles all */ - /* weird cases, like when the first point is off the curve, or when */ - /* there are simply no `on' points in the contour! */ - /* */ - /* */ - /* first :: The index of the first point in the contour. */ - /* */ - /* last :: The index of the last point in the contour. */ - /* */ - /* flipped :: If set, flip the direction of the curve. */ - /* */ - /* */ - /* SUCCESS on success, FAILURE on error. */ - /* */ - static - Bool Decompose_Curve( RAS_ARGS UShort first, - UShort last, - int flipped ) - { - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_start; - - FT_Vector* points; - FT_Vector* point; - FT_Vector* limit; - char* tags; - - char tag; /* current point's state */ - - - points = ras.outline.points; - limit = points + last; - - v_start.x = SCALED( points[first].x ); - v_start.y = SCALED( points[first].y ); - v_last.x = SCALED( points[last].x ); - v_last.y = SCALED( points[last].y ); - - if ( flipped ) - { - SWAP_( v_start.x, v_start.y ); - SWAP_( v_last.x, v_last.y ); - } - - v_control = v_start; - - point = points + first; - tags = ras.outline.tags + first; - tag = FT_CURVE_TAG( tags[0] ); - - /* A contour cannot start with a cubic control point! */ - if ( tag == FT_Curve_Tag_Cubic ) - goto Invalid_Outline; - - /* check first point to determine origin */ - if ( tag == FT_Curve_Tag_Conic ) - { - /* first point is conic control. Yes, this happens. */ - if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On ) - { - /* start at last point if it is on the curve */ - v_start = v_last; - limit--; - } - else - { - /* if both first and last points are conic, */ - /* start at their middle and record its position */ - /* for closure */ - v_start.x = ( v_start.x + v_last.x ) / 2; - v_start.y = ( v_start.y + v_last.y ) / 2; - - v_last = v_start; - } - point--; - tags--; - } - - ras.lastX = v_start.x; - ras.lastY = v_start.y; - - while ( point < limit ) - { - point++; - tags++; - - tag = FT_CURVE_TAG( tags[0] ); - - switch ( tag ) - { - case FT_Curve_Tag_On: /* emit a single line_to */ - { - Long x, y; - - - x = SCALED( point->x ); - y = SCALED( point->y ); - if ( flipped ) - SWAP_( x, y ); - - if ( Line_To( RAS_VARS x, y ) ) - goto Fail; - continue; - } - - case FT_Curve_Tag_Conic: /* consume conic arcs */ - { - v_control.x = SCALED( point[0].x ); - v_control.y = SCALED( point[0].y ); - - if ( flipped ) - SWAP_( v_control.x, v_control.y ); - - Do_Conic: - if ( point < limit ) - { - FT_Vector v_middle; - Long x, y; - - - point++; - tags++; - tag = FT_CURVE_TAG( tags[0] ); - - x = SCALED( point[0].x ); - y = SCALED( point[0].y ); - - if ( flipped ) - SWAP_( x, y ); - - if ( tag == FT_Curve_Tag_On ) - { - if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) - goto Fail; - continue; - } - - if ( tag != FT_Curve_Tag_Conic ) - goto Invalid_Outline; - - v_middle.x = ( v_control.x + x ) / 2; - v_middle.y = ( v_control.y + y ) / 2; - - if ( Conic_To( RAS_VARS v_control.x, v_control.y, - v_middle.x, v_middle.y ) ) - goto Fail; - - v_control.x = x; - v_control.y = y; - - goto Do_Conic; - } - - if ( Conic_To( RAS_VARS v_control.x, v_control.y, - v_start.x, v_start.y ) ) - goto Fail; - - goto Close; - } - - default: /* FT_Curve_Tag_Cubic */ - { - Long x1, y1, x2, y2, x3, y3; - - - if ( point + 1 > limit || - FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) - goto Invalid_Outline; - - point += 2; - tags += 2; - - x1 = SCALED( point[-2].x ); - y1 = SCALED( point[-2].y ); - x2 = SCALED( point[-1].x ); - y2 = SCALED( point[-1].y ); - x3 = SCALED( point[ 0].x ); - y3 = SCALED( point[ 0].y ); - - if ( flipped ) - { - SWAP_( x1, y1 ); - SWAP_( x2, y2 ); - SWAP_( x3, y3 ); - } - - if ( point <= limit ) - { - if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) - goto Fail; - continue; - } - - if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) - goto Fail; - goto Close; - } - } - } - - /* close the contour with a line segment */ - if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) - goto Fail; - - Close: - return SUCCESS; - - Invalid_Outline: - ras.error = Raster_Err_Invalid; - - Fail: - return FAILURE; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Convert_Glyph */ - /* */ - /* */ - /* Converts a glyph into a series of segments and arcs and makes a */ - /* profiles list with them. */ - /* */ - /* */ - /* flipped :: If set, flip the direction of curve. */ - /* */ - /* */ - /* SUCCESS on success, FAILURE if any error was encountered during */ - /* rendering. */ - /* */ - static - Bool Convert_Glyph( RAS_ARGS int flipped ) - { - Short i; - UShort start; - - PProfile lastProfile; - - - ras.fProfile = NULL; - ras.joint = FALSE; - ras.fresh = FALSE; - - ras.maxBuff = ras.sizeBuff - AlignProfileSize; - - ras.numTurns = 0; - - ras.cProfile = (PProfile)ras.top; - ras.cProfile->offset = ras.top; - ras.num_Profs = 0; - - start = 0; - - for ( i = 0; i < ras.outline.n_contours; i++ ) - { - ras.state = Unknown; - ras.gProfile = NULL; - - if ( Decompose_Curve( RAS_VARS start, ras.outline.contours[i], flipped ) ) - return FAILURE; - - start = ras.outline.contours[i] + 1; - - /* We must now see whether the extreme arcs join or not */ - if ( FRAC( ras.lastY ) == 0 && - ras.lastY >= ras.minY && - ras.lastY <= ras.maxY ) - if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow ) - ras.top--; - /* Note that ras.gProfile can be nil if the contour was too small */ - /* to be drawn. */ - - lastProfile = ras.cProfile; - if ( End_Profile( RAS_VAR ) ) - return FAILURE; - - /* close the `next profile in contour' linked list */ - if ( ras.gProfile ) - lastProfile->next = ras.gProfile; - } - - if ( Finalize_Profile_Table( RAS_VAR ) ) - return FAILURE; - - return ( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /** **/ - /** SCAN-LINE SWEEPS AND DRAWING **/ - /** **/ - /*************************************************************************/ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* Init_Linked */ - /* */ - /* Initializes an empty linked list. */ - /* */ - static - void Init_Linked( TProfileList* l ) - { - *l = NULL; - } - - - /*************************************************************************/ - /* */ - /* InsNew */ - /* */ - /* Inserts a new profile in a linked list. */ - /* */ - static - void InsNew( PProfileList list, - PProfile profile ) - { - PProfile *old, current; - Long x; - - - old = list; - current = *old; - x = profile->X; - - while ( current ) - { - if ( x < current->X ) - break; - old = ¤t->link; - current = *old; - } - - profile->link = current; - *old = profile; - } - - - /*************************************************************************/ - /* */ - /* DelOld */ - /* */ - /* Removes an old profile from a linked list. */ - /* */ - static - void DelOld( PProfileList list, - PProfile profile ) - { - PProfile *old, current; - - - old = list; - current = *old; - - while ( current ) - { - if ( current == profile ) - { - *old = current->link; - return; - } - - old = ¤t->link; - current = *old; - } - - /* we should never get there, unless the profile was not part of */ - /* the list. */ - } - - - /*************************************************************************/ - /* */ - /* Update */ - /* */ - /* Update all X offsets of a drawing list. */ - /* */ - static - void Update( PProfile first ) - { - PProfile current = first; - - - while ( current ) - { - current->X = *current->offset; - current->offset += current->flow; - current->height--; - current = current->link; - } - } - - - /*************************************************************************/ - /* */ - /* Sort */ - /* */ - /* Sorts a trace list. In 95%, the list is already sorted. We need */ - /* an algorithm which is fast in this case. Bubble sort is enough */ - /* and simple. */ - /* */ - static - void Sort( PProfileList list ) - { - PProfile *old, current, next; - - - /* First, set the new X coordinate of each profile */ - Update( *list ); - - /* Then sort them */ - old = list; - current = *old; - - if ( !current ) - return; - - next = current->link; - - while ( next ) - { - if ( current->X <= next->X ) - { - old = ¤t->link; - current = *old; - - if ( !current ) - return; - } - else - { - *old = next; - current->link = next->link; - next->link = current; - - old = list; - current = *old; - } - - next = current->link; - } - } - - - /*************************************************************************/ - /* */ - /* Vertical Sweep Procedure Set */ - /* */ - /* These four routines are used during the vertical black/white */ - /* sweep phase by the generic Draw_Sweep() function. */ - /* */ - /*************************************************************************/ - - static - void Vertical_Sweep_Init( RAS_ARGS Short* min, - Short* max ) - { - Long pitch = ras.target.pitch; - - UNUSED( max ); - - - ras.traceIncr = (Short)-pitch; - ras.traceOfs = -*min * pitch; - if ( pitch > 0 ) - ras.traceOfs += ( ras.target.rows - 1 ) * pitch; - - ras.gray_min_x = 0; - ras.gray_max_x = 0; - } - - - static - void Vertical_Sweep_Span( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - Short c1, c2; - Byte f1, f2; - Byte* target; - - UNUSED( y ); - UNUSED( left ); - UNUSED( right ); - - - /* Drop-out control */ - - e1 = TRUNC( CEILING( x1 ) ); - - if ( x2 - x1 - ras.precision <= ras.precision_jitter ) - e2 = e1; - else - e2 = TRUNC( FLOOR( x2 ) ); - - if ( e2 >= 0 && e1 < ras.bWidth ) - { - if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bWidth ) e2 = ras.bWidth - 1; - - c1 = (Short)( e1 >> 3 ); - c2 = (Short)( e2 >> 3 ); - - f1 = (unsigned char)0xFF >> ( e1 & 7 ); - f2 = ~((unsigned char)0x7F >> ( e2 & 7 )); - - if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; - if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2; - - target = ras.bTarget + ras.traceOfs + c1; - c2 -= c1; - - if ( c2 > 0 ) - { - target[0] |= f1; - - /* memset() is slower than the following code on many platforms. */ - /* This is due to the fact that, in the vast majority of cases, */ - /* the span length in bytes is relatively small. */ - c2--; - while ( c2 > 0 ) - { - *(++target) = 0xFF; - c2--; - } - target[1] |= f2; - } - else - *target |= ( f1 & f2 ); - } - } - - - static - void Vertical_Sweep_Drop( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - Short c1, f1; - - - /* Drop-out control */ - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 > e2 ) - { - if ( e1 == e2 + ras.precision ) - { - switch ( ras.dropOutControl ) - { - case 1: - e1 = e2; - break; - - case 4: - e1 = CEILING( (x1 + x2 + 1) / 2 ); - break; - - case 2: - case 5: - /* Drop-out Control Rule #4 */ - - /* The spec is not very clear regarding rule #4. It */ - /* presents a method that is way too costly to implement */ - /* while the general idea seems to get rid of `stubs'. */ - /* */ - /* Here, we only get rid of stubs recognized if: */ - /* */ - /* upper stub: */ - /* */ - /* - P_Left and P_Right are in the same contour */ - /* - P_Right is the successor of P_Left in that contour */ - /* - y is the top of P_Left and P_Right */ - /* */ - /* lower stub: */ - /* */ - /* - P_Left and P_Right are in the same contour */ - /* - P_Left is the successor of P_Right in that contour */ - /* - y is the bottom of P_Left */ - /* */ - - /* FIXXXME: uncommenting this line solves the disappearing */ - /* bit problem in the `7' of verdana 10pts, but */ - /* makes a new one in the `C' of arial 14pts */ - -#if 0 - if ( x2 - x1 < ras.precision_half ) -#endif - { - /* upper stub test */ - if ( left->next == right && left->height <= 0 ) - return; - - /* lower stub test */ - if ( right->next == left && left->start == y ) - return; - } - - /* check that the rightmost pixel isn't set */ - - e1 = TRUNC( e1 ); - - c1 = (Short)( e1 >> 3 ); - f1 = e1 & 7; - - if ( e1 >= 0 && e1 < ras.bWidth && - ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) - return; - - if ( ras.dropOutControl == 2 ) - e1 = e2; - else - e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); - - break; - - default: - return; /* unsupported mode */ - } - } - else - return; - } - - e1 = TRUNC( e1 ); - - if ( e1 >= 0 && e1 < ras.bWidth ) - { - c1 = (Short)( e1 >> 3 ); - f1 = e1 & 7; - - if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; - if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; - - ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); - } - } - - - static - void Vertical_Sweep_Step( RAS_ARG ) - { - ras.traceOfs += ras.traceIncr; - } - - - /***********************************************************************/ - /* */ - /* Horizontal Sweep Procedure Set */ - /* */ - /* These four routines are used during the horizontal black/white */ - /* sweep phase by the generic Draw_Sweep() function. */ - /* */ - /***********************************************************************/ - - static - void Horizontal_Sweep_Init( RAS_ARGS Short* min, - Short* max ) - { - /* nothing, really */ - UNUSED( raster ); - UNUSED( min ); - UNUSED( max ); - } - - - static - void Horizontal_Sweep_Span( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - PByte bits; - Byte f1; - - UNUSED( left ); - UNUSED( right ); - - - if ( x2 - x1 < ras.precision ) - { - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 == e2 ) - { - bits = ras.bTarget + ( y >> 3 ); - f1 = (Byte)( 0x80 >> ( y & 7 ) ); - - e1 = TRUNC( e1 ); - - if ( e1 >= 0 && e1 < ras.target.rows ) - { - PByte p; - - - p = bits - e1*ras.target.pitch; - if ( ras.target.pitch > 0 ) - p += ( ras.target.rows - 1 ) * ras.target.pitch; - - p[0] |= f1; - } - } - } - } - - - static - void Horizontal_Sweep_Drop( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - PByte bits; - Byte f1; - - - /* During the horizontal sweep, we only take care of drop-outs */ - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 > e2 ) - { - if ( e1 == e2 + ras.precision ) - { - switch ( ras.dropOutControl ) - { - case 1: - e1 = e2; - break; - - case 4: - e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); - break; - - case 2: - case 5: - - /* Drop-out Control Rule #4 */ - - /* The spec is not very clear regarding rule #4. It */ - /* presents a method that is way too costly to implement */ - /* while the general idea seems to get rid of `stubs'. */ - /* */ - - /* rightmost stub test */ - if ( left->next == right && left->height <= 0 ) - return; - - /* leftmost stub test */ - if ( right->next == left && left->start == y ) - return; - - /* check that the rightmost pixel isn't set */ - - e1 = TRUNC( e1 ); - - bits = ras.bTarget + ( y >> 3 ); - f1 = (Byte)( 0x80 >> ( y & 7 ) ); - - bits -= e1 * ras.target.pitch; - if ( ras.target.pitch > 0 ) - bits += ( ras.target.rows - 1 ) * ras.target.pitch; - - if ( e1 >= 0 && - e1 < ras.target.rows && - *bits & f1 ) - return; - - if ( ras.dropOutControl == 2 ) - e1 = e2; - else - e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); - - break; - - default: - return; /* unsupported mode */ - } - } - else - return; - } - - bits = ras.bTarget + ( y >> 3 ); - f1 = (Byte)( 0x80 >> ( y & 7 ) ); - - e1 = TRUNC( e1 ); - - if ( e1 >= 0 && e1 < ras.target.rows ) - { - bits -= e1 * ras.target.pitch; - if ( ras.target.pitch > 0 ) - bits += ( ras.target.rows - 1 ) * ras.target.pitch; - - bits[0] |= f1; - } - } - - - static - void Horizontal_Sweep_Step( RAS_ARG ) - { - /* Nothing, really */ - UNUSED( raster ); - } - - -#ifdef FT_RASTER_OPTION_ANTI_ALIASING - - - /*************************************************************************/ - /* */ - /* Vertical Gray Sweep Procedure Set */ - /* */ - /* These two routines are used during the vertical gray-levels sweep */ - /* phase by the generic Draw_Sweep() function. */ - /* */ - /* NOTES */ - /* */ - /* - The target pixmap's width *must* be a multiple of 4. */ - /* */ - /* - You have to use the function Vertical_Sweep_Span() for the gray */ - /* span call. */ - /* */ - /*************************************************************************/ - - static - void Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, - Short* max ) - { - Long pitch, byte_len; - - - *min = *min & -2; - *max = ( *max + 3 ) & -2; - - ras.traceOfs = 0; - pitch = ras.target.pitch; - byte_len = -pitch; - ras.traceIncr = (Short)byte_len; - ras.traceG = ( *min / 2 ) * byte_len; - - if ( pitch > 0 ) - { - ras.traceG += ( ras.target.rows - 1 ) * pitch; - byte_len = -byte_len; - } - - ras.gray_min_x = (Short)byte_len; - ras.gray_max_x = -(Short)byte_len; - } - - - static - void Vertical_Gray_Sweep_Step( RAS_ARG ) - { - Int c1, c2; - PByte pix, bit, bit2; - Int* count = ras.count_table; - Byte* grays; - - - ras.traceOfs += ras.gray_width; - - if ( ras.traceOfs > ras.gray_width ) - { - pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; - grays = ras.grays; - - if ( ras.gray_max_x >= 0 ) - { - Long last_pixel = ras.target.width - 1; - Int last_cell = last_pixel >> 2; - Int last_bit = last_pixel & 3; - Bool over = 0; - - if ( ras.gray_max_x >= last_cell && last_bit != 3 ) - { - ras.gray_max_x = last_cell - 1; - over = 1; - } - - if ( ras.gray_min_x < 0 ) - ras.gray_min_x = 0; - - bit = ras.bTarget + ras.gray_min_x; - bit2 = bit + ras.gray_width; - - c1 = ras.gray_max_x - ras.gray_min_x; - - while ( c1 >= 0 ) - { - c2 = count[*bit] + count[*bit2]; - - if ( c2 ) - { - pix[0] = grays[(c2 >> 12) & 0x000F]; - pix[1] = grays[(c2 >> 8 ) & 0x000F]; - pix[2] = grays[(c2 >> 4 ) & 0x000F]; - pix[3] = grays[ c2 & 0x000F]; - - *bit = 0; - *bit2 = 0; - } - - bit++; - bit2++; - pix += 4; - c1--; - } - - if ( over ) - { - c2 = count[*bit] + count[*bit2]; - if ( c2 ) - { - switch ( last_bit ) - { - case 2: - pix[2] = grays[(c2 >> 4 ) & 0x000F]; - case 1: - pix[1] = grays[(c2 >> 8 ) & 0x000F]; - default: - pix[0] = grays[(c2 >> 12) & 0x000F]; - } - - *bit = 0; - *bit2 = 0; - } - } - } - - ras.traceOfs = 0; - ras.traceG += ras.traceIncr; - - ras.gray_min_x = 32000; - ras.gray_max_x = -32000; - } - } - - - static - void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - /* nothing, really */ - UNUSED( raster ); - UNUSED( y ); - UNUSED( x1 ); - UNUSED( x2 ); - UNUSED( left ); - UNUSED( right ); - } - - - static - void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, - FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - PByte pixel; - Byte color; - - - /* During the horizontal sweep, we only take care of drop-outs */ - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 > e2 ) - { - if ( e1 == e2 + ras.precision ) - { - switch ( ras.dropOutControl ) - { - case 1: - e1 = e2; - break; - - case 4: - e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); - break; - - case 2: - case 5: - - /* Drop-out Control Rule #4 */ - - /* The spec is not very clear regarding rule #4. It */ - /* presents a method that is way too costly to implement */ - /* while the general idea seems to get rid of `stubs'. */ - /* */ - - /* rightmost stub test */ - if ( left->next == right && left->height <= 0 ) - return; - - /* leftmost stub test */ - if ( right->next == left && left->start == y ) - return; - - if ( ras.dropOutControl == 2 ) - e1 = e2; - else - e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); - - break; - - default: - return; /* unsupported mode */ - } - } - else - return; - } - - if ( e1 >= 0 ) - { - if ( x2 - x1 >= ras.precision_half ) - color = ras.grays[2]; - else - color = ras.grays[1]; - - e1 = TRUNC( e1 ) / 2; - if ( e1 < ras.target.rows ) - { - pixel = ras.gTarget - e1 * ras.target.pitch + y / 2; - if ( ras.target.pitch > 0 ) - pixel += ( ras.target.rows - 1 ) * ras.target.pitch; - - if ( pixel[0] == ras.grays[0] ) - pixel[0] = color; - } - } - } - - -#endif /* FT_RASTER_OPTION_ANTI_ALIASING */ - - - /*************************************************************************/ - /* */ - /* Generic Sweep Drawing routine */ - /* */ - /*************************************************************************/ - - static - Bool Draw_Sweep( RAS_ARG ) - { - Short y, y_change, y_height; - - PProfile P, Q, P_Left, P_Right; - - Short min_Y, max_Y, top, bottom, dropouts; - - Long x1, x2, xs, e1, e2; - - TProfileList wait; - TProfileList draw_left, draw_right; - - - /* Init empty linked lists */ - - Init_Linked( &wait ); - - Init_Linked( &draw_left ); - Init_Linked( &draw_right ); - - /* first, compute min and max Y */ - - P = ras.fProfile; - max_Y = (short)TRUNC( ras.minY ); - min_Y = (short)TRUNC( ras.maxY ); - - while ( P ) - { - Q = P->link; - - bottom = (Short)P->start; - top = (Short)P->start + P->height - 1; - - if ( min_Y > bottom ) min_Y = bottom; - if ( max_Y < top ) max_Y = top; - - P->X = 0; - InsNew( &wait, P ); - - P = Q; - } - - /* Check the Y-turns */ - if ( ras.numTurns == 0 ) - { - ras.error = Raster_Err_Invalid; - return FAILURE; - } - - /* Now inits the sweep */ - - ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); - - /* Then compute the distance of each profile from min_Y */ - - P = wait; - - while ( P ) - { - P->countL = P->start - min_Y; - P = P->link; - } - - /* Let's go */ - - y = min_Y; - y_height = 0; - - if ( ras.numTurns > 0 && - ras.sizeBuff[-ras.numTurns] == min_Y ) - ras.numTurns--; - - while ( ras.numTurns > 0 ) - { - /* look in the wait list for new activations */ - - P = wait; - - while ( P ) - { - Q = P->link; - P->countL -= y_height; - if ( P->countL == 0 ) - { - DelOld( &wait, P ); - - switch ( P->flow ) - { - case Flow_Up: - InsNew( &draw_left, P ); - break; - - case Flow_Down: - InsNew( &draw_right, P ); - break; - } - } - - P = Q; - } - - /* Sort the drawing lists */ - - Sort( &draw_left ); - Sort( &draw_right ); - - y_change = (Short)ras.sizeBuff[-ras.numTurns--]; - y_height = y_change - y; - - while ( y < y_change ) - { - /* Let's trace */ - - dropouts = 0; - - P_Left = draw_left; - P_Right = draw_right; - - while ( P_Left ) - { - x1 = P_Left ->X; - x2 = P_Right->X; - - if ( x1 > x2 ) - { - xs = x1; - x1 = x2; - x2 = xs; - } - - if ( x2 - x1 <= ras.precision ) - { - e1 = FLOOR( x1 ); - e2 = CEILING( x2 ); - - if ( ras.dropOutControl != 0 && - ( e1 > e2 || e2 == e1 + ras.precision ) ) - { - /* a drop out was detected */ - - P_Left ->X = x1; - P_Right->X = x2; - - /* mark profile for drop-out processing */ - P_Left->countL = 1; - dropouts++; - - goto Skip_To_Next; - } - } - - ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); - - Skip_To_Next: - - P_Left = P_Left->link; - P_Right = P_Right->link; - } - - /* now perform the dropouts _after_ the span drawing */ - /* drop-outs processing has been moved out of the loop */ - /* for performance tuning */ - if ( dropouts > 0 ) - goto Scan_DropOuts; - - Next_Line: - - ras.Proc_Sweep_Step( RAS_VAR ); - - y++; - - if ( y < y_change ) - { - Sort( &draw_left ); - Sort( &draw_right ); - } - } - - /* Now finalize the profiles that needs it */ - - { - PProfile Q, P; - - - P = draw_left; - while ( P ) - { - Q = P->link; - if ( P->height == 0 ) - DelOld( &draw_left, P ); - P = Q; - } - } - - { - PProfile Q, P = draw_right; - - - while ( P ) - { - Q = P->link; - if ( P->height == 0 ) - DelOld( &draw_right, P ); - P = Q; - } - } - } - - /* for gray-scaling, flushes the bitmap scanline cache */ - while ( y <= max_Y ) - { - ras.Proc_Sweep_Step( RAS_VAR ); - y++; - } - - return SUCCESS; - - Scan_DropOuts: - - P_Left = draw_left; - P_Right = draw_right; - - while ( P_Left ) - { - if ( P_Left->countL ) - { - P_Left->countL = 0; -#if 0 - dropouts--; /* -- this is useful when debugging only */ -#endif - ras.Proc_Sweep_Drop( RAS_VARS y, - P_Left->X, - P_Right->X, - P_Left, - P_Right ); - } - - P_Left = P_Left->link; - P_Right = P_Right->link; - } - - goto Next_Line; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Render_Single_Pass */ - /* */ - /* */ - /* Performs one sweep with sub-banding. */ - /* */ - /* */ - /* flipped :: If set, flip the direction of the outline. */ - /* */ - /* */ - /* Renderer error code. */ - /* */ - static - int Render_Single_Pass( RAS_ARGS Bool flipped ) - { - Short i, j, k; - - - while ( ras.band_top >= 0 ) - { - ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; - ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; - - ras.top = ras.buff; - - ras.error = Raster_Err_None; - - if ( Convert_Glyph( RAS_VARS flipped ) ) - { - if ( ras.error != Raster_Err_Overflow ) - return FAILURE; - - ras.error = Raster_Err_None; - - /* sub-banding */ - -#ifdef DEBUG_RASTER - ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); -#endif - - i = ras.band_stack[ras.band_top].y_min; - j = ras.band_stack[ras.band_top].y_max; - - k = ( i + j ) / 2; - - if ( ras.band_top >= 7 || k < i ) - { - ras.band_top = 0; - ras.error = Raster_Err_Invalid; - - return ras.error; - } - - ras.band_stack[ras.band_top + 1].y_min = k; - ras.band_stack[ras.band_top + 1].y_max = j; - - ras.band_stack[ras.band_top].y_max = k - 1; - - ras.band_top++; - } - else - { - if ( ras.fProfile ) - if ( Draw_Sweep( RAS_VAR ) ) - return ras.error; - ras.band_top--; - } - } - - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Render_Glyph */ - /* */ - /* */ - /* Renders a glyph in a bitmap. Sub-banding if needed. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* XXX Fixme: ftraster's error codes don't harmonize with FT2's ones! */ - /* */ - LOCAL_FUNC - FT_Error Render_Glyph( RAS_ARG ) - { - FT_Error error; - - - Set_High_Precision( RAS_VARS ras.outline.flags & - ft_outline_high_precision ); - ras.scale_shift = ras.precision_shift; - ras.dropOutControl = 2; - ras.second_pass = !( ras.outline.flags & ft_outline_single_pass ); - - /* Vertical Sweep */ - ras.Proc_Sweep_Init = Vertical_Sweep_Init; - ras.Proc_Sweep_Span = Vertical_Sweep_Span; - ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; - ras.Proc_Sweep_Step = Vertical_Sweep_Step; - - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.rows - 1; - - ras.bWidth = ras.target.width; - ras.bTarget = (Byte*)ras.target.buffer; - - if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) - return error; - - /* Horizontal Sweep */ - if ( ras.second_pass && ras.dropOutControl != 0 ) - { - ras.Proc_Sweep_Init = Horizontal_Sweep_Init; - ras.Proc_Sweep_Span = Horizontal_Sweep_Span; - ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; - ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.width - 1; - - if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) - return error; - } - - return FT_Err_Ok; - } - - -#ifdef FT_RASTER_OPTION_ANTI_ALIASING - - - /*************************************************************************/ - /* */ - /* */ - /* Render_Gray_Glyph */ - /* */ - /* */ - /* Renders a glyph with grayscaling. Sub-banding if needed. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - LOCAL_FUNC - FT_Error Render_Gray_Glyph( RAS_ARG ) - { - Long pixel_width; - FT_Error error; - - - Set_High_Precision( RAS_VARS ras.outline.flags & - ft_outline_high_precision ); - ras.scale_shift = ras.precision_shift + 1; - ras.dropOutControl = 2; - ras.second_pass = !( ras.outline.flags & ft_outline_single_pass ); - - - /* Vertical Sweep */ - - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = 2 * ras.target.rows - 1; - - ras.bWidth = ras.gray_width; - pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); - - if ( ras.bWidth > pixel_width ) - ras.bWidth = pixel_width; - - ras.bWidth = ras.bWidth * 8; - ras.bTarget = (Byte*)ras.gray_lines; - ras.gTarget = (Byte*)ras.target.buffer; - - ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; - ras.Proc_Sweep_Span = Vertical_Sweep_Span; - ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; - ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; - - error = Render_Single_Pass( RAS_VARS 0 ); - if (error) - return error; - - /* Horizontal Sweep */ - if ( ras.second_pass && ras.dropOutControl != 0 ) - { - ras.Proc_Sweep_Init = Horizontal_Sweep_Init; - ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; - ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; - ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.width * 2 - 1; - - error = Render_Single_Pass( RAS_VARS 1 ); - if (error) - return error; - } - - return FT_Err_Ok; - } - -#else /* FT_RASTER_OPTION_ANTI_ALIASING */ - - LOCAL_FUNC - FT_Error Render_Gray_Glyph( RAS_ARG ) - { - UNUSED_RASTER; - return Raster_Err_Unsupported; - } - -#endif - - - static - void ft_black_init( TRaster_Instance* raster ) - { - FT_UInt n; - FT_ULong c; - - /* setup count table */ - for ( n = 0; n < 256; n++ ) - { - c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 ); - - c = ( ( c << 6 ) & 0x3000 ) | - ( ( c << 4 ) & 0x0300 ) | - ( ( c << 2 ) & 0x0030 ) | - (c & 0x0003 ); - - raster->count_table[n] = c; - } - - /* set default 5-levels gray palette */ - for ( n = 0; n < 5; n++ ) - raster->grays[n] = n * 255 / 4; - - raster->gray_width = RASTER_GRAY_LINES / 2; - } - - /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ - /**** a static object. *****/ - -#ifdef _STANDALONE_ - - - static - int ft_black_new( void* memory, - FT_Raster *araster ) - { - static FT_RasterRec_ the_raster; - - - *araster = &the_raster; - memset( &the_raster, sizeof ( the_raster ), 0 ); - ft_black_init( &the_raster ); - - return 0; - } - - - static - void ft_black_done( FT_Raster raster ) - { - /* nothing */ - raster->init = 0; - } - - -#else /* _STANDALONE_ */ - - - static - int ft_black_new( FT_Memory memory, - TRaster_Instance** araster ) - { - FT_Error error; - TRaster_Instance* raster; - - - *araster = 0; - if ( !ALLOC( raster, sizeof ( *raster ) ) ) - { - raster->memory = memory; - ft_black_init( raster ); - - *araster = raster; - } - - return error; - } - - - static - void ft_black_done( TRaster_Instance* raster ) - { - FT_Memory memory = (FT_Memory)raster->memory; - FREE( raster ); - } - - -#endif /* _STANDALONE_ */ - - - static - void ft_black_reset( TRaster_Instance* raster, - const char* pool_base, - long pool_size ) - { - if ( raster && pool_base && pool_size >= 4096 ) - { - /* save the pool */ - raster->buff = (PLong)pool_base; - raster->sizeBuff = raster->buff + pool_size / sizeof ( Long ); - } - } - - - static - void ft_black_set_mode( TRaster_Instance* raster, - unsigned long mode, - const char* palette ) - { - if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) - { - /* set 5-levels gray palette */ - raster->grays[0] = palette[0]; - raster->grays[1] = palette[1]; - raster->grays[2] = palette[2]; - raster->grays[3] = palette[3]; - raster->grays[4] = palette[4]; - } - } - - - static - int ft_black_render( TRaster_Instance* raster, - FT_Raster_Params* params ) - { - FT_Outline* outline = (FT_Outline*)params->source; - FT_Bitmap* target_map = params->target; - - - if ( !raster || !raster->buff || !raster->sizeBuff ) - return Raster_Err_Not_Ini; - - if ( !outline || !outline->contours || !outline->points ) - return Raster_Err_Invalid; - - /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return Raster_Err_None; - - if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) - return Raster_Err_Invalid; - - if ( !target_map || !target_map->buffer ) - return Raster_Err_Invalid; - - /* this version of the raster does not support direct rendering, sorry */ - if ( params->flags & ft_raster_flag_direct ) - return Raster_Err_Unsupported; - - ras.outline = *outline; - ras.target = *target_map; - - return ( params->flags & ft_raster_flag_aa - ? Render_Gray_Glyph( raster ) - : Render_Glyph( raster ) ); - } - - - FT_Raster_Funcs ft_standard_raster = - { - ft_glyph_format_outline, - (FT_Raster_New_Func) ft_black_new, - (FT_Raster_Reset_Func) ft_black_reset, - (FT_Raster_Set_Mode_Func)ft_black_set_mode, - (FT_Raster_Render_Func) ft_black_render, - (FT_Raster_Done_Func) ft_black_done - }; - - -/* END */ diff --git a/src/renderer/ftraster.h b/src/renderer/ftraster.h deleted file mode 100644 index 371ed2783..000000000 --- a/src/renderer/ftraster.h +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftraster.h */ -/* */ -/* The FreeType glyph rasterizer (specification). */ -/* */ -/* Copyright 1996-2000 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. */ -/* */ -/***************************************************************************/ - - -#ifndef FTRASTER_H -#define FTRASTER_H - -#ifdef __cplusplus - extern "C" { -#endif - -#include - - /*************************************************************************/ - /* */ - /* Uncomment the following line if you are using ftraster.c as a */ - /* standalone module, fully independent of FreeType. */ - /* */ -/* #define _STANDALONE_ */ - -#ifndef FT_EXPORT_VAR -#define FT_EXPORT_VAR(x) extern x -#endif - - FT_EXPORT_VAR(FT_Raster_Funcs) ft_standard_raster; - -#ifdef __cplusplus - } -#endif - -#endif /* FTRASTER_H */ - - -/* END */ diff --git a/src/renderer/module.mk b/src/renderer/module.mk deleted file mode 100644 index a54ed57b1..000000000 --- a/src/renderer/module.mk +++ /dev/null @@ -1,11 +0,0 @@ -make_module_list: add_renderer_module - -# XXX: important, the standard renderer *MUST* be first on this list! -# -add_renderer_module: - $(OPEN_DRIVER)ft_standard_renderer_class$(CLOSE_DRIVER) - $(ECHO_DRIVER)standard $(ECHO_DRIVER_DESC)standard outline renderer module$(ECHO_DRIVER_DONE) - $(OPEN_DRIVER)ft_smooth_renderer_class$(CLOSE_DRIVER) - $(ECHO_DRIVER)smooth $(ECHO_DRIVER_DESC)smooth outline renderer module$(ECHO_DRIVER_DONE) - -# EOF diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c deleted file mode 100644 index 8fab2fbc0..000000000 --- a/src/renderer/renderer.c +++ /dev/null @@ -1,261 +0,0 @@ -/***************************************************************************/ -/* */ -/* renderer.c */ -/* */ -/* FreeType renderer module (body). */ -/* */ -/* Copyright 2000 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 - - - /* initialize renderer - init its raster */ - static - FT_Error ft_renderer_init( FT_Renderer render ) - { - FT_Library library = FT_MODULE_LIBRARY( render ); - - - render->clazz->raster_class->raster_reset( render->raster, - library->raster_pool, - library->raster_pool_size ); - - return 0; - } - - - /* set render-specific mode */ - static - FT_Error ft_renderer_set_mode( FT_Renderer render, - FT_ULong mode_tag, - FT_Pointer data ) - { - /* we simply pass it to the raster */ - return render->clazz->raster_class->raster_set_mode( render->raster, - mode_tag, - data ); - } - - - /* transform a given glyph image */ - static - FT_Error ft_renderer_transform( FT_Renderer render, - FT_GlyphSlot slot, - FT_Matrix* matrix, - FT_Vector* delta ) - { - FT_Error error = FT_Err_Ok; - - - if ( slot->format != render->glyph_format ) - { - error = FT_Err_Invalid_Argument; - goto Exit; - } - - if ( matrix ) - FT_Outline_Transform( &slot->outline, matrix ); - - if ( delta ) - FT_Outline_Translate( &slot->outline, delta->x, delta->y ); - - Exit: - return error; - } - - - /* return the glyph's control box */ - static - void ft_renderer_get_cbox( FT_Renderer render, - FT_GlyphSlot slot, - FT_BBox* cbox ) - { - MEM_Set( cbox, 0, sizeof ( *cbox ) ); - - if ( slot->format == render->glyph_format ) - FT_Outline_Get_CBox( &slot->outline, cbox ); - } - - - /* convert a slot's glyph image into a bitmap */ - static - FT_Error ft_renderer_render( FT_Renderer render, - FT_GlyphSlot slot, - FT_UInt mode, - FT_Vector* origin ) - { - FT_Error error; - FT_Outline* outline; - FT_BBox cbox; - FT_UInt width, height, pitch; - FT_Bitmap* bitmap; - FT_Memory memory; - - FT_Raster_Params params; - - - /* check glyph image format */ - if ( slot->format != render->glyph_format ) - { - error = FT_Err_Invalid_Argument; - goto Exit; - } - - outline = &slot->outline; - - /* translate the outline to the new origin if needed */ - if ( origin ) - FT_Outline_Translate( outline, origin->x, origin->y ); - - /* compute the control box, and grid fit it */ - FT_Outline_Get_CBox( outline, &cbox ); - - cbox.xMin &= -64; - cbox.yMin &= -64; - cbox.xMax = ( cbox.xMax + 63 ) & -64; - cbox.yMax = ( cbox.yMax + 63 ) & -64; - - width = ( cbox.xMax - cbox.xMin ) >> 6; - height = ( cbox.yMax - cbox.yMin ) >> 6; - bitmap = &slot->bitmap; - memory = slot->face->memory; - - /* release old bitmap buffer */ - if ( ( slot->flags & ft_glyph_own_bitmap ) ) - { - FREE( bitmap->buffer ); - slot->flags &= ~ft_glyph_own_bitmap; - } - - /* allocate new one, depends on pixel format */ - if ( mode & ft_render_mode_antialias ) - { - pitch = width; - bitmap->pixel_mode = ft_pixel_mode_grays; - bitmap->num_grays = 256; - } - else - { - pitch = ( width + 7 ) >> 3; - bitmap->pixel_mode = ft_pixel_mode_mono; - } - - bitmap->width = width; - bitmap->rows = height; - bitmap->pitch = pitch; - - if ( ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) - goto Exit; - - slot->flags |= ft_glyph_own_bitmap; - - /* translate outline to render it into the bitmap */ - FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin ); - - /* set up parameters */ - params.target = bitmap; - params.source = outline; - params.flags = 0; - - if ( bitmap->pixel_mode == ft_pixel_mode_grays ) - params.flags |= ft_raster_flag_aa; - - /* render outline into the bitmap */ - error = render->raster_render( render->raster, ¶ms ); - if ( error ) - goto Exit; - - slot->format = ft_glyph_format_bitmap; - slot->bitmap_left = cbox.xMin >> 6; - slot->bitmap_top = cbox.yMax >> 6; - - Exit: - return error; - } - - -#ifndef FT_CONFIG_OPTION_NO_STD_RASTER - - -#include - - - const FT_Renderer_Class ft_standard_renderer_class = - { - { - ft_module_renderer, - sizeof ( FT_RendererRec ), - - "standard renderer", - 0x10000L, - 0x20000L, - - 0, /* module specific interface */ - - (FT_Module_Constructor)ft_renderer_init, - (FT_Module_Destructor) 0, - (FT_Module_Requester) 0 - }, - - ft_glyph_format_outline, - - (FTRenderer_render) ft_renderer_render, - (FTRenderer_transform)ft_renderer_transform, - (FTRenderer_getCBox) ft_renderer_get_cbox, - (FTRenderer_setMode) ft_renderer_set_mode, - - (FT_Raster_Funcs*) &ft_standard_raster - }; - - -#endif /* !FT_CONFIG_OPTION_NO_STD_RASTER */ - - -#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER - - -#include - - - const FT_Renderer_Class ft_smooth_renderer_class = - { - { - ft_module_renderer, - sizeof ( FT_RendererRec ), - - "smooth renderer", - 0x10000L, - 0x20000L, - - 0, /* module specific interface */ - - (FT_Module_Constructor)ft_renderer_init, - (FT_Module_Destructor) 0, - (FT_Module_Requester) 0 - }, - - ft_glyph_format_outline, - - (FTRenderer_render) ft_renderer_render, - (FTRenderer_transform)ft_renderer_transform, - (FTRenderer_getCBox) ft_renderer_get_cbox, - (FTRenderer_setMode) ft_renderer_set_mode, - - (FT_Raster_Funcs*) &ft_grays_raster - }; - - -#endif /* !FT_CONFIG_OPTION_NO_SMOOTH_RASTER */ - - -/* END */ diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h deleted file mode 100644 index 5a760b836..000000000 --- a/src/renderer/renderer.h +++ /dev/null @@ -1,38 +0,0 @@ -/***************************************************************************/ -/* */ -/* renderer.h */ -/* */ -/* FreeType renderer module (specification). */ -/* */ -/* Copyright 2000 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. */ -/* */ -/***************************************************************************/ - - -#ifndef RENDERER_H -#define RENDERER_H - - -#include - - -#ifndef FT_CONFIG_OPTION_NO_STD_RASTER - FT_EXPORT_VAR( const FT_Renderer_Class ) ft_std_renderer_class; -#endif - -#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER - FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_renderer_class; -#endif - - -#endif /* RENDERER_H */ - - -/* END */ diff --git a/src/renderer/rules.mk b/src/renderer/rules.mk deleted file mode 100644 index 600fc56c5..000000000 --- a/src/renderer/rules.mk +++ /dev/null @@ -1,75 +0,0 @@ -# -# FreeType 2 renderer module build rules -# - - -# Copyright 1996-2000 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. - - -# renderer driver directory -# -REND_DIR := $(SRC_)renderer -REND_DIR_ := $(REND_DIR)$(SEP) - - -# additional include flags used when compiling the driver -# -REND_INCLUDE := $(REND_DIR) - -# compilation flags for the driver -# -REND_CFLAGS := $(REND_INCLUDE:%=$I%) -REND_COMPILE := $(FT_COMPILE) $(REND_CFLAGS) - - -# renderer driver sources (i.e., C files) -# -REND_DRV_SRC := $(REND_DIR_)ftraster.c \ - $(REND_DIR_)ftgrays.c \ - $(REND_DIR_)renderer.c - -# renderer driver headers -# -REND_DRV_H := $(REND_DRV_SRC:%c=%h) - - -# renderer driver object(s) -# -# REND_DRV_OBJ_M is used during `multi' builds. -# REND_DRV_OBJ_S is used during `single' builds. -# -REND_DRV_OBJ_M := $(REND_DRV_SRC:$(REND_DIR_)%.c=$(OBJ_)%.$O) -REND_DRV_OBJ_S := $(REND_DRV_OBJ_M) - -# renderer driver source file for single build -# -#REND_DRV_SRC_S := $(REND_DIR_)renderer.c - - -# renderer driver - single object -# -#$(REND_DRV_OBJ_S): $(REND_DRV_SRC_S) $(REND_DRV_SRC) \ -# $(FREETYPE_H) $(REND_DRV_H) -# $(REND_COMPILE) $T$@ $(REND_DRV_SRC_S) - - -# renderer driver - multiple objects -# -$(OBJ_)%.$O: $(REND_DIR_)%.c $(FREETYPE_H) $(REND_DRV_H) - $(REND_COMPILE) $T$@ $< - - -# update main driver object lists -# -DRV_OBJS_S += $(REND_DRV_OBJ_M) -DRV_OBJS_M += $(REND_DRV_OBJ_M) - - -# EOF