diff --git a/demos/Makefile b/demos/Makefile index 041436a47..c88e7ac78 100644 --- a/demos/Makefile +++ b/demos/Makefile @@ -281,22 +281,15 @@ else $(LINK) - $(BIN_)ftview$E: $(OBJ_)ftview.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(OBJ_)ftrast2.$O $(OBJ_)ftrast.$O - $(GRAPH_LINK2) + $(BIN_)ftview$E: $(OBJ_)ftview.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) + $(GRAPH_LINK) $(BIN_)ftstring$E: $(OBJ_)ftstring.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(GRAPH_LINK) - - $(BIN_)try$E: $(OBJ_)try.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(OBJ_)ftgrays2.$O - $(GRAPH_LINK) $(OBJ_)ftgrays2.$O - $(BIN_)fttimer$E: $(OBJ_)fttimer.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(GRAPH_LINK) - $(BIN_)fttimer2$E: $(OBJ_)fttimer2.$O $(FTLIB) $(GRAPH_LIB) $(COMMON_OBJ) $(OBJ_)ftgrays2.$O - $(GRAPH_LINK) $(OBJ_)ftgrays2.$O - endif diff --git a/demos/src/ftgrays2.c b/demos/src/ftgrays2.c deleted file mode 100644 index 80aba2ac6..000000000 --- a/demos/src/ftgrays2.c +++ /dev/null @@ -1,2250 +0,0 @@ -/*****************************************************************************/ -/* */ -/* ftgrays2.c - a new version of the standard FreeType anti-aliaser */ -/* */ -/* (c) 2000 David Turner - */ -/* */ -/* Beware, this code is still in heavy beta.. */ -/* */ -/* After writing a "perfect" anti-aliaser (see ftgrays.c), it is clear */ -/* that the standard FreeType renderer is better at generating glyph images */ -/* because it uses an approximation that simply produces more contrasted */ -/* edges, making its output more legible.. */ -/* */ -/* This code is an attempt to rewrite the standard renderer in order to */ -/* support the following: */ -/* */ -/* - get rid of al rendering artifacts produced by the original algorithm */ -/* - allow direct composition, by generating the output image as a "list" */ -/* of span in successive scan-lines (the standard code is forced to use */ -/* an intermediate buffer, and this is just _bad_ :-) */ -/* */ -/* */ -/* This thing works, but it's slower than the original ftraster.c, */ -/* probably because the bezier intersection code is different.. */ -/* */ -/* Note that Type 1 fonts, using a reverse fill algorithm are not */ -/* supported for now (this should come soon though..) */ -/* */ - -#include - -#define _STANDALONE_ - -#define DEBUG_GRAYS -#define DIRECT_BEZIER -#define PRECISION_STEP ONE_HALF -#define xxxDYNAMIC_BEZIER_STEPS - -#define ErrRaster_Invalid_Outline -1 -#define ErrRaster_Overflow -2 - -#include "ftgrays2.h" - -/* include the FreeType main header if necessary */ -#ifndef _STANDALONE_ -#include "freetype.h" /* for FT_MulDiv & FT_Outline_Decompose */ -#endif - -#ifdef DEBUG_GRAYS -#include -#endif - -typedef int TScan; -typedef long TPos; -typedef float TDist; - -#define FT_MAX_GRAY_SPANS 32 - -typedef struct FT_GraySpan_ -{ - short x; - short len; - unsigned char coverage; - -} FT_GraySpan; - -typedef int (*FT_GraySpan_Func)( int y, - int count, - FT_GraySpan* spans, - void* user ); - -typedef enum { - - dir_up = 0, - dir_down = 1, - dir_right = 2, - dir_left = 3, - - dir_horizontal = 2, - dir_reverse = 1, - dir_silent = 4, - - dir_unknown = 8 - -} TDir; - - -typedef struct TCell_ -{ - unsigned short x; - unsigned short y; - unsigned short pos; - TDir dir; - -} TCell, *PCell; - - - -typedef struct TRaster_ -{ - PCell cells; - PCell cursor; - PCell cell_limit; - int max_cells; - int num_cells; - - TScan min_ex, max_ex; - TScan min_ey, max_ey; - TPos min_x, min_y; - TPos max_x, max_y; - - TScan ex, ey; - TScan cx, cy; - TPos x, y; - - PCell contour_cell; /* first contour cell */ - - char joint; - char horizontal; - TDir dir; - PCell last; - - FT_Vector starter; - FT_Vector* start; - - int error; - - FT_Vector* arc; - FT_Vector bez_stack[32*3]; - int lev_stack[32]; - - FT_Outline outline; - FT_Bitmap target; - - FT_GraySpan gray_spans[ FT_MAX_GRAY_SPANS ]; - int num_gray_spans; - - FT_GraySpan_Func render_span; - void* render_span_closure; - int span_y; - -} TRaster, *PRaster; - - - -#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 - - #define RAS_ARG - #define RAS_ARG_ - #define RAS_VAR - #define RAS_VAR_ - - static TRaster ras; - -#endif - -#define FMulDiv(a,b,c) ((long)(a)*(b)/(c)) - -#ifdef _STANDALONE_ -#define SMulDiv(a,b,c) FMulDiv(a,b,c) /* XXXX - TO BE CHANGED LATER */ -#else -#define SMulDiv(a,b,c) FT_MulDiv(a,b,c) -#endif - -/* note: PIXEL_BITS must not be less than 6 !! */ -#define PIXEL_BITS 6 - -#define ONE_PIXEL (1L << PIXEL_BITS) -#define ONE_HALF (ONE_PIXEL/2) -#define PIXEL_MASK (-1L << PIXEL_BITS) -#define TRUNC(x) ((x) >> PIXEL_BITS) -#define FRAC(x) ((x) & (ONE_PIXEL-1)) -#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_HALF) & -ONE_PIXEL) - -#define UPSCALE(x) ((x) << (PIXEL_BITS-6)) -#define DOWNSCALE(x) ((x) >> (PIXEL_BITS-6)) - -#define WRITE_CELL(top,u,v,dir) write_cell( RAS_VAR_ top, u, v, dir ) - -/****************************************************************************/ -/* */ -/* 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.cell_limit = ras.cells + ras.max_cells; - ras.num_cells = 0; -} - - -/****************************************************************************/ -/* */ -/* WRITE ONE CELL IN THE RENDER POOL */ -/* */ -static -int write_cell( RAS_ARG_ PCell cell, TPos u, TPos v, TDir dir ) -{ -#ifdef DEBUG_GRAYS - static const char dirs[5] = "udrl?"; -#endif - if (dir & dir_horizontal) - { - /* only keep horizontal cells within our clipping box */ - if ( u < ras.min_y || u >= ras.max_y || - v < ras.min_x || v >= ras.max_x ) goto Nope; - - /* get rid of horizontal cells with pos == 0, they're irrelevant */ - if ( FRAC(u) == 0 ) goto Nope; - - cell->y = (unsigned short)TRUNC( u - ras.min_y ); - cell->x = (unsigned short)TRUNC( v - ras.min_x ); - } - else - { - /* get rid of vertical cells that are below or above our clipping */ - /* box. Also discard all cells that are on the right of the clipping */ - /* box.. */ - if (u >= ras.max_x || v < ras.min_y || v >= ras.max_y) goto Nope; - u -= ras.min_x; - v -= ras.min_y; - - /* all cells that are on the left of the clipping box are located */ - /* on the same virtual "border" cell.. */ - if (u < 0) u = -1; - cell->x = (unsigned short)TRUNC( u ); - cell->y = (unsigned short)TRUNC( v ); - } - cell->dir = dir; - cell->pos = FRAC(u); - -#ifdef DEBUG_GRAYS - fprintf( stderr, "[%d,%d,%c,%d]\n", - (int)cell->y, - (int)cell->x, - dirs[dir], - cell->pos ); -#endif - return 1; -Nope: - return 0; -} - -/****************************************************************************/ -/* */ -/* 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_x = ras.max_x = 0; - ras.min_y = ras.max_y = 0; - goto Exit; - } - - ras.min_x = ras.max_x = vec->x; - ras.min_y = ras.max_y = vec->y; - vec++; - - for ( ; vec < limit; vec++ ) - { - TPos x = vec->x; - TPos y = vec->y; - - if ( x < ras.min_x ) ras.min_x = x; - if ( x > ras.max_x ) ras.max_x = x; - if ( y < ras.min_y ) ras.min_y = y; - if ( y > ras.max_y ) ras.max_y = y; - } - - /* grid-fit the bounding box to integer pixels */ - ras.min_x &= -64; - ras.min_y &= -64; - ras.max_x = (ras.max_x+63) & -64; - ras.max_y = (ras.max_y+63) & -64; - -Exit: - ras.min_ex = ras.min_x >> 6; - ras.max_ex = ras.max_x >> 6; - ras.min_ey = ras.min_y >> 6; - ras.max_ey = ras.max_y >> 6; -} - - /*************************************************************************/ - /* */ - /* */ - /* compute_intersects */ - /* */ - /* */ - /* Computes the scan-line intersections of a given line and store */ - /* the corresonding cells in the render pool.. */ - /* */ - /* */ - /* u1 :: The start u coordinate. */ - /* v1 :: The start v coordinate. */ - /* u2 :: The end u coordinate. */ - /* v2 :: The end v coordinate. */ - /* minv :: The minimum vertical grid coordinate. */ - /* maxv :: The maximum vertical grid coordinate. */ - /* dir :: The line direction.. */ - /* */ - /* */ - /* error code. 0 means success.. */ - /* */ - static - int compute_intersects( RAS_ARG_ TPos u1, TPos v1, - TPos u2, TPos v2, - TPos minv, TPos maxv, - TDir dir ) - { - TPos du, dv, u, v, iu, iv, ru, nu; - TScan e1, e2, size; - PCell top; - int reverse; - - /* exit if dv == 0 */ - if ( v1 == v2 ) goto Exit; - - /* adjust to scanline center */ - v1 -= ONE_HALF; - v2 -= ONE_HALF; - maxv -= ONE_PIXEL; - - /* reverse direction in order to get dv > 0 */ - reverse = 0; - if ( v2 < v1 ) - { - TPos tmp; - v1 = -v1; v2 = -v2; - tmp = minv; minv = -maxv; maxv = -tmp; - reverse = 1; - } - - /* check that we have an intersection */ - if ( v2 < minv || v1 > maxv ) - goto Exit; - - du = u2 - u1; - dv = v2 - v1; - - /* set the silent flag */ - if (du > dv) - dir |= dir_silent; - - /* compute the first scanline in "e1" */ - e1 = CEILING(v1); - if (e1 == v1 && ras.joint) - e1 += ONE_PIXEL; - - /* compute the last scanline in "e2" */ - if (v2 <= maxv) - { - e2 = FLOOR(v2); - ras.joint = (v2 == e2); - } - else - { - e2 = maxv; - ras.joint = 0; - } - - size = TRUNC(e2-e1) + 1; - if (size <= 0) goto Exit; - - /* check that there is enough space in the render pool */ - if ( ras.cursor + size > ras.cell_limit ) - { - ras.error = ErrRaster_Overflow; - goto Fail; - } - - if (e1-v1 > 0) - u1 += SMulDiv( e1-v1, du, dv ); - - u = u1; - v = e1; if (reverse) v = -e1; - v += ONE_HALF; - iv = (1-2*reverse)*ONE_PIXEL; - - /* compute decision variables */ - if (du) - { - du <<= PIXEL_BITS; - iu = du / dv; - ru = du % dv; - if (ru < 0) - { - iu --; - ru += dv; - } - - nu = -dv; - ru <<= 1; - dv <<= 1; - } - else - { - iu = 0; - ru = 0; - nu = -dv; - } - - top = ras.cursor; - for ( ; size > 0; size-- ) - { - if (WRITE_CELL( top, u, v, dir )) - top++; - - u += iu; - nu += ru; - if (nu >= 0) - { - nu -= dv; - u++; - } - v += iv; - } - ras.cursor = top; - - Exit: - return 0; - - Fail: - return 1; - } - - - - /*************************************************************************/ - /* */ - /* */ - /* render_line */ - /* */ - /* */ - /* This function injects a new line segment in the render pool. */ - /* */ - /* */ - /* x :: target x coordinate (scaled subpixels) */ - /* y :: target y coordinate (scaled subpixels) */ - /* raster :: A pointer to the current raster object. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - static - int render_line( RAS_ARG_ TPos x, TPos y ) - { - TPos minv, maxv; - TDir new_dir; - - minv = ras.min_y; - maxv = ras.max_y; - if (ras.horizontal) - { - minv = ras.min_x; - maxv = ras.max_x; - } - - new_dir = ras.dir; - - /* first of all, detect a change of direction */ - if ( y != ras.y ) - { - new_dir = ( y > ras.y ) ? dir_up : dir_down; - if (ras.horizontal) new_dir |= dir_horizontal; - - if ( new_dir != ras.dir ) - { - ras.joint = 0; - ras.dir = new_dir; - } - } - - /* then compute line intersections */ - if ( compute_intersects( RAS_VAR_ ras.x, ras.y, x, y, - minv, maxv, new_dir ) ) - goto Fail; - - ras.x = x; - ras.y = y; - - return 0; - - Fail: - 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 -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; -} - - - -#ifndef DIRECT_BEZIER -static -int render_conic( RAS_ARG_ TPos x1, TPos y1, TPos x2, TPos y2 ) -{ - TPos x0, y0; - TPos dx, dy; - int top, level; - int* levels; - FT_Vector* arc; - - x0 = ras.x; - y0 = ras.y; - - dx = x0 + x2 - 2*x1; if (dx < 0) dx = -dx; - dy = y0 + y2 - 2*y1; if (dy < 0) dy = -dy; - if (dx < dy) dx = dy; - level = 1; - dx = DOWNSCALE(dx)/32; - while ( dx > 0 ) - { - dx >>= 1; - level++; - } - - if (level <= 1) - return render_line( RAS_VAR_ x2, y2 ); - - arc = ras.bez_stack; - arc[0].x = x2; - arc[0].y = y2; - arc[1].x = x1; - arc[1].y = y1; - arc[2].x = x0; - arc[2].y = y0; - - levels = ras.lev_stack; - top = 0; - levels[0] = level; - - for (;;) - { - level = levels[top]; - if (level > 1) - { - split_conic(arc); - arc += 2; - top ++; - levels[top] = levels[top-1] = level-1; - } - else - { - if (render_line( RAS_VAR_ arc[0].x, arc[0].y )) return 1; - top--; - arc-=2; - if (top < 0) - return 0; - } - } -} - - -static -int render_cubic( RAS_ARG_ TPos x1, TPos y1, - TPos x2, TPos y2, - TPos x3, TPos y3 ) -{ - TPos x0, y0; - TPos dx, dy, da, db; - int top, level; - int* levels; - FT_Vector* arc; - - x0 = ras.x; - y0 = ras.y; - - dx = x0 + x3 - 2*x1; if (dx < 0) dx = -dx; - dy = y0 + y3 - 2*y1; if (dy < 0) dy = -dy; - da = dy; if (da < dx) da = dx; - - dx = x0 + x3 - 3*(x1+x2); if (dx < 0) dx = -dx; - dy = y0 + y3 - 3*(y1+y2); if (dy < 0) dy = -dy; - db = dy; if (db < dx) db = dx; - - da = DOWNSCALE(da); - db = DOWNSCALE(db); - - level = 1; - da = da/64; - db = db/128; - while ( da > 0 || db > 0 ) - { - da >>= 1; - db >>= 2; - level++; - } - - if (level <= 1) - return render_line( RAS_VAR_ x3, y3 ); - - arc = ras.bez_stack; - arc[0].x = x3; - arc[0].y = y3; - arc[1].x = x2; - arc[1].y = y2; - arc[2].x = x1; - arc[2].y = y1; - arc[3].x = x0; - arc[3].y = y0; - - levels = ras.lev_stack; - top = 0; - levels[0] = level; - - for (;;) - { - level = levels[top]; - if (level > 1) - { - split_cubic(arc); - arc += 3; - top ++; - levels[top] = levels[top-1] = level-1; - } - else - { - if (render_line( RAS_VAR_ arc[0].x, arc[0].y )) return 1; - top --; - arc -= 3; - if (top < 0) - return 0; - } - } -} -#else /* !DIRECT_BEZIER */ - /* A function type describing the functions used to split bezier arcs */ - typedef void (*TSplitter)( FT_Vector* base ); - -#ifdef DYNAMIC_BEZIER_STEPS - static - TPos Dynamic_Bezier_Threshold( RAS_ARG_ int degree, FT_Vector* arc ) - { - TPos min_x, max_x, min_y, max_y, A, B; - TPos wide_x, wide_y, threshold; - - FT_Vector* cur = arc; - FT_Vector* limit = cur + degree; - - /* first of all, set the threshold to the maximum x or y extent */ - min_x = max_x = arc[0].x; - min_y = max_y = arc[0].y; - cur++; - for ( ; cur < limit; cur++ ) - { - TPos x = cur->x; - TPos y = cur->y; - - if ( x < min_x ) min_x = x; - if ( x > max_x ) max_x = x; - - if ( y < min_y ) min_y = y; - if ( y > max_y ) max_y = y; - } - wide_x = (max_x - min_x) << 4; - wide_y = (max_y - min_y) << 4; - - threshold = wide_x; - if (threshold < wide_y) threshold = wide_y; - - /* now compute the second and third order error values */ - - wide_x = arc[0].x + arc[1].x - arc[2].x*2; - wide_y = arc[0].y + arc[1].y - arc[2].y*2; - - if (wide_x < 0) wide_x = -wide_x; - if (wide_y < 0) wide_y = -wide_y; - - A = wide_x; if ( A < wide_y ) A = wide_y; - - if (degree >= 3) - { - wide_x = arc[3].x - arc[0].x + 3*(arc[2].x - arc[3].x); - wide_y = arc[3].y - arc[0].y + 3*(arc[2].y - arc[3].y); - - if (wide_x < 0) wide_x = -wide_x; - if (wide_y < 0) wide_y = -wide_y; - - B = wide_x; if ( B < wide_y ) B = wide_y; - } - else - B = 0; - - while ( A > 0 || B > 0 ) - { - threshold >>= 1; - A >>= 2; - B >>= 3; - } - - if (threshold < PRECISION_STEP) - threshold = PRECISION_STEP; - - return threshold; - } -#endif /* DYNAMIC_BEZIER_STEPS */ - - static - int render_bezier( RAS_ARG_ int degree, - TSplitter splitter, - TPos minv, - TPos maxv, - TDir dir ) - { - TPos v1, v2, u, v, e1, e2, threshold; - int reverse; - - FT_Vector* arc; - FT_Vector init; - - PCell top; - - arc = ras.arc; - init = arc[0]; - - arc[0].y -= ONE_HALF; - arc[1].y -= ONE_HALF; - arc[2].y -= ONE_HALF; - maxv -= ONE_PIXEL; - - top = ras.cursor; - - /* ensure that our segment is ascending */ - v1 = arc[degree].y; - v2 = arc[0].y; - reverse = 0; - if ( v2 < v1 ) - { - TPos tmp; - v1 = -v1; - v2 = -v2; - arc[0].y = v2; - arc[1].y = -arc[1].y; - arc[degree].y = v1; - if (degree > 2) - arc[2].y = -arc[2].y; - - tmp = minv; minv = -maxv; maxv = -tmp; - reverse = 1; - } - - if ( v2 < minv || v1 > maxv ) - goto Fin; - - /* compute the first scanline in "e1" */ - e1 = CEILING(v1); - if (e1 == v1 && ras.joint) - e1 += ONE_PIXEL; - - /* compute the last scanline in "e2" */ - if (v2 <= maxv) - { - e2 = FLOOR(v2); - ras.joint = (v2 == e2); - } - else - { - e2 = maxv; - ras.joint = 0; - } - - /* exit if the current scanline is already above the max scanline */ - if ( e2 < e1 ) - goto Fin; - - /* check for overflow */ - if ( ( top + TRUNC(e2-e1)+1 ) >= ras.cell_limit ) - { - ras.cursor = top; - ras.error = ErrRaster_Overflow; - return 1; - } - -#ifdef DYNAMIC_BEZIER_STEPS - /* compute dynamic bezier step threshold */ - threshold = Dynamic_Bezier_Threshold( RAS_VAR_ degree, arc ); -#else - threshold = PRECISION_STEP; -#endif - - /* loop while there is still an arc on the bezier stack */ - /* and the current scan line is below y max == e2 */ - while ( arc >= ras.arc && e1 <= e2 ) - { - ras.joint = 0; - - v2 = arc[0].y; /* final y of the top-most arc */ - - if ( v2 > e1 ) /* the arc intercepts the current scanline */ - { - v1 = arc[degree].y; /* start y of top-most arc */ - - if ( v2 >= e1 + ONE_PIXEL || v2 - v1 >= threshold ) - { - /* if the arc's height is too great, split it */ - splitter( arc ); - arc += degree; - } - else - { - /* otherwise, approximate it as a segment and compute */ - /* its intersection with the current scanline */ - u = arc[degree].x + - FMulDiv( arc[0].x-arc[degree].x, - e1 - v1, - v2 - v1 ); - - v = e1; if (reverse) v = -e1; - v += ONE_HALF; - if (WRITE_CELL( top, u, v, dir )) - top++; - - arc -= degree; /* pop the arc */ - e1 += ONE_PIXEL; /* go to next scanline */ - } - } - else - { - if ( v2 == e1 ) /* if the arc falls on the scanline */ - { /* record its _joint_ intersection */ - ras.joint = 1; - u = arc[degree].x; - v = e1; if (reverse) v = -e1; - v += ONE_HALF; - if (WRITE_CELL( top, u, v, dir )) - top++; - - e1 += ONE_PIXEL; /* go to next scanline */ - } - arc -= degree; /* pop the arc */ - } - } - - Fin: - ras.arc[0] = init; - ras.cursor = top; - return 0; - } - - -static -int render_conic( RAS_ARG_ TPos x1, TPos y1, TPos x2, TPos y2 ) -{ - TPos x0, y0; - TPos minv, maxv; - FT_Vector* arc; - - x0 = ras.x; - y0 = ras.y; - - minv = ras.min_y; - maxv = ras.max_y; - if (ras.horizontal) - { - minv = ras.min_x; - maxv = ras.max_x; - } - - arc = ras.bez_stack; - arc[2].x = ras.x; arc[2].y = ras.y; - arc[1].x = x1; arc[1].y = y1; - arc[0].x = x2; arc[0].y = y2; - - do - { - TDir dir; - TPos ymin, ymax; - - y0 = arc[2].y; - y1 = arc[1].y; - y2 = arc[0].y; - x2 = arc[0].x; - - /* first, categorize the Bezier arc */ - ymin = y0; - ymax = y2; - if (ymin > ymax) - { - ymin = y2; - ymax = y0; - } - - if (y1 < ymin || y1 > ymax) - { - /* this arc isn't y-monotonous, split it */ - split_conic( arc ); - arc += 2; - } - else if ( y0 == y2 ) - { - /* this arc is flat, ignore it */ - arc -= 2; - } - else - { - /* the arc is y-monotonous, either ascending or descending */ - /* detect a change of direction */ - dir = ( y0 < y2 ) ? dir_up : dir_down; - if (ras.horizontal) dir |= dir_horizontal; - if (dir != ras.dir) - { - ras.joint = 0; - ras.dir = dir; - } - - ras.arc = arc; - if (render_bezier( RAS_VAR_ 2, split_conic, minv, maxv, dir )) - goto Fail; - arc -= 2; - } - } while ( arc >= ras.bez_stack ); - - ras.x = x2; - ras.y = y2; - return 0; -Fail: - return 1; -} - -static -int render_cubic( RAS_ARG_ TPos x1, TPos y1, TPos x2, TPos y2, TPos x3, TPos y3 ) -{ - TPos x0, y0; - TPos minv, maxv; - FT_Vector* arc; - - x0 = ras.x; - y0 = ras.y; - - minv = ras.min_y; - maxv = ras.max_y; - if (ras.horizontal) - { - minv = ras.min_x; - maxv = ras.max_x; - } - - arc = ras.bez_stack; - arc[0].x = ras.x; arc[0].y = ras.y; - arc[1].x = x1; arc[1].y = y1; - arc[2].x = x2; arc[2].y = y2; - arc[3].x = x3; arc[3].y = y3; - - do - { - TDir dir; - TPos ymin1, ymax1, ymin2, ymax2; - - y0 = arc[3].y; - y1 = arc[2].y; - y2 = arc[1].y; - y3 = arc[0].y; - x3 = arc[0].x; - - /* first, categorize the Bezier arc */ - ymin1 = y0; - ymax1 = y3; - if (ymin1 > ymax1) - { - ymin1 = y3; - ymax1 = y0; - } - - ymin2 = y1; - ymax2 = y2; - if (ymin2 > ymax2) - { - ymin2 = y2; - ymax2 = y1; - } - - if ( ymin2 < ymin1 || ymax2 > ymax1) - { - /* this arc isn't y-monotonous, split it */ - split_cubic( arc ); - arc += 3; - } - else if ( y0 == y3 ) - { - /* this arc is flat, ignore it */ - arc -= 3; - } - else - { - /* the arc is y-monotonous, either ascending or descending */ - /* detect a change of direction */ - dir = ( y0 < y3 ) ? dir_up : dir_down; - if (ras.horizontal) dir |= dir_horizontal; - if (dir != ras.dir) - { - ras.joint = 0; - ras.dir = dir; - } - - ras.arc = arc; - if (render_bezier( RAS_VAR_ 3, split_cubic, minv, maxv, dir )) - goto Fail; - arc -= 3; - } - } while ( arc >= ras.bez_stack ); - - ras.x = x2; - ras.y = y2; - return 0; -Fail: - return 1; -} - -#endif /* !DIRECT_BEZIER */ - - -static -int is_less_than( PCell a, PCell b ) -{ - if (a->y < b->y) goto Yes; - if (a->y == b->y) - { - if (a->x < b->x) goto Yes; - if (a->x == b->x) - { - TDir ad = a->dir & (dir_horizontal|dir_silent); - TDir bd = b->dir & (dir_horizontal|dir_silent); - if ( ad < bd ) goto Yes; - if ( ad == bd && a->pos < b->pos) goto Yes; - } - } - return 0; -Yes: - return 1; -} - -/* a macro comparing two cell pointers. returns true if a <= b */ -#define LESS_THAN(a,b) is_less_than( (PCell)(a), (PCell)(b) ) -#define SWAP_CELLS(a,b,temp) { temp = *(a); *(a) = *(b); *(b) = temp; } -#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 - -#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 4 /* 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; - - if ( len > QSORT_THRESHOLD) - { - /* we use base+len/2 as the pivot */ - SWAP_CELLS( base, base+len/2, 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 ); - } - /* move pivot to correct place */ - 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 - - -#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 -#endif - -#ifdef _STANDALONE_ -#if 1 - static - int FT_Outline_Decompose( FT_Outline* outline, - FT_Outline_Funcs* interface, - void* user ) - { - typedef enum _phases - { - phase_point, - phase_conic, - phase_cubic, - phase_cubic2 - - } TPhase; - - FT_Vector v_first; - 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 */ - - - 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_first = outline->points[first]; - v_last = outline->points[last]; - - v_start = v_control = v_first; - - 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 */ - { - error = interface->line_to( point, user ); - if (error) goto Exit; - continue; - } - - - case FT_Curve_Tag_Conic: /* consume conic arcs */ - { - v_control = point[0]; - - Do_Conic: - if (point < limit) - { - FT_Vector v_middle; - - point++; - tags++; - tag = FT_CURVE_TAG( tags[0] ); - - if (tag == FT_Curve_Tag_On) - { - error = interface->conic_to( &v_control, point, user ); - if (error) goto Exit; - continue; - } - - if (tag != FT_Curve_Tag_Conic) - goto Invalid_Outline; - - v_middle.x = (v_control.x + point->x)/2; - v_middle.y = (v_control.y + point->y)/2; - - error = interface->conic_to( &v_control, &v_middle, user ); - if (error) goto Exit; - - v_control = point[0]; - goto Do_Conic; - } - - error = interface->conic_to( &v_control, &v_start, user ); - goto Close; - } - - default: /* FT_Curve_Tag_Cubic */ - { - if ( point+1 > limit || - FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) - goto Invalid_Outline; - - point += 2; - tags += 2; - - if (point <= limit) - { - error = interface->cubic_to( point-2, point-1, point, user ); - if (error) goto Exit; - continue; - } - - error = interface->cubic_to( point-2, point-1, &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 -1; - } -#else - static - int FT_Outline_Decompose( FT_Outline* outline, - FT_Outline_Funcs* interface, - void* user ) - { - typedef enum _phases - { - phase_point, - phase_conic, - phase_cubic, - phase_cubic2 - - } TPhase; - - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_control2; - FT_Vector v_start; - - FT_Vector* point; - char* tags; - - int n; /* index of contour in outline */ - int first; /* index of first point in contour */ - int index; /* current point's index */ - - int error; - - char tag; /* current point's state */ - TPhase phase; - - - first = 0; - - for ( n = 0; n < outline->n_contours; n++ ) - { - int last; /* index of last point in contour */ - - - last = outline->contours[n]; - - v_start = outline->points[first]; - v_last = outline->points[last]; - - v_control = v_start; - - tag = FT_CURVE_TAG( outline->tags[first] ); - index = first; - - /* A contour cannot start with a cubic control point! */ - - if ( tag == FT_Curve_Tag_Cubic ) - return ErrRaster_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; - } - 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; - } - phase = phase_conic; - } - else - phase = phase_point; - - - /* Begin a new contour with MOVE_TO */ - - error = interface->move_to( &v_start, user ); - if ( error ) - return error; - - point = outline->points + first; - tags = outline->tags + first; - - /* now process each contour point individually */ - - while ( index < last ) - { - index++; - point++; - tags++; - - tag = FT_CURVE_TAG( tags[0] ); - - switch ( phase ) - { - case phase_point: /* the previous point was on the curve */ - - switch ( tag ) - { - /* two succesive on points -> emit segment */ - case FT_Curve_Tag_On: - error = interface->line_to( point, user ); - break; - - /* on point + conic control -> remember control point */ - case FT_Curve_Tag_Conic: - v_control = point[0]; - phase = phase_conic; - break; - - /* on point + cubic control -> remember first control */ - default: - v_control = point[0]; - phase = phase_cubic; - break; - } - break; - - case phase_conic: /* the previous point was a conic control */ - - switch ( tag ) - { - /* conic control + on point -> emit conic arc */ - case FT_Curve_Tag_On: - error = interface->conic_to( &v_control, point, user ); - phase = phase_point; - break; - - /* two successive conics -> emit conic arc `in between' */ - case FT_Curve_Tag_Conic: - { - FT_Vector v_middle; - - - v_middle.x = (v_control.x + point->x)/2; - v_middle.y = (v_control.y + point->y)/2; - - error = interface->conic_to( &v_control, - &v_middle, user ); - v_control = point[0]; - } - break; - - default: - error = ErrRaster_Invalid_Outline; - } - break; - - case phase_cubic: /* the previous point was a cubic control */ - - /* this point _must_ be a cubic control too */ - if ( tag != FT_Curve_Tag_Cubic ) - return ErrRaster_Invalid_Outline; - - v_control2 = point[0]; - phase = phase_cubic2; - break; - - - case phase_cubic2: /* the two previous points were cubics */ - - /* this point _must_ be an on point */ - if ( tag != FT_Curve_Tag_On ) - error = ErrRaster_Invalid_Outline; - else - error = interface->cubic_to( &v_control, &v_control2, - point, user ); - phase = phase_point; - break; - } - - /* lazy error testing */ - if ( error ) - return error; - } - - /* end of contour, close curve cleanly */ - error = 0; - - tag = FT_CURVE_TAG( outline->tags[first] ); - - switch ( phase ) - { - case phase_point: - if ( tag == FT_Curve_Tag_On ) - error = interface->line_to( &v_start, user ); - break; - - case phase_conic: - error = interface->conic_to( &v_control, &v_start, user ); - break; - - case phase_cubic2: - if ( tag == FT_Curve_Tag_On ) - error = interface->cubic_to( &v_control, &v_control2, - &v_start, user ); - else - error = ErrRaster_Invalid_Outline; - break; - - default: - error = ErrRaster_Invalid_Outline; - break; - } - - if ( error ) - return error; - - first = last + 1; - } - - return 0; - } - -#endif -#endif /* _STANDALONE_ */ - - - static - int Move_To2( FT_Vector* to, - FT_Raster raster ) - { - PRaster rast = (PRaster)raster; - FT_Pos* to_x; - FT_Pos* to_y; - - to_x = &to->x; - to_y = &to->y; - if (rast->horizontal) - { - to_x = &to->y; - to_y = &to->x; - } - - rast->starter.x = UPSCALE(*to_x); - rast->starter.y = UPSCALE(*to_y); - - rast->joint = 0; - rast->dir = dir_unknown; - rast->last = 0; - rast->start = 0; - - if ((*to_x & 63) == 32) - { - rast->starter.x |= 1; - rast->start = to; - } - if ((*to_y & 63) == 32) - { - rast->starter.y |= 1; - rast->start = to; - } - - rast->x = rast->starter.x; - rast->y = rast->starter.y; - return 0; - } - - - static - int Line_To2( FT_Vector* to, - FT_Raster raster ) - { - TPos x, y; - PRaster rast = (PRaster)raster; - - if ( to == rast->start ) - { - x = rast->starter.x; - y = rast->starter.y; - } - else - { - if ( rast->horizontal ) - { - x = to->y; - y = to->x; - } - else - { - x = to->x; - y = to->y; - } - x = UPSCALE(x); - y = UPSCALE(y); - } - - return render_line( rast, x, y ); - } - - - static - int Conic_To2( FT_Vector* control, - FT_Vector* to, - FT_Raster raster ) - { - PRaster rast = (PRaster)raster; - FT_Vector ctr, to2; - - ctr = *control; - to2 = *to; - if (rast->horizontal) - { - ctr.x = control->y; - ctr.y = control->x; - to2.x = to->y; - to2.y = to->x; - } - - if ( to == rast->start ) - to2 = rast->starter; - else - { - to2.x = UPSCALE(to2.x); - to2.y = UPSCALE(to2.y); - } - - return render_conic( rast, UPSCALE(ctr.x), UPSCALE(ctr.y), to2.x, to2.y ); - } - - - static - int Cubic_To2( FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to, - FT_Raster raster ) - { - PRaster rast = (PRaster)raster; - FT_Vector ctr1, ctr2, to2; - - ctr1 = *control1; - ctr2 = *control2; - to2 = *to; - if (rast->horizontal) - { - ctr1.x = control1->y; ctr1.y = control1->x; - ctr2.x = control2->y; ctr2.y = control2->x; - to2.x = to->y; to2.y = to->x; - } - - if ( to == rast->start ) - to2 = rast->starter; - else - { - to2.x = UPSCALE(to2.x); - to2.y = UPSCALE(to2.y); - } - - return render_cubic( rast, UPSCALE(ctr1.x), UPSCALE(ctr1.y), - UPSCALE(ctr2.x), UPSCALE(ctr2.y), - to2.x, to2.y ); - } - - - static - void grays_render_span( int y, int count, FT_GraySpan* spans, PRaster raster ) - { - unsigned char *p, *q, *limit; - 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) - { - q = p + spans->x; - limit = q + spans->len; - for ( ; q < limit; q++ ) - q[0] = spans->coverage >> 1; - } - } - } - -#ifdef DEBUG_GRAYS -#include - - static - void dump_cells( RAS_ARG ) - { - static const char dirs[5] = "udrl?"; - 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: ", (int)cell->y ); - y = cell->y; - } - fprintf( stderr, "[%d %c %d]", - (int)cell->x, - dirs[cell->dir & 3], - cell->pos ); - } - fprintf(stderr, "\n" ); - } -#endif - - static - void grays_hline( RAS_ARG_ TScan y, TScan x, int coverage, int acount ) - { - FT_GraySpan* span; - int count; - - /* compute the coverage line's coverage, depending on the */ - /* outline fill rule.. */ - /* */ - /* The coverage percentage is area/ONE_PIXEL */ - /* */ - - coverage <<= 1; - coverage >>= (PIXEL_BITS-6); - - if (coverage < 0) - coverage = -coverage; - - if (coverage >= 256) - coverage = 255; - - if (coverage) - { - x += ras.min_ex; - - /* 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.min_ey + ras.span_y, count, ras.gray_spans, ras.render_span_closure ); - /* 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++) - { - if (span->len > 1) - fprintf( stderr, "[%d..%d]:%02x ", span->x, span->x + span->len-1, span->coverage ); - else - fprintf( stderr, "[%d]:%02x ", span->x, span->coverage ); - } - fprintf( stderr, "\n" ); - } -#endif - - 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 char)acount; - span->coverage = (unsigned char)coverage; - ras.num_gray_spans++; - } - } - - - - static - void grays_sweep( RAS_ARG_ FT_Bitmap* target ) - { - TScan x, y, cover, x_black; - int varea, harea, hpos; - PCell start, cur, limit; - - cur = ras.cells; - limit = cur + ras.num_cells; - - cover = 0; - ras.span_y = -1; - ras.num_gray_spans = 0; - - cover = 0; - x_black = 32000; - - /* fprintf( stderr, "%2d:", cur->y ); */ - - for (;;) - { - int is_black, icover; - int area, numv; - - start = cur; - y = start->y; - x = start->x; - icover = cover; - varea = cover << PIXEL_BITS; - harea = 0; - hpos = varea; - numv = 0; - - /* accumulate all start cells */ - for (;;) - { -#if 0 - /* we ignore silent cells for now XXXX */ - if (!(cur->dir & dir_silent)) -#endif - { - switch ((cur->dir)&3) - { - case dir_up: - varea += ONE_PIXEL - cur->pos; - if (cur->pos <= 32) - hpos = ONE_PIXEL; - cover++; - numv++; - break; - - case dir_down: - varea -= ONE_PIXEL - cur->pos; - if (cur->pos <= 32) - hpos = 0; - cover--; - numv++; - break; -#if 0 - case dir_left: - harea += ONE_PIXEL - cur->pos; - break; - - default: - harea -= ONE_PIXEL - cur->pos; - break; -#else - default: - ; -#endif - } - } - - ++cur; - if (cur >= limit || cur->y != start->y || cur->x != start->x) - break; - } - - /* nom compute the "real" area in the pixel */ - if (varea < 0) varea += ONE_PIXEL; - if (harea < 0) harea += ONE_PIXEL; - - if (varea == 0) - area = 2*harea; - - else if (harea == 0) - area = 2*varea; - - else - area = (varea+harea+ONE_PIXEL) >> 1; - - is_black = ( area >= 2*ONE_PIXEL ); - - /* if the start cell isn't black, we may need to draw a black */ - /* segment from a previous cell.. */ - if ( !is_black && start->x > x_black ) - { - /* printf( stderr, " b[%d..%d]", x_black, start->x-1 ); */ - grays_hline( RAS_VAR_ y, x_black, 2*ONE_PIXEL, start->x - x_black ); - } - - /* if the cell is black, then record its position in "x_black" */ - if ( is_black ) - { - if ( x_black > start->x ) - x_black = start->x; - } - - /* if the cell is gray, draw a single gray pixel, then record */ - /* the next cell's position in "x_black" if "cover" is black */ - else - { - x_black = 32000; - if ( area ) - { - /* fprintf( stderr, " [%d:%d]", start->x, varea ); */ - grays_hline( RAS_VAR_ y, start->x, area, 1 ); - if (cover) - x_black = start->x+1; - } - } - - - /* now process scanline changes/end */ - if (cur >= limit || cur->y != start->y) - { - if (cover && x_black < ras.max_ex) - { - /* fprintf( stderr, " f[%d..%d]", x_black, ras.max_ex-1 ); */ - grays_hline( RAS_VAR_ y, x_black, 2*ONE_PIXEL, ras.max_ex-x_black ); - } - - if (cur >= limit) - break; - - /* fprintf( stderr, "\n%2d:", cur->y ); */ - cover = 0; - x_black = 32000; - } - } - 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_closure ); - -#ifdef DEBUG_GRAYS - { - int n; - FT_GraySpan* span; - - fprintf( stderr, "y=%3d ", ras.span_y ); - span = ras.gray_spans; - for (n = 0; n < ras.num_gray_spans; n++, span++) - { - if (span->len > 1) - fprintf( stderr, "[%d..%d]:%02x ", span->x, span->x + span->len-1, span->coverage ); - else - fprintf( stderr, "[%d]:%02x ", span->x, span->coverage ); - } - fprintf( stderr, "\n" ); - } -#endif - } - - static - int Convert_Glyph( RAS_ARG_ FT_Outline* outline ) - { - static - FT_Outline_Funcs interface = - { - (FT_Outline_MoveTo_Func)Move_To2, - (FT_Outline_LineTo_Func)Line_To2, - (FT_Outline_ConicTo_Func)Conic_To2, - (FT_Outline_CubicTo_Func)Cubic_To2 - }; - - /* Set up state in the raster object */ - compute_cbox( RAS_VAR_ outline ); - - 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; - - ras.min_x = UPSCALE(ras.min_ex << 6); - ras.min_y = UPSCALE(ras.min_ey << 6); - ras.max_x = UPSCALE(ras.max_ex << 6); - ras.max_y = UPSCALE(ras.max_ey << 6); - - ras.num_cells = 0; - ras.contour_cell = 0; - ras.horizontal = 0; - - /* compute vertical intersections */ - if (FT_Outline_Decompose( outline, &interface, &ras )) - return 1; -#if 0 - /* compute horizontal intersections */ - ras.horizontal = 1; - return FT_Outline_Decompose( outline, &interface, &ras ); -#else - return 0; -#endif - } - - - - - - - extern - int grays2_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 -1; - - if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) - return -1; - - if ( !target_map || !target_map->buffer ) - return -1; - - ras.outline = *outline; - ras.target = *target_map; - ras.num_cells = 0; - ras.cursor = ras.cells; - - if (Convert_Glyph( (PRaster)raster, outline )) - return 1; - - ras.num_cells = ras.cursor - ras.cells; -#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 - -#if 1 - ras.render_span = (FT_GraySpan_Func)grays_render_span; - ras.render_span_closure = &ras; - - grays_sweep( (PRaster)raster, target_map ); - return 0; -#else - return 0; -#endif - } - - - /**** RASTER OBJECT CREATION : in standalone mode, we simply use *****/ - /**** a static object .. *****/ -#ifdef _STANDALONE_ - - static - int grays2_raster_new( void* memory, FT_Raster *araster ) - { - static TRaster the_raster; - *araster = (FT_Raster)&the_raster; - memset( &the_raster, sizeof(the_raster), 0 ); - return 0; - } - - static - void grays2_raster_done( FT_Raster raster ) - { - /* nothing */ - (void)raster; - } - -#else - -#include "ftobjs.h" - - static - int grays2_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 grays2_raster_done( FT_Raster raster ) - { - FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; - FREE( raster ); - } - -#endif - - - - - static - void grays2_raster_reset( FT_Raster raster, - const char* pool_base, - long pool_size ) - { - if (raster && pool_base && pool_size >= 4096) - init_cells( (PRaster)raster, (char*)pool_base, pool_size ); - } - - - FT_Raster_Funcs ft_grays2_raster = - { - ft_glyph_format_outline, - - (FT_Raster_New_Func) grays2_raster_new, - (FT_Raster_Reset_Func) grays2_raster_reset, - (FT_Raster_Set_Mode_Func) 0, - (FT_Raster_Render_Func) grays2_raster_render, - (FT_Raster_Done_Func) grays2_raster_done - }; - diff --git a/demos/src/ftgrays2.h b/demos/src/ftgrays2.h deleted file mode 100644 index cba7bbe66..000000000 --- a/demos/src/ftgrays2.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef FTGRAYS2_H -#define FTGRAYS2_H - -#include - - extern - FT_Raster_Funcs ft_grays2_raster; - -#endif diff --git a/demos/src/ftrast.c b/demos/src/ftrast.c deleted file mode 100644 index 99ce1d737..000000000 --- a/demos/src/ftrast.c +++ /dev/null @@ -1,3039 +0,0 @@ -/******************************************************************* - * - * ftraster.c 1.5 - * - * 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 "ftrast.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 */ - /* which are: */ - /* */ - /* 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 wether is 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. Additionaly, 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 - -/* required by the tracing mode */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_raster - -#include - - -/* The default render pool size */ -#define RASTER_RENDER_POOL 8192 - -/* XXXXX */ -#define FT_CONFIG_OPTION_GRAY_SCALING - -/* The size of the two-lines intermediate bitmap used */ -/* for anti-aliasing */ -#define RASTER_GRAY_LINES 1024 - -#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 uses in case where 'b' is typically */ -/* a small value and the result of (a*b) is known to fit in 32 bits. */ -#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) - -/* On the other hand, SMulDiv is for "Slow MulDiv", and is used typically */ -/* for clipping computations. It simply uses the TT_MulDiv() function */ -/* defined in "ttcalc.h" */ -/* */ -/* So, the following definition fits the bill nicely, and we don't need */ -/* to use the one in 'ttcalc' anymore, even for 16-bit systems... */ -#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 */ - -#else - -#define RAS_ARGS TRaster_Instance* raster, -#define RAS_ARG TRaster_Instance* raster - -#define RAS_VARS raster, -#define RAS_VAR raster - -#endif - - - 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 */ - - Byte grays[5]; /* Palette of gray levels used for render */ - - Byte* 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' */ - - 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; - -#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_STATIC_RASTER */ - - /****************************************************************/ - /****************************************************************/ - /** **/ - /** PROFILES COMPUTATION **/ - /** **/ - /****************************************************************/ - /****************************************************************/ - - -/************************************************************************/ -/* */ -/* Function: Set_High_Precision */ -/* */ -/* Description: Sets precision variables according to param flag. */ -/* */ -/* Input: 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_TRACE7(( "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; - } - - -/****************************************************************************/ -/* */ -/* Function: New_Profile */ -/* */ -/* Description: Creates a new Profile in the render pool. */ -/* */ -/* Input: aState state/orientation of the new Profile */ -/* */ -/* Returns: 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_TRACE7(( "New ascending profile = %lx\n", (long)ras.cProfile )); - break; - - case Descending: - ras.cProfile->flow = Flow_Down; - FT_TRACE7(( "New descending profile = %lx\n", (long)ras.cProfile )); - break; - - default: - FT_ERROR(( "Invalid profile direction in Raster:New_Profile !!\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; - } - - -/****************************************************************************/ -/* */ -/* Function: End_Profile */ -/* */ -/* Description: Finalizes the current Profile. */ -/* */ -/* Input: None */ -/* */ -/* Returns: 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(( "Negative height encountered in End_Profile!\n" )); - ras.error = Raster_Err_Neg_Height; - return FAILURE; - } - - if ( h > 0 ) - { - FT_TRACE1(( "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; - } - - -/****************************************************************************/ -/* */ -/* Function: Insert_Y_Turn */ -/* */ -/* Description: Insert a salient into the sorted list placed on top */ -/* of the render pool */ -/* */ -/* Input: New y scanline position */ -/* */ -/****************************************************************************/ - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Finalize_Profile_Table */ -/* */ -/* Description: Adjusts all links in the Profiles list. */ -/* */ -/* Input: None */ -/* */ -/* Returns: None. */ -/* */ -/****************************************************************************/ - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Split_Conic */ -/* */ -/* Description: Subdivides one conic bezier into two joint */ -/* sub-arcs in the Bezier stack. */ -/* */ -/* Input: None (subdivided bezier is taken from the top of the */ -/* stack). */ -/* */ -/* Returns: None. */ -/* */ -/* */ -/* Note: 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; - } - - - -/****************************************************************************/ -/* */ -/* Function: Line_Up */ -/* */ -/* Description: Computes the x-coordinates of an ascending line segment */ -/* and stores them in the render pool. */ -/* */ -/* Input: x1,y1,x2,y2 Segment start (x1,y1) and end (x2,y2) points */ -/* */ -/* Returns: 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; - } - - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Bezier_Up */ -/* */ -/* Description: Computes thes x-coordinates of an ascending bezier arc */ -/* and stores them in the render pool. */ -/* */ - - /* A function type describing the functions used to split bezier arcs */ - typedef void (*TSplitter)( TPoint* base ); - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Bezier_Down */ -/* */ -/* Description: Computes the x-coordinates of a descending bezier arc */ -/* and stores them in the render pool. */ -/* */ - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Line_To */ -/* */ -/* Description: Injects a new line segment and adjusts Profiles list. */ -/* */ -/* Input: x, y : segment endpoint (start point in LastX,LastY) */ -/* */ -/* Returns: 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Conic_To */ -/* */ -/* Description: Injects a new conic arc and adjusts the profile list. */ -/* */ - - 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; - } - -/****************************************************************************/ -/* */ -/* Function: Cubic_To */ -/* */ -/* Description: Injects a new cubic arc and adjusts the profile list. */ -/* */ - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Decompose_Curve */ -/* */ -/* Description: 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! */ -/* */ -/* Input: first, last : indexes of first and last point in */ -/* contour. */ -/* */ -/* Returns: SUCCESS on success. */ -/* FAILURE on error. */ -/* */ -/****************************************************************************/ - -#undef SWAP_ -#define SWAP_(x,y) { Long swap = x; x = y; y = swap; } - - - 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; - } - -/****************************************************************************/ -/* */ -/* Function: Convert_Glyph */ -/* */ -/* Description: Converts a glyph into a series of segments and arcs */ -/* and makes a Profiles list with them. */ -/* */ -/* Input: _xCoord, _yCoord : coordinates tables. */ -/* */ -/* Uses the 'Flag' table too. */ -/* */ -/* Returns: 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 if 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 */ -/* */ -/* Inits 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 three 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 when: */ - /* */ - /* 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 ( x2-x1 < ras.precision_half ) */ - { - /* 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 three 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; - } - } - } -#if 0 - e2 = TRUNC( e2 ); - - if ( e2 >= 0 && e2 < ras.target.rows ) - { - PByte p; - - p = bits - e2*ras.target.pitch; - if (ras.target.pitch > 0) - p += (ras.target.rows-1)*ras.target.pitch; - - p[0] |= f1; - } -#endif - } - - - 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_CONFIG_OPTION_GRAY_SCALING - -/***********************************************************************/ -/* */ -/* 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 ) - { - if ( ras.gray_max_x >= ras.target.width ) - ras.gray_max_x = ras.target.width-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 --; - } - } - - 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_CONFIG_OPTION_GRAY_SCALING */ - - -/********************************************************************/ -/* */ -/* 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; - /* dropouts--; -- this is useful when debugging only */ - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Render_Single_Pass */ -/* */ -/* Description: Performs one sweep with sub-banding. */ -/* */ -/* Input: _XCoord, _YCoord : x and y coordinates arrays */ -/* */ -/* Returns: SUCCESS on success */ -/* FAILURE if any error was encountered during render. */ -/* */ -/****************************************************************************/ - - static FT_Error 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 FT_Err_Ok; - } - - -/****************************************************************************/ -/* */ -/* Function: Render_Glyph */ -/* */ -/* Description: Renders a glyph in a bitmap. Sub-banding if needed. */ -/* */ -/* Input: AGlyph Glyph record */ -/* */ -/* Returns: SUCCESS on success. */ -/* FAILURE if any error was encountered during rendering. */ -/* */ -/****************************************************************************/ - - 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; - } - - -/****************************************************************************/ -/* */ -/* Function: Render_Gray_Glyph */ -/* */ -/* Description: Renders a glyph with grayscaling. Sub-banding if needed. */ -/* */ -/* Input: AGlyph Glyph record */ -/* */ -/* Returns: SUCCESS on success */ -/* FAILURE if any error was encountered during rendering. */ -/* */ -/****************************************************************************/ - - LOCAL_FUNC - FT_Error Render_Gray_Glyph( RAS_ARG ) - { - Long byte_len; - FT_Error error; - -#if 0 - if ( palette ) - { - for ( i = 0; i < 5; i++ ) - ras.grays[i] = palette[i]; - } - - if ( target_map ) - ras.target = *target_map; -#endif - - 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; - - byte_len = ras.target.pitch; - if (byte_len < 0) - byte_len = -byte_len; - - if ( ras.bWidth > byte_len/4 ) - ras.bWidth = byte_len/4; - - 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; - } - - - -#if 0 -/************************************************/ -/* */ -/* InitRasterizer */ -/* */ -/* Raster Initialization. */ -/* Gets the bitmap description and render pool */ -/* addresses. */ -/* */ -/************************************************/ - -#undef ras - - LOCAL_FUNC - FT_Error TTRaster_Done( PEngine_Instance engine ) - { - TRaster_Instance* ras = (TRaster_Instance*)engine->raster_component; - - - if ( !ras ) - return FT_Err_Ok; - - FREE( ras->buff ); - FREE( ras->gray_lines ); - - return FT_Err_Ok; - } - - - LOCAL_FUNC - FT_Error TTRaster_Init( PEngine_Instance engine ) - { - FT_Error error; - - Int i, l, j, c; - - TRaster_Instance* ras; - - -#ifdef FT_CONFIG_OPTION_STATIC_RASTER - ras = engine->raster_component = &cur_ras; -#else - if ( ALLOC( engine->raster_component, sizeof ( TRaster_Instance ) ) ) - return error; - - ras = (TRaster_Instance*)engine->raster_component; -#endif - - if ( ALLOC( ras->buff, RASTER_RENDER_POOL ) || - ALLOC( ras->gray_lines, RASTER_GRAY_LINES ) ) - return error; - - ras->sizeBuff = ras->buff + ( RASTER_RENDER_POOL/sizeof(long) ); - ras->gray_width = RASTER_GRAY_LINES/2; - - /* Initialization of Count_Table */ - - for ( i = 0; i < 256; i++ ) - { - l = 0; - j = i; - - for ( c = 0; c < 4; c++ ) - { - l <<= 4; - - if ( j & 0x80 ) l++; - if ( j & 0x40 ) l++; - - j = ( j << 2 ) & 0xFF; - } - - ras->count_table[i] = l; - } - - ras->dropOutControl = 2; - ras->error = Raster_Err_None; - - return FT_Err_Ok; - } -#endif - - /**** 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 ); - return 0; - } - - static - void ft_black_done( FT_Raster raster ) - { - /* nothing */ - raster->init = 0; - } - -#else - -#include - - 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; - *araster = raster; - } - - return error; - } - - static - void ft_black_done( TRaster_Instance* raster ) - { - FT_Memory memory = (FT_Memory)raster->memory; - FREE( raster ); - } - -#endif - - - 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 - 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 ) ); - -#if 0 - /* Note that we always use drop-out mode 2, because it seems that */ - /* it's the only way to do to get results consistent with Windows */ - /* rendering.. */ - ras.dropout_mode = 2; - - ras.second_pass = (outline->flags & ft_outline_single_pass) == 0; - SET_High_Precision( (char)((outline->flags & ft_outline_high_precision)!= 0) ); - - return ( params->flags & ft_raster_flag_aa - ? Raster_Render8( raster ) - : Raster_Render1( raster ) ); -#endif - } - - - FT_Raster_Funcs ft_black_raster = - { - ft_glyph_format_outline, - (FT_Raster_New_Func) ft_black_new, - (FT_Raster_Reset_Func) ft_black_reset, - (FT_Raster_Set_Mode_Func) 0, - (FT_Raster_Render_Func) ft_black_render, - (FT_Raster_Done_Func) ft_black_done - }; - - - -/* END */ diff --git a/demos/src/ftrast.h b/demos/src/ftrast.h deleted file mode 100644 index 25db0dcd8..000000000 --- a/demos/src/ftrast.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef FTRASTER_H -#define FTRASTER_H - -#include - - extern FT_Raster_Funcs ft_black_raster; - -#endif diff --git a/demos/src/ftrast2.c b/demos/src/ftrast2.c deleted file mode 100644 index 1d235667f..000000000 --- a/demos/src/ftrast2.c +++ /dev/null @@ -1,3856 +0,0 @@ -/******************************************************************* - * - * ftraster.c 2.0 - * - * The FreeType glyph rasterizer (body). - * - * Copyright 1996-1998 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. - * - * The "raster" component implements FreeType's scan-line converter, - * the one used to generate bitmaps and pixmaps from vectorial outlines - * descriptions. - * - * It has been rewritten entirely for FreeType 2.0, in order to become - * completely independent of the rest of the library. It should now be - * possible to include it more easily in all kinds of libraries and - * applications, which do not necessarily need the font engines and - * API. - * - * This version features : - * - * - support for third-order bezier arcs - * - * - improved performance of the 5-levels anti-aliasing algorithm - * - * - 17-levels anti-aliasing for smoother curves, though the - * difference isn't always noticeable, depending on your palette - * - * - an API to decompose a raster outline into a path (i.e. into - * a series of segments and arcs). - * - ******************************************************************/ - -#include "ftrast2.h" -#include /* for FT_Outline_Decompose */ - -#ifndef EXPORT_FUNC -#define EXPORT_FUNC /* nothing */ -#endif - - -/**************************************************************************/ -/* */ -/* We need a 32-bit unsigned word for our optimized 2x2 filter.. The */ -/* following uses the ANSI header file to compute exactly */ -/* wether to use unsigned int or unsigned long */ -/* */ -#include - -/* The number of bytes in an `int' type. */ -#if UINT_MAX == 0xFFFFFFFF -typedef unsigned int Word32; -typedef int Int32; -#elif ULONG_MAX == 0xFFFFFFFF -typedef unsigned long Word32; -typedef long Int32; -#else -#error "could not find a 32-bit word on this machine !!" -#endif - - - -#ifndef _xxFREETYPE_ - -/**************************************************************************/ -/* */ -/* The following defines are used when the raster is compiled as a */ -/* stand-alone object. Each of them is commented, and you're free to */ -/* toggle them to suit your needs.. */ -/* */ - -/**************************************************************************/ -/* */ -/* FT_RASTER_OPTION_ANTI_ALIAS */ -/* */ -/* Define this configuration macro if you want to support anti-aliasing */ -/* */ -#define FT_RASTER_OPTION_ANTI_ALIAS - -/**************************************************************************/ -/* */ -/* FT_RASTER_OPTION_CONIC_BEZIERS */ -/* */ -/* Define this configuration macro if your source outlines contain */ -/* second-order Bezier arcs. Typically, these are TrueType outlines.. */ -/* */ -#define FT_RASTER_CONIC_BEZIERS - -/**************************************************************************/ -/* */ -/* FT_RASTER_OPTION_CUBIC_BEZIERS */ -/* */ -/* Define this configuration macro if your source outlines contain */ -/* third-order Bezier arcs. Typically, these are Type1 outlines.. */ -/* */ -#define FT_RASTER_CUBIC_BEZIERS - -/**************************************************************************/ -/* */ -/* FT_RASTER_ANTI_ALIAS_5 */ -/* */ -/* Define this configuration macro if you want to enable the 5-grays */ -/* anti-aliasing mode.. Ignored if FT_RASTER_OPTION_ANTI_ALIAS isn't */ -/* defined.. */ -/* */ -#define FT_RASTER_ANTI_ALIAS_5 - -/**************************************************************************/ -/* */ -/* FT_RASTER_ANTI_ALIAS_17 */ -/* */ -/* Define this configuration macro if you want to enable the 17-grays */ -/* anti-aliasing mode.. Ignored if FT_RASTER_OPTION_ANTI_ALIAS isn't */ -/* defined.. */ -/* */ -#undef FT_RASTER_ANTI_ALIAS_17 - -/**************************************************************************/ -/* */ -/* FT_RASTER_LITTLE_ENDIAN */ -/* FT_RASTER_BIG_ENDIAN */ -/* */ -/* The default anti-alias routines are processor-independent, but slow. */ -/* Define one of these macros to suit your own system, and enjoy */ -/* greatly improved rendering speed */ -/* */ - -/* #define FT_RASTER_LITTLE_ENDIAN */ -/* #define FT_RASTER_BIG_ENDIAN */ - -#else /* _FREETYPE_ */ - -/**************************************************************************/ -/* */ -/* The following defines are used when the raster is compiled within */ -/* the FreeType base layer. Don't change these unless you really know */ -/* what you're doing.. */ -/* */ - -#ifdef FT_CONFIG_OPTION_ANTI_ALIAS -#define FT_RASTER_OPTION_ANTI_ALIAS -#endif - -#define FT_RASTER_CONIC_BEZIERS -#define FT_RASTER_CUBIC_BEZIERS - -#define FT_RASTER_ANTI_ALIAS_5 -#undef FT_RASTER_ANTI_ALIAS_17 - -#ifdef FT_CONFIG_OPTION_LITTLE_ENDIAN -#define FT_RASTER_LITTLE_ENDIAN -#endif - -#ifdef FT_CONFIG_OPTION_BIG_ENDIAN -#define FT_RASTER_BIG_ENDIAN -#endif - -#endif /* _FREETYPE_ */ - - -/* FT_RASTER_ANY_ENDIAN indicates that no endianess was defined */ -/* through one of the configuration macros */ -/* */ -#if !defined(FT_RASTER_LITTLE_ENDIAN) && !defined(FT_RASTER_BIG_ENDIAN) -#define FT_RASTER_ANY_ENDIAN -#endif - - -/* 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 - - -#undef FAILURE -#define FAILURE TRUE - -#undef SUCCESS -#define SUCCESS FALSE - - -/* Please don't touch the following macros. Their importance is historical */ -/* to FreeType, but they have some nice effects, like getting rid of all */ -/* '->' symbols when accessing the raster object.. (replacing them with */ -/* a simple '.' ) */ - -/* used in function signatures to define the _first_ argument */ -#define RAS_ARGS FT_Raster raster, -#define RAS_ARG FT_Raster raster - -/* used to call a function within this component, first parameter */ -#define RAS_VARS raster, -#define RAS_VAR raster - -/* used to access the current raster object, with a '.' instead of a '->' */ -#define ras (*raster) - -#define UNUSED_RASTER (void)raster; - -/* For anti-aliasing modes, we use a 2 or 4 lines intermediate bitmap which */ -/* is filtered repeatedly to render each pixmap row. The following macro */ -/* defines this buffer's size in bytes (which is part of raster objects) */ -#define ANTI_ALIAS_BUFFER_SIZE 2048 - - -/* Error codes returned by the scan-line converter/raster */ - -#define ErrRaster_Ok 0 -#define ErrRaster_Uninitialised_Object 1 -#define ErrRaster_Overflow 2 -#define ErrRaster_Negative_Height 3 -#define ErrRaster_Invalid_Outline 4 -#define ErrRaster_Invalid_Map 5 -#define ErrRaster_AntiAlias_Unsupported 6 -#define ErrRaster_Invalid_Pool 7 -#define ErrRaster_Unimplemented 8 -#define ErrRaster_Bad_Palette_Count 9 - - -#define SET_High_Precision(p) Set_High_Precision( RAS_VARS p ) - -/* Fast MulDiv, as 'b' is always < 64, don't use intermediate precision */ -#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) - - -/* Define DEBUG_RASTER if you want to generate a debug version of the */ -/* rasterizer. This will progressively draw the glyphs while all the */ -/* computation are done directly on the graphics screen (the glyphs */ -/* will be inverted). */ - -/* Note that DEBUG_RASTER should only be used for debugging with b/w */ -/* rendering, not with gray levels. */ - -/* The definition of DEBUG_RASTER should appear in the file */ -/* "ftconfig.h". */ - -#ifdef DEBUG_RASTER - extern char* vio; /* A pointer to VRAM or display buffer */ -#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 */ - /* We always use 26.6, but hackers are free */ - /* to experiment with different values */ - - - /* The type of the pixel coordinates used within the render pool during */ - /* scan-line conversion. We use longs to store either 26.6 or 22.10 fixed */ - /* float values, depending on the "precision" we want to use (resp. low */ - /* or high). These are ideals in order to subdivise bezier arcs in halves */ - /* though simple additions and shifts. */ - - typedef Int32 TPos, *PPos; - - - /* The type of a scanline position/coordinate within a map */ - typedef int TScan, *PScan; - - - - - /* boolean type */ - typedef char TBool; - - /* unsigned char type and array */ - typedef unsigned char TByte, *PByte; - - /* unsigned short type and array */ - typedef unsigned short UShort, *PUShort; - - /* flow */ - enum _TFlow - { - FT_Flow_Error = 0, - FT_Flow_Down = -1, - FT_Flow_Up = 1 - }; - - - /* states/directions of each line, arc and profile */ - enum _TDirection - { - Unknown, - Ascending, - Descending, - Flat - }; - typedef enum _TDirection TDirection; - - - struct _TProfile; - typedef struct _TProfile TProfile; - typedef TProfile* PProfile; - - struct _TProfile - { - TPos X; /* current coordinate during sweep */ - PProfile link; /* link to next profile - various purpose */ - PPos offset; /* start of profile's data in render pool */ - int flow; /* Profile orientation: Asc/Descending */ - TScan height; /* profile's height in scanlines */ - TScan start; /* profile's starting scanline */ - - TScan 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 */ - /* */ - struct _TBand - { - TScan y_min; /* band's minimum */ - TScan y_max; /* band's maximum */ - }; - - typedef struct _TBand TBand; - - -/* The size in _TPos_ of a profile record in the render pool */ -#define AlignProfileSize ((sizeof(TProfile)+sizeof(TPos)-1) / sizeof(TPos)) - - - /* prototypes used for sweep function dispatch */ - typedef void Function_Sweep_Init( RAS_ARGS int* min, int* max ); - - typedef void Function_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ); - - typedef int Function_Test_Pixel( RAS_ARGS TScan y, - int x ); - - typedef void Function_Set_Pixel( RAS_ARGS TScan y, - int x, - int color ); - - typedef void Function_Sweep_Step( RAS_ARG ); - - -/* compute lowest integer coordinate below a given x */ -#define FLOOR( x ) ( (x) & ras.precision_mask ) - -/* compute highest integer coordinate above a given x */ -#define CEILING( x ) ( ((x) + ras.precision - 1) & ras.precision_mask ) - -/* get integer coordinate of a given 26.6 or 22.10 'x' coordinate - no round */ -#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) - -/* get the fractional part of a given coordinate */ -#define FRAC( x ) ( (x) & (ras.precision - 1) ) - -/* scale an 'input coordinate' (as found in FT_Outline structures) into */ -/* a 'work coordinate', which depends on current resolution and render */ -/* mode.. */ -#define SCALED( x ) ( ((x) << ras.scale_shift) - ras.precision_half ) - - -/* DEBUG_PSET is used to plot a single pixel in VRam during debug mode */ -#ifdef DEBUG_RASTER -#define DEBUG_PSET Pset() -#else -#define DEBUG_PSET -#endif - - struct _TPoint - { - TPos x, y; - }; - typedef struct _TPoint TPoint; - - - /* 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 FT_RasterRec_ - { - PPos cursor; /* Current cursor in render pool */ - - PPos pool; /* The render pool base address */ - PPos pool_size; /* The render pool's size */ - PPos pool_limit; /* Limit of profiles zone in pool */ - - int bit_width; /* target bitmap width */ - PByte bit_buffer; /* target bitmap buffer */ - PByte pix_buffer; /* target pixmap buffer */ - - TPoint last; - long minY, maxY; - - int error; - - int precision_bits; /* precision related variables */ - int precision; - int precision_half; - long precision_mask; - int precision_shift; - int precision_step; - int precision_jitter; - - FT_Outline* outline; - - int n_points; /* number of points in current glyph */ - int n_contours; /* number of contours in current glyph */ - int n_turns; /* number of Y-turns in outline */ - - TPoint* arc; /* current Bezier arc pointer */ - - int num_profs; /* current number of profiles */ - - TBool fresh; /* signals a fresh new profile which */ - /* 'start' field must be completed */ - TBool joint; /* signals that the last arc ended */ - /* exactly on a scanline. Allows */ - /* removal of doublets */ - PProfile cur_prof; /* current profile */ - PProfile start_prof; /* head of linked list of profiles */ - PProfile first_prof; /* contour's first profile in case */ - /* of impact */ - TDirection state; /* rendering state */ - - FT_Bitmap target; /* description of target bit/pixmap */ - - int trace_bit; /* current offset in target bitmap */ - int trace_pix; /* current offset in target pixmap */ - - int trace_incr; /* sweep's increment in target bitmap */ - - int gray_min_x; /* current min x during gray rendering */ - int 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_Step* Proc_Sweep_Step; - Function_Test_Pixel* Proc_Test_Pixel; - Function_Set_Pixel* Proc_Set_Pixel; - - int scale_shift; /* == 0 for bitmaps */ - /* == 1 for 5-levels pixmaps */ - /* == 2 for 17-levels pixmaps */ - - TByte dropout_mode; /* current drop_out control method */ - - TBool 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. */ - - TBool flipped; /* this flag is set during the rendering to */ - /* indicate the second pass.. */ - - TBand band_stack[16]; /* band stack used for sub-banding */ - int band_top; /* band stack top */ - - TPoint arcs[ 2*MaxBezier+1 ]; /* The Bezier stack */ - - void* memory; - -#if defined(FT_RASTER_OPTION_ANTI_ALIAS) - - long grays[20]; /* Palette of gray levels used for render */ - - int gray_width; /* length in bytes of the monochrome */ - /* intermediate scanline of gray_lines. */ - /* Each gray pixel takes 2 or 4 bits long */ - - /* The gray_lines must hold 2 lines, thus with size */ - /* in bytes of at least 'gray_width*2' */ - - int grays_count; /* number of entries in the palette */ - - char gray_lines[ANTI_ALIAS_BUFFER_SIZE]; - /* Intermediate table used to render the */ - /* graylevels pixmaps. */ - /* gray_lines is a buffer holding 2 or 4 */ - /* monochrome scanlines */ - - int count_table[256]; /* Look-up table used to quickly count */ - /* set bits in a gray 2x2 cell */ -#endif - }; - - - -#ifdef DEBUG_RASTER - - /************************************************/ - /* */ - /* Pset: */ - /* */ - /* Used for debugging only. Plots a point */ - /* in VRAM during rendering (not afterwards). */ - /* */ - /* NOTE: This procedure relies on the value */ - /* of cProfile->start, which may not */ - /* be set when Pset is called sometimes. */ - /* This will usually result in a dot */ - /* plotted on the first screen scanline */ - /* (far away its original position). */ - /* */ - /* This "bug" reflects nothing wrong */ - /* in the current implementation, and */ - /* the bitmap is rendered correctly, */ - /* so don't panic if you see 'flying' */ - /* dots in debugging mode. */ - /* */ - /* - David */ - /* */ - /************************************************/ - - static void Pset( RAS_ARG ) - { - long o; - long x; - - x = ras.cursor[-1]; - - switch ( ras.cur_prof->flow ) - { - case FT_Flow_Up: - o = Vio_ScanLineWidth * - ( ras.cursor - ras.cur_prof->offset + ras.cur_prof->start ) + - ( x / (ras.precision*8) ); - break; - - case FT_Flow_Down: - o = Vio_ScanLineWidth * - ( ras.cur_prof->start - ras.cursor + ras.cur_prof->offset ) + - ( x / (ras.precision*8) ); - break; - } - - if ( o > 0 ) - Vio[o] |= (unsigned)0x80 >> ( (x/ras.precision) & 7 ); - } - - - static void Clear_Band( RAS_ARGS Int y1, Int y2 ) - { - MEM_Set( Vio + y1*Vio_ScanLineWidth, (y2-y1+1)*Vio_ScanLineWidth, 0 ); - } - -#endif /* DEBUG_RASTER */ - - -/************************************************************************/ -/* */ -/* 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; - } - - ras.precision = 1 << 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 :: state/orientation of the new Profile */ -/* */ -/* */ -/* SUCCESS or FAILURE */ -/* */ -/**************************************************************************/ - - static - TBool New_Profile( RAS_ARGS TDirection direction ) - { - if ( ras.start_prof == NULL ) - { - ras.cur_prof = (PProfile)ras.cursor; - ras.start_prof = ras.cur_prof; - ras.cursor += AlignProfileSize; - } - - if ( ras.cursor >= ras.pool_limit ) - { - ras.error = ErrRaster_Overflow; - return FAILURE; - } - - switch ( direction ) - { - case Ascending: - ras.cur_prof->flow = FT_Flow_Up; - break; - - case Descending: - ras.cur_prof->flow = FT_Flow_Down; - break; - - default: - ras.error = ErrRaster_Invalid_Map; - return FAILURE; - } - - { - PProfile cur = ras.cur_prof; - - cur->start = 0; - cur->height = 0; - cur->offset = ras.cursor; - cur->link = (PProfile)0; - cur->next = (PProfile)0; - } - - if ( ras.first_prof == NULL ) - ras.first_prof = ras.cur_prof; - - ras.state = direction; - ras.fresh = TRUE; - ras.joint = FALSE; - - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* End_Profile */ -/* */ -/* Finalizes the current Profile. */ -/* */ -/* */ -/* SUCCESS or FAILURE */ -/* */ -/****************************************************************************/ - - static - TBool End_Profile( RAS_ARG ) - { - int h; - - h = ras.cursor - ras.cur_prof->offset; - - if ( h < 0 ) - { - ras.error = ErrRaster_Negative_Height; - return FAILURE; - } - - if ( h > 0 ) - { - PProfile old, new; - - old = ras.cur_prof; - old->height = h; - ras.cur_prof = new = (PProfile)ras.cursor; - - ras.cursor += AlignProfileSize; - - new->height = 0; - new->offset = ras.cursor; - old->next = new; - - ras.num_profs++; - } - - if ( ras.cursor >= ras.pool_limit ) - { - ras.error = ErrRaster_Overflow; - return FAILURE; - } - - ras.joint = FALSE; - - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* Insert_Y_Turn */ -/* */ -/* */ -/* Insert a salient into the sorted list placed on top */ -/* of the render pool */ -/* */ -/* */ -/* y :: new scanline position */ -/* */ -/****************************************************************************/ - - static - TBool Insert_Y_Turn( RAS_ARGS TScan y ) - { - PPos y_turns; - TScan y2; - int n; - - n = ras.n_turns-1; - y_turns = ras.pool_size - ras.n_turns; - - /* 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) - { - ras.pool_limit--; - ras.n_turns++; - ras.pool_size[-ras.n_turns ] = y; - - if ( ras.pool_limit <= ras.cursor ) - { - ras.error = ErrRaster_Overflow; - return FAILURE; - } - } - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* Finalize_Profile_Table */ -/* */ -/* */ -/* Adjusts all links in the Profiles list. */ -/* */ -/****************************************************************************/ - - static - TBool Finalize_Profile_Table( RAS_ARG ) - { - int n, bottom, top; - PProfile p; - - - n = ras.num_profs; - - if ( n > 1 ) - { - p = ras.start_prof; - while ( n > 0 ) - { - if (n > 1) - p->link = (PProfile)( p->offset + p->height ); - else - p->link = NULL; - - switch (p->flow) - { - case FT_Flow_Down: - bottom = p->start - p->height+1; - top = p->start; - p->start = bottom; - p->offset += p->height-1; - break; - - case FT_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.start_prof = NULL; - - return SUCCESS; - } - - - -/****************************************************************************/ -/* */ -/* Line_Up */ -/* */ -/* */ -/* Computes the scan-line intersections of an ascending line segment */ -/* and stores them in the render pool. */ -/* */ -/* */ -/* x1 :: start x coordinate */ -/* y1 :: start y coordinates */ -/* x2 :: end x coordinate */ -/* y2 :: end y coordinate */ -/* miny :: minimum vertical grid coordinate */ -/* maxy :: maximum vertical grid coordinate */ -/* */ -/* */ -/* SUCCESS or FAILURE. */ -/* */ -/****************************************************************************/ - - static - TBool Line_Up( RAS_ARGS TPos x1, TPos y1, - TPos x2, TPos y2, - TPos miny, TPos maxy ) - { - TPos Dx, Dy; - int e1, e2, f1, f2, size; - TPos Ix, Rx, Ax; - - PPos top; - - - Dx = x2 - x1; - Dy = y2 - y1; - - if ( Dy <= 0 || y2 < miny || y1 > maxy ) - return SUCCESS; - - if ( y1 < miny ) - { - x1 += FMulDiv( 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.cursor--; - ras.joint = FALSE; - } - - ras.joint = ( f2 == 0 ); - - if ( ras.fresh ) - { - ras.cur_prof->start = e1; - ras.fresh = FALSE; - } - - size = e2 - e1 + 1; - if ( ras.cursor + size >= ras.pool_limit ) - { - ras.error = ErrRaster_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.cursor; - - while ( size > 0 ) - { - *top++ = x1; - - DEBUG_PSET; - - x1 += Ix; - Ax += Rx; - if ( Ax >= 0 ) - { - Ax -= Dy; - x1 += Dx; - } - size--; - } - - ras.cursor = top; - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* Line_Down */ -/* */ -/* */ -/* Computes the scan-line intersections of a descending line segment */ -/* and stores them in the render pool. */ -/* */ -/* */ -/* x1 :: start x coordinate */ -/* y1 :: start y coordinates */ -/* x2 :: end x coordinate */ -/* y2 :: end y coordinate */ -/* miny :: minimum vertical grid coordinate */ -/* maxy :: maximum vertical grid coordinate */ -/* */ -/* */ -/* SUCCESS or FAILURE. */ -/* */ -/****************************************************************************/ - - static - TBool Line_Down( RAS_ARGS TPos x1, TPos y1, - TPos x2, TPos y2, - TPos miny, TPos maxy ) - { - TBool result, fresh; - - fresh = ras.fresh; - result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); - - if ( fresh && !ras.fresh ) - ras.cur_prof->start = -ras.cur_prof->start; - - return result; - } - - - - -#ifdef FT_RASTER_CONIC_BEZIERS -/****************************************************************************/ -/* */ -/* Split_Conic */ -/* */ -/* */ -/* Subdivides one second-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_Conic( TPoint* 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; - } -#endif - -#ifdef FT_RASTER_CUBIC_BEZIERS -/****************************************************************************/ -/* */ -/* 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 ) - { - 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; - } -#endif - - - /* A function type describing the functions used to split bezier arcs */ - typedef void (*TSplitter)( TPoint* base ); - -#ifdef FT_DYNAMIC_BEZIER_STEPS - static - TPos Dynamic_Bezier_Threshold( RAS_ARGS int degree, TPoint* arc ) - { - TPos min_x, max_x, min_y, max_y, A, B; - TPos wide_x, wide_y, threshold; - TPoint* cur = arc; - TPoint* limit = cur + degree; - - /* first of all, set the threshold to the maximum x or y extent */ - min_x = max_x = arc[0].x; - min_y = max_y = arc[0].y; - cur++; - for ( ; cur < limit; cur++ ) - { - TPos x = cur->x; - TPos y = cur->y; - - if ( x < min_x ) min_x = x; - if ( x > max_x ) max_x = x; - - if ( y < min_y ) min_y = y; - if ( y > max_y ) max_y = y; - } - wide_x = (max_x - min_x) << 4; - wide_y = (max_y - min_y) << 4; - - threshold = wide_x; - if (threshold < wide_y) threshold = wide_y; - - /* now compute the second and third order error values */ - - wide_x = arc[0].x + arc[1].x - arc[2].x*2; - wide_y = arc[0].y + arc[1].y - arc[2].y*2; - - if (wide_x < 0) wide_x = -wide_x; - if (wide_y < 0) wide_y = -wide_y; - - A = wide_x; if ( A < wide_y ) A = wide_y; - - if (degree >= 3) - { - wide_x = arc[3].x - arc[0].x + 3*(arc[2].x - arc[3].x); - wide_y = arc[3].y - arc[0].y + 3*(arc[2].y - arc[3].y); - - if (wide_x < 0) wide_x = -wide_x; - if (wide_y < 0) wide_y = -wide_y; - - B = wide_x; if ( B < wide_y ) B = wide_y; - } - else - B = 0; - - while ( A > 0 || B > 0 ) - { - threshold >>= 1; - A >>= 2; - B >>= 3; - } - - if (threshold < PRECISION_STEP) - threshold = PRECISION_STEP; - - return threshold; - } -#endif - - /*************************************************************************/ - /* */ - /* */ - /* Bezier_Up */ - /* */ - /* */ - /* Computes the scan-line intersections of an ascending second-order */ - /* Bezier arc and stores them in the render pool. The arc is taken */ - /* from the top of the stack. */ - /* */ - /* */ - /* miny :: The minimum vertical grid coordinate. */ - /* maxy :: The maximum vertical grid coordinate. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TBool Bezier_Up( RAS_ARGS int degree, - TSplitter splitter, - TPos miny, - TPos maxy ) - { - TPos y1, y2, e, e2, e0, threshold; - int f1; - - TPoint* arc; - TPoint* start_arc; - - PPos top; - - - arc = ras.arc; - y1 = arc[degree].y; - y2 = arc[0].y; - top = ras.cursor; - - if ( y2 < miny || y1 > maxy ) - goto Fin; - - e2 = FLOOR( y2 ); /* integer end y */ - - if ( e2 > maxy ) - e2 = maxy; - - e0 = miny; - - if ( y1 < miny ) - { - e = e0; /* integer start y == current scanline */ - } - else - { - e = CEILING( y1 ); /* integer start y == current scanline */ - f1 = FRAC( y1 ); /* fractional shift of start y */ - e0 = e; /* first integer scanline to be pushed */ - - if ( f1 == 0 ) /* do we start on an integer scanline? */ - { - if ( ras.joint ) - { - top--; - ras.joint = FALSE; - } - - *top++ = arc[degree].x; /* write directly start position */ - - DEBUG_PSET; - - e += ras.precision; /* go to next scanline */ - } - } - - /* record start position if necessary */ - if ( ras.fresh ) - { - ras.cur_prof->start = TRUNC( e0 ); - ras.fresh = FALSE; - } - - /* exit if the current scanline is already above the max scanline */ - if ( e2 < e ) - goto Fin; - - /* check for overflow */ - if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.pool_limit ) - { - ras.cursor = top; - ras.error = ErrRaster_Overflow; - return FAILURE; - } - - -#ifdef FT_DYNAMIC_BEZIER_STEPS - /* compute dynamic bezier step threshold */ - threshold = Dynamic_Bezier_Threshold( RAS_VAR_ degree, arc ); -#else - threshold = ras.precision_step; -#endif - - start_arc = arc; - - /* loop while there is still an arc on the bezier stack */ - /* and the current scan line is below y max == e2 */ - while ( arc >= start_arc && e <= e2 ) - { - ras.joint = FALSE; - - y2 = arc[0].y; /* final y of the top-most arc */ - - if ( y2 > e ) /* the arc intercepts the current scanline */ - { - y1 = arc[degree].y; /* start y of top-most arc */ - -#ifdef OLD - if ( y2-y1 >= ras.precision_step ) -#else - if ( y2 >= e + ras.precision || y2 - y1 >= threshold ) -#endif - { - /* if the arc's height is too great, split it */ - splitter( arc ); - arc += degree; - } - else - { - /* otherwise, approximate it as a segment and compute */ - /* its intersection with the current scanline */ - *top++ = arc[degree].x + - FMulDiv( arc[0].x-arc[degree].x, - e - y1, - y2 - y1 ); - - DEBUG_PSET; - - arc -= degree; /* pop the arc */ - e += ras.precision; /* go to next scanline */ - } - } - else - { - if ( y2 == e ) /* if the arc falls on the scanline */ - { /* record its _joint_ intersection */ - ras.joint = TRUE; - *top++ = arc[0].x; - - DEBUG_PSET; - - e += ras.precision; /* go to next scanline */ - } - arc -= degree; /* pop the arc */ - } - } - - Fin: - ras.cursor = top; - ras.arc -= degree; - return SUCCESS; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Bezier_Down */ - /* */ - /* */ - /* Computes the scan-line intersections of a descending second-order */ - /* Bezier arc and stores them in the render pool. The arc is taken */ - /* from the top of the stack. */ - /* */ - /* */ - /* miny :: The minimum vertical grid coordinate. */ - /* maxy :: The maximum vertical grid coordinate. */ - /* */ - /* */ - /* SUCCESS or FAILURE. */ - /* */ - static - TBool Bezier_Down( RAS_ARGS int degree, - TSplitter splitter, - TPos miny, - TPos maxy ) - { - TPoint* arc = ras.arc; - TBool 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.cur_prof->start = -ras.cur_prof->start; - - arc[0].y = -arc[0].y; - return result; - } - - -/****************************************************************************/ -/* */ -/* Check_Contour */ -/* */ -/* */ -/* perform some check at contour closure. */ -/* */ -/* */ -/* SUCCESS or FAILURE */ -/* */ -/****************************************************************************/ - - static - TBool Check_Contour( RAS_ARG ) - { - PProfile lastProfile; - - /* We must now see if the extreme arcs join or not */ - if ( ( FRAC( ras.last.y ) == 0 && - ras.last.y >= ras.minY && - ras.last.y <= ras.maxY ) ) - { - if ( ras.first_prof && ras.first_prof->flow == ras.cur_prof->flow ) - ras.cursor--; - } - - lastProfile = ras.cur_prof; - if ( End_Profile( RAS_VAR ) ) return FAILURE; - - /* close the 'next profile in contour' linked list */ - lastProfile->next = ras.first_prof; - - return SUCCESS; - } - -/****************************************************************************/ -/* */ -/* Move_To */ -/* */ -/* */ -/* This function injects a new contour in the render pool.. */ -/* */ -/* */ -/* to :: pointer to the contour's first point */ -/* raster :: a pointer to the current raster object */ -/* */ -/* */ -/* Error code, 0 means success */ -/* */ -/* */ -/* This function is used as a "FTRasterMoveTo_Func" by the outline */ -/* decomposer.. */ -/* */ -/****************************************************************************/ - - static - int Move_To( FT_Vector* to, - FT_Raster raster ) - { - /* if there was already a contour being built, perform some checks */ - if ( ras.start_prof ) - if ( Check_Contour( RAS_VAR ) ) - return FAILURE; - - /* set the "current last point" */ - if (ras.flipped) - { - ras.last.x = to->y; - ras.last.y = to->x; - } - else - { - ras.last.x = to->x; - ras.last.y = to->y; - } - - ras.state = Unknown; - ras.first_prof = NULL; - - return SUCCESS; - } - -/****************************************************************************/ -/* */ -/* Line_To */ -/* */ -/* */ -/* This function injects a new line segment in the render pool and */ -/* adjusts the profiles list accordingly.. */ -/* */ -/* */ -/* to :: pointer to the target position */ -/* raster :: a pointer to the current raster object */ -/* */ -/* */ -/* Error code, 0 means success */ -/* */ -/* */ -/* This function is used as a "FTRasterLineTo_Func" by the outline */ -/* decomposer.. */ -/* */ -/****************************************************************************/ - - static - int Line_To( FT_Vector* to, - FT_Raster raster ) - { - TPos x; - TPos y; - TDirection new_state; - - if ( ras.flipped ) - { - x = to->y; - y = to->x; - } - else - { - x = to->x; - y = to->y; - } - - /* First, detect a change of direction */ - if ( y != ras.last.y ) - { - new_state = ( y > ras.last.y ? Ascending : Descending ); - if (new_state != ras.state) - { - if (ras.state != Unknown && End_Profile( RAS_VAR )) - goto Fail; - - if ( New_Profile( RAS_VARS new_state) ) - goto Fail; - } - } - - /* Then compute the lines */ - if ( (ras.state == Ascending ? Line_Up : Line_Down) - ( RAS_VARS ras.last.x, ras.last.y, x, y, ras.minY, ras.maxY ) ) - goto Fail; - - ras.last.x = x; - ras.last.y = y; - - return SUCCESS; - Fail: - return FAILURE; - } - -#ifdef FT_RASTER_CONIC_BEZIERS - -/****************************************************************************/ -/* */ -/* Conic_To */ -/* */ -/* */ -/* Injects a new conic bezier arc and adjusts the profile list */ -/* accordingly. */ -/* */ -/* */ -/* control :: pointer to intermediate control point */ -/* to :: pointer to end point */ -/* raster :: handle to current raster object */ -/* */ -/* */ -/* Error code, 0 means success */ -/* */ -/* */ -/* This function is used as a "FTRasterConicTo_Func" by the outline */ -/* decomposer.. */ -/* */ -/****************************************************************************/ - - static - void Push_Conic( RAS_ARGS FT_Vector* p2, - FT_Vector* p3 ) - { - #undef STORE - #define STORE( _arc, point ) \ - { \ - TPos x = point->x; \ - TPos y = point->y; \ - if (ras.flipped) \ - { \ - _arc.x = y; \ - _arc.y = x; \ - } \ - else \ - { \ - _arc.x = x; \ - _arc.y = y; \ - } \ - } - - TPoint* arc; - ras.arc = arc = ras.arcs; - - arc[2] = ras.last; - STORE( arc[1], p2 ); - STORE( arc[0], p3 ); - #undef STORE - } - - - static - int Conic_To( FT_Vector* control, - FT_Vector* to, - FT_Raster raster ) - { - TPos y1, y2, y3, x3; - TDirection state_bez; - - - Push_Conic( RAS_VARS control, to ); - - 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 ) - { - if ( y2 == y1 ) - state_bez = Flat; - else - state_bez = Unknown; - } - else if ( y1 < y3 ) - { - if ( y2 < y1 || y2 > y3 ) - state_bez = Unknown; - else - state_bez = Ascending; - } - else - { - if ( y2 < y3 || y2 > y1 ) - state_bez = Unknown; - else - state_bez = Descending; - } - - /* split non-monotonic arcs, ignore flat ones, or */ - /* computes the up and down ones */ - - switch ( state_bez ) - { - case Flat: - ras.arc -= 2; - break; - - case Unknown: - Split_Conic( ras.arc ); - ras.arc += 2; - break; - - default: - /* 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 ( (ras.state == Ascending ? Bezier_Up : Bezier_Down) - ( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) - goto Fail; - } - } while ( ras.arc >= ras.arcs ); - - ras.last.x = x3; - ras.last.y = y3; - - return 0; - Fail: - return FAILURE; - } - -#else - static - int Conic_To( FT_Vector* control, - FT_Vector* to, - FT_Raster raster ) - { - (void)control; - (void)to; - (void)raster; - - return ErrRaster_Invalid_Outline; - } -#endif /* CONIC_BEZIERS */ - - -#ifdef FT_RASTER_CUBIC_BEZIERS -/****************************************************************************/ -/* */ -/* Cubic_To */ -/* */ -/* */ -/* Injects a new cubic bezier arc and adjusts the profile list */ -/* accordingly. */ -/* */ -/* */ -/* control1 :: pointer to first control point */ -/* control2 :: pointer to second control point */ -/* to :: pointer to end point */ -/* raster :: handle to current raster object */ -/* */ -/* */ -/* Error code, 0 means success */ -/* */ -/* */ -/* This function is used as a "FTRasterCubicTo_Func" by the outline */ -/* decomposer.. */ -/* */ -/****************************************************************************/ - - static - void Push_Cubic( RAS_ARGS FT_Vector* p2, - FT_Vector* p3, - FT_Vector* p4 ) - { - #undef STORE - #define STORE( _arc, point ) \ - { \ - TPos x = point->x; \ - TPos y = point->y; \ - if (ras.flipped) \ - { \ - _arc.x = y; \ - _arc.y = x; \ - } \ - else \ - { \ - _arc.x = x; \ - _arc.y = y; \ - } \ - } - - TPoint* arc; - ras.arc = arc = ras.arcs; - - arc[3] = ras.last; - STORE( arc[2], p2 ); - STORE( arc[1], p3 ); - STORE( arc[0], p4 ); - - #undef STORE - } - - - static - int Cubic_To( FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to, - FT_Raster raster ) - { - TPos y1, y2, y3, y4, x4; - TDirection state_bez; - - - Push_Cubic( RAS_VARS control1, control2, to ); - - 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 ) - { - if ( y1 == y2 && y1 == y3 ) - state_bez = Flat; - else - state_bez = Unknown; - } - else if ( y1 < y4 ) - { - if ( y2 < y1 || y2 > y4 || y3 < y1 || y3 > y4 ) - state_bez = Unknown; - else - state_bez = Ascending; - } - else - { - if ( y2 < y4 || y2 > y1 || y3 < y4 || y3 > y1 ) - state_bez = Unknown; - else - state_bez = Descending; - } - - /* split non-monotonic arcs, ignore flat ones, or */ - /* computes the up and down ones */ - - switch ( state_bez ) - { - case Flat: - ras.arc -= 3; - break; - - case Unknown: - Split_Cubic( ras.arc ); - ras.arc += 3; - break; - - default: - /* 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 ( (ras.state == Ascending ? Bezier_Up : Bezier_Down) - ( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) - goto Fail; - } - } while ( ras.arc >= ras.arcs ); - - ras.last.x = x4; - ras.last.y = y4; - - return 0; - Fail: - return FAILURE; - } - -#else - int Cubic_To( FT_Vector* control1, - FT_Vector* control2, - FT_Vector* to, - FT_Raster raster ) - { - (void)control1; - (void)control2; - (void)to; - (void)raster; - - return ErrRaster_Invalid_Outline; - } -#endif /* CUBIC_BEZIERS */ - - -/****************************************************************************/ -/* */ -/* Convert_Glyph */ -/* */ -/* */ -/* Converts a glyph into a series of segments and arcs and makes */ -/* a profiles list with them.. */ -/* */ -/* */ -/* outline :: glyph outline */ -/* */ -/* */ -/* SUCCESS or FAILURE */ -/* */ -/****************************************************************************/ - - static - TBool Convert_Glyph( RAS_ARGS 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 - }; - - /* Set up state in the raster object */ - ras.start_prof = NULL; - ras.joint = FALSE; - ras.fresh = FALSE; - - ras.pool_limit = ras.pool_size - AlignProfileSize; - - ras.n_turns = 0; - - ras.cur_prof = (PProfile)ras.cursor; - ras.cur_prof->offset = ras.cursor; - ras.num_profs = 0; - - interface.shift = ras.scale_shift; - interface.delta = ras.precision_half; - - /* Now decompose curve */ - if ( FT_Outline_Decompose( outline, &interface, &ras ) ) return FAILURE; - /* XXX : the error condition is in ras.error */ - - /* Check the last contour if needed */ - if ( Check_Contour( RAS_VAR ) ) return FAILURE; - - /* Finalize profiles list */ - return Finalize_Profile_Table( RAS_VAR ); - } - - -/************************************************/ -/* */ -/* Init_Linked */ -/* */ -/* Inits 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; - TPos 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 Bitmap Sweep Routines *********/ -/******** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - -/***********************************************************************/ -/* */ -/* Vertical_Sweep_Init */ -/* */ -/* */ -/* Initialise the vertical bitmap sweep. Called by the generic */ -/* sweep/draw routine before its loop.. */ -/* */ -/* */ -/* min :: address of current minimum scanline */ -/* max :: address of current maximum scanline */ -/* */ -/***********************************************************************/ - - static - void Vertical_Sweep_Init( RAS_ARGS int* min, int* max ) - { - long pitch = ras.target.pitch; - - (void)max; - - ras.trace_incr = -pitch; - ras.trace_bit = -*min*pitch; - if (pitch > 0) - ras.trace_bit += (ras.target.rows-1)*pitch; - - ras.gray_min_x = 0; - ras.gray_max_x = 0; - } - -/***********************************************************************/ -/* */ -/* Vertical_Sweep_Span */ -/* */ -/* */ -/* draws a single horizontal bitmap span during the vertical */ -/* bitmap sweep. */ -/* */ -/* */ -/* y :: current scanline */ -/* x1 :: left span edge */ -/* x2 :: right span edge */ -/* */ -/***********************************************************************/ - - static void Vertical_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ) - { - TPos e1, e2; - int c1, c2; - TByte f1, f2; - TByte* target; - - /* Drop-out control */ - (void)y; - - e1 = TRUNC( CEILING( x1 ) ); - if ( x2-x1-ras.precision <= ras.precision_jitter ) - e2 = e1; - else - e2 = TRUNC( FLOOR( x2 ) ); - - if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width ) - { - if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bit_width ) e2 = ras.bit_width-1; - - c1 = e1 >> 3; - c2 = e2 >> 3; - - f1 = ((unsigned char)0xFF >> (e1 & 7)); - f2 = ~((unsigned char)0x7F >> (e2 & 7)); - - target = ras.bit_buffer + ras.trace_bit + 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 ); - } - } - -/***********************************************************************/ -/* */ -/* Vertical_Test_Pixel */ -/* */ -/* */ -/* test a pixel 'light' during the vertical bitmap sweep. Used */ -/* during drop-out control only.. */ -/* */ -/* */ -/* y :: current scanline */ -/* x :: current x coordinate */ -/* */ -/***********************************************************************/ - - static - int Vertical_Test_Pixel( RAS_ARGS TScan y, - int x ) - { - int c1 = x >> 3; - (void)y; - return ( x >= 0 && x < ras.bit_width && - ras.bit_buffer[ras.trace_bit + c1] & (0x80 >> (x & 7)) ); - } - -/***********************************************************************/ -/* */ -/* Vertical_Set_Pixel */ -/* */ -/* */ -/* Sets a single pixel in a bitmap during the vertical sweep. */ -/* Used during drop-out control.. */ -/* */ -/* */ -/* y :: current scanline */ -/* x :: current x coordinate */ -/* color :: ignored by this function */ -/* */ -/***********************************************************************/ - - static - void Vertical_Set_Pixel( RAS_ARGS int y, - int x, - int color ) - { - (void)color; /* unused here */ - (void)y; - - if ( x >= 0 && x < ras.bit_width ) - { - int c1 = x >> 3; - - if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; - if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; - - ras.bit_buffer[ras.trace_bit+c1] |= (char)(0x80 >> (x & 7)); - } - } - -/***********************************************************************/ -/* */ -/* Vertical_Sweep_Step */ -/* */ -/* */ -/* Called whenever the sweep jumps to anothr scanline. */ -/* Only updates the pointers in the vertical bitmap sweep */ -/* */ -/***********************************************************************/ - - static - void Vertical_Sweep_Step( RAS_ARG ) - { - ras.trace_bit += ras.trace_incr; - } - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/******** *********/ -/******** Horizontal Bitmap Sweep Routines *********/ -/******** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - -/***********************************************************************/ -/* */ -/* Horizontal_Sweep_Init */ -/* */ -/* */ -/* Initialise the horizontal bitmap sweep. Called by the generic */ -/* sweep/draw routine before its loop.. */ -/* */ -/* */ -/* min :: address of current minimum pixel column */ -/* max :: address of current maximum pixel column */ -/* */ -/***********************************************************************/ - - static void Horizontal_Sweep_Init( RAS_ARGS int* min, int* max ) - { - /* nothing, really */ - UNUSED_RASTER - (void)min; - (void)max; - } - - -/***********************************************************************/ -/* */ -/* Horizontal_Sweep_Span */ -/* */ -/* */ -/* draws a single vertical bitmap span during the horizontal */ -/* bitmap sweep. Actually, this function is only used to */ -/* check for weird drop-out cases.. */ -/* */ -/* */ -/* y :: current pixel column */ -/* x1 :: top span edge */ -/* x2 :: bottom span edge */ -/* */ -/***********************************************************************/ - - static void Horizontal_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ) - { - TPos e1, e2; - PByte bits; - TByte f1; - - (void)y; - - /* During the horizontal sweep, we only take care of drop-outs */ - if ( x2-x1 < ras.precision ) - { - e1 = CEILING( x1 ); - e2 = FLOOR( x2 ); - - if ( e1 == e2 ) - { - bits = ras.bit_buffer + (y >> 3); - f1 = (TByte)(0x80 >> (y & 7)); - - e1 = TRUNC( e1 ); - - if ( e1 >= 0 && e1 < ras.target.rows ) - { - long pitch = ras.target.pitch; - - bits -= e1*pitch; - if (pitch > 0) - bits += (ras.target.rows-1)*pitch; - - bits[0] |= f1; - } - } - } - } - - -/***********************************************************************/ -/* */ -/* Horizontal_Test_Pixel */ -/* */ -/* */ -/* test a pixel 'light' during the horizontal bitmap sweep. Used */ -/* during drop-out control only.. */ -/* */ -/* */ -/* y :: current pixel column */ -/* x :: current row/scanline */ -/* */ -/***********************************************************************/ - - static - int Horizontal_Test_Pixel( RAS_ARGS int y, - int x ) - { - char* bits = (char*)ras.bit_buffer + (y >> 3); - int f1 = (TByte)(0x80 >> (y & 7)); - long pitch = ras.target.pitch; - - bits -= x*pitch; - if (pitch > 0) - bits += (ras.target.rows-1)*pitch; - - return ( x >= 0 && x < ras.target.rows && (bits[0] & f1) ); - } - -/***********************************************************************/ -/* */ -/* Horizontal_Set_Pixel */ -/* */ -/* */ -/* Sets a single pixel in a bitmap during the horizontal sweep. */ -/* Used during drop-out control.. */ -/* */ -/* */ -/* y :: current pixel column */ -/* x :: current row/scanline */ -/* color :: ignored by this function */ -/* */ -/***********************************************************************/ - - static - void Horizontal_Set_Pixel( RAS_ARGS int y, - int x, - int color ) - { - char* bits = (char*)ras.bit_buffer + (y >> 3); - int f1 = (TByte)(0x80 >> (y & 7)); - long pitch = ras.target.pitch; - - (void)color; /* unused here */ - - bits -= x*pitch; - if (pitch > 0) - bits += (ras.target.rows-1)*pitch; - - if ( x >= 0 && x < ras.target.rows ) - bits[0] |= f1; - } - -/***********************************************************************/ -/* */ -/* Horizontal_Sweep_Step */ -/* */ -/* */ -/* Called whenever the sweep jumps to another pixel column. */ -/* */ -/***********************************************************************/ - - static void Horizontal_Sweep_Step( RAS_ARG ) - { - /* Nothing, really */ - UNUSED_RASTER; - } - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/******** *********/ -/******** Anti-Aliased Vertical Bitmap Sweep Routines *********/ -/******** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - -#ifdef FT_RASTER_OPTION_ANTI_ALIAS - -#ifdef FT_RASTER_ANTI_ALIAS_5 -/***********************************************************************/ -/* */ -/* 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 - const Word32 LMask5[17] = - { 0xF0F0F0F0, 0xF0F0F070, 0xF0F0F030, 0xF0F0F010, - 0xF0F0F000, 0xF0F07000, 0xF0F03000, 0xF0F01000, - 0xF0F00000, 0xF0700000, 0xF0300000, 0xF0100000, - 0xF0000000, 0x70000000, 0x30000000, 0x10000000, - 0x00000000 }; - - static - const Word32 LPos5[17] = - { 0x80000000, 0x40000000, 0x20000000, 0x10000000, - 0x00800000, 0x00400000, 0x00200000, 0x00100000, - 0x00008000, 0x00004000, 0x00002000, 0x00001000, - 0x00000080, 0x00000040, 0x00000020, 0x00000010 }; - - static void Vertical_Gray5_Sweep_Init( RAS_ARGS int* min, int* max ) - { - long pitch; - - *min = *min & -2; - *max = ( *max+3 ) & -2; - - ras.trace_bit = 0; - - pitch = ras.target.pitch; - ras.trace_incr = -pitch; - ras.trace_pix = - (*min/2)*pitch; - if (pitch > 0) - ras.trace_pix += (ras.target.rows-1)*pitch; - - ras.gray_min_x = 32000; - ras.gray_max_x = -32000; - } - - static void Vertical_Gray5_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ) - { - TPos e1, e2; - int c1, c2; - TByte* target; - - unsigned int f1, f2; - unsigned int shift, fill; - - /* Drop-out control */ - - e1 = TRUNC( CEILING( x1 ) ); - if ( x2-x1 <= ras.precision+ras.precision_jitter ) - e2 = e1; - else - e2 = FLOOR ( x2 ); - - e2 = TRUNC( e2 ); - - if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width ) - { - if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bit_width ) e2 = ras.bit_width-1; - - shift = (y & 1)*4; - - c1 = e1 >> 4; - c2 = e2 >> 4; - - fill = LMask5[0]; - f1 = LMask5[ e1 & 15 ]; - f2 = fill ^ LMask5[ 1+(e2 & 15) ]; - - f1 >>= shift; - f2 >>= shift; - fill >>= shift; - - if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; - if ( ras.gray_max_x < c2 ) ras.gray_max_x = c2; - - target = ras.bit_buffer + c1*4; - c2 -= c1; - - if (c2 > 0) - { - Word32* slice = (Word32*)target; - - slice[0] |= f1; - c2--; - while (c2 > 0) - { - * ++slice |= fill; - c2--; - } - slice[1] |= f2; - } - else - ((Word32*)target)[0] |= ( f1 & f2 ); - } - } - - - static - int Vertical_Gray5_Test_Pixel( RAS_ARGS int y, - int x ) - { - int c1 = x >> 4; - Word32 mask = LPos5[ x & 15 ] >> ((y & 1)*4); - - (void)y; - - return ( x >= 0 && - x < ras.bit_width && - ((Word32*)ras.bit_buffer + c1)[0] & mask ); - } - - - static - void Vertical_Gray5_Set_Pixel( RAS_ARGS int y, - int x, - int color ) - { - (void)color; /* unused here */ - (void)y; - - if ( x >= 0 && x < ras.bit_width ) - { - int c1 = x >> 4; - Word32 mask = LPos5[ x & 15 ] >> ((y & 1)*4); - - if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; - if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; - - ((Word32*)ras.bit_buffer + c1)[0] |= mask; - } - } - - - static void Vertical_Gray5_Sweep_Step( RAS_ARG ) - { - int c1; - PByte pix, bit; - int* count = ras.count_table; - long* grays; - - - ras.trace_bit++; - - if ( ras.trace_bit > 1 ) - { - pix = ras.pix_buffer + ras.trace_pix + ras.gray_min_x*8; - grays = ras.grays; - - if ( ras.gray_max_x >= 0 ) - { - if ( ras.gray_max_x*8 >= ras.target.width ) - ras.gray_max_x = (ras.target.width+7)/8-1; - - if ( ras.gray_min_x < 0 ) - ras.gray_min_x = 0; - - bit = ras.bit_buffer + ras.gray_min_x*4; - c1 = (ras.gray_max_x - ras.gray_min_x + 1); - - while ( c1 >= 0 ) - { - if ( *(short*)bit ) - { -#if defined( FT_RASTER_LITTLE_ENDIAN ) - /* little endian storage */ - *((long*)pix) = (count[bit[1]] << 16) | count[bit[0]]; -#elif defined( FT_RASTER_BIG_ENDIAN ) - /* big-endian storage */ - *((long*)pix) = (count[bit[0]] << 16) | count[bit[1]]; -#else - /* endian-independent storage */ - int c; - c = count[bit[1]]; - pix[4] = (TByte)(c >> 8); - pix[5] = (TByte)(c & 0xFF); - c = count[bit[0]]; - pix[6] = (TByte)(c >> 8); - pix[7] = (TByte)(c & 0xFF); -#endif - *(short*)bit = 0; - } - - bit += 2; - - if ( *(short*)bit ) - { -#if defined( FT_RASTER_LITTLE_ENDIAN ) - /* little endian storage */ - *((long*)pix + 1)= (count[bit[1]] << 16) | count[bit[0]]; -#elif defined( FT_RASTER_BIG_ENDIAN ) - /* big-endian storage */ - *((long*)pix + 1) = (count[bit[0]] << 16) | count[bit[1]]; -#else - /* endian-independent storage */ - int c; - c = count[bit[1]]; - pix[0] = (TByte)(c >> 8); - pix[1] = (TByte)(c & 0xFF); - c = count[bit[0]]; - pix[2] = (TByte)(c >> 8); - pix[3] = (TByte)(c & 0xFF); -#endif - *(short*)bit = 0; - } - pix += 8; - bit += 2; - c1 --; - } - } - - ras.trace_bit = 0; - ras.trace_pix += ras.trace_incr; - - ras.gray_min_x = 32000; - ras.gray_max_x = -32000; - } - } - - - - static void Horizontal_Gray5_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ) - { - /* nothing, really */ - UNUSED_RASTER - (void)y; - (void)x1; - (void)x2; - } - - - static - int Horizontal_Gray5_Test_Pixel( RAS_ARGS TScan y, - int x ) - { - /* don't do anything here */ - UNUSED_RASTER - (void)x; - (void)y; - - return 0; - } - - - static - void Horizontal_Gray5_Set_Pixel( RAS_ARGS TScan y, - int x, - int color ) - { - char* pixel; - - x = x/2; - - if (x < ras.target.rows) - { - long pitch; - - pixel = (char*)ras.pix_buffer + (y/2); - pitch = ras.target.pitch; - pixel -= x*pitch; - if (pitch > 0) - pixel += (ras.target.rows-1)*pitch; - - if (pixel[0] == ras.grays[0]) - pixel[0] = (char)ras.grays[1+color]; - } - } -#endif /* FT_RASTER_ANTI_ALIAS_5 */ - -#ifdef FT_RASTER_ANTI_ALIAS_17 -/***********************************************************************/ -/* */ -/* 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_Gray17_Sweep_Init( RAS_ARGS int* min, int* max ) - { - long pitch = ras.target.pitch; - - *min = *min & -4; - *max = ( *max+7 ) & -4; - - ras.trace_bit = 0; - ras.trace_incr = -pitch; - ras.trace_bit = - (*min/4)*pitch; - if (pitch > 0) - ras.trace_bit += (ras.target.rows-1)*pitch; - - ras.gray_min_x = 32000; - ras.gray_max_x = -32000; - } - - - static void Vertical_Gray17_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ) - { - static - const unsigned int LMask[9] = -#ifdef FT_RASTER_LITTLE_ENDIAN - { 0xF000F000, 0xF0007000, 0xF0003000, 0xF0001000, - 0xF0000000, 0x70000000, 0x30000000, 0x10000000, - 0x00000000 }; -#else - { 0xF000F000, 0x7000F000, 0x3000F000, 0x1000F000, - 0x0000F000, 0x00007000, 0x00003000, 0x00001000, - 0x00000000 }; -#endif - - TPos e1, e2; - int c1, c2; - TByte* target; - - unsigned int f1, f2; - unsigned int shift, fill; - - /* Drop-out control */ - - e1 = TRUNC( CEILING( x1 ) ); - if ( x2-x1 <= ras.precision+ras.precision_jitter ) - e2 = e1; - else - e2 = FLOOR ( x2 ); - e2 = TRUNC( e2 ); - - if ( e1 <= e2 && e2 >= 0 && e1 < ras.bit_width ) - { - if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bit_width ) e2 = ras.bit_width-1; - - shift = (y & 3)*4; - - c1 = e1 >> 3; - c2 = e2 >> 3; - - fill = LMask[0]; - f1 = LMask[ e1 & 7 ]; - f2 = fill ^ LMask[ 1+(e2 & 7) ]; - - f1 >>= shift; - f2 >>= shift; - fill >>= shift; - - if ( ras.gray_min_x > c1/2 ) ras.gray_min_x = c1/2; - if ( ras.gray_max_x < c2/2 ) ras.gray_max_x = c2/2; - - target = ras.bit_buffer + c1*4; - c2 -= c1; - - if (c2 > 0) - { - int* slice = (int*)target; - - slice[0] |= f1; - c2--; - while (c2 > 0) - { - * ++slice |= fill; - c2--; - } - slice[1] |= f2; - } - else - ((int*)target)[0] |= ( f1 & f2 ); - } - } - - - static - int Vertical_Gray17_Test_Pixel( RAS_ARGS int y, - int x ) - { - int c1 = x >> 2; - int f1 = x & 3; - int mask = (0x8000 >> f1) >> ((y & 3)*4); - - return ( x >= 0 && - x < ras.bit_width && - ((short*)ras.bit_buffer)[c1] & mask ); - } - - - static - void Vertical_Gray17_Set_Pixel( RAS_ARGS int y, - int x, - int color ) - { - (void)color; /* unused here */ - - if ( x >= 0 && x < ras.bit_width ) - { - int c1 = x >> 2; - int f1 = x & 3; - int mask = (0x8000 >> f1) >> ((y & 3)*4); - - if ( ras.gray_min_x > c1/4 ) ras.gray_min_x = c1/4; - if ( ras.gray_max_x < c1/4 ) ras.gray_max_x = c1/4; - - ((short*)ras.bit_buffer)[c1] |= mask; - } - } - - - static void Vertical_Gray17_Sweep_Step( RAS_ARG ) - { - int c1; - PByte pix, bit; - long* grays; - - - ras.trace_bit++; - - if ( ras.trace_bit > 3 ) - { - pix = ras.pix_buffer + ras.trace_pix + ras.gray_min_x*4; - grays = ras.grays; - - if ( ras.gray_max_x >= 0 ) - { - if ( ras.gray_max_x >= ras.target.width/4 ) - ras.gray_max_x = (ras.target.width+3)/4-1; - - if ( ras.gray_min_x < 0 ) - ras.gray_min_x = 0; - - bit = ras.bit_buffer + ras.gray_min_x*8; - c1 = (ras.gray_max_x - ras.gray_min_x + 1); - - while ( c1 >= 0 ) - { - if ( *(long*)bit || *(long*)(bit+4) ) - { - int* table = ras.count_table; - -#if defined( FT_RASTER_LITTLE_ENDIAN ) - /* little-endian specific storage */ - *(long*)pix = grays[ table[ bit[0] ] + - table[ bit[1] ] ] | - - ( grays[ table[ bit[2] ] + - table[ bit[3] ] ] << 8 ) | - - ( grays[ table[ bit[4] ] + - table[ bit[5] ] ] << 16 ) | - - ( grays[ table[ bit[6] ] + - table[ bit[7] ] ] << 24 ); - -#elif defined( FT_RASTER_BIG_ENDIAN ) - /* big-endian specific storage */ - *(long*)pix = ( grays[ table[ bit[0] ] + - table[ bit[1] ] ] << 24 | - - ( grays[ table[ bit[2] ] + - table[ bit[3] ] ] << 16 ) | - - ( grays[ table[ bit[4] ] + - table[ bit[5] ] ] << 8 ) | - - ( grays[ table[ bit[6] ] + - table[ bit[7] ] ] ); -#else - /* endianess-independent storage */ - pix[0] = grays[ table[bit[0]] + table[bit[1]] ]; - pix[1] = grays[ table[bit[2]] + table[bit[3]] ]; - pix[2] = grays[ table[bit[4]] + table[bit[5]] ]; - pix[3] = grays[ table[bit[6]] + table[bit[7]] ]; -#endif - *(long*)( bit ) = 0; - *(long*)(bit+4) = 0; - } - pix += 4; - bit += 8; - c1 --; - } - } - ras.trace_bit = 0; - ras.trace_pix += ras.trace_incr; - - ras.gray_min_x = 32000; - ras.gray_max_x = -32000; - } - } - - - - static void Horizontal_Gray17_Sweep_Span( RAS_ARGS TScan y, - TPos x1, - TPos x2 ) - { - /* nothing, really */ - UNUSED_RASTER - (void)y; - (void)x1; - (void)x2; - } - - - static - int Horizontal_Gray17_Test_Pixel( RAS_ARGS TScan y, - int x ) - { - /* don't do anything here */ - UNUSED_RASTER - (void)x; - (void)y; - - return 0; - } - - - static - void Horizontal_Gray17_Set_Pixel( RAS_ARGS TScan y, - int x, - int color ) - { - char* pixel; - - x = x/4; - - if (x < ras.target.rows) - { - long pitch = ras.target.pitch; - - pixel = (char*)ras.pix_buffer + (y/4); - pixel -= x*pitch; - if (pitch > 0) - pixel += (ras.target.rows-1)*pitch; - - if (pixel[0] == ras.grays[0]) - pixel[0] = ras.grays[1+color]; - } - } -#endif /* FT_RASTER_ANTI_ALIAS_17 */ - -#endif /* FT_RASTER_OPTION_ANTI_ALIAS */ - -/********************************************************************/ -/* */ -/* Generic Sweep Drawing routine */ -/* */ -/********************************************************************/ - - static TBool Draw_Sweep( RAS_ARG ) - { - TScan y, y_change, y_height; - - PProfile P, Q, P_Left, P_Right; - - TScan min_Y, max_Y, top, bottom, dropouts; - - TPos x1, x2, e1, e2; - - TProfileList wait; - TProfileList draw; - - /* Init empty linked lists */ - - Init_Linked( &wait ); - Init_Linked( &draw ); - - /* first, compute min and max Y */ - - P = ras.start_prof; - max_Y = TRUNC( ras.minY ); - min_Y = TRUNC( ras.maxY ); - - while ( P ) - { - Q = P->link; - - bottom = P->start; - top = 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.n_turns == 0 ) - { - ras.error = ErrRaster_Invalid_Outline; - 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.n_turns > 0 && - ras.pool_size[-ras.n_turns] == min_Y ) - ras.n_turns--; - - while (ras.n_turns > 0) - { - PProfile prof = wait; - - /* look in the wait list for new activations */ - while (prof) - { - PProfile next = prof->link; - - prof->countL -= y_height; - if ( prof->countL == 0 ) - { - DelOld( &wait, prof ); - InsNew( &draw, prof ); - } - prof = next; - } - - /* Sort the drawing lists */ - Sort( &draw ); - - y_change = ras.pool_size[-ras.n_turns--]; - y_height = y_change - y; - - while ( y < y_change ) - { - int window; - PProfile left; - - /* Let's trace */ - - dropouts = 0; - - if (!draw) - goto Next_Line; - - left = draw; - window = left->flow; - prof = left->link; - - while (prof) - { - PProfile next = prof->link; - - window += prof->flow; - - if ( window == 0 ) - { - x1 = left->X; - x2 = prof->X; -#if 1 - if ( x1 > x2 ) - { - TPos xs = x1; - x1 = x2; - x2 = xs; - } -#endif - if ( x2-x1 <= ras.precision && ras.dropout_mode ) - { -#if 1 - e1 = CEILING( x1 ); - e2 = FLOOR( x2 ); -#else - e1 = FLOOR(x1); - e2 = CEILING(x2); -#endif - if ( e1 > e2 || e2 == e1+ ras.precision ) - { - /* a drop out was detected */ - - left->X = x1; - prof->X = x2; - - /* mark profiles for drop-out processing */ - left->countL = 1; - prof->countL = 2; - dropouts++; - goto Skip_To_Next; - } - } - - ras.Proc_Sweep_Span( RAS_VARS y, x1, x2 ); - - Skip_To_Next: - left = next; - } - prof = next; - } - - /* 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 ); - } - - /* Now finalize the profiles that needs it */ - - { - PProfile prof, next; - prof = draw; - while (prof) - { - next = prof->link; - if (prof->height == 0) - DelOld( &draw, prof ); - prof = next; - } - } - } - - /* 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; - while (dropouts > 0) - { - TPos e1, e2; - PProfile left, right; - - while (P_Left->countL != 1) P_Left = P_Left->link; - P_Right = P_Left->link; - while (P_Right->countL != 2) P_Right = P_Right->link; - - P_Left->countL = 0; - P_Right->countL = 0; - - /* Now perform the dropout control */ - x1 = P_Left->X; - x2 = P_Right->X; - - left = ( ras.flipped ? P_Right : P_Left ); - right = ( ras.flipped ? P_Left : P_Right ); - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 > e2 ) - { - if ( e1 == e2 + ras.precision ) - { - switch ( ras.dropout_mode ) - { - 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 when: */ - /* */ - /* 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 */ - /* */ - - /* upper stub test */ - if ( ( left->next == right && left->height <= 0 ) || - - /* lower stub test */ - ( right->next == left && left->start == y ) || - - /* check that the rightmost pixel isn't set */ - ras.Proc_Test_Pixel( RAS_VARS y, TRUNC(e1)) ) - goto Next_Dropout; - - if ( ras.dropout_mode == 2 ) - e1 = e2; - else - e1 = CEILING( (x1+x2+1)/2 ); - - break; - - default: - goto Next_Dropout; /* Unsupported mode */ - } - } - else - goto Next_Dropout; - } - - ras.Proc_Set_Pixel( RAS_VARS y, - TRUNC(e1), - (x2-x1 >= ras.precision_half) & 1 ); - Next_Dropout: - - dropouts--; - } - goto Next_Line; - } - - - -/****************************************************************************/ -/* */ -/* Function: Render_Single_Pass */ -/* */ -/* Description: Performs one sweep with sub-banding. */ -/* */ -/* Input: _XCoord, _YCoord : x and y coordinates arrays */ -/* */ -/* Returns: SUCCESS on success */ -/* FAILURE if any error was encountered during render. */ -/* */ -/****************************************************************************/ - - static - int Render_Single_Pass( RAS_ARGS int flipped ) - { - int i, j, k; - - ras.flipped = flipped; - - while ( ras.band_top >= 0 ) - { -#if 1 - 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; -#else - ras.maxY = ((long)ras.band_stack[ras.band_top].y_max << - (ras.scale_shift+6))-1; - - ras.minY = (long)ras.band_stack[ras.band_top].y_min << - (ras.scale_shift+6); -#endif - ras.cursor = ras.pool; - ras.error = 0; - - if ( Convert_Glyph( RAS_VARS ras.outline ) ) - { - if ( ras.error != ErrRaster_Overflow ) return FAILURE; - ras.error = ErrRaster_Ok; - - /* 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 = ( j-i ) >> 1; - - if ( ras.band_top >= 7 || k == 0 ) - { - ras.band_top = 0; - ras.error = ErrRaster_Invalid_Outline; - return ras.error; - } - - ras.band_stack[ras.band_top+1].y_min = i + k; - ras.band_stack[ras.band_top+1].y_max = j; - - ras.band_stack[ras.band_top].y_max = i + k; - - ras.band_top++; - } - else - { - if ( ras.start_prof ) - if ( Draw_Sweep( RAS_VAR ) ) return ras.error; - ras.band_top--; - } - } - - return 0; /* success */ - } - - -#if 0 - void Compute_BBox( FT_Outline* outline, - FT_BBox* bbox ) - { - int n; - FT_Vector* vec; - - vec = outline->points; - bbox->xMin = bbox->xMax = vec->x; - bbox->yMin = bbox->yMax = vec->y; - - n = outline->n_points-1; - while ( n > 0 ) - { - FT_Pos x, y; - - vec++; - - x = vec->x; - if ( bbox->xMin > x ) bbox->xMin = x; - if ( bbox->xMax < x ) bbox->xMax = x; - - y = vec->y; - if ( bbox->yMin > y ) bbox->yMin = y; - if ( bbox->yMax < y ) bbox->yMax = y; - - n--; - } - } -#endif - - static - int Raster_Render1( FT_Raster raster ) - { - int error; - long byte_len; - - byte_len = ras.target.pitch; - if (byte_len < 0) byte_len = -byte_len; - - if ( ras.target.width > byte_len*8 ) - return ErrRaster_Invalid_Map; - - ras.scale_shift = (ras.precision_bits-6); - - /* Vertical Sweep */ - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.rows - 1; - - ras.Proc_Sweep_Init = Vertical_Sweep_Init; - ras.Proc_Sweep_Span = Vertical_Sweep_Span; - ras.Proc_Sweep_Step = Vertical_Sweep_Step; - ras.Proc_Test_Pixel = Vertical_Test_Pixel; - ras.Proc_Set_Pixel = Vertical_Set_Pixel; - - ras.bit_width = ras.target.width; - ras.bit_buffer = (unsigned char*)ras.target.buffer; - - if ( (error = Render_Single_Pass( RAS_VARS 0 )) != 0 ) - return error; - - /* Horizontal Sweep */ - - if ( ras.second_pass && ras.dropout_mode != 0 ) - { - ras.Proc_Sweep_Init = Horizontal_Sweep_Init; - ras.Proc_Sweep_Span = Horizontal_Sweep_Span; - ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - ras.Proc_Test_Pixel = Horizontal_Test_Pixel; - ras.Proc_Set_Pixel = Horizontal_Set_Pixel; - - 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 ErrRaster_Ok; - } - - - -#ifdef FT_RASTER_OPTION_ANTI_ALIAS - static - int Raster_Render8( FT_Raster raster ) - { - int error; - long byte_len; - - byte_len = ras.target.pitch; - if (byte_len < 0) byte_len = -byte_len; - - if ( ras.target.width > byte_len ) - return ErrRaster_Invalid_Map; - - /* Vertical Sweep */ - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.rows; - -#if !defined(FT_RASTER_ANTI_ALIAS_5) && !defined(FT_RASTER_ANTI_ALIAS_17) - return ErrRaster_Unimplemented; -#endif - -#ifdef FT_RASTER_ANTI_ALIAS_5 - if ( ras.grays_count == 5 ) - { - ras.scale_shift = (ras.precision_bits-5); - ras.bit_width = ras.gray_width/2; - if ( ras.bit_width > (ras.target.width+3)/4 ) - ras.bit_width = (ras.target.width+3)/4; - - ras.bit_width = ras.bit_width * 8; - ras.bit_buffer = (unsigned char*)ras.gray_lines; - ras.pix_buffer = (unsigned char*)ras.target.buffer; - - ras.Proc_Sweep_Init = Vertical_Gray5_Sweep_Init; - ras.Proc_Sweep_Span = Vertical_Gray5_Sweep_Span; - ras.Proc_Sweep_Step = Vertical_Gray5_Sweep_Step; - ras.Proc_Test_Pixel = Vertical_Gray5_Test_Pixel; - ras.Proc_Set_Pixel = Vertical_Gray5_Set_Pixel; - } -#endif - -#ifdef FT_RASTER_ANTI_ALIAS_17 - if ( ras.grays_count == 17 ) - { - ras.scale_shift = (ras.precision_bits-4); - ras.bit_width = ras.gray_width/4; - if ( ras.bit_width > (ras.target.width+1)/2 ) - ras.bit_width = (ras.target.width+1)/2; - - ras.bit_width = ras.bit_width * 8; - ras.bit_buffer = (unsigned char*)ras.gray_lines; - ras.pix_buffer = (unsigned char*)ras.target.buffer; - - ras.Proc_Sweep_Init = Vertical_Gray17_Sweep_Init; - ras.Proc_Sweep_Span = Vertical_Gray17_Sweep_Span; - ras.Proc_Sweep_Step = Vertical_Gray17_Sweep_Step; - ras.Proc_Test_Pixel = Vertical_Gray17_Test_Pixel; - ras.Proc_Set_Pixel = Vertical_Gray17_Set_Pixel; - } -#endif - - error = Render_Single_Pass( RAS_VARS 0 ); - if (error) - return error; - - /* Horizontal Sweep */ - - if ( ras.second_pass && ras.dropout_mode != 0 ) - { -#ifdef FT_RASTER_ANTI_ALIAS_5 - if ( ras.grays_count == 5 ) - { - ras.Proc_Sweep_Init = Horizontal_Sweep_Init; - ras.Proc_Sweep_Span = Horizontal_Gray5_Sweep_Span; - ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - ras.Proc_Test_Pixel = Horizontal_Gray5_Test_Pixel; - ras.Proc_Set_Pixel = Horizontal_Gray5_Set_Pixel; - } -#endif - -#ifdef FT_RASTER_ANTI_ALIAS_17 - if ( ras.grays_count == 17 ) - { - ras.Proc_Sweep_Init = Horizontal_Sweep_Init; - ras.Proc_Sweep_Span = Horizontal_Gray17_Sweep_Span; - ras.Proc_Sweep_Step = Horizontal_Sweep_Step; - ras.Proc_Test_Pixel = Horizontal_Gray17_Test_Pixel; - ras.Proc_Set_Pixel = Horizontal_Gray17_Set_Pixel; - } -#endif - ras.band_top = 0; - ras.band_stack[0].y_min = 0; - ras.band_stack[0].y_max = ras.target.width-1; - - error = Render_Single_Pass( RAS_VARS 1 ); - if (error) - return error; - } - - return ErrRaster_Ok; - } - -#else /* ANTI_ALIAS */ - - static - int Raster_Render8( FT_Raster raster ) - { - UNUSED_RASTER - return ErrRaster_Unimplemented; - } - -#endif /* FT_RASTER_OPTION_ANTI_ALIAS */ - - - -#ifdef FT_RASTER_OPTION_ANTI_ALIAS -/****************************************************************************/ -/* */ -/* Reset_Palette_5 */ -/* */ -/* Resets lookup table when the 5-gray-levels palette changes */ -/* */ -/****************************************************************************/ - -static -void Reset_Palette_5( RAS_ARG ) -{ - int i; - - for ( i = 0; i < 256; i++ ) - { - int cnt1, cnt2; - - cnt1 = ((i & 128) >> 7) + - ((i & 64) >> 6) + - ((i & 8) >> 3) + - ((i & 4) >> 2); - - cnt2 = ((i & 32) >> 5) + - ((i & 16) >> 4) + - ((i & 2) >> 1) + - (i & 1); - - /* */ - /* Note that when the endianess isn't specified through one of the */ - /* configuration, we use the big-endian storage in 'count_table' */ - /* */ - -#if defined( FT_RASTER_LITTLE_ENDIAN ) - ras.count_table[i] = (ras.grays[cnt2] << 8) | ras.grays[cnt1]; -#else - ras.count_table[i] = (ras.grays[cnt1] << 8) | ras.grays[cnt2]; -#endif - } -} - -/****************************************************************************/ -/* */ -/* Reset_Palette_17 */ -/* */ -/* Resets lookup table when 17-gray-levels palette changes */ -/* */ -/****************************************************************************/ - -#ifdef FT_RASTER_ANTI_ALIAS_17 -static -void Reset_Palette_17( RAS_ARG ) -{ - int i; - - for ( i = 0; i < 256; i++ ) - ras.count_table[i] = - ((i & 128) >> 7) + - ((i & 64) >> 6) + - ((i & 8) >> 3) + - ((i & 4) >> 2) + - ((i & 32) >> 5) + - ((i & 16) >> 4) + - ((i & 2) >> 1) + - (i & 1); -} -#endif /* ANTI_ALIAS_17 */ - -#endif /* TT_RASTER_OPTION_ANTI_ALIAS */ - - - - /**********************************************************************/ - /* */ - /* FT_Raster_SetPalette */ - /* */ - /* */ - /* Set the pixmap rendering palette. anti-aliasing modes are */ - /* implemented/possible, they differ from the number of */ - /* entries in the palette. */ - /* */ - /* */ - /* count :: the number of palette entries. Valid values are */ - /* 2, 5 and 17, which are the number of intermediate */ - /* gray levels supported */ - /* */ - /* palette :: an array of 'count' chars giving the 8-bit palette */ - /* of intermediate "gray" levels for anti-aliased */ - /* rendering. */ - /* */ - /* In all modes, palette[0] corresponds to the background, */ - /* while palette[count-1] to the foreground. Hence, a count */ - /* of 2 corresponds to no anti-aliasing; a count of 5 uses */ - /* 3 intermediate levels between the background and */ - /* foreground, while a count of 17 uses 15 of them.. */ - /* */ - /* */ - /* An error code, used as a FT_Error by the FreeType library. */ - /* */ - /* */ - /* By default, a new object uses mode 5, with a palette of */ - /* 0,1,2,3 and 4. You don't need to set the palette if you */ - /* don't need to render pixmaps.. */ - /* */ - /**********************************************************************/ - - EXPORT_FUNC - int FT_Raster_SetPalette( FT_Raster raster, - int count, - const char* palette ) - { - (void)raster; - (void)palette; - - switch (count) - { -#ifdef FT_RASTER_OPTION_ANTI_ALIAS - - /******************************/ - /* The case of 17 gray levels */ - /******************************/ - - case 17: -#ifdef FT_RASTER_ANTI_ALIAS_17 - { - int n; - - raster->grays_count = count; - for ( n = 0; n < count; n++ ) - raster->grays[n] = (unsigned char)palette[n]; - Reset_Palette_17( RAS_VAR ); - break; - } -#else - return ErrRaster_Unimplemented; -#endif - - /*****************************/ - /* The case of 5 gray levels */ - /*****************************/ - - case 5: -#ifdef FT_RASTER_ANTI_ALIAS_5 - { - int n; - - raster->grays_count = count; - for ( n = 0; n < count; n++ ) - raster->grays[n] = (unsigned char)palette[n]; - Reset_Palette_5( RAS_VAR ); - break; - } -#else - return ErrRaster_Unimplemented; -#endif - -#endif /* FT_RASTER_OPTION_ANTI_ALIAS */ - default: - return ErrRaster_Bad_Palette_Count; - } - - return ErrRaster_Ok; - } - - - /**** RASTER OBJECT CREATION : in standalone mode, we simply use *****/ - /**** a static object .. *****/ -#ifdef _STANDALONE_ - - static - int ft_black2_new( void* memory, FT_Raster *araster ) - { - static FT_RasterRec_ the_raster; - *araster = &the_raster; - memset( &the_raster, sizeof(the_raster), 0 ); - return 0; - } - - static - void ft_black2_done( FT_Raster raster ) - { - /* nothing */ - raster->init = 0; - } - -#else - -#include - - static - int ft_black2_new( FT_Memory memory, FT_Raster *araster ) - { - FT_Error error; - FT_Raster raster; - - *araster = 0; - if ( !ALLOC( raster, sizeof(*raster) )) - { - raster->memory = memory; - *araster = raster; - } - - return error; - } - - static - void ft_black2_done( FT_Raster raster ) - { - FT_Memory memory = (FT_Memory)raster->memory; - FREE( raster ); - } - -#endif - - - static void ft_black2_reset( FT_Raster raster, - const char* pool_base, - long pool_size ) - { - static const char default_palette[5] = { 0, 1, 2, 3, 4 }; - - /* check the object address */ - if ( !raster ) - return; - - /* check the render pool - we won't go under 4 Kb */ - if ( !pool_base || pool_size < 4096 ) - return; - - /* save the pool */ - raster->pool = (PPos)pool_base; - raster->pool_size = (PPos)(pool_base + (pool_size & -8)); - -#ifdef FT_RASTER_OPTION_ANTI_ALIAS - raster->gray_width = ANTI_ALIAS_BUFFER_SIZE/2; - /* clear anti-alias intermediate lines */ - { - char* p = raster->gray_lines; - int size = ANTI_ALIAS_BUFFER_SIZE; - do - { - *p++ = 0; - size--; - - } while (size > 0); - } -#endif - - /* set the default palette : 5 levels = 0, 1, 2, 3 and 4 */ - FT_Raster_SetPalette( raster, 5, default_palette ); - } - - - static - int ft_black2_render( FT_Raster raster, - FT_Raster_Params* params ) - { - FT_Outline* outline = (FT_Outline*)params->source; - FT_Bitmap* target_map = params->target; - - if ( !raster || !raster->pool || !raster->pool_size ) - return ErrRaster_Uninitialised_Object; - - if ( !outline || !outline->contours || !outline->points ) - return ErrRaster_Invalid_Outline; - - /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) - 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 ErrRaster_Invalid_Map; - - /* this version of the raster does not support direct rendering, sorry */ - if ( params->flags & ft_raster_flag_direct ) - return ErrRaster_Unimplemented; - - ras.outline = outline; - ras.target = *target_map; - - ras.dropout_mode = 2; - ras.second_pass = !(outline->flags & ft_outline_single_pass); - SET_High_Precision( (outline->flags & ft_outline_high_precision) ); - - return ( params->flags & ft_raster_flag_aa - ? Raster_Render8(raster) - : Raster_Render1(raster) ); - } - - - FT_Raster_Funcs ft_black2_raster = - { - ft_glyph_format_outline, - (FT_Raster_New_Func) ft_black2_new, - (FT_Raster_Reset_Func) ft_black2_reset, - (FT_Raster_Set_Mode_Func) 0, - (FT_Raster_Render_Func) ft_black2_render, - (FT_Raster_Done_Func) ft_black2_done - }; - - diff --git a/demos/src/ftrast2.h b/demos/src/ftrast2.h deleted file mode 100644 index 54342d9a2..000000000 --- a/demos/src/ftrast2.h +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************* - * - * ftraster.h v 2.0 - * - * The FreeType glyph scan-line converter (interface) - * - * 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 FTRAST2_H -#define FTRAST2_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef EXPORT_VAR -#define EXPORT_VAR(x) extern x -#endif - - EXPORT_VAR(FT_Raster_Funcs) ft_black2_raster; - -#ifdef __cplusplus -} -#endif - -#endif /* FTRAST2_H */ - - -/* END */ diff --git a/demos/src/ftview.c b/demos/src/ftview.c index 9e2a9b07c..3448e86d7 100644 --- a/demos/src/ftview.c +++ b/demos/src/ftview.c @@ -16,6 +16,9 @@ /****************************************************************************/ #include +#include +#include + #include "common.h" #include @@ -26,10 +29,6 @@ #include "graph.h" #include "grfont.h" -#include -#include "ftrast.h" -#include "ftrast2.h" - #define DIM_X 500 #define DIM_Y 400 @@ -276,7 +275,7 @@ $\243^\250*\265\371%!\247:/;.,?<>"; { if ( !(error = LoadChar( i, hinted )) ) { -#ifdef DEBUG + #ifdef DEBUG if (i <= first_glyph+6) { LOG(( "metrics[%02d] = [%x %x]\n", @@ -287,8 +286,8 @@ $\243^\250*\265\371%!\247:/;.,?<>"; if (i == first_glyph+6) LOG(( "-------------------------\n")); } + #endif -#endif Render_Glyph( x, y ); x += ( glyph->metrics.horiAdvance >> 6 ) + 1; @@ -337,7 +336,7 @@ $\243^\250*\265\371%!\247:/;.,?<>"; { if ( !(error = LoadChar( FT_Get_Char_Index( face, (unsigned char)*p ), hinted )) ) { -#ifdef DEBUG + #ifdef DEBUG if (i <= first_glyph+6) { LOG(( "metrics[%02d] = [%x %x]\n", @@ -348,8 +347,8 @@ $\243^\250*\265\371%!\247:/;.,?<>"; if (i == first_glyph+6) LOG(( "-------------------------\n")); } + #endif -#endif Render_Glyph( x, y ); x += ( glyph->metrics.horiAdvance >> 6 ) + 1; @@ -421,19 +420,10 @@ $\243^\250*\265\371%!\247:/;.,?<>"; static void reset_raster( void ) { - FT_Error error; - - error = 1; - if ( !antialias) - { - error = FT_Set_Raster( library, use_grays ? &ft_black2_raster - : &ft_black_raster ); - } - else if ( use_grays && antialias ) - error = FT_Set_Raster( library, &ft_grays_raster ); - - if (error) - (void)FT_Set_Raster( library, &std_raster ); + if ( antialias && use_grays ) + FT_Set_Raster( library, &ft_grays_raster ); + else + FT_Set_Raster( library, &std_raster ); } diff --git a/demos/src/t1dump.c b/demos/src/t1dump.c deleted file mode 100644 index b349ebfda..000000000 --- a/demos/src/t1dump.c +++ /dev/null @@ -1,1031 +0,0 @@ -/****************************************************************************/ -/* */ -/* t1dump.c 1.0 */ -/* */ -/* Copyright 1999 - The FreeType Project http://www.freetype.org */ -/* */ -/* T1Dump is a very simply Type 1 font dumper. It can be used to */ -/* write the following information to the standard ouput, or any */ -/* given file: */ -/* */ -/* - a description of the font file (including name, properties, etc..) */ -/* - the decrypted private dictionary, 'as is', i.e. in binary form */ -/* - the stream of tokens from the font file (useful to debug the */ -/* Type1 driver or to look at the font's internal structure..) */ -/* - the charstring commands of a given subroutine */ -/* - the charstring commands of a given glyph */ -/* - the encoding */ -/* - the glyph names */ -/* */ - -#include -#include - -#include "freetype.h" -#include -#include -#include -#include - -FT_Library library; /* root library object */ -FT_Face face; /* truetype face */ -T1_Face t1_face; -FT_Error error; -FILE* target; - - void Panic( const char* message ) - { - fprintf( stderr, "%s\n error code = 0x%04x\n", message, error ); - exit(1); - } - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** DUMP FONT INFORMATION *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - T1_Error Dump_Font_Info( void ) - { - T1_FontInfo* info = &t1_face->font_info; - T1_Private* priv = &t1_face->private_dict; - T1_Int n; - - fprintf( target, "Font Name : %s\n", t1_face->font_name ); - - fprintf( target, "Version : %s\n", info->version ); - fprintf( target, "Full Name : %s\n", info->full_name ); - fprintf( target, "Family : %s\n", info->family_name ); - fprintf( target, "Weight : %s\n", info->weight ); - fprintf( target, "Italic angle : %ld\n", info->italic_angle ); - - fprintf( target, "Fixed pitch : %s\n", - info->is_fixed_pitch ? "yes" : "no" ); - - fprintf( target, "Underline : pos %d, thickness %d\n", - info->underline_position, - info->underline_thickness ); - - fprintf( target, "Unique ID : %d\n", priv->unique_id ); - fprintf( target, "lenIV : %d\n", priv->lenIV ); - - fprintf( target, "blues : [" ); - for ( n = 0; n < priv->num_blues; n++ ) - fprintf( target, " %d", priv->blue_values[n] ); - fprintf( target, " ]\n" ); - - fprintf( target, "other blues : [" ); - for ( n = 0; n < priv->num_other_blues; n++ ) - fprintf( target, " %d", priv->other_blues[n] ); - fprintf( target, " ]\n" ); - - fprintf( target, "family blues : [" ); - for ( n = 0; n < priv->num_family_blues; n++ ) - fprintf( target, " %d", priv->family_blues[n] ); - fprintf( target, " ]\n" ); - - fprintf( target, "family other : [" ); - for ( n = 0; n < priv->num_family_other_blues; n++ ) - fprintf( target, " %d", priv->family_other_blues[n] ); - fprintf( target, " ]\n" ); - - fprintf( target, "Blue scale : %f\n", priv->blue_scale*1.0/65536.0 ); - fprintf( target, "Blue shift : %d\n", priv->blue_shift ); - fprintf( target, "Blue fuzz : %d\n", priv->blue_fuzz ); - - fprintf( target, "Std width : %d\n", priv->standard_width ); - fprintf( target, "Std height : %d\n", priv->standard_height ); - fprintf( target, "Force bold : %s\n", priv->force_bold ? "yes" : "no" ); - fprintf( target, "Round stem : %s\n", priv->round_stem_up ? "yes" : "no" ); - - fprintf( target, "Stem snap W : [" ); - for ( n = 0; n < priv->num_snap_widths; n++ ) - fprintf( target, " %d", priv->stem_snap_widths[n] ); - fprintf( target, " ]\n" ); - - fprintf( target, "Stem snap H : [" ); - for ( n = 0; n < priv->num_snap_heights; n++ ) - fprintf( target, " %d", priv->stem_snap_heights[n] ); - fprintf( target, " ]\n" ); - - fprintf( target, "Language : %ld\n", priv->language_group ); - fprintf( target, "Password : %ld\n", priv->password ); - fprintf( target, "Min feature : [ %d %d ]\n", - priv->min_feature[0], - priv->min_feature[1] ); - - fprintf( target, "Font BBOX : [ %ld %ld %ld %ld ]\n", - t1_face->font_bbox.xMin, - t1_face->font_bbox.yMin, - t1_face->font_bbox.xMax, - t1_face->font_bbox.yMax ); - - fprintf( target, "Font matrix : [ %f %f %f %f ]\n", - 1.0*t1_face->font_matrix.xx/65536000.0, - 1.0*t1_face->font_matrix.xy/65536000.0, - 1.0*t1_face->font_matrix.yx/65536000.0, - 1.0*t1_face->font_matrix.yy/65536000.0 ); -#if 0 - fprintf( target, - fprintf( target, - fprintf( target, - fprintf( target, - fprintf( target, - fprintf( target, -#endif - fprintf( target, "Num glyphs : %d\n", t1_face->num_glyphs ); - fprintf( target, "Num subrs : %d\n", t1_face->num_subrs ); - - return 0; - } - - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** DUMP PRIVATE DICT IN RAW FORM *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - T1_Error parse_int( T1_Tokenizer tokzer, - T1_Long* result ) - { - T1_Bool sign = 0; - T1_Long sum = 0; - T1_Token* token = &tokzer->token; - T1_Byte* base = tokzer->base + token->start; - T1_Byte* limit = base + token->len; - - if (base >= limit) - goto Fail; - - /* check sign */ - if ( *base == '+' ) - base++; - - else if ( *base == '-' ) - { - sign++; - base++; - } - - /* parse digits */ - if ( base >= limit ) - goto Fail; - - do - { - sum = ( 10*sum + (*base++ - '0') ); - - } while (base < limit); - - if (sign) - sum = -sum; - - *result = sum; - return T1_Err_Ok; - - Fail: - *result = 0; - return T1_Err_Syntax_Error; - } - - - - - - static - T1_Error Dump_Private_Dict( const char* filename ) - { - struct FT_StreamRec_ stream_rec; - FT_Stream stream = &stream_rec; - T1_Error error; - T1_Tokenizer tokenizer; - - error = FT_New_Stream( filename, stream ); - if (error) return error; - - stream->memory = library->memory; - - error = New_Tokenizer( stream, &tokenizer ); - if (error) goto Exit; - - /* go directly to the Private dictionary */ - error = Open_PrivateDict( tokenizer ); - if (error) - Panic( "Could not open private dictionary !!" ); - - /* Write it to the target file */ - fwrite( tokenizer->base, tokenizer->limit, 1, target ); - - Exit: - if (stream->close) - stream->close(stream); - - return error; - } - - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** DUMP TYPE 1 TOKEN STREAM *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - T1_Error Dump_Type1_Tokens( const char* filename ) - { - struct FT_StreamRec_ stream_rec; - FT_Stream stream = &stream_rec; - - T1_Error error; - T1_Tokenizer tokenizer; - - error = FT_New_Stream( filename, stream ); - if (error) return error; - - stream->memory = library->memory; - - error = New_Tokenizer( stream, &tokenizer ); - if (error) goto Exit; - - /* Dump the first segment of the Type1 font */ - do - { - T1_Token* token; - T1_String temp_string[128]; - T1_Int len; - - error = Read_Token( tokenizer ); - if (error) { error = 0; break; } - - /* dump the token */ - token = &tokenizer->token; - len = token->len; - if (len > 127) len = 127; - - strncpy( temp_string, - (T1_String*)(tokenizer->base + token->start), - len ); - temp_string[len] = '\0'; - - fprintf( target, "%s\n", temp_string ); - - /* Exit the loop when we encounter a "currentfile" token */ - if ( token->kind == tok_keyword && - token->kind2 == key_currentfile ) - break; - - } while (1); - - error = Open_PrivateDict( tokenizer ); - if (error) - Panic( "** could not open private dictionary **\n" ); - else - { - T1_Int num = 0; - T1_Bool last_num = 0; - - do - { - T1_Token* token; - T1_String temp_string[128]; - T1_Int len; - - error = Read_Token( tokenizer ); - if (error) { error = 0; break; } - - /* dump the token */ - token = &tokenizer->token; - len = token->len; - if (len > 127) len = 127; - - strncpy( temp_string, - (T1_String*)(tokenizer->base + token->start), - len ); - temp_string[len] = '\0'; - - /* detect "RD" uses */ - if ( token->kind == tok_keyword && - ( token->kind2 == key_RD || - token->kind2 == key_RD_alternate ) && - last_num ) - { - fprintf( target, "%s [%d binary bytes] ", temp_string, num ); - tokenizer->cursor += num; - } - else - { - fprintf( target, "%s\n", temp_string ); - - /* exit dump when we encounter a 'closefile' */ - if ( token->kind == tok_keyword && - token->kind2 == key_closefile ) - break; - - /* record numerical value if any */ - if ( token->kind == tok_number ) - { - T1_Long sum; - - if ( !parse_int( tokenizer, &sum ) ) - { - num = sum; - last_num = 1; - } - else - last_num = 0; - } - else - last_num = 0; - } - - } while (1); - } - - Exit: - if (stream->close) - stream->close(stream); - return error; - } - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** DUMP CHARACTER ENCODING *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - void Dump_Encoding( void ) - { - T1_Encoding* encode = &t1_face->encoding; - int n; - - fprintf( target, "characters count = %d\n", encode->num_chars ); - - fprintf( target, "first code = %d, last code = %d\n", - encode->code_first, encode->code_last ); - - for ( n = 0; n < encode->num_chars; n++ ) - { - int code = (int)encode->char_index[n]; - - if (code || n == 0) - fprintf( target, "%3d %s\n", n, t1_face->glyph_names[code] ); - } - } - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** DUMP SUBROUTINES AND GLYPH CHARSTRINGS *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - void Dump_CharStrings( T1_Byte* base, - T1_Int len ) - { - T1_Byte* cur = base; - T1_Byte* limit = base + len; - T1_String temp_name[128]; - T1_String* string; - - T1_Int x = 0; - - while ( cur < limit ) - { - switch (*cur++) - { - case 1: string = "hstem"; break; - - case 3: string = "vstem"; break; - case 4: string = "vmoveto"; break; - case 5: string = "rlineto"; break; - case 6: string = "hlineto"; break; - case 7: string = "vlineto"; break; - case 8: string = "rrcurveto"; break; - case 9: string = "closepath"; break; - case 10: string = "callsubr"; break; - case 11: string = "return"; break; - - case 13: string = "hsbw"; break; - case 14: string = "endchar"; break; - - case 21: string = "rmoveto"; break; - case 22: string = "hmoveto"; break; - - case 30: string = "vhcurveto"; break; - case 31: string = "hvcurveto"; break; - - case 12: - { - if (cur > limit) - Panic( "invalid charstrings stream\n" ); - - switch (*cur++) - { - case 0: string = "dotsection"; break; - case 1: string = "vstem3"; break; - case 2: string = "hstem3"; break; - case 6: string = "seac"; break; - case 7: string = "sbw"; break; - case 12: string = "div"; break; - case 16: string = "callothersubr"; break; - case 17: string = "pop"; break; - case 33: string = "setcurrentpoint"; break; - - default: - sprintf( temp_name, "escape(12)+unknown(%d)", cur[1] ); - string = temp_name; - } - } - break; - - case 255: /* four bytes integer */ - { - T1_Long sum; - - if (cur+4 > limit) - Panic( "invalid charstrings stream\n" ); - - sum = ((long)cur[0] << 24) | - ((long)cur[1] << 16) | - ((long)cur[2] << 8) | - cur[3]; - sprintf( temp_name, "%ld ", sum ); - string = temp_name; - cur += 4; - } - break; - - default: - if (cur[-1] >= 32) - { - if (cur[-1] < 247) - { - sprintf( temp_name, "%ld", (long)cur[-1] - 139 ); - } - else if (cur[-1] < 251) - { - cur++; - sprintf( temp_name, "%ld", - ((long)(cur[-2]-247) << 8) + cur[-1] + 108 ); - } - else - { - cur++; - sprintf( temp_name, "%ld", - -((long)(cur[-2]-251) << 8) - cur[-1] - 108 ); - } - string = temp_name; - } - else - { - sprintf( temp_name, "unknown(%d)", cur[-1] ); - string = temp_name; - } - } - - /* now print the charstring command */ - { - int len = strlen(string)+1; - - if ( x+len > 60 ) - { - x = 0; - fprintf( target, "\n" ); - } - else - fprintf( target, " " ); - - fprintf( target, "%s", string ); - x += len; - } - } - } - - - - static - void Dump_Glyph( int glyph_index ) - { - fprintf( target, "glyph name: %s\n", t1_face->glyph_names[glyph_index] ); - Dump_CharStrings( t1_face->charstrings [glyph_index], - t1_face->charstrings_len [glyph_index] ); - } - - static - void Dump_Subrs( int subrs_index ) - { - Dump_CharStrings( t1_face->subrs [ subrs_index ], - t1_face->subrs_len[ subrs_index ] ); - } - - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** EXECUTE GLYPH CHARSTRINGS *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - T1_Error operator_endchar( T1_Builder* builder ) - { - (void)builder; - fprintf( target, "endchar\n" ); - return 0; - } - - - static - T1_Error operator_sbw( T1_Builder* builder, - T1_Pos sbx, - T1_Pos sby, - T1_Pos wx, - T1_Pos wy ) - { - (void)builder; - fprintf( target, "set bearing [%ld,%ld] width [%ld,%ld]\n", - sbx, sby, wx, wy ); - return 0; - } - -#if 0 - static - T1_Error operator_seac( T1_Builder* builder, - T1_Pos asb, - T1_Pos adx, - T1_Pos ady, - T1_Int bchar, - T1_Int achar ) - { - (void)builder; - fprintf( target, "accented char: %ld [%ld,%ld] b=%d, a=%d\n", - asb, adx, ady, bchar, achar ); - return 0; - } -#endif - - static - T1_Error operator_closepath( T1_Builder* builder ) - { - (void)builder; - fprintf( target, "closepath\n" ); - return 0; - } - - - static - T1_Error operator_rlineto( T1_Builder* builder, - T1_Pos dx, - T1_Pos dy ) - { - (void)builder; - fprintf( target, "%ld %ld rlineto\n", dx, dy ); - return 0; - } - - - static - T1_Error operator_rmoveto( T1_Builder* builder, - T1_Pos dx, - T1_Pos dy ) - { - (void)builder; - fprintf( target, "%ld %ld rmoveto\n", dx, dy ); - return 0; - } - - - static - T1_Error operator_rrcurveto( T1_Builder* builder, - T1_Pos dx1, - T1_Pos dy1, - T1_Pos dx2, - T1_Pos dy2, - T1_Pos dx3, - T1_Pos dy3 ) - { - (void)builder; - fprintf( target, "%ld %ld %ld %ld %ld %ld rrcurveto\n", - dx1, dy1, dx2, dy2, dx3, dy3 ); - return 0; - } - - - static - T1_Error operator_dotsection( T1_Builder* builder ) - { - (void)builder; - fprintf( target, "dotsection\n" ); - return 0; - } - - - static - T1_Error operator_stem( T1_Builder* builder, - T1_Pos pos, - T1_Pos width, - T1_Bool vertical ) - { - (void)builder; - fprintf( target, "%ld %ld %s\n", pos, width, - vertical ? "vstem" : "hstem" ); - return 0; - } - - - static - T1_Error operator_stem3( T1_Builder* builder, - T1_Pos pos0, - T1_Pos width0, - T1_Pos pos1, - T1_Pos width1, - T1_Pos pos2, - T1_Pos width2, - T1_Bool vertical ) - { - (void)builder; - fprintf( target, "%ld %ld %ld %ld %ld %ld %s\n", - pos0, width0, pos1, width1, pos2, width2, - vertical ? "vstem3" : "hstem3" ); - return 0; - } - - -#if 0 - static - T1_Error operator_flex( T1_Builder* builder, - T1_Pos threshold, - T1_Pos end_x, - T1_Pos end_y ) - { - (void)builder; - fprintf( target, "%ld %ld %ld flex\n", threshold, end_x, end_y ); - return 0; - } -#endif - - static - T1_Error operator_changehints( T1_Builder* builder ) - { - (void)builder; - fprintf( target, "-- change hints --\n" ); - return 0; - } - - - static - T1_Error Execute_CharString( int glyph_index ) - { - static const T1_Builder_Funcs builds = - { - operator_endchar, - operator_sbw, - operator_closepath, - operator_rlineto, - operator_rmoveto, - operator_rrcurveto, - }; - - static const T1_Hinter_Funcs hints = - { - operator_dotsection, - operator_changehints, - operator_stem, - operator_stem3, - }; - - T1_Decoder decoder; - T1_Error error; - - T1_Init_Decoder( &decoder, &hints ); - T1_Init_Builder( &decoder.builder, t1_face, 0, 0, &builds ); - - error = T1_Parse_CharStrings( &decoder, - t1_face->charstrings [glyph_index], - t1_face->charstrings_len[glyph_index], - t1_face->num_subrs, - t1_face->subrs, - t1_face->subrs_len ); - return error; - } - - - - - - - - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** DEBUG FONT LOADING *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - static - T1_Error Debug_Type1_Font( const char* filename ) - { - struct FT_StreamRec_ stream_rec; - T1_FaceRec t1facerec; - T1_Tokenizer tokenizer; - T1_Parser parser; - T1_Error error; - FT_Stream stream = &stream_rec; - - error = FT_New_Stream( filename, stream ); - if (error) goto Exit; - - stream->memory = library->memory; - - /* create an empty face record */ - memset( &t1facerec, 0, sizeof(t1facerec) ); - t1facerec.root.memory = library->memory; - t1facerec.root.stream = stream; - - t1_face = &t1facerec; - - /* open the tokenizer, this will also check the font format */ - error = New_Tokenizer( stream, &tokenizer ); - if (error) goto Fail; - - /* Now, load the font program into the face object */ - Init_T1_Parser( &parser, t1_face, tokenizer ); - - /* force token dump */ - parser.dump_tokens = 1; - - error = Parse_T1_FontProgram( &parser ); - - Done_Tokenizer( tokenizer ); - - Fail: - if (stream->close) - stream->close( stream ); - Exit: - return error; - } - -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ -/********** *********/ -/********** *********/ -/********** MAIN PROGRAM *********/ -/********** *********/ -/********** *********/ -/**************************************************************************/ -/**************************************************************************/ -/**************************************************************************/ - - - static - void Usage() - { - fprintf( stderr, "t1dump - a simple Type 1 font dumper\n" ); - fprintf( stderr, "(c) The FreeType project - www.freetype.org\n" ); - fprintf( stderr, "-------------------------------------------\n\n" ); - - fprintf( stderr, "usage : t1dump [options] fontfile(.pfb|.pfa)\n\n" ); - - fprintf( stderr, " options\n" ); - fprintf( stderr, " -o filename : dumps to a specific file\n" ); - fprintf( stderr, " -g index : dump glyph charstring\n" ); - fprintf( stderr, " -s index : dump subrs charstring\n" ); - fprintf( stderr, " -x index : execute glyph charstring\n" ); - fprintf( stderr, " -e : dump encoding\n" ); - fprintf( stderr, " -t : dumps the Type 1 token stream\n" ); - fprintf( stderr, " -d : debug font loading\n" ); - fprintf( stderr, " -p : dumps private dictionary 'as is'\n\n" ); - - exit(1); - } - - -typedef enum Request_ -{ - req_dump_info, - req_dump_private, - req_dump_tokens, - req_dump_encoding, - req_dump_glyph, - req_dump_subr, - req_load_font, - req_execute_glyph, - req_debug_font - -} Request; - - -static char* file_name; -static int glyph_index; -static Request request = req_dump_info; - -static FT_Driver t1_driver; - - int main( int argc, char** argv ) - { - char valid; - - - /* Check number of arguments */ - if ( argc < 2 ) Usage(); - - /* Check options */ - target = stdout; - - argv++; - while (argv[0][0] == '-') - { - valid = 0; - switch (argv[0][1]) - { - case 'p': - request = req_dump_private; - valid = 1; - break; - - case 't': - request = req_dump_tokens; - valid = 1; - break; - - case 'e': - request = req_dump_encoding; - valid = 1; - break; - - case 'd': - request = req_debug_font; - valid = 1; - break; - - case 'o': - if (argc < 2) Usage(); - target = fopen( argv[1], "w" ); - if (!target) - Panic( "Could not open/create destination file" ); - argv++; - argc--; - valid = 1; - break; - - case 'g': - case 's': - case 'x': - if (argc < 2) Usage(); - if ( sscanf( argv[1], "%d", &glyph_index ) != 1 ) - Usage(); - - switch (argv[0][1]) - { - case 'g': request = req_dump_glyph; break; - case 's': request = req_dump_subr; break; - case 'x': request = req_execute_glyph; break; - } - argv++; - argc--; - valid = 1; - break; - - default: - ; - } - - if (valid) - { - argv++; - argc--; - if (argc < 2) Usage(); - } - else - break; - } - - /* Get file name */ - file_name = argv[0]; - - /* Instead of calling FT_Init_FreeType, we set up our own system */ - /* object and library. This is reserved for FreeType 2 wizards !! */ - - /* Init library, read face object, get driver, create size */ - error = FT_Init_FreeType( &library ); - if (error) Panic( "could not initialise FreeType library" ); - - t1_driver = FT_Get_Driver( library, "type1" ); - if (!t1_driver) Panic( "no Type1 driver in current FreeType lib" ); - - error = FT_New_Face( library, file_name, 0, &face ); - if (error) Panic( "could not find/open/create font file" ); - - if (face->driver != t1_driver) - Panic( "font format is not Type 1 !" ); - - switch (request) - { - case req_dump_private: - error = Dump_Private_Dict(file_name); - break; - - case req_dump_tokens: - error = Dump_Type1_Tokens(file_name); - break; - - case req_debug_font: - error = Debug_Type1_Font(file_name); - break; - - default: - error = FT_New_Face( library, file_name, 0, &face ); - if (error) Panic( "could not load Type 1 font" ); - - t1_face = (T1_Face)face; - - /* check glyph index, it is 0 by default */ - if ( glyph_index < 0 || glyph_index >= t1_face->num_glyphs ) - Panic( "invalid glyph index\n" ); - - switch (request) - { - case req_dump_glyph: - Dump_Glyph( glyph_index ); - break; - - case req_dump_subr: - Dump_Subrs( glyph_index ); - break; - - case req_execute_glyph: - Execute_CharString( glyph_index ); - break; - - case req_dump_encoding: - Dump_Encoding(); - break; - - default: - Dump_Font_Info(); - } - } - - if (error) Panic( "could not dump Type 1 font" ); - - FT_Done_FreeType( library ); - return 0; - }