ref: 33aab6e5b6c14d3cf2c4334f79a8debf959c9e38
parent: 529d4ea7a08021bfd2abcc703515f13f19d2f4ee
author: David Turner <[email protected]>
date: Tue May 16 18:36:55 EDT 2000
removed obsolete files + update
--- a/demos/Makefile
+++ b/demos/Makefile
@@ -281,21 +281,14 @@
$(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
--- a/demos/src/ftgrays2.c
+++ /dev/null
@@ -1,2250 +1,0 @@
-/*****************************************************************************/
-/* */
-/* ftgrays2.c - a new version of the standard FreeType anti-aliaser */
-/* */
-/* (c) 2000 David Turner - <[email protected]> */
-/* */
-/* 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 <ftimage.h>
-
-#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 <stdio.h>
-#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;
-}
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* compute_intersects */
- /* */
- /* <Description> */
- /* Computes the scan-line intersections of a given line and store */
- /* the corresonding cells in the render pool.. */
- /* */
- /* <Input> */
- /* 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.. */
- /* */
- /* <Return> */
- /* 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;
- }
-
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* render_line */
- /* */
- /* <Description> */
- /* This function injects a new line segment in the render pool. */
- /* */
- /* <Input> */
- /* x :: target x coordinate (scaled subpixels) */
- /* y :: target y coordinate (scaled subpixels) */
- /* raster :: A pointer to the current raster object. */
- /* */
- /* <Return> */
- /* 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 <stdio.h>
-
- 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
- };
-
--- a/demos/src/ftgrays2.h
+++ /dev/null
@@ -1,9 +1,0 @@
-#ifndef FTGRAYS2_H
-#define FTGRAYS2_H
-
-#include <ftimage.h>
-
- extern
- FT_Raster_Funcs ft_grays2_raster;
-
-#endif
--- a/demos/src/ftrast.c
+++ /dev/null
@@ -1,3039 +1,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 <freetype/internal/ftcalc.h> /* 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 <freetype/internal/ftdebug.h>
-
-
-/* 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 ;-) */
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> Split_Cubic */
- /* */
- /* <Description> */
- /* Subdivides a third-order Bezier arc into two joint sub-arcs in */
- /* the Bezier stack. */
- /* */
- /* <Note> */
- /* 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 <freetype/internal/ftobjs.h>
-
- 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 */
--- a/demos/src/ftrast.h
+++ /dev/null
@@ -1,8 +1,0 @@
-#ifndef FTRASTER_H
-#define FTRASTER_H
-
-#include <freetype/ftimage.h>
-
- extern FT_Raster_Funcs ft_black_raster;
-
-#endif
--- a/demos/src/ftrast2.c
+++ /dev/null
@@ -1,3856 +1,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 <freetype/freetype.h> /* 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 <limits.h> header file to compute exactly */
-/* wether to use unsigned int or unsigned long */
-/* */
-#include <limits.h>
-
-/* 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 */
-
-
-/************************************************************************/
-/* */
-/* <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;
- }
-
- 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;
- }
-
-
-/**************************************************************************/
-/* */
-/* <Function> New_Profile */
-/* */
-/* <Description> Creates a new Profile in the render pool. */
-/* */
-/* <Input> */
-/* aState :: state/orientation of the new Profile */
-/* */
-/* <Return> */
-/* 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;
- }
-
-
-/****************************************************************************/
-/* */
-/* <Function> End_Profile */
-/* */
-/* <Description> Finalizes the current Profile. */
-/* */
-/* <Return> */
-/* 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;
- }
-
-
-/****************************************************************************/
-/* */
-/* <Function> Insert_Y_Turn */
-/* */
-/* <Description> */
-/* Insert a salient into the sorted list placed on top */
-/* of the render pool */
-/* */
-/* <Input> */
-/* 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;
- }
-
-
-/****************************************************************************/
-/* */
-/* <Function> Finalize_Profile_Table */
-/* */
-/* <Description> */
-/* 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;
- }
-
-
-
-/****************************************************************************/
-/* */
-/* <Function> Line_Up */
-/* */
-/* <Description> */
-/* Computes the scan-line intersections of an ascending line segment */
-/* and stores them in the render pool. */
-/* */
-/* <Input> */
-/* 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 */
-/* */
-/* <Return> */
-/* 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;
- }
-
-
-/****************************************************************************/
-/* */
-/* <Function> Line_Down */
-/* */
-/* <Description> */
-/* Computes the scan-line intersections of a descending line segment */
-/* and stores them in the render pool. */
-/* */
-/* <Input> */
-/* 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 */
-/* */
-/* <Return> */
-/* 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
-/****************************************************************************/
-/* */
-/* <Function> Split_Conic */
-/* */
-/* <Description> */
-/* Subdivides one second-order Bezier arc into two joint sub-arcs in */
-/* the Bezier stack. */
-/* */
-/* <Note> */
-/* 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
-/****************************************************************************/
-/* */
-/* <Function> Split_Cubic */
-/* */
-/* <Description> */
-/* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
-/* Bezier stack. */
-/* */
-/* <Note> */
-/* 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
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Bezier_Up */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Input> */
- /* miny :: The minimum vertical grid coordinate. */
- /* maxy :: The maximum vertical grid coordinate. */
- /* */
- /* <Return> */
- /* 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;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Bezier_Down */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Input> */
- /* miny :: The minimum vertical grid coordinate. */
- /* maxy :: The maximum vertical grid coordinate. */
- /* */
- /* <Return> */
- /* 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;
- }
-
-
-/****************************************************************************/
-/* */
-/* <Function> Check_Contour */
-/* */
-/* <Description> */
-/* perform some check at contour closure. */
-/* */
-/* <Return> */
-/* 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;
- }
-
-/****************************************************************************/
-/* */
-/* <Function> Move_To */
-/* */
-/* <Description> */
-/* This function injects a new contour in the render pool.. */
-/* */
-/* <Input> */
-/* to :: pointer to the contour's first point */
-/* raster :: a pointer to the current raster object */
-/* */
-/* <Return> */
-/* Error code, 0 means success */
-/* */
-/* <Note> */
-/* 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;
- }
-
-/****************************************************************************/
-/* */
-/* <Function> Line_To */
-/* */
-/* <Description> */
-/* This function injects a new line segment in the render pool and */
-/* adjusts the profiles list accordingly.. */
-/* */
-/* <Input> */
-/* to :: pointer to the target position */
-/* raster :: a pointer to the current raster object */
-/* */
-/* <Return> */
-/* Error code, 0 means success */
-/* */
-/* <Note> */
-/* 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
-
-/****************************************************************************/
-/* */
-/* <Function> Conic_To */
-/* */
-/* <Description> */
-/* Injects a new conic bezier arc and adjusts the profile list */
-/* accordingly. */
-/* */
-/* <Input> */
-/* control :: pointer to intermediate control point */
-/* to :: pointer to end point */
-/* raster :: handle to current raster object */
-/* */
-/* <Return> */
-/* Error code, 0 means success */
-/* */
-/* <Note> */
-/* 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
-/****************************************************************************/
-/* */
-/* <Function> Cubic_To */
-/* */
-/* <Description> */
-/* Injects a new cubic bezier arc and adjusts the profile list */
-/* accordingly. */
-/* */
-/* <Input> */
-/* control1 :: pointer to first control point */
-/* control2 :: pointer to second control point */
-/* to :: pointer to end point */
-/* raster :: handle to current raster object */
-/* */
-/* <Return> */
-/* Error code, 0 means success */
-/* */
-/* <Note> */
-/* 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 */
-
-
-/****************************************************************************/
-/* */
-/* <Function> Convert_Glyph */
-/* */
-/* <Description> */
-/* Converts a glyph into a series of segments and arcs and makes */
-/* a profiles list with them.. */
-/* */
-/* <Input> */
-/* outline :: glyph outline */
-/* */
-/* <Return> */
-/* 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 *********/
-/******** *********/
-/**************************************************************************/
-/**************************************************************************/
-/**************************************************************************/
-
-
-/***********************************************************************/
-/* */
-/* <Function> Vertical_Sweep_Init */
-/* */
-/* <Description> */
-/* Initialise the vertical bitmap sweep. Called by the generic */
-/* sweep/draw routine before its loop.. */
-/* */
-/* <Input> */
-/* 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;
- }
-
-/***********************************************************************/
-/* */
-/* <Function> Vertical_Sweep_Span */
-/* */
-/* <Description> */
-/* draws a single horizontal bitmap span during the vertical */
-/* bitmap sweep. */
-/* */
-/* <Input> */
-/* 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 );
- }
- }
-
-/***********************************************************************/
-/* */
-/* <Function> Vertical_Test_Pixel */
-/* */
-/* <Description> */
-/* test a pixel 'light' during the vertical bitmap sweep. Used */
-/* during drop-out control only.. */
-/* */
-/* <Input> */
-/* 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)) );
- }
-
-/***********************************************************************/
-/* */
-/* <Function> Vertical_Set_Pixel */
-/* */
-/* <Description> */
-/* Sets a single pixel in a bitmap during the vertical sweep. */
-/* Used during drop-out control.. */
-/* */
-/* <Input> */
-/* 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));
- }
- }
-
-/***********************************************************************/
-/* */
-/* <Function> Vertical_Sweep_Step */
-/* */
-/* <Description> */
-/* 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 *********/
-/******** *********/
-/**************************************************************************/
-/**************************************************************************/
-/**************************************************************************/
-
-/***********************************************************************/
-/* */
-/* <Function> Horizontal_Sweep_Init */
-/* */
-/* <Description> */
-/* Initialise the horizontal bitmap sweep. Called by the generic */
-/* sweep/draw routine before its loop.. */
-/* */
-/* <Input> */
-/* 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;
- }
-
-
-/***********************************************************************/
-/* */
-/* <Function> Horizontal_Sweep_Span */
-/* */
-/* <Description> */
-/* draws a single vertical bitmap span during the horizontal */
-/* bitmap sweep. Actually, this function is only used to */
-/* check for weird drop-out cases.. */
-/* */
-/* <Input> */
-/* 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;
- }
- }
- }
- }
-
-
-/***********************************************************************/
-/* */
-/* <Function> Horizontal_Test_Pixel */
-/* */
-/* <Description> */
-/* test a pixel 'light' during the horizontal bitmap sweep. Used */
-/* during drop-out control only.. */
-/* */
-/* <Input> */
-/* 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) );
- }
-
-/***********************************************************************/
-/* */
-/* <Function> Horizontal_Set_Pixel */
-/* */
-/* <Description> */
-/* Sets a single pixel in a bitmap during the horizontal sweep. */
-/* Used during drop-out control.. */
-/* */
-/* <Input> */
-/* 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;
- }
-
-/***********************************************************************/
-/* */
-/* <Function> Horizontal_Sweep_Step */
-/* */
-/* <Description> */
-/* 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
-/****************************************************************************/
-/* */
-/* <Function> Reset_Palette_5 */
-/* */
-/* <Description> 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
- }
-}
-
-/****************************************************************************/
-/* */
-/* <Function> Reset_Palette_17 */
-/* */
-/* <Description> 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 */
-
-
-
- /**********************************************************************/
- /* */
- /* <Function> FT_Raster_SetPalette */
- /* */
- /* <Description> */
- /* Set the pixmap rendering palette. anti-aliasing modes are */
- /* implemented/possible, they differ from the number of */
- /* entries in the palette. */
- /* */
- /* <Input> */
- /* 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.. */
- /* */
- /* <Return> */
- /* An error code, used as a FT_Error by the FreeType library. */
- /* */
- /* <Note> */
- /* 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 <freetype/internal/ftobjs.h>
-
- 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
- };
-
-
--- a/demos/src/ftrast2.h
+++ /dev/null
@@ -1,41 +1,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 <freetype/ftimage.h>
-
-#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 */
--- a/demos/src/ftview.c
+++ b/demos/src/ftview.c
@@ -16,6 +16,9 @@
/****************************************************************************/
#include <freetype/freetype.h>
+#include <freetype/ftraster.h>
+#include <freetype/ftgrays.h>
+
#include "common.h"
#include <stdio.h>
@@ -26,10 +29,6 @@
#include "graph.h"
#include "grfont.h"
-#include <freetype/ftgrays.h>
-#include "ftrast.h"
-#include "ftrast2.h"
-
#define DIM_X 500
#define DIM_Y 400
@@ -276,7 +275,7 @@
{
if ( !(error = LoadChar( i, hinted )) )
{
-#ifdef DEBUG
+ #ifdef DEBUG
if (i <= first_glyph+6)
{
LOG(( "metrics[%02d] = [%x %x]\n",
@@ -287,8 +286,8 @@
if (i == first_glyph+6)
LOG(( "-------------------------\n"));
}
+ #endif
-#endif
Render_Glyph( x, y );
x += ( glyph->metrics.horiAdvance >> 6 ) + 1;
@@ -337,7 +336,7 @@
{
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 @@
if (i == first_glyph+6)
LOG(( "-------------------------\n"));
}
+ #endif
-#endif
Render_Glyph( x, y );
x += ( glyph->metrics.horiAdvance >> 6 ) + 1;
@@ -421,19 +420,10 @@
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 );
}
--- a/demos/src/t1dump.c
+++ /dev/null
@@ -1,1031 +1,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 <stdio.h>
-#include <stdlib.h>
-
-#include "freetype.h"
-#include <t1tokens.h>
-#include <t1gload.h>
-#include <t1load.h>
-#include <t1parse.h>
-
-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;
- }