diff options
author | Peter Breitenlohner <peb@mppmu.mpg.de> | 2009-03-20 07:35:59 +0000 |
---|---|---|
committer | Peter Breitenlohner <peb@mppmu.mpg.de> | 2009-03-20 07:35:59 +0000 |
commit | 70a2688732ce8e027c0bbf4cbdc55621c9ca5b57 (patch) | |
tree | 0a618c7df46f5a6c6334bcc5b2264cc23ebdbc89 /Build/source/libs/libttf/ttraster.c | |
parent | 200cfaafaed3d870382579503f73a3838b427d51 (diff) |
new build system
git-svn-id: svn://tug.org/texlive/trunk@12443 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/libttf/ttraster.c')
-rw-r--r-- | Build/source/libs/libttf/ttraster.c | 2729 |
1 files changed, 0 insertions, 2729 deletions
diff --git a/Build/source/libs/libttf/ttraster.c b/Build/source/libs/libttf/ttraster.c deleted file mode 100644 index 5daee1439cf..00000000000 --- a/Build/source/libs/libttf/ttraster.c +++ /dev/null @@ -1,2729 +0,0 @@ -/******************************************************************* - * - * ttraster.c 1.5 - * - * The FreeType glyph rasterizer (body). - * - * Copyright 1996-1999 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. - * - * NOTES: - * - * This version supports the following: - * - * - direct grayscaling - * - sub-banding - * - drop-out modes 4 and 5 - * - second pass for complete drop-out control (bitmap only) - * - variable precision - * - * Changes between 1.5 and 1.4: - * - * Performance tuning. - * - * Changes between 1.4 and 1.3: - * - * Mainly performance tunings: - * - * - Line_Down() and Bezier_Down() now use the functions Line_Up() - * and Bezier_Up() to do their work. - * - optimized Split_Bezier() - * - optimized linked lists used during sweeps - * - ******************************************************************/ - -#include "ttraster.h" -#include "ttdebug.h" -#include "tttypes.h" -#include "ttengine.h" -#include "ttcalc.h" /* for TT_MulDiv only */ - -#include "ttmemory.h" /* only used to allocate memory on engine init */ - -/* required by the tracing mode */ -#undef TT_COMPONENT -#define TT_COMPONENT trace_raster - - -/* The default render pool size */ -#define RASTER_RENDER_POOL 64000 - -/* The size of the two-lines intermediate bitmap used */ -/* for anti-aliasing */ -#define RASTER_GRAY_LINES 2048 - - -#define Raster_Err_None TT_Err_Ok -#define Raster_Err_Not_Ini TT_Err_Raster_Not_Initialized -#define Raster_Err_Overflow TT_Err_Raster_Pool_Overflow -#define Raster_Err_Neg_Height TT_Err_Raster_Negative_Height -#define Raster_Err_Invalid TT_Err_Raster_Invalid_Value -#define Raster_Err_Gray_Unsupported TT_Err_Raster_Gray_Unsupported - - -/* 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 TT_MulDiv - - -/* 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 */ -/* "ttconfig.h". */ - -#ifdef DEBUG_RASTER - extern Char* Vio; /* A pointer to VRAM or display buffer */ -#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 - -#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 */ - - /* States of each line, arc and profile */ - enum TStates_ - { - Unknown, - Ascending, - Descending, - Flat - }; - - typedef enum TStates_ TStates; - - struct TProfile_; - typedef struct TProfile_ TProfile; - typedef TProfile* PProfile; - - struct TProfile_ - { - TT_F26Dot6 X; /* current coordinate during sweep */ - PProfile link; /* link to next profile - various purpose */ - PStorage 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; - - - /* I use the classic trick of two dummy records for the head and tail */ - /* of a linked list; this reduces tests in insertion/deletion/sorting. */ - /* NOTE: used during sweeps only. */ - - /* Simple record used to implement a stack of bands, required */ - /* by the sub-banding mechanism */ - - struct TBand_ - { - Short y_min; /* band's minimum */ - Short y_max; /* band's maximum */ - }; - - typedef struct TBand_ TBand; - - -#define AlignProfileSize \ - (( sizeof(TProfile)+sizeof(long)-1 ) / sizeof(long)) - - - /* Left fill bitmask */ - static const Byte LMask[8] = - { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 }; - - /* Right fill bitmask */ - static const Byte RMask[8] = - { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; - - /* 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, - TT_F26Dot6 x1, - TT_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 ) - -#ifdef DEBUG_RASTER -#define DEBUG_PSET Pset() -#else -#define DEBUG_PSET -#endif - - struct TPoint_ - { - Long 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 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 */ - - PStorage buff; /* The profiles buffer */ - PStorage sizeBuff; /* Render pool size */ - PStorage maxBuff; /* Profiles buffer size */ - PStorage top; /* Current cursor in buffer */ - - TT_Error error; - - PByte flags; /* current flags table */ - PUShort outs; /* current outlines table */ - - UShort nPoints; /* number of points in current glyph */ - Short nContours; /* number of contours in current glyph */ - 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 */ - - TT_Raster_Map target; /* description of target bit/pixmap */ - - 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; - - TT_Vector* coords; - - 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 */ - }; - - -#ifdef TT_CONFIG_OPTION_STATIC_RASTER - - static TRaster_Instance cur_ras; -#define ras cur_ras - -#else - -#define ras (*raster) - -#endif /* TT_STATIC_RASTER */ - - -#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.top[-1]; - - switch ( ras.cProfile->flow ) - { - case TT_Flow_Up: - o = Vio_ScanLineWidth * - ( ras.top-ras.cProfile->offset + ras.cProfile->start ) + - ( x / (ras.precision*8) ); - break; - - case TT_Flow_Down: - o = Vio_ScanLineWidth * - ( ras.cProfile->start-ras.top + ras.cProfile->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 Bool 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; - } - - PTRACE7(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); - - 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 */ -/* */ -/* 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 = TT_Flow_Up; - PTRACE7(( "New ascending profile = %lx\n", (long)ras.cProfile )); - break; - - case Descending: - ras.cProfile->flow = TT_Flow_Down; - PTRACE7(( "New descending profile = %lx\n", (long)ras.cProfile )); - break; - - default: - PTRACE0(( "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 ) - { - PTRACE0(( "Negative height encountered in End_Profile!\n" )); - ras.error = Raster_Err_Neg_Height; - return FAILURE; - } - - if ( h > 0 ) - { - PTRACE1(( "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 ) - { - PTRACE1(( "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 ) - { - PStorage 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 TT_Flow_Down: - bottom = p->start - p->height+1; - top = p->start; - p->start = bottom; - p->offset += p->height-1; - break; - - case TT_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_Bezier */ -/* */ -/* Description: Subdivides one Bezier arc 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_Bezier( 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: Push_Bezier */ -/* */ -/* Description: Clears the Bezier stack and pushes a new arc on top of it. */ -/* */ -/* Input: x1,y1 x2,y2 x3,y3 new Bezier arc */ -/* */ -/* Returns: None. */ -/* */ -/****************************************************************************/ - - static void Push_Bezier( RAS_ARGS Long x1, Long y1, - Long x2, Long y2, - Long x3, Long y3 ) - { - ras.arc = ras.arcs; - ras.arc[2].x = x1; ras.arc[2].y = y1; - ras.arc[1].x = x2; ras.arc[1].y = y2; - ras.arc[0].x = x3; ras.arc[0].y = y3; - } - - -/****************************************************************************/ -/* */ -/* 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; - - PStorage 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; - - DEBUG_PSET; - - 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. */ -/* */ -/* Input: None. The arc is taken from the top of the Bezier stack. */ -/* */ -/* Returns: SUCCESS on success. */ -/* FAILURE on Render Pool overflow. */ -/* */ -/****************************************************************************/ - - static Bool Bezier_Up( RAS_ARGS Long miny, Long maxy ) - { - Long y1, y2, e, e2, e0; - Short f1; - - TPoint* arc; - TPoint* start_arc; - - PStorage top; - - - arc = ras.arc; - y1 = arc[2].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[2].x; - - DEBUG_PSET; - - 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[2].y; - if ( y2 - y1 >= ras.precision_step ) - { - Split_Bezier( arc ); - arc += 2; - } - else - { - *top++ = arc[2].x + FMulDiv( arc[0].x - arc[2].x, - e - y1, - y2 - y1 ); - DEBUG_PSET; - - arc -= 2; - e += ras.precision; - } - } - else - { - if ( y2 == e ) - { - ras.joint = TRUE; - *top++ = arc[0].x; - - DEBUG_PSET; - - e += ras.precision; - } - arc -= 2; - } - } - - Fin: - ras.top = top; - ras.arc -= 2; - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* Function: Bezier_Down */ -/* */ -/* Description: Computes the x-coordinates of a descending bezier arc */ -/* and stores them in the render pool. */ -/* */ -/* Input: None. Arc is taken from the top of the Bezier stack. */ -/* */ -/* Returns: SUCCESS on success. */ -/* FAILURE on Render Pool overflow. */ -/* */ -/****************************************************************************/ - - static Bool Bezier_Down( RAS_ARGS 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; - - fresh = ras.fresh; - - result = Bezier_Up( RAS_VARS -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: Bezier_To */ -/* */ -/* Description: Injects a new bezier arc and adjusts the profile list. */ -/* */ -/* Input: x, y : arc endpoint (start point in LastX, LastY) */ -/* Cx, Cy : control point */ -/* */ -/* Returns: SUCCESS on success. */ -/* FAILURE on Render Pool overflow or Incorrect Profile. */ -/* */ -/****************************************************************************/ - - static Bool Bezier_To( RAS_ARGS Long x, - Long y, - Long cx, - Long cy ) - { - Long y1, y2, y3, x3; - TStates state_bez; - - - Push_Bezier( RAS_VARS ras.lastX, ras.lastY, cx, cy, x, 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 == y2 ) - { - if ( y2 == y3 ) - state_bez = Flat; - else if ( y2 > y3 ) - state_bez = Descending; - else - state_bez = Ascending; - } - else if ( y1 > y2 ) - { - if ( y2 >= y3 ) - state_bez = Descending; - else - state_bez = Unknown; - } - else if ( y2 <= y3 ) - state_bez = Ascending; - else - state_bez = Unknown; - - /* 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_Bezier( ras.arc ); - ras.arc += 2; - break; - - default: - /* detect a change of direction */ - - if ( ras.state != state_bez ) - { - if ( ras.state != Unknown ) - if ( End_Profile( RAS_VAR ) ) return FAILURE; - - if ( New_Profile( RAS_VARS state_bez ) ) return FAILURE; - } - - /* compute */ - - switch ( ras.state ) - { - case Ascending: - if ( Bezier_Up ( RAS_VARS ras.minY, ras.maxY ) ) - return FAILURE; - break; - - case Descending: - if ( Bezier_Down( RAS_VARS ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; - } - } - } while ( ras.arc >= ras.arcs ); - - ras.lastX = x3; - ras.lastY = y3; - - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* 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, - Bool flipped ) - { - Long x, y; /* current point */ - Long cx, cy; /* current Bezier control point */ - Long mx, my; /* current middle point */ - - Long x_first, y_first; /* first point's coordinates */ - Long x_last, y_last; /* last point's coordinates */ - - UShort index; /* current point's index */ - Bool on_curve; /* current point's state */ - - x_first = SCALED( ras.coords[first].x ); - y_first = SCALED( ras.coords[first].y ); - - if ( flipped ) SWAP_( x_first,y_first ); - - x_last = SCALED( ras.coords[last].x ); - y_last = SCALED( ras.coords[last].y ); - - if ( flipped ) SWAP_( x_last,y_last ); - - ras.lastX = cx = x_first; - ras.lastY = cy = y_first; - - on_curve = (ras.flags[first] & 1); - index = first; - - /* check first point to determine origin */ - if ( !on_curve ) - { - /* first point is off the curve. Yes, this happens... */ - if ( ras.flags[last] & 1 ) - { - ras.lastX = x_last; /* start at last point if it */ - ras.lastY = y_last; /* is on the curve */ - } - else - { - /* if both first and last points are off the curve, */ - /* start at their middle and record its position */ - /* for closure */ - ras.lastX = (ras.lastX + x_last)/2; - ras.lastY = (ras.lastY + y_last)/2; - - x_last = ras.lastX; - y_last = ras.lastY; - } - } - - /* now process each contour point individually */ - while ( index < last ) - { - index++; - x = SCALED( ras.coords[index].x ); - y = SCALED( ras.coords[index].y ); - - if ( flipped ) SWAP_( x, y ); - - if ( on_curve ) - { - /* the previous point was on the curve */ - on_curve = ( ras.flags[index] & 1 ); - if ( on_curve ) - { - /* two successive on points => emit segment */ - if ( Line_To( RAS_VARS x, y ) ) return FAILURE; - } - else - { - /* else, keep current control point for next bezier */ - cx = x; - cy = y; - } - } - else - { - /* the previous point was off the curve */ - on_curve = ( ras.flags[index] & 1 ); - if ( on_curve ) - { - /* reaching an `on' point */ - if ( Bezier_To( RAS_VARS x, y, cx, cy ) ) return FAILURE; - } - else - { - /* two successive `off' points => create middle point */ - mx = ( cx + x ) / 2; - my = ( cy + y ) / 2; - - if ( Bezier_To( RAS_VARS mx, my, cx, cy ) ) return FAILURE; - - cx = x; - cy = y; - } - } - } - - /* end of contour, close curve cleanly */ - if ( ras.flags[first] & 1 ) - { - if ( on_curve ) - return Line_To( RAS_VARS x_first, y_first ); - else - return Bezier_To( RAS_VARS x_first, y_first, cx, cy ); - } - else - if ( !on_curve ) - return Bezier_To( RAS_VARS x_last, y_last, cx, cy ); - - return SUCCESS; - } - - -/****************************************************************************/ -/* */ -/* 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.nContours; i++ ) - { - ras.state = Unknown; - ras.gProfile = NULL; - - if ( Decompose_Curve( RAS_VARS start, ras.outs[i], flipped ) ) - return FAILURE; - - start = ras.outs[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 ); - } - - -/************************************************/ -/* */ -/* 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 ) - { - switch ( ras.target.flow ) - { - case TT_Flow_Up: - ras.traceOfs = *min * ras.target.cols; - ras.traceIncr = ras.target.cols; - break; - - default: - ras.traceOfs = ( ras.target.rows - 1 - *min ) * ras.target.cols; - ras.traceIncr = -ras.target.cols; - } - - ras.gray_min_x = 0; - ras.gray_max_x = 0; - } - - - static void Vertical_Sweep_Span( RAS_ARGS Short y, - TT_F26Dot6 x1, - TT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - Short c1, c2; - Short f1, f2; - Byte* target; - - - /* 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 = e1 & 7; - f2 = 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; - - if ( c1 != c2 ) - { - *target |= LMask[f1]; - - if ( c2 > c1 + 1 ) - MEM_Set( target + 1, 0xFF, c2 - c1 - 1 ); - - target[c2 - c1] |= RMask[f2]; - } - else - *target |= ( LMask[f1] & RMask[f2] ); - } - } - - - static void Vertical_Sweep_Drop( RAS_ARGS Short y, - TT_F26Dot6 x1, - TT_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 */ - } - - - static void Horizontal_Sweep_Span( RAS_ARGS Short y, - TT_F26Dot6 x1, - TT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - Long e1, e2; - PByte bits; - Byte f1; - - - 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 ) - { - if ( ras.target.flow == TT_Flow_Down ) - bits[(ras.target.rows-1 - e1) * ras.target.cols] |= f1; - else - bits[e1 * ras.target.cols] |= f1; - } - } - } -#if 0 - e2 = TRUNC( e2 ); - - if ( e2 >= 0 && e2 < ras.target.rows ) - if ( ras.target.flow == TT_Flow_Down ) - bits[(ras.target.rows-1-e2) * ras.target.cols] |= f1; - else - bits[e2 * ras.target.cols] |= f1; -#endif - } - - - static void Horizontal_Sweep_Drop( RAS_ARGS Short y, - TT_F26Dot6 x1, - TT_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)); - - if ( ras.target.flow == TT_Flow_Down ) - bits += (ras.target.rows-1-e1) * ras.target.cols; - else - bits += e1 * ras.target.cols; - - 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 ) - { - if (ras.target.flow==TT_Flow_Down) - bits[(ras.target.rows-1-e1) * ras.target.cols] |= f1; - else - bits[e1 * ras.target.cols] |= f1; - } - } - - - static void Horizontal_Sweep_Step( RAS_ARG ) - { - /* Nothing, really */ - } - - -#ifdef TT_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 ) - { - *min = *min & -2; - *max = ( *max + 3 ) & -2; - - ras.traceOfs = 0; - - switch ( ras.target.flow ) - { - case TT_Flow_Up: - ras.traceG = (*min / 2) * ras.target.cols; - ras.traceIncr = ras.target.cols; - break; - - default: - ras.traceG = (ras.target.rows-1 - *min/2) * ras.target.cols; - ras.traceIncr = -ras.target.cols; - } - - ras.gray_min_x = ras.target.cols; - ras.gray_max_x = -ras.target.cols; - } - - - 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 & 0xF000) >> 12]; - pix[1] = grays[(c2 & 0x0F00) >> 8]; - pix[2] = grays[(c2 & 0x00F0) >> 4]; - 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 = ras.target.cols; - ras.gray_max_x = -ras.target.cols; - } - } - - - static void Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, - TT_F26Dot6 x1, - TT_F26Dot6 x2, - PProfile left, - PProfile right ) - { - /* nothing, really */ - } - - static void Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, - TT_F26Dot6 x1, - TT_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 ) - { - if ( ras.target.flow == TT_Flow_Down ) - pixel = ras.gTarget + - (ras.target.rows - 1 - e1) * ras.target.cols + y / 2; - else - pixel = ras.gTarget + - e1 * ras.target.cols + y / 2; - - if (pixel[0] == ras.grays[0]) - pixel[0] = color; - } - } - } - -#endif /* TT_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 = 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.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 TT_Flow_Up: InsNew( &draw_left, P ); break; - case TT_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 TT_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 TT_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 - TT_Error Render_Glyph( RAS_ARGS TT_Outline* glyph, - TT_Raster_Map* target_map ) - { - TT_Error error; - - - if ( glyph->n_points == 0 || glyph->n_contours <= 0 ) - return TT_Err_Ok; - - if ( !ras.buff ) - { - ras.error = Raster_Err_Not_Ini; - return ras.error; - } - - if ( glyph->n_points < glyph->contours[glyph->n_contours - 1] ) - { - ras.error = TT_Err_Too_Many_Points; - return ras.error; - } - - if ( target_map ) - ras.target = *target_map; - - ras.outs = glyph->contours; - ras.flags = glyph->flags; - ras.nPoints = glyph->n_points; - ras.nContours = glyph->n_contours; - ras.coords = glyph->points; - - Set_High_Precision( RAS_VARS glyph->high_precision ); - ras.scale_shift = ras.precision_shift; - ras.dropOutControl = glyph->dropout_mode; - ras.second_pass = glyph->second_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.bitmap; - - 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 TT_Err_Ok; - } - - -#ifdef TT_CONFIG_OPTION_GRAY_SCALING - -/****************************************************************************/ -/* */ -/* 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 - TT_Error Render_Gray_Glyph( RAS_ARGS TT_Outline* glyph, - TT_Raster_Map* target_map, - Byte* palette ) - { - Int i; - TT_Error error; - - if ( !ras.buff ) - { - ras.error = Raster_Err_Not_Ini; - return ras.error; - } - - if ( glyph->n_points == 0 || glyph->n_contours <= 0 ) - return TT_Err_Ok; - - if ( glyph->n_points < glyph->contours[glyph->n_contours - 1] ) - { - ras.error = TT_Err_Too_Many_Points; - return ras.error; - } - - if ( palette ) - { - for ( i = 0; i < 5; i++ ) - ras.grays[i] = palette[i]; - } - - if ( target_map ) - ras.target = *target_map; - - ras.outs = glyph->contours; - ras.flags = glyph->flags; - ras.nPoints = glyph->n_points; - ras.nContours = glyph->n_contours; - ras.coords = glyph->points; - - Set_High_Precision( RAS_VARS glyph->high_precision ); - ras.scale_shift = ras.precision_shift+1; - ras.dropOutControl = glyph->dropout_mode; - ras.second_pass = glyph->second_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; - if ( ras.bWidth > ras.target.cols/4 ) - ras.bWidth = ras.target.cols/4; - - ras.bWidth = ras.bWidth * 8; - ras.bTarget = (Byte*)ras.gray_lines; - ras.gTarget = (Byte*)ras.target.bitmap; - - 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 TT_Err_Ok; - } - -#endif /* TT_CONFIG_OPTION_GRAY_SCALING */ - - -/************************************************/ -/* */ -/* InitRasterizer */ -/* */ -/* Raster Initialization. */ -/* Gets the bitmap description and render pool */ -/* addresses. */ -/* */ -/************************************************/ - -#undef ras - - LOCAL_FUNC - TT_Error TTRaster_Done( PEngine_Instance engine ) - { - TRaster_Instance* ras = (TRaster_Instance*)engine->raster_component; - - - if ( !ras ) - return TT_Err_Ok; - - FREE( ras->buff ); - FREE( ras->gray_lines ); - -#ifndef TT_CONFIG_OPTION_STATIC_RASTER - FREE( engine->raster_component ); -#endif - - return TT_Err_Ok; - } - - - LOCAL_FUNC - TT_Error TTRaster_Init( PEngine_Instance engine ) - { - TT_Error error; - - Int i, l, j, c; - - TRaster_Instance* ras; - - -#ifdef TT_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; - - MUTEX_Create( engine->raster_lock ); - - /* 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 TT_Err_Ok; - } - - -/* END */ |