1*37da2899SCharles.Forsyth /***************************************************************************/ 2*37da2899SCharles.Forsyth /* */ 3*37da2899SCharles.Forsyth /* ftraster.c */ 4*37da2899SCharles.Forsyth /* */ 5*37da2899SCharles.Forsyth /* The FreeType glyph rasterizer (body). */ 6*37da2899SCharles.Forsyth /* */ 7*37da2899SCharles.Forsyth /* Copyright 1996-2001, 2002 by */ 8*37da2899SCharles.Forsyth /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9*37da2899SCharles.Forsyth /* */ 10*37da2899SCharles.Forsyth /* This file is part of the FreeType project, and may only be used, */ 11*37da2899SCharles.Forsyth /* modified, and distributed under the terms of the FreeType project */ 12*37da2899SCharles.Forsyth /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13*37da2899SCharles.Forsyth /* this file you indicate that you have read the license and */ 14*37da2899SCharles.Forsyth /* understand and accept it fully. */ 15*37da2899SCharles.Forsyth /* */ 16*37da2899SCharles.Forsyth /***************************************************************************/ 17*37da2899SCharles.Forsyth 18*37da2899SCharles.Forsyth /*************************************************************************/ 19*37da2899SCharles.Forsyth /* */ 20*37da2899SCharles.Forsyth /* This is a rewrite of the FreeType 1.x scan-line converter */ 21*37da2899SCharles.Forsyth /* */ 22*37da2899SCharles.Forsyth /*************************************************************************/ 23*37da2899SCharles.Forsyth 24*37da2899SCharles.Forsyth 25*37da2899SCharles.Forsyth #include <ft2build.h> 26*37da2899SCharles.Forsyth #include "ftraster.h" 27*37da2899SCharles.Forsyth #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */ 28*37da2899SCharles.Forsyth 29*37da2899SCharles.Forsyth 30*37da2899SCharles.Forsyth /*************************************************************************/ 31*37da2899SCharles.Forsyth /* */ 32*37da2899SCharles.Forsyth /* A simple technical note on how the raster works */ 33*37da2899SCharles.Forsyth /* ----------------------------------------------- */ 34*37da2899SCharles.Forsyth /* */ 35*37da2899SCharles.Forsyth /* Converting an outline into a bitmap is achieved in several steps: */ 36*37da2899SCharles.Forsyth /* */ 37*37da2899SCharles.Forsyth /* 1 - Decomposing the outline into successive `profiles'. Each */ 38*37da2899SCharles.Forsyth /* profile is simply an array of scanline intersections on a given */ 39*37da2899SCharles.Forsyth /* dimension. A profile's main attributes are */ 40*37da2899SCharles.Forsyth /* */ 41*37da2899SCharles.Forsyth /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */ 42*37da2899SCharles.Forsyth /* */ 43*37da2899SCharles.Forsyth /* o an array of intersection coordinates for each scanline */ 44*37da2899SCharles.Forsyth /* between `Ymin' and `Ymax'. */ 45*37da2899SCharles.Forsyth /* */ 46*37da2899SCharles.Forsyth /* o a direction, indicating whether it was built going `up' or */ 47*37da2899SCharles.Forsyth /* `down', as this is very important for filling rules. */ 48*37da2899SCharles.Forsyth /* */ 49*37da2899SCharles.Forsyth /* 2 - Sweeping the target map's scanlines in order to compute segment */ 50*37da2899SCharles.Forsyth /* `spans' which are then filled. Additionally, this pass */ 51*37da2899SCharles.Forsyth /* performs drop-out control. */ 52*37da2899SCharles.Forsyth /* */ 53*37da2899SCharles.Forsyth /* The outline data is parsed during step 1 only. The profiles are */ 54*37da2899SCharles.Forsyth /* built from the bottom of the render pool, used as a stack. The */ 55*37da2899SCharles.Forsyth /* following graphics shows the profile list under construction: */ 56*37da2899SCharles.Forsyth /* */ 57*37da2899SCharles.Forsyth /* ____________________________________________________________ _ _ */ 58*37da2899SCharles.Forsyth /* | | | | | */ 59*37da2899SCharles.Forsyth /* | profile | coordinates for | profile | coordinates for |--> */ 60*37da2899SCharles.Forsyth /* | 1 | profile 1 | 2 | profile 2 |--> */ 61*37da2899SCharles.Forsyth /* |_________|___________________|_________|_________________|__ _ _ */ 62*37da2899SCharles.Forsyth /* */ 63*37da2899SCharles.Forsyth /* ^ ^ */ 64*37da2899SCharles.Forsyth /* | | */ 65*37da2899SCharles.Forsyth /* start of render pool top */ 66*37da2899SCharles.Forsyth /* */ 67*37da2899SCharles.Forsyth /* The top of the profile stack is kept in the `top' variable. */ 68*37da2899SCharles.Forsyth /* */ 69*37da2899SCharles.Forsyth /* As you can see, a profile record is pushed on top of the render */ 70*37da2899SCharles.Forsyth /* pool, which is then followed by its coordinates/intersections. If */ 71*37da2899SCharles.Forsyth /* a change of direction is detected in the outline, a new profile is */ 72*37da2899SCharles.Forsyth /* generated until the end of the outline. */ 73*37da2899SCharles.Forsyth /* */ 74*37da2899SCharles.Forsyth /* Note that when all profiles have been generated, the function */ 75*37da2899SCharles.Forsyth /* Finalize_Profile_Table() is used to record, for each profile, its */ 76*37da2899SCharles.Forsyth /* bottom-most scanline as well as the scanline above its upmost */ 77*37da2899SCharles.Forsyth /* boundary. These positions are called `y-turns' because they (sort */ 78*37da2899SCharles.Forsyth /* of) correspond to local extrema. They are stored in a sorted list */ 79*37da2899SCharles.Forsyth /* built from the top of the render pool as a downwards stack: */ 80*37da2899SCharles.Forsyth /* */ 81*37da2899SCharles.Forsyth /* _ _ _______________________________________ */ 82*37da2899SCharles.Forsyth /* | | */ 83*37da2899SCharles.Forsyth /* <--| sorted list of | */ 84*37da2899SCharles.Forsyth /* <--| extrema scanlines | */ 85*37da2899SCharles.Forsyth /* _ _ __________________|____________________| */ 86*37da2899SCharles.Forsyth /* */ 87*37da2899SCharles.Forsyth /* ^ ^ */ 88*37da2899SCharles.Forsyth /* | | */ 89*37da2899SCharles.Forsyth /* maxBuff sizeBuff = end of pool */ 90*37da2899SCharles.Forsyth /* */ 91*37da2899SCharles.Forsyth /* This list is later used during the sweep phase in order to */ 92*37da2899SCharles.Forsyth /* optimize performance (see technical note on the sweep below). */ 93*37da2899SCharles.Forsyth /* */ 94*37da2899SCharles.Forsyth /* Of course, the raster detects whether the two stacks collide and */ 95*37da2899SCharles.Forsyth /* handles the situation propertly. */ 96*37da2899SCharles.Forsyth /* */ 97*37da2899SCharles.Forsyth /*************************************************************************/ 98*37da2899SCharles.Forsyth 99*37da2899SCharles.Forsyth 100*37da2899SCharles.Forsyth /*************************************************************************/ 101*37da2899SCharles.Forsyth /*************************************************************************/ 102*37da2899SCharles.Forsyth /** **/ 103*37da2899SCharles.Forsyth /** CONFIGURATION MACROS **/ 104*37da2899SCharles.Forsyth /** **/ 105*37da2899SCharles.Forsyth /*************************************************************************/ 106*37da2899SCharles.Forsyth /*************************************************************************/ 107*37da2899SCharles.Forsyth 108*37da2899SCharles.Forsyth /* define DEBUG_RASTER if you want to compile a debugging version */ 109*37da2899SCharles.Forsyth #define xxxDEBUG_RASTER 110*37da2899SCharles.Forsyth 111*37da2899SCharles.Forsyth /* The default render pool size in bytes */ 112*37da2899SCharles.Forsyth #define RASTER_RENDER_POOL 8192 113*37da2899SCharles.Forsyth 114*37da2899SCharles.Forsyth /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */ 115*37da2899SCharles.Forsyth /* 5-levels anti-aliasing */ 116*37da2899SCharles.Forsyth #ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS 117*37da2899SCharles.Forsyth #define FT_RASTER_OPTION_ANTI_ALIASING 118*37da2899SCharles.Forsyth #endif 119*37da2899SCharles.Forsyth 120*37da2899SCharles.Forsyth /* The size of the two-lines intermediate bitmap used */ 121*37da2899SCharles.Forsyth /* for anti-aliasing, in bytes. */ 122*37da2899SCharles.Forsyth #define RASTER_GRAY_LINES 2048 123*37da2899SCharles.Forsyth 124*37da2899SCharles.Forsyth 125*37da2899SCharles.Forsyth /*************************************************************************/ 126*37da2899SCharles.Forsyth /*************************************************************************/ 127*37da2899SCharles.Forsyth /** **/ 128*37da2899SCharles.Forsyth /** OTHER MACROS (do not change) **/ 129*37da2899SCharles.Forsyth /** **/ 130*37da2899SCharles.Forsyth /*************************************************************************/ 131*37da2899SCharles.Forsyth /*************************************************************************/ 132*37da2899SCharles.Forsyth 133*37da2899SCharles.Forsyth /*************************************************************************/ 134*37da2899SCharles.Forsyth /* */ 135*37da2899SCharles.Forsyth /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 136*37da2899SCharles.Forsyth /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 137*37da2899SCharles.Forsyth /* messages during execution. */ 138*37da2899SCharles.Forsyth /* */ 139*37da2899SCharles.Forsyth #undef FT_COMPONENT 140*37da2899SCharles.Forsyth #define FT_COMPONENT trace_raster 141*37da2899SCharles.Forsyth 142*37da2899SCharles.Forsyth 143*37da2899SCharles.Forsyth #ifdef _STANDALONE_ 144*37da2899SCharles.Forsyth 145*37da2899SCharles.Forsyth 146*37da2899SCharles.Forsyth /* This macro is used to indicate that a function parameter is unused. */ 147*37da2899SCharles.Forsyth /* Its purpose is simply to reduce compiler warnings. Note also that */ 148*37da2899SCharles.Forsyth /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 149*37da2899SCharles.Forsyth /* ANSI compilers (e.g. LCC). */ 150*37da2899SCharles.Forsyth #define FT_UNUSED( x ) (x) = (x) 151*37da2899SCharles.Forsyth 152*37da2899SCharles.Forsyth /* Disable the tracing mechanism for simplicity -- developers can */ 153*37da2899SCharles.Forsyth /* activate it easily by redefining these two macros. */ 154*37da2899SCharles.Forsyth #ifndef FT_ERROR 155*37da2899SCharles.Forsyth #define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ 156*37da2899SCharles.Forsyth #endif 157*37da2899SCharles.Forsyth 158*37da2899SCharles.Forsyth #ifndef FT_TRACE 159*37da2899SCharles.Forsyth #define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ 160*37da2899SCharles.Forsyth #endif 161*37da2899SCharles.Forsyth 162*37da2899SCharles.Forsyth #define Raster_Err_None 0 163*37da2899SCharles.Forsyth #define Raster_Err_Not_Ini -1 164*37da2899SCharles.Forsyth #define Raster_Err_Overflow -2 165*37da2899SCharles.Forsyth #define Raster_Err_Neg_Height -3 166*37da2899SCharles.Forsyth #define Raster_Err_Invalid -4 167*37da2899SCharles.Forsyth #define Raster_Err_Unsupported -5 168*37da2899SCharles.Forsyth 169*37da2899SCharles.Forsyth 170*37da2899SCharles.Forsyth #else /* _STANDALONE_ */ 171*37da2899SCharles.Forsyth 172*37da2899SCharles.Forsyth 173*37da2899SCharles.Forsyth #include FT_INTERNAL_OBJECTS_H 174*37da2899SCharles.Forsyth #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */ 175*37da2899SCharles.Forsyth 176*37da2899SCharles.Forsyth #include "rasterrs.h" 177*37da2899SCharles.Forsyth 178*37da2899SCharles.Forsyth #define Raster_Err_None Raster_Err_Ok 179*37da2899SCharles.Forsyth #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized 180*37da2899SCharles.Forsyth #define Raster_Err_Overflow Raster_Err_Raster_Overflow 181*37da2899SCharles.Forsyth #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height 182*37da2899SCharles.Forsyth #define Raster_Err_Invalid Raster_Err_Invalid_Outline 183*37da2899SCharles.Forsyth #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph 184*37da2899SCharles.Forsyth 185*37da2899SCharles.Forsyth 186*37da2899SCharles.Forsyth #endif /* _STANDALONE_ */ 187*37da2899SCharles.Forsyth 188*37da2899SCharles.Forsyth 189*37da2899SCharles.Forsyth #ifndef FT_MEM_SET 190*37da2899SCharles.Forsyth #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) 191*37da2899SCharles.Forsyth #endif 192*37da2899SCharles.Forsyth 193*37da2899SCharles.Forsyth 194*37da2899SCharles.Forsyth /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ 195*37da2899SCharles.Forsyth /* typically a small value and the result of a*b is known to fit into */ 196*37da2899SCharles.Forsyth /* 32 bits. */ 197*37da2899SCharles.Forsyth #define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsyth /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ 200*37da2899SCharles.Forsyth /* for clipping computations. It simply uses the FT_MulDiv() function */ 201*37da2899SCharles.Forsyth /* defined in `ftcalc.h'. */ 202*37da2899SCharles.Forsyth #define SMulDiv FT_MulDiv 203*37da2899SCharles.Forsyth 204*37da2899SCharles.Forsyth /* The rasterizer is a very general purpose component; please leave */ 205*37da2899SCharles.Forsyth /* the following redefinitions there (you never know your target */ 206*37da2899SCharles.Forsyth /* environment). */ 207*37da2899SCharles.Forsyth 208*37da2899SCharles.Forsyth #ifndef TRUE 209*37da2899SCharles.Forsyth #define TRUE 1 210*37da2899SCharles.Forsyth #endif 211*37da2899SCharles.Forsyth 212*37da2899SCharles.Forsyth #ifndef FALSE 213*37da2899SCharles.Forsyth #define FALSE 0 214*37da2899SCharles.Forsyth #endif 215*37da2899SCharles.Forsyth 216*37da2899SCharles.Forsyth #ifndef NULL 217*37da2899SCharles.Forsyth #define NULL (void*)0 218*37da2899SCharles.Forsyth #endif 219*37da2899SCharles.Forsyth 220*37da2899SCharles.Forsyth #ifndef SUCCESS 221*37da2899SCharles.Forsyth #define SUCCESS 0 222*37da2899SCharles.Forsyth #endif 223*37da2899SCharles.Forsyth 224*37da2899SCharles.Forsyth #ifndef FAILURE 225*37da2899SCharles.Forsyth #define FAILURE 1 226*37da2899SCharles.Forsyth #endif 227*37da2899SCharles.Forsyth 228*37da2899SCharles.Forsyth 229*37da2899SCharles.Forsyth #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ 230*37da2899SCharles.Forsyth /* Setting this constant to more than 32 is a */ 231*37da2899SCharles.Forsyth /* pure waste of space. */ 232*37da2899SCharles.Forsyth 233*37da2899SCharles.Forsyth #define Pixel_Bits 6 /* fractional bits of *input* coordinates */ 234*37da2899SCharles.Forsyth 235*37da2899SCharles.Forsyth 236*37da2899SCharles.Forsyth /*************************************************************************/ 237*37da2899SCharles.Forsyth /*************************************************************************/ 238*37da2899SCharles.Forsyth /** **/ 239*37da2899SCharles.Forsyth /** SIMPLE TYPE DECLARATIONS **/ 240*37da2899SCharles.Forsyth /** **/ 241*37da2899SCharles.Forsyth /*************************************************************************/ 242*37da2899SCharles.Forsyth /*************************************************************************/ 243*37da2899SCharles.Forsyth 244*37da2899SCharles.Forsyth typedef int Int; 245*37da2899SCharles.Forsyth typedef unsigned int UInt; 246*37da2899SCharles.Forsyth typedef short Short; 247*37da2899SCharles.Forsyth typedef unsigned short UShort, *PUShort; 248*37da2899SCharles.Forsyth typedef long Long, *PLong; 249*37da2899SCharles.Forsyth typedef unsigned long ULong; 250*37da2899SCharles.Forsyth 251*37da2899SCharles.Forsyth typedef unsigned char Byte, *PByte; 252*37da2899SCharles.Forsyth typedef char Bool; 253*37da2899SCharles.Forsyth 254*37da2899SCharles.Forsyth typedef struct TPoint_ 255*37da2899SCharles.Forsyth { 256*37da2899SCharles.Forsyth Long x; 257*37da2899SCharles.Forsyth Long y; 258*37da2899SCharles.Forsyth 259*37da2899SCharles.Forsyth } TPoint; 260*37da2899SCharles.Forsyth 261*37da2899SCharles.Forsyth 262*37da2899SCharles.Forsyth typedef enum TFlow_ 263*37da2899SCharles.Forsyth { 264*37da2899SCharles.Forsyth Flow_None = 0, 265*37da2899SCharles.Forsyth Flow_Up = 1, 266*37da2899SCharles.Forsyth Flow_Down = -1 267*37da2899SCharles.Forsyth 268*37da2899SCharles.Forsyth } TFlow; 269*37da2899SCharles.Forsyth 270*37da2899SCharles.Forsyth 271*37da2899SCharles.Forsyth /* States of each line, arc, and profile */ 272*37da2899SCharles.Forsyth typedef enum TStates_ 273*37da2899SCharles.Forsyth { 274*37da2899SCharles.Forsyth Unknown_State, 275*37da2899SCharles.Forsyth Ascending_State, 276*37da2899SCharles.Forsyth Descending_State, 277*37da2899SCharles.Forsyth Flat_State 278*37da2899SCharles.Forsyth 279*37da2899SCharles.Forsyth } TStates; 280*37da2899SCharles.Forsyth 281*37da2899SCharles.Forsyth 282*37da2899SCharles.Forsyth typedef struct TProfile_ TProfile; 283*37da2899SCharles.Forsyth typedef TProfile* PProfile; 284*37da2899SCharles.Forsyth 285*37da2899SCharles.Forsyth struct TProfile_ 286*37da2899SCharles.Forsyth { 287*37da2899SCharles.Forsyth FT_F26Dot6 X; /* current coordinate during sweep */ 288*37da2899SCharles.Forsyth PProfile link; /* link to next profile - various purpose */ 289*37da2899SCharles.Forsyth PLong offset; /* start of profile's data in render pool */ 290*37da2899SCharles.Forsyth int flow; /* Profile orientation: Asc/Descending */ 291*37da2899SCharles.Forsyth long height; /* profile's height in scanlines */ 292*37da2899SCharles.Forsyth long start; /* profile's starting scanline */ 293*37da2899SCharles.Forsyth 294*37da2899SCharles.Forsyth unsigned countL; /* number of lines to step before this */ 295*37da2899SCharles.Forsyth /* profile becomes drawable */ 296*37da2899SCharles.Forsyth 297*37da2899SCharles.Forsyth PProfile next; /* next profile in same contour, used */ 298*37da2899SCharles.Forsyth /* during drop-out control */ 299*37da2899SCharles.Forsyth }; 300*37da2899SCharles.Forsyth 301*37da2899SCharles.Forsyth typedef PProfile TProfileList; 302*37da2899SCharles.Forsyth typedef PProfile* PProfileList; 303*37da2899SCharles.Forsyth 304*37da2899SCharles.Forsyth 305*37da2899SCharles.Forsyth /* Simple record used to implement a stack of bands, required */ 306*37da2899SCharles.Forsyth /* by the sub-banding mechanism */ 307*37da2899SCharles.Forsyth typedef struct TBand_ 308*37da2899SCharles.Forsyth { 309*37da2899SCharles.Forsyth Short y_min; /* band's minimum */ 310*37da2899SCharles.Forsyth Short y_max; /* band's maximum */ 311*37da2899SCharles.Forsyth 312*37da2899SCharles.Forsyth } TBand; 313*37da2899SCharles.Forsyth 314*37da2899SCharles.Forsyth 315*37da2899SCharles.Forsyth #define AlignProfileSize \ 316*37da2899SCharles.Forsyth ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) ) 317*37da2899SCharles.Forsyth 318*37da2899SCharles.Forsyth 319*37da2899SCharles.Forsyth #ifdef TT_STATIC_RASTER 320*37da2899SCharles.Forsyth 321*37da2899SCharles.Forsyth 322*37da2899SCharles.Forsyth #define RAS_ARGS /* void */ 323*37da2899SCharles.Forsyth #define RAS_ARG /* void */ 324*37da2899SCharles.Forsyth 325*37da2899SCharles.Forsyth #define RAS_VARS /* void */ 326*37da2899SCharles.Forsyth #define RAS_VAR /* void */ 327*37da2899SCharles.Forsyth 328*37da2899SCharles.Forsyth #define FT_UNUSED_RASTER do ; while ( 0 ) 329*37da2899SCharles.Forsyth 330*37da2899SCharles.Forsyth 331*37da2899SCharles.Forsyth #else /* TT_STATIC_RASTER */ 332*37da2899SCharles.Forsyth 333*37da2899SCharles.Forsyth 334*37da2899SCharles.Forsyth #define RAS_ARGS TRaster_Instance* raster, 335*37da2899SCharles.Forsyth #define RAS_ARG TRaster_Instance* raster 336*37da2899SCharles.Forsyth 337*37da2899SCharles.Forsyth #define RAS_VARS raster, 338*37da2899SCharles.Forsyth #define RAS_VAR raster 339*37da2899SCharles.Forsyth 340*37da2899SCharles.Forsyth #define FT_UNUSED_RASTER FT_UNUSED( raster ) 341*37da2899SCharles.Forsyth 342*37da2899SCharles.Forsyth 343*37da2899SCharles.Forsyth #endif /* TT_STATIC_RASTER */ 344*37da2899SCharles.Forsyth 345*37da2899SCharles.Forsyth 346*37da2899SCharles.Forsyth typedef struct TRaster_Instance_ TRaster_Instance; 347*37da2899SCharles.Forsyth 348*37da2899SCharles.Forsyth 349*37da2899SCharles.Forsyth /* prototypes used for sweep function dispatch */ 350*37da2899SCharles.Forsyth typedef void 351*37da2899SCharles.Forsyth Function_Sweep_Init( RAS_ARGS Short* min, 352*37da2899SCharles.Forsyth Short* max ); 353*37da2899SCharles.Forsyth 354*37da2899SCharles.Forsyth typedef void 355*37da2899SCharles.Forsyth Function_Sweep_Span( RAS_ARGS Short y, 356*37da2899SCharles.Forsyth FT_F26Dot6 x1, 357*37da2899SCharles.Forsyth FT_F26Dot6 x2, 358*37da2899SCharles.Forsyth PProfile left, 359*37da2899SCharles.Forsyth PProfile right ); 360*37da2899SCharles.Forsyth 361*37da2899SCharles.Forsyth typedef void 362*37da2899SCharles.Forsyth Function_Sweep_Step( RAS_ARG ); 363*37da2899SCharles.Forsyth 364*37da2899SCharles.Forsyth 365*37da2899SCharles.Forsyth /* NOTE: These operations are only valid on 2's complement processors */ 366*37da2899SCharles.Forsyth 367*37da2899SCharles.Forsyth #define FLOOR( x ) ( (x) & -ras.precision ) 368*37da2899SCharles.Forsyth #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) 369*37da2899SCharles.Forsyth #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) 370*37da2899SCharles.Forsyth #define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) 371*37da2899SCharles.Forsyth #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) 372*37da2899SCharles.Forsyth 373*37da2899SCharles.Forsyth /* Note that I have moved the location of some fields in the */ 374*37da2899SCharles.Forsyth /* structure to ensure that the most used variables are used */ 375*37da2899SCharles.Forsyth /* at the top. Thus, their offset can be coded with less */ 376*37da2899SCharles.Forsyth /* opcodes, and it results in a smaller executable. */ 377*37da2899SCharles.Forsyth 378*37da2899SCharles.Forsyth struct TRaster_Instance_ 379*37da2899SCharles.Forsyth { 380*37da2899SCharles.Forsyth Int precision_bits; /* precision related variables */ 381*37da2899SCharles.Forsyth Int precision; 382*37da2899SCharles.Forsyth Int precision_half; 383*37da2899SCharles.Forsyth Long precision_mask; 384*37da2899SCharles.Forsyth Int precision_shift; 385*37da2899SCharles.Forsyth Int precision_step; 386*37da2899SCharles.Forsyth Int precision_jitter; 387*37da2899SCharles.Forsyth 388*37da2899SCharles.Forsyth Int scale_shift; /* == precision_shift for bitmaps */ 389*37da2899SCharles.Forsyth /* == precision_shift+1 for pixmaps */ 390*37da2899SCharles.Forsyth 391*37da2899SCharles.Forsyth PLong buff; /* The profiles buffer */ 392*37da2899SCharles.Forsyth PLong sizeBuff; /* Render pool size */ 393*37da2899SCharles.Forsyth PLong maxBuff; /* Profiles buffer size */ 394*37da2899SCharles.Forsyth PLong top; /* Current cursor in buffer */ 395*37da2899SCharles.Forsyth 396*37da2899SCharles.Forsyth FT_Error error; 397*37da2899SCharles.Forsyth 398*37da2899SCharles.Forsyth Int numTurns; /* number of Y-turns in outline */ 399*37da2899SCharles.Forsyth 400*37da2899SCharles.Forsyth TPoint* arc; /* current Bezier arc pointer */ 401*37da2899SCharles.Forsyth 402*37da2899SCharles.Forsyth UShort bWidth; /* target bitmap width */ 403*37da2899SCharles.Forsyth PByte bTarget; /* target bitmap buffer */ 404*37da2899SCharles.Forsyth PByte gTarget; /* target pixmap buffer */ 405*37da2899SCharles.Forsyth 406*37da2899SCharles.Forsyth Long lastX, lastY, minY, maxY; 407*37da2899SCharles.Forsyth 408*37da2899SCharles.Forsyth UShort num_Profs; /* current number of profiles */ 409*37da2899SCharles.Forsyth 410*37da2899SCharles.Forsyth Bool fresh; /* signals a fresh new profile which */ 411*37da2899SCharles.Forsyth /* 'start' field must be completed */ 412*37da2899SCharles.Forsyth Bool joint; /* signals that the last arc ended */ 413*37da2899SCharles.Forsyth /* exactly on a scanline. Allows */ 414*37da2899SCharles.Forsyth /* removal of doublets */ 415*37da2899SCharles.Forsyth PProfile cProfile; /* current profile */ 416*37da2899SCharles.Forsyth PProfile fProfile; /* head of linked list of profiles */ 417*37da2899SCharles.Forsyth PProfile gProfile; /* contour's first profile in case */ 418*37da2899SCharles.Forsyth /* of impact */ 419*37da2899SCharles.Forsyth 420*37da2899SCharles.Forsyth TStates state; /* rendering state */ 421*37da2899SCharles.Forsyth 422*37da2899SCharles.Forsyth FT_Bitmap target; /* description of target bit/pixmap */ 423*37da2899SCharles.Forsyth FT_Outline outline; 424*37da2899SCharles.Forsyth 425*37da2899SCharles.Forsyth Long traceOfs; /* current offset in target bitmap */ 426*37da2899SCharles.Forsyth Long traceG; /* current offset in target pixmap */ 427*37da2899SCharles.Forsyth 428*37da2899SCharles.Forsyth Short traceIncr; /* sweep's increment in target bitmap */ 429*37da2899SCharles.Forsyth 430*37da2899SCharles.Forsyth Short gray_min_x; /* current min x during gray rendering */ 431*37da2899SCharles.Forsyth Short gray_max_x; /* current max x during gray rendering */ 432*37da2899SCharles.Forsyth 433*37da2899SCharles.Forsyth /* dispatch variables */ 434*37da2899SCharles.Forsyth 435*37da2899SCharles.Forsyth Function_Sweep_Init* Proc_Sweep_Init; 436*37da2899SCharles.Forsyth Function_Sweep_Span* Proc_Sweep_Span; 437*37da2899SCharles.Forsyth Function_Sweep_Span* Proc_Sweep_Drop; 438*37da2899SCharles.Forsyth Function_Sweep_Step* Proc_Sweep_Step; 439*37da2899SCharles.Forsyth 440*37da2899SCharles.Forsyth Byte dropOutControl; /* current drop_out control method */ 441*37da2899SCharles.Forsyth 442*37da2899SCharles.Forsyth Bool second_pass; /* indicates wether a horizontal pass */ 443*37da2899SCharles.Forsyth /* should be performed to control */ 444*37da2899SCharles.Forsyth /* drop-out accurately when calling */ 445*37da2899SCharles.Forsyth /* Render_Glyph. Note that there is */ 446*37da2899SCharles.Forsyth /* no horizontal pass during gray */ 447*37da2899SCharles.Forsyth /* rendering. */ 448*37da2899SCharles.Forsyth 449*37da2899SCharles.Forsyth TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ 450*37da2899SCharles.Forsyth 451*37da2899SCharles.Forsyth TBand band_stack[16]; /* band stack used for sub-banding */ 452*37da2899SCharles.Forsyth Int band_top; /* band stack top */ 453*37da2899SCharles.Forsyth 454*37da2899SCharles.Forsyth Int count_table[256]; /* Look-up table used to quickly count */ 455*37da2899SCharles.Forsyth /* set bits in a gray 2x2 cell */ 456*37da2899SCharles.Forsyth 457*37da2899SCharles.Forsyth void* memory; 458*37da2899SCharles.Forsyth 459*37da2899SCharles.Forsyth #ifdef FT_RASTER_OPTION_ANTI_ALIASING 460*37da2899SCharles.Forsyth 461*37da2899SCharles.Forsyth Byte grays[5]; /* Palette of gray levels used for */ 462*37da2899SCharles.Forsyth /* render. */ 463*37da2899SCharles.Forsyth 464*37da2899SCharles.Forsyth Byte gray_lines[RASTER_GRAY_LINES]; 465*37da2899SCharles.Forsyth /* Intermediate table used to render the */ 466*37da2899SCharles.Forsyth /* graylevels pixmaps. */ 467*37da2899SCharles.Forsyth /* gray_lines is a buffer holding two */ 468*37da2899SCharles.Forsyth /* monochrome scanlines */ 469*37da2899SCharles.Forsyth 470*37da2899SCharles.Forsyth Short gray_width; /* width in bytes of one monochrome */ 471*37da2899SCharles.Forsyth /* intermediate scanline of gray_lines. */ 472*37da2899SCharles.Forsyth /* Each gray pixel takes 2 bits long there */ 473*37da2899SCharles.Forsyth 474*37da2899SCharles.Forsyth /* The gray_lines must hold 2 lines, thus with size */ 475*37da2899SCharles.Forsyth /* in bytes of at least `gray_width*2'. */ 476*37da2899SCharles.Forsyth 477*37da2899SCharles.Forsyth #endif /* FT_RASTER_ANTI_ALIASING */ 478*37da2899SCharles.Forsyth 479*37da2899SCharles.Forsyth #if 0 480*37da2899SCharles.Forsyth PByte flags; /* current flags table */ 481*37da2899SCharles.Forsyth PUShort outs; /* current outlines table */ 482*37da2899SCharles.Forsyth FT_Vector* coords; 483*37da2899SCharles.Forsyth 484*37da2899SCharles.Forsyth UShort nPoints; /* number of points in current glyph */ 485*37da2899SCharles.Forsyth Short nContours; /* number of contours in current glyph */ 486*37da2899SCharles.Forsyth #endif 487*37da2899SCharles.Forsyth 488*37da2899SCharles.Forsyth }; 489*37da2899SCharles.Forsyth 490*37da2899SCharles.Forsyth 491*37da2899SCharles.Forsyth #ifdef FT_CONFIG_OPTION_STATIC_RASTER 492*37da2899SCharles.Forsyth 493*37da2899SCharles.Forsyth static TRaster_Instance cur_ras; 494*37da2899SCharles.Forsyth #define ras cur_ras 495*37da2899SCharles.Forsyth 496*37da2899SCharles.Forsyth #else 497*37da2899SCharles.Forsyth 498*37da2899SCharles.Forsyth #define ras (*raster) 499*37da2899SCharles.Forsyth 500*37da2899SCharles.Forsyth #endif /* FT_CONFIG_OPTION_STATIC_RASTER */ 501*37da2899SCharles.Forsyth 502*37da2899SCharles.Forsyth 503*37da2899SCharles.Forsyth /*************************************************************************/ 504*37da2899SCharles.Forsyth /*************************************************************************/ 505*37da2899SCharles.Forsyth /** **/ 506*37da2899SCharles.Forsyth /** PROFILES COMPUTATION **/ 507*37da2899SCharles.Forsyth /** **/ 508*37da2899SCharles.Forsyth /*************************************************************************/ 509*37da2899SCharles.Forsyth /*************************************************************************/ 510*37da2899SCharles.Forsyth 511*37da2899SCharles.Forsyth 512*37da2899SCharles.Forsyth /*************************************************************************/ 513*37da2899SCharles.Forsyth /* */ 514*37da2899SCharles.Forsyth /* <Function> */ 515*37da2899SCharles.Forsyth /* Set_High_Precision */ 516*37da2899SCharles.Forsyth /* */ 517*37da2899SCharles.Forsyth /* <Description> */ 518*37da2899SCharles.Forsyth /* Sets precision variables according to param flag. */ 519*37da2899SCharles.Forsyth /* */ 520*37da2899SCharles.Forsyth /* <Input> */ 521*37da2899SCharles.Forsyth /* High :: Set to True for high precision (typically for ppem < 18), */ 522*37da2899SCharles.Forsyth /* false otherwise. */ 523*37da2899SCharles.Forsyth /* */ 524*37da2899SCharles.Forsyth static void Set_High_Precision(RAS_ARGS Int High)525*37da2899SCharles.Forsyth Set_High_Precision( RAS_ARGS Int High ) 526*37da2899SCharles.Forsyth { 527*37da2899SCharles.Forsyth if ( High ) 528*37da2899SCharles.Forsyth { 529*37da2899SCharles.Forsyth ras.precision_bits = 10; 530*37da2899SCharles.Forsyth ras.precision_step = 128; 531*37da2899SCharles.Forsyth ras.precision_jitter = 24; 532*37da2899SCharles.Forsyth } 533*37da2899SCharles.Forsyth else 534*37da2899SCharles.Forsyth { 535*37da2899SCharles.Forsyth ras.precision_bits = 6; 536*37da2899SCharles.Forsyth ras.precision_step = 32; 537*37da2899SCharles.Forsyth ras.precision_jitter = 2; 538*37da2899SCharles.Forsyth } 539*37da2899SCharles.Forsyth 540*37da2899SCharles.Forsyth FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); 541*37da2899SCharles.Forsyth 542*37da2899SCharles.Forsyth ras.precision = 1 << ras.precision_bits; 543*37da2899SCharles.Forsyth ras.precision_half = ras.precision / 2; 544*37da2899SCharles.Forsyth ras.precision_shift = ras.precision_bits - Pixel_Bits; 545*37da2899SCharles.Forsyth ras.precision_mask = -ras.precision; 546*37da2899SCharles.Forsyth } 547*37da2899SCharles.Forsyth 548*37da2899SCharles.Forsyth 549*37da2899SCharles.Forsyth /*************************************************************************/ 550*37da2899SCharles.Forsyth /* */ 551*37da2899SCharles.Forsyth /* <Function> */ 552*37da2899SCharles.Forsyth /* New_Profile */ 553*37da2899SCharles.Forsyth /* */ 554*37da2899SCharles.Forsyth /* <Description> */ 555*37da2899SCharles.Forsyth /* Creates a new profile in the render pool. */ 556*37da2899SCharles.Forsyth /* */ 557*37da2899SCharles.Forsyth /* <Input> */ 558*37da2899SCharles.Forsyth /* aState :: The state/orientation of the new profile. */ 559*37da2899SCharles.Forsyth /* */ 560*37da2899SCharles.Forsyth /* <Return> */ 561*37da2899SCharles.Forsyth /* SUCCESS on success. FAILURE in case of overflow or of incoherent */ 562*37da2899SCharles.Forsyth /* profile. */ 563*37da2899SCharles.Forsyth /* */ 564*37da2899SCharles.Forsyth static Bool New_Profile(RAS_ARGS TStates aState)565*37da2899SCharles.Forsyth New_Profile( RAS_ARGS TStates aState ) 566*37da2899SCharles.Forsyth { 567*37da2899SCharles.Forsyth if ( !ras.fProfile ) 568*37da2899SCharles.Forsyth { 569*37da2899SCharles.Forsyth ras.cProfile = (PProfile)ras.top; 570*37da2899SCharles.Forsyth ras.fProfile = ras.cProfile; 571*37da2899SCharles.Forsyth ras.top += AlignProfileSize; 572*37da2899SCharles.Forsyth } 573*37da2899SCharles.Forsyth 574*37da2899SCharles.Forsyth if ( ras.top >= ras.maxBuff ) 575*37da2899SCharles.Forsyth { 576*37da2899SCharles.Forsyth ras.error = Raster_Err_Overflow; 577*37da2899SCharles.Forsyth return FAILURE; 578*37da2899SCharles.Forsyth } 579*37da2899SCharles.Forsyth 580*37da2899SCharles.Forsyth switch ( aState ) 581*37da2899SCharles.Forsyth { 582*37da2899SCharles.Forsyth case Ascending_State: 583*37da2899SCharles.Forsyth ras.cProfile->flow = Flow_Up; 584*37da2899SCharles.Forsyth FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile )); 585*37da2899SCharles.Forsyth break; 586*37da2899SCharles.Forsyth 587*37da2899SCharles.Forsyth case Descending_State: 588*37da2899SCharles.Forsyth ras.cProfile->flow = Flow_Down; 589*37da2899SCharles.Forsyth FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile )); 590*37da2899SCharles.Forsyth break; 591*37da2899SCharles.Forsyth 592*37da2899SCharles.Forsyth default: 593*37da2899SCharles.Forsyth FT_ERROR(( "New_Profile: invalid profile direction!\n" )); 594*37da2899SCharles.Forsyth ras.error = Raster_Err_Invalid; 595*37da2899SCharles.Forsyth return FAILURE; 596*37da2899SCharles.Forsyth } 597*37da2899SCharles.Forsyth 598*37da2899SCharles.Forsyth ras.cProfile->start = 0; 599*37da2899SCharles.Forsyth ras.cProfile->height = 0; 600*37da2899SCharles.Forsyth ras.cProfile->offset = ras.top; 601*37da2899SCharles.Forsyth ras.cProfile->link = (PProfile)0; 602*37da2899SCharles.Forsyth ras.cProfile->next = (PProfile)0; 603*37da2899SCharles.Forsyth 604*37da2899SCharles.Forsyth if ( !ras.gProfile ) 605*37da2899SCharles.Forsyth ras.gProfile = ras.cProfile; 606*37da2899SCharles.Forsyth 607*37da2899SCharles.Forsyth ras.state = aState; 608*37da2899SCharles.Forsyth ras.fresh = TRUE; 609*37da2899SCharles.Forsyth ras.joint = FALSE; 610*37da2899SCharles.Forsyth 611*37da2899SCharles.Forsyth return SUCCESS; 612*37da2899SCharles.Forsyth } 613*37da2899SCharles.Forsyth 614*37da2899SCharles.Forsyth 615*37da2899SCharles.Forsyth /*************************************************************************/ 616*37da2899SCharles.Forsyth /* */ 617*37da2899SCharles.Forsyth /* <Function> */ 618*37da2899SCharles.Forsyth /* End_Profile */ 619*37da2899SCharles.Forsyth /* */ 620*37da2899SCharles.Forsyth /* <Description> */ 621*37da2899SCharles.Forsyth /* Finalizes the current profile. */ 622*37da2899SCharles.Forsyth /* */ 623*37da2899SCharles.Forsyth /* <Return> */ 624*37da2899SCharles.Forsyth /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ 625*37da2899SCharles.Forsyth /* */ 626*37da2899SCharles.Forsyth static Bool End_Profile(RAS_ARG)627*37da2899SCharles.Forsyth End_Profile( RAS_ARG ) 628*37da2899SCharles.Forsyth { 629*37da2899SCharles.Forsyth Long h; 630*37da2899SCharles.Forsyth PProfile oldProfile; 631*37da2899SCharles.Forsyth 632*37da2899SCharles.Forsyth 633*37da2899SCharles.Forsyth h = (Long)( ras.top - ras.cProfile->offset ); 634*37da2899SCharles.Forsyth 635*37da2899SCharles.Forsyth if ( h < 0 ) 636*37da2899SCharles.Forsyth { 637*37da2899SCharles.Forsyth FT_ERROR(( "End_Profile: negative height encountered!\n" )); 638*37da2899SCharles.Forsyth ras.error = Raster_Err_Neg_Height; 639*37da2899SCharles.Forsyth return FAILURE; 640*37da2899SCharles.Forsyth } 641*37da2899SCharles.Forsyth 642*37da2899SCharles.Forsyth if ( h > 0 ) 643*37da2899SCharles.Forsyth { 644*37da2899SCharles.Forsyth FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n", 645*37da2899SCharles.Forsyth (long)ras.cProfile, ras.cProfile->start, h )); 646*37da2899SCharles.Forsyth 647*37da2899SCharles.Forsyth oldProfile = ras.cProfile; 648*37da2899SCharles.Forsyth ras.cProfile->height = h; 649*37da2899SCharles.Forsyth ras.cProfile = (PProfile)ras.top; 650*37da2899SCharles.Forsyth 651*37da2899SCharles.Forsyth ras.top += AlignProfileSize; 652*37da2899SCharles.Forsyth 653*37da2899SCharles.Forsyth ras.cProfile->height = 0; 654*37da2899SCharles.Forsyth ras.cProfile->offset = ras.top; 655*37da2899SCharles.Forsyth oldProfile->next = ras.cProfile; 656*37da2899SCharles.Forsyth ras.num_Profs++; 657*37da2899SCharles.Forsyth } 658*37da2899SCharles.Forsyth 659*37da2899SCharles.Forsyth if ( ras.top >= ras.maxBuff ) 660*37da2899SCharles.Forsyth { 661*37da2899SCharles.Forsyth FT_TRACE1(( "overflow in End_Profile\n" )); 662*37da2899SCharles.Forsyth ras.error = Raster_Err_Overflow; 663*37da2899SCharles.Forsyth return FAILURE; 664*37da2899SCharles.Forsyth } 665*37da2899SCharles.Forsyth 666*37da2899SCharles.Forsyth ras.joint = FALSE; 667*37da2899SCharles.Forsyth 668*37da2899SCharles.Forsyth return SUCCESS; 669*37da2899SCharles.Forsyth } 670*37da2899SCharles.Forsyth 671*37da2899SCharles.Forsyth 672*37da2899SCharles.Forsyth /*************************************************************************/ 673*37da2899SCharles.Forsyth /* */ 674*37da2899SCharles.Forsyth /* <Function> */ 675*37da2899SCharles.Forsyth /* Insert_Y_Turn */ 676*37da2899SCharles.Forsyth /* */ 677*37da2899SCharles.Forsyth /* <Description> */ 678*37da2899SCharles.Forsyth /* Inserts a salient into the sorted list placed on top of the render */ 679*37da2899SCharles.Forsyth /* pool. */ 680*37da2899SCharles.Forsyth /* */ 681*37da2899SCharles.Forsyth /* <Input> */ 682*37da2899SCharles.Forsyth /* New y scanline position. */ 683*37da2899SCharles.Forsyth /* */ 684*37da2899SCharles.Forsyth /* <Return> */ 685*37da2899SCharles.Forsyth /* SUCCESS on success. FAILURE in case of overflow. */ 686*37da2899SCharles.Forsyth /* */ 687*37da2899SCharles.Forsyth static Bool Insert_Y_Turn(RAS_ARGS Int y)688*37da2899SCharles.Forsyth Insert_Y_Turn( RAS_ARGS Int y ) 689*37da2899SCharles.Forsyth { 690*37da2899SCharles.Forsyth PLong y_turns; 691*37da2899SCharles.Forsyth Int y2, n; 692*37da2899SCharles.Forsyth 693*37da2899SCharles.Forsyth 694*37da2899SCharles.Forsyth n = ras.numTurns - 1; 695*37da2899SCharles.Forsyth y_turns = ras.sizeBuff - ras.numTurns; 696*37da2899SCharles.Forsyth 697*37da2899SCharles.Forsyth /* look for first y value that is <= */ 698*37da2899SCharles.Forsyth while ( n >= 0 && y < y_turns[n] ) 699*37da2899SCharles.Forsyth n--; 700*37da2899SCharles.Forsyth 701*37da2899SCharles.Forsyth /* if it is <, simply insert it, ignore if == */ 702*37da2899SCharles.Forsyth if ( n >= 0 && y > y_turns[n] ) 703*37da2899SCharles.Forsyth while ( n >= 0 ) 704*37da2899SCharles.Forsyth { 705*37da2899SCharles.Forsyth y2 = (Int)y_turns[n]; 706*37da2899SCharles.Forsyth y_turns[n] = y; 707*37da2899SCharles.Forsyth y = y2; 708*37da2899SCharles.Forsyth n--; 709*37da2899SCharles.Forsyth } 710*37da2899SCharles.Forsyth 711*37da2899SCharles.Forsyth if ( n < 0 ) 712*37da2899SCharles.Forsyth { 713*37da2899SCharles.Forsyth if ( ras.maxBuff <= ras.top ) 714*37da2899SCharles.Forsyth { 715*37da2899SCharles.Forsyth ras.error = Raster_Err_Overflow; 716*37da2899SCharles.Forsyth return FAILURE; 717*37da2899SCharles.Forsyth } 718*37da2899SCharles.Forsyth ras.maxBuff--; 719*37da2899SCharles.Forsyth ras.numTurns++; 720*37da2899SCharles.Forsyth ras.sizeBuff[-ras.numTurns] = y; 721*37da2899SCharles.Forsyth } 722*37da2899SCharles.Forsyth 723*37da2899SCharles.Forsyth return SUCCESS; 724*37da2899SCharles.Forsyth } 725*37da2899SCharles.Forsyth 726*37da2899SCharles.Forsyth 727*37da2899SCharles.Forsyth /*************************************************************************/ 728*37da2899SCharles.Forsyth /* */ 729*37da2899SCharles.Forsyth /* <Function> */ 730*37da2899SCharles.Forsyth /* Finalize_Profile_Table */ 731*37da2899SCharles.Forsyth /* */ 732*37da2899SCharles.Forsyth /* <Description> */ 733*37da2899SCharles.Forsyth /* Adjusts all links in the profiles list. */ 734*37da2899SCharles.Forsyth /* */ 735*37da2899SCharles.Forsyth /* <Return> */ 736*37da2899SCharles.Forsyth /* SUCCESS on success. FAILURE in case of overflow. */ 737*37da2899SCharles.Forsyth /* */ 738*37da2899SCharles.Forsyth static Bool Finalize_Profile_Table(RAS_ARG)739*37da2899SCharles.Forsyth Finalize_Profile_Table( RAS_ARG ) 740*37da2899SCharles.Forsyth { 741*37da2899SCharles.Forsyth Int bottom, top; 742*37da2899SCharles.Forsyth UShort n; 743*37da2899SCharles.Forsyth PProfile p; 744*37da2899SCharles.Forsyth 745*37da2899SCharles.Forsyth 746*37da2899SCharles.Forsyth n = ras.num_Profs; 747*37da2899SCharles.Forsyth 748*37da2899SCharles.Forsyth if ( n > 1 ) 749*37da2899SCharles.Forsyth { 750*37da2899SCharles.Forsyth p = ras.fProfile; 751*37da2899SCharles.Forsyth while ( n > 0 ) 752*37da2899SCharles.Forsyth { 753*37da2899SCharles.Forsyth if ( n > 1 ) 754*37da2899SCharles.Forsyth p->link = (PProfile)( p->offset + p->height ); 755*37da2899SCharles.Forsyth else 756*37da2899SCharles.Forsyth p->link = NULL; 757*37da2899SCharles.Forsyth 758*37da2899SCharles.Forsyth switch ( p->flow ) 759*37da2899SCharles.Forsyth { 760*37da2899SCharles.Forsyth case Flow_Down: 761*37da2899SCharles.Forsyth bottom = (Int)( p->start - p->height + 1 ); 762*37da2899SCharles.Forsyth top = (Int)p->start; 763*37da2899SCharles.Forsyth p->start = bottom; 764*37da2899SCharles.Forsyth p->offset += p->height - 1; 765*37da2899SCharles.Forsyth break; 766*37da2899SCharles.Forsyth 767*37da2899SCharles.Forsyth case Flow_Up: 768*37da2899SCharles.Forsyth default: 769*37da2899SCharles.Forsyth bottom = (Int)p->start; 770*37da2899SCharles.Forsyth top = (Int)( p->start + p->height - 1 ); 771*37da2899SCharles.Forsyth } 772*37da2899SCharles.Forsyth 773*37da2899SCharles.Forsyth if ( Insert_Y_Turn( RAS_VARS bottom ) || 774*37da2899SCharles.Forsyth Insert_Y_Turn( RAS_VARS top + 1 ) ) 775*37da2899SCharles.Forsyth return FAILURE; 776*37da2899SCharles.Forsyth 777*37da2899SCharles.Forsyth p = p->link; 778*37da2899SCharles.Forsyth n--; 779*37da2899SCharles.Forsyth } 780*37da2899SCharles.Forsyth } 781*37da2899SCharles.Forsyth else 782*37da2899SCharles.Forsyth ras.fProfile = NULL; 783*37da2899SCharles.Forsyth 784*37da2899SCharles.Forsyth return SUCCESS; 785*37da2899SCharles.Forsyth } 786*37da2899SCharles.Forsyth 787*37da2899SCharles.Forsyth 788*37da2899SCharles.Forsyth /*************************************************************************/ 789*37da2899SCharles.Forsyth /* */ 790*37da2899SCharles.Forsyth /* <Function> */ 791*37da2899SCharles.Forsyth /* Split_Conic */ 792*37da2899SCharles.Forsyth /* */ 793*37da2899SCharles.Forsyth /* <Description> */ 794*37da2899SCharles.Forsyth /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */ 795*37da2899SCharles.Forsyth /* stack. */ 796*37da2899SCharles.Forsyth /* */ 797*37da2899SCharles.Forsyth /* <Input> */ 798*37da2899SCharles.Forsyth /* None (subdivided Bezier is taken from the top of the stack). */ 799*37da2899SCharles.Forsyth /* */ 800*37da2899SCharles.Forsyth /* <Note> */ 801*37da2899SCharles.Forsyth /* This routine is the `beef' of this component. It is _the_ inner */ 802*37da2899SCharles.Forsyth /* loop that should be optimized to hell to get the best performance. */ 803*37da2899SCharles.Forsyth /* */ 804*37da2899SCharles.Forsyth static void Split_Conic(TPoint * base)805*37da2899SCharles.Forsyth Split_Conic( TPoint* base ) 806*37da2899SCharles.Forsyth { 807*37da2899SCharles.Forsyth Long a, b; 808*37da2899SCharles.Forsyth 809*37da2899SCharles.Forsyth 810*37da2899SCharles.Forsyth base[4].x = base[2].x; 811*37da2899SCharles.Forsyth b = base[1].x; 812*37da2899SCharles.Forsyth a = base[3].x = ( base[2].x + b ) / 2; 813*37da2899SCharles.Forsyth b = base[1].x = ( base[0].x + b ) / 2; 814*37da2899SCharles.Forsyth base[2].x = ( a + b ) / 2; 815*37da2899SCharles.Forsyth 816*37da2899SCharles.Forsyth base[4].y = base[2].y; 817*37da2899SCharles.Forsyth b = base[1].y; 818*37da2899SCharles.Forsyth a = base[3].y = ( base[2].y + b ) / 2; 819*37da2899SCharles.Forsyth b = base[1].y = ( base[0].y + b ) / 2; 820*37da2899SCharles.Forsyth base[2].y = ( a + b ) / 2; 821*37da2899SCharles.Forsyth 822*37da2899SCharles.Forsyth /* hand optimized. gcc doesn't seem to be too good at common */ 823*37da2899SCharles.Forsyth /* expression substitution and instruction scheduling ;-) */ 824*37da2899SCharles.Forsyth } 825*37da2899SCharles.Forsyth 826*37da2899SCharles.Forsyth 827*37da2899SCharles.Forsyth /*************************************************************************/ 828*37da2899SCharles.Forsyth /* */ 829*37da2899SCharles.Forsyth /* <Function> */ 830*37da2899SCharles.Forsyth /* Split_Cubic */ 831*37da2899SCharles.Forsyth /* */ 832*37da2899SCharles.Forsyth /* <Description> */ 833*37da2899SCharles.Forsyth /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */ 834*37da2899SCharles.Forsyth /* Bezier stack. */ 835*37da2899SCharles.Forsyth /* */ 836*37da2899SCharles.Forsyth /* <Note> */ 837*37da2899SCharles.Forsyth /* This routine is the `beef' of the component. It is one of _the_ */ 838*37da2899SCharles.Forsyth /* inner loops that should be optimized like hell to get the best */ 839*37da2899SCharles.Forsyth /* performance. */ 840*37da2899SCharles.Forsyth /* */ 841*37da2899SCharles.Forsyth static void Split_Cubic(TPoint * base)842*37da2899SCharles.Forsyth Split_Cubic( TPoint* base ) 843*37da2899SCharles.Forsyth { 844*37da2899SCharles.Forsyth Long a, b, c, d; 845*37da2899SCharles.Forsyth 846*37da2899SCharles.Forsyth 847*37da2899SCharles.Forsyth base[6].x = base[3].x; 848*37da2899SCharles.Forsyth c = base[1].x; 849*37da2899SCharles.Forsyth d = base[2].x; 850*37da2899SCharles.Forsyth base[1].x = a = ( base[0].x + c + 1 ) >> 1; 851*37da2899SCharles.Forsyth base[5].x = b = ( base[3].x + d + 1 ) >> 1; 852*37da2899SCharles.Forsyth c = ( c + d + 1 ) >> 1; 853*37da2899SCharles.Forsyth base[2].x = a = ( a + c + 1 ) >> 1; 854*37da2899SCharles.Forsyth base[4].x = b = ( b + c + 1 ) >> 1; 855*37da2899SCharles.Forsyth base[3].x = ( a + b + 1 ) >> 1; 856*37da2899SCharles.Forsyth 857*37da2899SCharles.Forsyth base[6].y = base[3].y; 858*37da2899SCharles.Forsyth c = base[1].y; 859*37da2899SCharles.Forsyth d = base[2].y; 860*37da2899SCharles.Forsyth base[1].y = a = ( base[0].y + c + 1 ) >> 1; 861*37da2899SCharles.Forsyth base[5].y = b = ( base[3].y + d + 1 ) >> 1; 862*37da2899SCharles.Forsyth c = ( c + d + 1 ) >> 1; 863*37da2899SCharles.Forsyth base[2].y = a = ( a + c + 1 ) >> 1; 864*37da2899SCharles.Forsyth base[4].y = b = ( b + c + 1 ) >> 1; 865*37da2899SCharles.Forsyth base[3].y = ( a + b + 1 ) >> 1; 866*37da2899SCharles.Forsyth } 867*37da2899SCharles.Forsyth 868*37da2899SCharles.Forsyth 869*37da2899SCharles.Forsyth /*************************************************************************/ 870*37da2899SCharles.Forsyth /* */ 871*37da2899SCharles.Forsyth /* <Function> */ 872*37da2899SCharles.Forsyth /* Line_Up */ 873*37da2899SCharles.Forsyth /* */ 874*37da2899SCharles.Forsyth /* <Description> */ 875*37da2899SCharles.Forsyth /* Computes the x-coordinates of an ascending line segment and stores */ 876*37da2899SCharles.Forsyth /* them in the render pool. */ 877*37da2899SCharles.Forsyth /* */ 878*37da2899SCharles.Forsyth /* <Input> */ 879*37da2899SCharles.Forsyth /* x1 :: The x-coordinate of the segment's start point. */ 880*37da2899SCharles.Forsyth /* */ 881*37da2899SCharles.Forsyth /* y1 :: The y-coordinate of the segment's start point. */ 882*37da2899SCharles.Forsyth /* */ 883*37da2899SCharles.Forsyth /* x2 :: The x-coordinate of the segment's end point. */ 884*37da2899SCharles.Forsyth /* */ 885*37da2899SCharles.Forsyth /* y2 :: The y-coordinate of the segment's end point. */ 886*37da2899SCharles.Forsyth /* */ 887*37da2899SCharles.Forsyth /* miny :: A lower vertical clipping bound value. */ 888*37da2899SCharles.Forsyth /* */ 889*37da2899SCharles.Forsyth /* maxy :: An upper vertical clipping bound value. */ 890*37da2899SCharles.Forsyth /* */ 891*37da2899SCharles.Forsyth /* <Return> */ 892*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow. */ 893*37da2899SCharles.Forsyth /* */ 894*37da2899SCharles.Forsyth static Bool Line_Up(RAS_ARGS Long x1,Long y1,Long x2,Long y2,Long miny,Long maxy)895*37da2899SCharles.Forsyth Line_Up( RAS_ARGS Long x1, 896*37da2899SCharles.Forsyth Long y1, 897*37da2899SCharles.Forsyth Long x2, 898*37da2899SCharles.Forsyth Long y2, 899*37da2899SCharles.Forsyth Long miny, 900*37da2899SCharles.Forsyth Long maxy ) 901*37da2899SCharles.Forsyth { 902*37da2899SCharles.Forsyth Long Dx, Dy; 903*37da2899SCharles.Forsyth Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ 904*37da2899SCharles.Forsyth Long Ix, Rx, Ax; 905*37da2899SCharles.Forsyth 906*37da2899SCharles.Forsyth PLong top; 907*37da2899SCharles.Forsyth 908*37da2899SCharles.Forsyth 909*37da2899SCharles.Forsyth Dx = x2 - x1; 910*37da2899SCharles.Forsyth Dy = y2 - y1; 911*37da2899SCharles.Forsyth 912*37da2899SCharles.Forsyth if ( Dy <= 0 || y2 < miny || y1 > maxy ) 913*37da2899SCharles.Forsyth return SUCCESS; 914*37da2899SCharles.Forsyth 915*37da2899SCharles.Forsyth if ( y1 < miny ) 916*37da2899SCharles.Forsyth { 917*37da2899SCharles.Forsyth /* Take care: miny-y1 can be a very large value; we use */ 918*37da2899SCharles.Forsyth /* a slow MulDiv function to avoid clipping bugs */ 919*37da2899SCharles.Forsyth x1 += SMulDiv( Dx, miny - y1, Dy ); 920*37da2899SCharles.Forsyth e1 = TRUNC( miny ); 921*37da2899SCharles.Forsyth f1 = 0; 922*37da2899SCharles.Forsyth } 923*37da2899SCharles.Forsyth else 924*37da2899SCharles.Forsyth { 925*37da2899SCharles.Forsyth e1 = (Int)TRUNC( y1 ); 926*37da2899SCharles.Forsyth f1 = (Int)FRAC( y1 ); 927*37da2899SCharles.Forsyth } 928*37da2899SCharles.Forsyth 929*37da2899SCharles.Forsyth if ( y2 > maxy ) 930*37da2899SCharles.Forsyth { 931*37da2899SCharles.Forsyth /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ 932*37da2899SCharles.Forsyth e2 = (Int)TRUNC( maxy ); 933*37da2899SCharles.Forsyth f2 = 0; 934*37da2899SCharles.Forsyth } 935*37da2899SCharles.Forsyth else 936*37da2899SCharles.Forsyth { 937*37da2899SCharles.Forsyth e2 = (Int)TRUNC( y2 ); 938*37da2899SCharles.Forsyth f2 = (Int)FRAC( y2 ); 939*37da2899SCharles.Forsyth } 940*37da2899SCharles.Forsyth 941*37da2899SCharles.Forsyth if ( f1 > 0 ) 942*37da2899SCharles.Forsyth { 943*37da2899SCharles.Forsyth if ( e1 == e2 ) 944*37da2899SCharles.Forsyth return SUCCESS; 945*37da2899SCharles.Forsyth else 946*37da2899SCharles.Forsyth { 947*37da2899SCharles.Forsyth x1 += FMulDiv( Dx, ras.precision - f1, Dy ); 948*37da2899SCharles.Forsyth e1 += 1; 949*37da2899SCharles.Forsyth } 950*37da2899SCharles.Forsyth } 951*37da2899SCharles.Forsyth else 952*37da2899SCharles.Forsyth if ( ras.joint ) 953*37da2899SCharles.Forsyth { 954*37da2899SCharles.Forsyth ras.top--; 955*37da2899SCharles.Forsyth ras.joint = FALSE; 956*37da2899SCharles.Forsyth } 957*37da2899SCharles.Forsyth 958*37da2899SCharles.Forsyth ras.joint = (char)( f2 == 0 ); 959*37da2899SCharles.Forsyth 960*37da2899SCharles.Forsyth if ( ras.fresh ) 961*37da2899SCharles.Forsyth { 962*37da2899SCharles.Forsyth ras.cProfile->start = e1; 963*37da2899SCharles.Forsyth ras.fresh = FALSE; 964*37da2899SCharles.Forsyth } 965*37da2899SCharles.Forsyth 966*37da2899SCharles.Forsyth size = e2 - e1 + 1; 967*37da2899SCharles.Forsyth if ( ras.top + size >= ras.maxBuff ) 968*37da2899SCharles.Forsyth { 969*37da2899SCharles.Forsyth ras.error = Raster_Err_Overflow; 970*37da2899SCharles.Forsyth return FAILURE; 971*37da2899SCharles.Forsyth } 972*37da2899SCharles.Forsyth 973*37da2899SCharles.Forsyth if ( Dx > 0 ) 974*37da2899SCharles.Forsyth { 975*37da2899SCharles.Forsyth Ix = ( ras.precision * Dx ) / Dy; 976*37da2899SCharles.Forsyth Rx = ( ras.precision * Dx ) % Dy; 977*37da2899SCharles.Forsyth Dx = 1; 978*37da2899SCharles.Forsyth } 979*37da2899SCharles.Forsyth else 980*37da2899SCharles.Forsyth { 981*37da2899SCharles.Forsyth Ix = -( ( ras.precision * -Dx ) / Dy ); 982*37da2899SCharles.Forsyth Rx = ( ras.precision * -Dx ) % Dy; 983*37da2899SCharles.Forsyth Dx = -1; 984*37da2899SCharles.Forsyth } 985*37da2899SCharles.Forsyth 986*37da2899SCharles.Forsyth Ax = -Dy; 987*37da2899SCharles.Forsyth top = ras.top; 988*37da2899SCharles.Forsyth 989*37da2899SCharles.Forsyth while ( size > 0 ) 990*37da2899SCharles.Forsyth { 991*37da2899SCharles.Forsyth *top++ = x1; 992*37da2899SCharles.Forsyth 993*37da2899SCharles.Forsyth x1 += Ix; 994*37da2899SCharles.Forsyth Ax += Rx; 995*37da2899SCharles.Forsyth if ( Ax >= 0 ) 996*37da2899SCharles.Forsyth { 997*37da2899SCharles.Forsyth Ax -= Dy; 998*37da2899SCharles.Forsyth x1 += Dx; 999*37da2899SCharles.Forsyth } 1000*37da2899SCharles.Forsyth size--; 1001*37da2899SCharles.Forsyth } 1002*37da2899SCharles.Forsyth 1003*37da2899SCharles.Forsyth ras.top = top; 1004*37da2899SCharles.Forsyth return SUCCESS; 1005*37da2899SCharles.Forsyth } 1006*37da2899SCharles.Forsyth 1007*37da2899SCharles.Forsyth 1008*37da2899SCharles.Forsyth /*************************************************************************/ 1009*37da2899SCharles.Forsyth /* */ 1010*37da2899SCharles.Forsyth /* <Function> */ 1011*37da2899SCharles.Forsyth /* Line_Down */ 1012*37da2899SCharles.Forsyth /* */ 1013*37da2899SCharles.Forsyth /* <Description> */ 1014*37da2899SCharles.Forsyth /* Computes the x-coordinates of an descending line segment and */ 1015*37da2899SCharles.Forsyth /* stores them in the render pool. */ 1016*37da2899SCharles.Forsyth /* */ 1017*37da2899SCharles.Forsyth /* <Input> */ 1018*37da2899SCharles.Forsyth /* x1 :: The x-coordinate of the segment's start point. */ 1019*37da2899SCharles.Forsyth /* */ 1020*37da2899SCharles.Forsyth /* y1 :: The y-coordinate of the segment's start point. */ 1021*37da2899SCharles.Forsyth /* */ 1022*37da2899SCharles.Forsyth /* x2 :: The x-coordinate of the segment's end point. */ 1023*37da2899SCharles.Forsyth /* */ 1024*37da2899SCharles.Forsyth /* y2 :: The y-coordinate of the segment's end point. */ 1025*37da2899SCharles.Forsyth /* */ 1026*37da2899SCharles.Forsyth /* miny :: A lower vertical clipping bound value. */ 1027*37da2899SCharles.Forsyth /* */ 1028*37da2899SCharles.Forsyth /* maxy :: An upper vertical clipping bound value. */ 1029*37da2899SCharles.Forsyth /* */ 1030*37da2899SCharles.Forsyth /* <Return> */ 1031*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow. */ 1032*37da2899SCharles.Forsyth /* */ 1033*37da2899SCharles.Forsyth static Bool Line_Down(RAS_ARGS Long x1,Long y1,Long x2,Long y2,Long miny,Long maxy)1034*37da2899SCharles.Forsyth Line_Down( RAS_ARGS Long x1, 1035*37da2899SCharles.Forsyth Long y1, 1036*37da2899SCharles.Forsyth Long x2, 1037*37da2899SCharles.Forsyth Long y2, 1038*37da2899SCharles.Forsyth Long miny, 1039*37da2899SCharles.Forsyth Long maxy ) 1040*37da2899SCharles.Forsyth { 1041*37da2899SCharles.Forsyth Bool result, fresh; 1042*37da2899SCharles.Forsyth 1043*37da2899SCharles.Forsyth 1044*37da2899SCharles.Forsyth fresh = ras.fresh; 1045*37da2899SCharles.Forsyth 1046*37da2899SCharles.Forsyth result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); 1047*37da2899SCharles.Forsyth 1048*37da2899SCharles.Forsyth if ( fresh && !ras.fresh ) 1049*37da2899SCharles.Forsyth ras.cProfile->start = -ras.cProfile->start; 1050*37da2899SCharles.Forsyth 1051*37da2899SCharles.Forsyth return result; 1052*37da2899SCharles.Forsyth } 1053*37da2899SCharles.Forsyth 1054*37da2899SCharles.Forsyth 1055*37da2899SCharles.Forsyth /* A function type describing the functions used to split Bezier arcs */ 1056*37da2899SCharles.Forsyth typedef void (*TSplitter)( TPoint* base ); 1057*37da2899SCharles.Forsyth 1058*37da2899SCharles.Forsyth 1059*37da2899SCharles.Forsyth /*************************************************************************/ 1060*37da2899SCharles.Forsyth /* */ 1061*37da2899SCharles.Forsyth /* <Function> */ 1062*37da2899SCharles.Forsyth /* Bezier_Up */ 1063*37da2899SCharles.Forsyth /* */ 1064*37da2899SCharles.Forsyth /* <Description> */ 1065*37da2899SCharles.Forsyth /* Computes the x-coordinates of an ascending Bezier arc and stores */ 1066*37da2899SCharles.Forsyth /* them in the render pool. */ 1067*37da2899SCharles.Forsyth /* */ 1068*37da2899SCharles.Forsyth /* <Input> */ 1069*37da2899SCharles.Forsyth /* degree :: The degree of the Bezier arc (either 2 or 3). */ 1070*37da2899SCharles.Forsyth /* */ 1071*37da2899SCharles.Forsyth /* splitter :: The function to split Bezier arcs. */ 1072*37da2899SCharles.Forsyth /* */ 1073*37da2899SCharles.Forsyth /* miny :: A lower vertical clipping bound value. */ 1074*37da2899SCharles.Forsyth /* */ 1075*37da2899SCharles.Forsyth /* maxy :: An upper vertical clipping bound value. */ 1076*37da2899SCharles.Forsyth /* */ 1077*37da2899SCharles.Forsyth /* <Return> */ 1078*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow. */ 1079*37da2899SCharles.Forsyth /* */ 1080*37da2899SCharles.Forsyth static Bool Bezier_Up(RAS_ARGS Int degree,TSplitter splitter,Long miny,Long maxy)1081*37da2899SCharles.Forsyth Bezier_Up( RAS_ARGS Int degree, 1082*37da2899SCharles.Forsyth TSplitter splitter, 1083*37da2899SCharles.Forsyth Long miny, 1084*37da2899SCharles.Forsyth Long maxy ) 1085*37da2899SCharles.Forsyth { 1086*37da2899SCharles.Forsyth Long y1, y2, e, e2, e0; 1087*37da2899SCharles.Forsyth Short f1; 1088*37da2899SCharles.Forsyth 1089*37da2899SCharles.Forsyth TPoint* arc; 1090*37da2899SCharles.Forsyth TPoint* start_arc; 1091*37da2899SCharles.Forsyth 1092*37da2899SCharles.Forsyth PLong top; 1093*37da2899SCharles.Forsyth 1094*37da2899SCharles.Forsyth 1095*37da2899SCharles.Forsyth arc = ras.arc; 1096*37da2899SCharles.Forsyth y1 = arc[degree].y; 1097*37da2899SCharles.Forsyth y2 = arc[0].y; 1098*37da2899SCharles.Forsyth top = ras.top; 1099*37da2899SCharles.Forsyth 1100*37da2899SCharles.Forsyth if ( y2 < miny || y1 > maxy ) 1101*37da2899SCharles.Forsyth goto Fin; 1102*37da2899SCharles.Forsyth 1103*37da2899SCharles.Forsyth e2 = FLOOR( y2 ); 1104*37da2899SCharles.Forsyth 1105*37da2899SCharles.Forsyth if ( e2 > maxy ) 1106*37da2899SCharles.Forsyth e2 = maxy; 1107*37da2899SCharles.Forsyth 1108*37da2899SCharles.Forsyth e0 = miny; 1109*37da2899SCharles.Forsyth 1110*37da2899SCharles.Forsyth if ( y1 < miny ) 1111*37da2899SCharles.Forsyth e = miny; 1112*37da2899SCharles.Forsyth else 1113*37da2899SCharles.Forsyth { 1114*37da2899SCharles.Forsyth e = CEILING( y1 ); 1115*37da2899SCharles.Forsyth f1 = (Short)( FRAC( y1 ) ); 1116*37da2899SCharles.Forsyth e0 = e; 1117*37da2899SCharles.Forsyth 1118*37da2899SCharles.Forsyth if ( f1 == 0 ) 1119*37da2899SCharles.Forsyth { 1120*37da2899SCharles.Forsyth if ( ras.joint ) 1121*37da2899SCharles.Forsyth { 1122*37da2899SCharles.Forsyth top--; 1123*37da2899SCharles.Forsyth ras.joint = FALSE; 1124*37da2899SCharles.Forsyth } 1125*37da2899SCharles.Forsyth 1126*37da2899SCharles.Forsyth *top++ = arc[degree].x; 1127*37da2899SCharles.Forsyth 1128*37da2899SCharles.Forsyth e += ras.precision; 1129*37da2899SCharles.Forsyth } 1130*37da2899SCharles.Forsyth } 1131*37da2899SCharles.Forsyth 1132*37da2899SCharles.Forsyth if ( ras.fresh ) 1133*37da2899SCharles.Forsyth { 1134*37da2899SCharles.Forsyth ras.cProfile->start = TRUNC( e0 ); 1135*37da2899SCharles.Forsyth ras.fresh = FALSE; 1136*37da2899SCharles.Forsyth } 1137*37da2899SCharles.Forsyth 1138*37da2899SCharles.Forsyth if ( e2 < e ) 1139*37da2899SCharles.Forsyth goto Fin; 1140*37da2899SCharles.Forsyth 1141*37da2899SCharles.Forsyth if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) 1142*37da2899SCharles.Forsyth { 1143*37da2899SCharles.Forsyth ras.top = top; 1144*37da2899SCharles.Forsyth ras.error = Raster_Err_Overflow; 1145*37da2899SCharles.Forsyth return FAILURE; 1146*37da2899SCharles.Forsyth } 1147*37da2899SCharles.Forsyth 1148*37da2899SCharles.Forsyth start_arc = arc; 1149*37da2899SCharles.Forsyth 1150*37da2899SCharles.Forsyth while ( arc >= start_arc && e <= e2 ) 1151*37da2899SCharles.Forsyth { 1152*37da2899SCharles.Forsyth ras.joint = FALSE; 1153*37da2899SCharles.Forsyth 1154*37da2899SCharles.Forsyth y2 = arc[0].y; 1155*37da2899SCharles.Forsyth 1156*37da2899SCharles.Forsyth if ( y2 > e ) 1157*37da2899SCharles.Forsyth { 1158*37da2899SCharles.Forsyth y1 = arc[degree].y; 1159*37da2899SCharles.Forsyth if ( y2 - y1 >= ras.precision_step ) 1160*37da2899SCharles.Forsyth { 1161*37da2899SCharles.Forsyth splitter( arc ); 1162*37da2899SCharles.Forsyth arc += degree; 1163*37da2899SCharles.Forsyth } 1164*37da2899SCharles.Forsyth else 1165*37da2899SCharles.Forsyth { 1166*37da2899SCharles.Forsyth *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x, 1167*37da2899SCharles.Forsyth e - y1, y2 - y1 ); 1168*37da2899SCharles.Forsyth arc -= degree; 1169*37da2899SCharles.Forsyth e += ras.precision; 1170*37da2899SCharles.Forsyth } 1171*37da2899SCharles.Forsyth } 1172*37da2899SCharles.Forsyth else 1173*37da2899SCharles.Forsyth { 1174*37da2899SCharles.Forsyth if ( y2 == e ) 1175*37da2899SCharles.Forsyth { 1176*37da2899SCharles.Forsyth ras.joint = TRUE; 1177*37da2899SCharles.Forsyth *top++ = arc[0].x; 1178*37da2899SCharles.Forsyth 1179*37da2899SCharles.Forsyth e += ras.precision; 1180*37da2899SCharles.Forsyth } 1181*37da2899SCharles.Forsyth arc -= degree; 1182*37da2899SCharles.Forsyth } 1183*37da2899SCharles.Forsyth } 1184*37da2899SCharles.Forsyth 1185*37da2899SCharles.Forsyth Fin: 1186*37da2899SCharles.Forsyth ras.top = top; 1187*37da2899SCharles.Forsyth ras.arc -= degree; 1188*37da2899SCharles.Forsyth return SUCCESS; 1189*37da2899SCharles.Forsyth } 1190*37da2899SCharles.Forsyth 1191*37da2899SCharles.Forsyth 1192*37da2899SCharles.Forsyth /*************************************************************************/ 1193*37da2899SCharles.Forsyth /* */ 1194*37da2899SCharles.Forsyth /* <Function> */ 1195*37da2899SCharles.Forsyth /* Bezier_Down */ 1196*37da2899SCharles.Forsyth /* */ 1197*37da2899SCharles.Forsyth /* <Description> */ 1198*37da2899SCharles.Forsyth /* Computes the x-coordinates of an descending Bezier arc and stores */ 1199*37da2899SCharles.Forsyth /* them in the render pool. */ 1200*37da2899SCharles.Forsyth /* */ 1201*37da2899SCharles.Forsyth /* <Input> */ 1202*37da2899SCharles.Forsyth /* degree :: The degree of the Bezier arc (either 2 or 3). */ 1203*37da2899SCharles.Forsyth /* */ 1204*37da2899SCharles.Forsyth /* splitter :: The function to split Bezier arcs. */ 1205*37da2899SCharles.Forsyth /* */ 1206*37da2899SCharles.Forsyth /* miny :: A lower vertical clipping bound value. */ 1207*37da2899SCharles.Forsyth /* */ 1208*37da2899SCharles.Forsyth /* maxy :: An upper vertical clipping bound value. */ 1209*37da2899SCharles.Forsyth /* */ 1210*37da2899SCharles.Forsyth /* <Return> */ 1211*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow. */ 1212*37da2899SCharles.Forsyth /* */ 1213*37da2899SCharles.Forsyth static Bool Bezier_Down(RAS_ARGS Int degree,TSplitter splitter,Long miny,Long maxy)1214*37da2899SCharles.Forsyth Bezier_Down( RAS_ARGS Int degree, 1215*37da2899SCharles.Forsyth TSplitter splitter, 1216*37da2899SCharles.Forsyth Long miny, 1217*37da2899SCharles.Forsyth Long maxy ) 1218*37da2899SCharles.Forsyth { 1219*37da2899SCharles.Forsyth TPoint* arc = ras.arc; 1220*37da2899SCharles.Forsyth Bool result, fresh; 1221*37da2899SCharles.Forsyth 1222*37da2899SCharles.Forsyth 1223*37da2899SCharles.Forsyth arc[0].y = -arc[0].y; 1224*37da2899SCharles.Forsyth arc[1].y = -arc[1].y; 1225*37da2899SCharles.Forsyth arc[2].y = -arc[2].y; 1226*37da2899SCharles.Forsyth if ( degree > 2 ) 1227*37da2899SCharles.Forsyth arc[3].y = -arc[3].y; 1228*37da2899SCharles.Forsyth 1229*37da2899SCharles.Forsyth fresh = ras.fresh; 1230*37da2899SCharles.Forsyth 1231*37da2899SCharles.Forsyth result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); 1232*37da2899SCharles.Forsyth 1233*37da2899SCharles.Forsyth if ( fresh && !ras.fresh ) 1234*37da2899SCharles.Forsyth ras.cProfile->start = -ras.cProfile->start; 1235*37da2899SCharles.Forsyth 1236*37da2899SCharles.Forsyth arc[0].y = -arc[0].y; 1237*37da2899SCharles.Forsyth return result; 1238*37da2899SCharles.Forsyth } 1239*37da2899SCharles.Forsyth 1240*37da2899SCharles.Forsyth 1241*37da2899SCharles.Forsyth /*************************************************************************/ 1242*37da2899SCharles.Forsyth /* */ 1243*37da2899SCharles.Forsyth /* <Function> */ 1244*37da2899SCharles.Forsyth /* Line_To */ 1245*37da2899SCharles.Forsyth /* */ 1246*37da2899SCharles.Forsyth /* <Description> */ 1247*37da2899SCharles.Forsyth /* Injects a new line segment and adjusts Profiles list. */ 1248*37da2899SCharles.Forsyth /* */ 1249*37da2899SCharles.Forsyth /* <Input> */ 1250*37da2899SCharles.Forsyth /* x :: The x-coordinate of the segment's end point (its start point */ 1251*37da2899SCharles.Forsyth /* is stored in `LastX'). */ 1252*37da2899SCharles.Forsyth /* */ 1253*37da2899SCharles.Forsyth /* y :: The y-coordinate of the segment's end point (its start point */ 1254*37da2899SCharles.Forsyth /* is stored in `LastY'). */ 1255*37da2899SCharles.Forsyth /* */ 1256*37da2899SCharles.Forsyth /* <Return> */ 1257*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ 1258*37da2899SCharles.Forsyth /* profile. */ 1259*37da2899SCharles.Forsyth /* */ 1260*37da2899SCharles.Forsyth static Bool Line_To(RAS_ARGS Long x,Long y)1261*37da2899SCharles.Forsyth Line_To( RAS_ARGS Long x, 1262*37da2899SCharles.Forsyth Long y ) 1263*37da2899SCharles.Forsyth { 1264*37da2899SCharles.Forsyth /* First, detect a change of direction */ 1265*37da2899SCharles.Forsyth 1266*37da2899SCharles.Forsyth switch ( ras.state ) 1267*37da2899SCharles.Forsyth { 1268*37da2899SCharles.Forsyth case Unknown_State: 1269*37da2899SCharles.Forsyth if ( y > ras.lastY ) 1270*37da2899SCharles.Forsyth { 1271*37da2899SCharles.Forsyth if ( New_Profile( RAS_VARS Ascending_State ) ) 1272*37da2899SCharles.Forsyth return FAILURE; 1273*37da2899SCharles.Forsyth } 1274*37da2899SCharles.Forsyth else 1275*37da2899SCharles.Forsyth { 1276*37da2899SCharles.Forsyth if ( y < ras.lastY ) 1277*37da2899SCharles.Forsyth if ( New_Profile( RAS_VARS Descending_State ) ) 1278*37da2899SCharles.Forsyth return FAILURE; 1279*37da2899SCharles.Forsyth } 1280*37da2899SCharles.Forsyth break; 1281*37da2899SCharles.Forsyth 1282*37da2899SCharles.Forsyth case Ascending_State: 1283*37da2899SCharles.Forsyth if ( y < ras.lastY ) 1284*37da2899SCharles.Forsyth { 1285*37da2899SCharles.Forsyth if ( End_Profile( RAS_VAR ) || 1286*37da2899SCharles.Forsyth New_Profile( RAS_VARS Descending_State ) ) 1287*37da2899SCharles.Forsyth return FAILURE; 1288*37da2899SCharles.Forsyth } 1289*37da2899SCharles.Forsyth break; 1290*37da2899SCharles.Forsyth 1291*37da2899SCharles.Forsyth case Descending_State: 1292*37da2899SCharles.Forsyth if ( y > ras.lastY ) 1293*37da2899SCharles.Forsyth { 1294*37da2899SCharles.Forsyth if ( End_Profile( RAS_VAR ) || 1295*37da2899SCharles.Forsyth New_Profile( RAS_VARS Ascending_State ) ) 1296*37da2899SCharles.Forsyth return FAILURE; 1297*37da2899SCharles.Forsyth } 1298*37da2899SCharles.Forsyth break; 1299*37da2899SCharles.Forsyth 1300*37da2899SCharles.Forsyth default: 1301*37da2899SCharles.Forsyth ; 1302*37da2899SCharles.Forsyth } 1303*37da2899SCharles.Forsyth 1304*37da2899SCharles.Forsyth /* Then compute the lines */ 1305*37da2899SCharles.Forsyth 1306*37da2899SCharles.Forsyth switch ( ras.state ) 1307*37da2899SCharles.Forsyth { 1308*37da2899SCharles.Forsyth case Ascending_State: 1309*37da2899SCharles.Forsyth if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, 1310*37da2899SCharles.Forsyth x, y, ras.minY, ras.maxY ) ) 1311*37da2899SCharles.Forsyth return FAILURE; 1312*37da2899SCharles.Forsyth break; 1313*37da2899SCharles.Forsyth 1314*37da2899SCharles.Forsyth case Descending_State: 1315*37da2899SCharles.Forsyth if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, 1316*37da2899SCharles.Forsyth x, y, ras.minY, ras.maxY ) ) 1317*37da2899SCharles.Forsyth return FAILURE; 1318*37da2899SCharles.Forsyth break; 1319*37da2899SCharles.Forsyth 1320*37da2899SCharles.Forsyth default: 1321*37da2899SCharles.Forsyth ; 1322*37da2899SCharles.Forsyth } 1323*37da2899SCharles.Forsyth 1324*37da2899SCharles.Forsyth ras.lastX = x; 1325*37da2899SCharles.Forsyth ras.lastY = y; 1326*37da2899SCharles.Forsyth 1327*37da2899SCharles.Forsyth return SUCCESS; 1328*37da2899SCharles.Forsyth } 1329*37da2899SCharles.Forsyth 1330*37da2899SCharles.Forsyth 1331*37da2899SCharles.Forsyth /*************************************************************************/ 1332*37da2899SCharles.Forsyth /* */ 1333*37da2899SCharles.Forsyth /* <Function> */ 1334*37da2899SCharles.Forsyth /* Conic_To */ 1335*37da2899SCharles.Forsyth /* */ 1336*37da2899SCharles.Forsyth /* <Description> */ 1337*37da2899SCharles.Forsyth /* Injects a new conic arc and adjusts the profile list. */ 1338*37da2899SCharles.Forsyth /* */ 1339*37da2899SCharles.Forsyth /* <Input> */ 1340*37da2899SCharles.Forsyth /* cx :: The x-coordinate of the arc's new control point. */ 1341*37da2899SCharles.Forsyth /* */ 1342*37da2899SCharles.Forsyth /* cy :: The y-coordinate of the arc's new control point. */ 1343*37da2899SCharles.Forsyth /* */ 1344*37da2899SCharles.Forsyth /* x :: The x-coordinate of the arc's end point (its start point is */ 1345*37da2899SCharles.Forsyth /* stored in `LastX'). */ 1346*37da2899SCharles.Forsyth /* */ 1347*37da2899SCharles.Forsyth /* y :: The y-coordinate of the arc's end point (its start point is */ 1348*37da2899SCharles.Forsyth /* stored in `LastY'). */ 1349*37da2899SCharles.Forsyth /* */ 1350*37da2899SCharles.Forsyth /* <Return> */ 1351*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ 1352*37da2899SCharles.Forsyth /* profile. */ 1353*37da2899SCharles.Forsyth /* */ 1354*37da2899SCharles.Forsyth static Bool Conic_To(RAS_ARGS Long cx,Long cy,Long x,Long y)1355*37da2899SCharles.Forsyth Conic_To( RAS_ARGS Long cx, 1356*37da2899SCharles.Forsyth Long cy, 1357*37da2899SCharles.Forsyth Long x, 1358*37da2899SCharles.Forsyth Long y ) 1359*37da2899SCharles.Forsyth { 1360*37da2899SCharles.Forsyth Long y1, y2, y3, x3, ymin, ymax; 1361*37da2899SCharles.Forsyth TStates state_bez; 1362*37da2899SCharles.Forsyth 1363*37da2899SCharles.Forsyth 1364*37da2899SCharles.Forsyth ras.arc = ras.arcs; 1365*37da2899SCharles.Forsyth ras.arc[2].x = ras.lastX; 1366*37da2899SCharles.Forsyth ras.arc[2].y = ras.lastY; 1367*37da2899SCharles.Forsyth ras.arc[1].x = cx; ras.arc[1].y = cy; 1368*37da2899SCharles.Forsyth ras.arc[0].x = x; ras.arc[0].y = y; 1369*37da2899SCharles.Forsyth 1370*37da2899SCharles.Forsyth do 1371*37da2899SCharles.Forsyth { 1372*37da2899SCharles.Forsyth y1 = ras.arc[2].y; 1373*37da2899SCharles.Forsyth y2 = ras.arc[1].y; 1374*37da2899SCharles.Forsyth y3 = ras.arc[0].y; 1375*37da2899SCharles.Forsyth x3 = ras.arc[0].x; 1376*37da2899SCharles.Forsyth 1377*37da2899SCharles.Forsyth /* first, categorize the Bezier arc */ 1378*37da2899SCharles.Forsyth 1379*37da2899SCharles.Forsyth if ( y1 <= y3 ) 1380*37da2899SCharles.Forsyth { 1381*37da2899SCharles.Forsyth ymin = y1; 1382*37da2899SCharles.Forsyth ymax = y3; 1383*37da2899SCharles.Forsyth } 1384*37da2899SCharles.Forsyth else 1385*37da2899SCharles.Forsyth { 1386*37da2899SCharles.Forsyth ymin = y3; 1387*37da2899SCharles.Forsyth ymax = y1; 1388*37da2899SCharles.Forsyth } 1389*37da2899SCharles.Forsyth 1390*37da2899SCharles.Forsyth if ( y2 < ymin || y2 > ymax ) 1391*37da2899SCharles.Forsyth { 1392*37da2899SCharles.Forsyth /* this arc has no given direction, split it! */ 1393*37da2899SCharles.Forsyth Split_Conic( ras.arc ); 1394*37da2899SCharles.Forsyth ras.arc += 2; 1395*37da2899SCharles.Forsyth } 1396*37da2899SCharles.Forsyth else if ( y1 == y3 ) 1397*37da2899SCharles.Forsyth { 1398*37da2899SCharles.Forsyth /* this arc is flat, ignore it and pop it from the Bezier stack */ 1399*37da2899SCharles.Forsyth ras.arc -= 2; 1400*37da2899SCharles.Forsyth } 1401*37da2899SCharles.Forsyth else 1402*37da2899SCharles.Forsyth { 1403*37da2899SCharles.Forsyth /* the arc is y-monotonous, either ascending or descending */ 1404*37da2899SCharles.Forsyth /* detect a change of direction */ 1405*37da2899SCharles.Forsyth state_bez = y1 < y3 ? Ascending_State : Descending_State; 1406*37da2899SCharles.Forsyth if ( ras.state != state_bez ) 1407*37da2899SCharles.Forsyth { 1408*37da2899SCharles.Forsyth /* finalize current profile if any */ 1409*37da2899SCharles.Forsyth if ( ras.state != Unknown_State && 1410*37da2899SCharles.Forsyth End_Profile( RAS_VAR ) ) 1411*37da2899SCharles.Forsyth goto Fail; 1412*37da2899SCharles.Forsyth 1413*37da2899SCharles.Forsyth /* create a new profile */ 1414*37da2899SCharles.Forsyth if ( New_Profile( RAS_VARS state_bez ) ) 1415*37da2899SCharles.Forsyth goto Fail; 1416*37da2899SCharles.Forsyth } 1417*37da2899SCharles.Forsyth 1418*37da2899SCharles.Forsyth /* now call the appropriate routine */ 1419*37da2899SCharles.Forsyth if ( state_bez == Ascending_State ) 1420*37da2899SCharles.Forsyth { 1421*37da2899SCharles.Forsyth if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) 1422*37da2899SCharles.Forsyth goto Fail; 1423*37da2899SCharles.Forsyth } 1424*37da2899SCharles.Forsyth else 1425*37da2899SCharles.Forsyth if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) 1426*37da2899SCharles.Forsyth goto Fail; 1427*37da2899SCharles.Forsyth } 1428*37da2899SCharles.Forsyth 1429*37da2899SCharles.Forsyth } while ( ras.arc >= ras.arcs ); 1430*37da2899SCharles.Forsyth 1431*37da2899SCharles.Forsyth ras.lastX = x3; 1432*37da2899SCharles.Forsyth ras.lastY = y3; 1433*37da2899SCharles.Forsyth 1434*37da2899SCharles.Forsyth return SUCCESS; 1435*37da2899SCharles.Forsyth 1436*37da2899SCharles.Forsyth Fail: 1437*37da2899SCharles.Forsyth return FAILURE; 1438*37da2899SCharles.Forsyth } 1439*37da2899SCharles.Forsyth 1440*37da2899SCharles.Forsyth 1441*37da2899SCharles.Forsyth /*************************************************************************/ 1442*37da2899SCharles.Forsyth /* */ 1443*37da2899SCharles.Forsyth /* <Function> */ 1444*37da2899SCharles.Forsyth /* Cubic_To */ 1445*37da2899SCharles.Forsyth /* */ 1446*37da2899SCharles.Forsyth /* <Description> */ 1447*37da2899SCharles.Forsyth /* Injects a new cubic arc and adjusts the profile list. */ 1448*37da2899SCharles.Forsyth /* */ 1449*37da2899SCharles.Forsyth /* <Input> */ 1450*37da2899SCharles.Forsyth /* cx1 :: The x-coordinate of the arc's first new control point. */ 1451*37da2899SCharles.Forsyth /* */ 1452*37da2899SCharles.Forsyth /* cy1 :: The y-coordinate of the arc's first new control point. */ 1453*37da2899SCharles.Forsyth /* */ 1454*37da2899SCharles.Forsyth /* cx2 :: The x-coordinate of the arc's second new control point. */ 1455*37da2899SCharles.Forsyth /* */ 1456*37da2899SCharles.Forsyth /* cy2 :: The y-coordinate of the arc's second new control point. */ 1457*37da2899SCharles.Forsyth /* */ 1458*37da2899SCharles.Forsyth /* x :: The x-coordinate of the arc's end point (its start point is */ 1459*37da2899SCharles.Forsyth /* stored in `LastX'). */ 1460*37da2899SCharles.Forsyth /* */ 1461*37da2899SCharles.Forsyth /* y :: The y-coordinate of the arc's end point (its start point is */ 1462*37da2899SCharles.Forsyth /* stored in `LastY'). */ 1463*37da2899SCharles.Forsyth /* */ 1464*37da2899SCharles.Forsyth /* <Return> */ 1465*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ 1466*37da2899SCharles.Forsyth /* profile. */ 1467*37da2899SCharles.Forsyth /* */ 1468*37da2899SCharles.Forsyth static Bool Cubic_To(RAS_ARGS Long cx1,Long cy1,Long cx2,Long cy2,Long x,Long y)1469*37da2899SCharles.Forsyth Cubic_To( RAS_ARGS Long cx1, 1470*37da2899SCharles.Forsyth Long cy1, 1471*37da2899SCharles.Forsyth Long cx2, 1472*37da2899SCharles.Forsyth Long cy2, 1473*37da2899SCharles.Forsyth Long x, 1474*37da2899SCharles.Forsyth Long y ) 1475*37da2899SCharles.Forsyth { 1476*37da2899SCharles.Forsyth Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; 1477*37da2899SCharles.Forsyth TStates state_bez; 1478*37da2899SCharles.Forsyth 1479*37da2899SCharles.Forsyth 1480*37da2899SCharles.Forsyth ras.arc = ras.arcs; 1481*37da2899SCharles.Forsyth ras.arc[3].x = ras.lastX; 1482*37da2899SCharles.Forsyth ras.arc[3].y = ras.lastY; 1483*37da2899SCharles.Forsyth ras.arc[2].x = cx1; ras.arc[2].y = cy1; 1484*37da2899SCharles.Forsyth ras.arc[1].x = cx2; ras.arc[1].y = cy2; 1485*37da2899SCharles.Forsyth ras.arc[0].x = x; ras.arc[0].y = y; 1486*37da2899SCharles.Forsyth 1487*37da2899SCharles.Forsyth do 1488*37da2899SCharles.Forsyth { 1489*37da2899SCharles.Forsyth y1 = ras.arc[3].y; 1490*37da2899SCharles.Forsyth y2 = ras.arc[2].y; 1491*37da2899SCharles.Forsyth y3 = ras.arc[1].y; 1492*37da2899SCharles.Forsyth y4 = ras.arc[0].y; 1493*37da2899SCharles.Forsyth x4 = ras.arc[0].x; 1494*37da2899SCharles.Forsyth 1495*37da2899SCharles.Forsyth /* first, categorize the Bezier arc */ 1496*37da2899SCharles.Forsyth 1497*37da2899SCharles.Forsyth if ( y1 <= y4 ) 1498*37da2899SCharles.Forsyth { 1499*37da2899SCharles.Forsyth ymin1 = y1; 1500*37da2899SCharles.Forsyth ymax1 = y4; 1501*37da2899SCharles.Forsyth } 1502*37da2899SCharles.Forsyth else 1503*37da2899SCharles.Forsyth { 1504*37da2899SCharles.Forsyth ymin1 = y4; 1505*37da2899SCharles.Forsyth ymax1 = y1; 1506*37da2899SCharles.Forsyth } 1507*37da2899SCharles.Forsyth 1508*37da2899SCharles.Forsyth if ( y2 <= y3 ) 1509*37da2899SCharles.Forsyth { 1510*37da2899SCharles.Forsyth ymin2 = y2; 1511*37da2899SCharles.Forsyth ymax2 = y3; 1512*37da2899SCharles.Forsyth } 1513*37da2899SCharles.Forsyth else 1514*37da2899SCharles.Forsyth { 1515*37da2899SCharles.Forsyth ymin2 = y3; 1516*37da2899SCharles.Forsyth ymax2 = y2; 1517*37da2899SCharles.Forsyth } 1518*37da2899SCharles.Forsyth 1519*37da2899SCharles.Forsyth if ( ymin2 < ymin1 || ymax2 > ymax1 ) 1520*37da2899SCharles.Forsyth { 1521*37da2899SCharles.Forsyth /* this arc has no given direction, split it! */ 1522*37da2899SCharles.Forsyth Split_Cubic( ras.arc ); 1523*37da2899SCharles.Forsyth ras.arc += 3; 1524*37da2899SCharles.Forsyth } 1525*37da2899SCharles.Forsyth else if ( y1 == y4 ) 1526*37da2899SCharles.Forsyth { 1527*37da2899SCharles.Forsyth /* this arc is flat, ignore it and pop it from the Bezier stack */ 1528*37da2899SCharles.Forsyth ras.arc -= 3; 1529*37da2899SCharles.Forsyth } 1530*37da2899SCharles.Forsyth else 1531*37da2899SCharles.Forsyth { 1532*37da2899SCharles.Forsyth state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; 1533*37da2899SCharles.Forsyth 1534*37da2899SCharles.Forsyth /* detect a change of direction */ 1535*37da2899SCharles.Forsyth if ( ras.state != state_bez ) 1536*37da2899SCharles.Forsyth { 1537*37da2899SCharles.Forsyth if ( ras.state != Unknown_State && 1538*37da2899SCharles.Forsyth End_Profile( RAS_VAR ) ) 1539*37da2899SCharles.Forsyth goto Fail; 1540*37da2899SCharles.Forsyth 1541*37da2899SCharles.Forsyth if ( New_Profile( RAS_VARS state_bez ) ) 1542*37da2899SCharles.Forsyth goto Fail; 1543*37da2899SCharles.Forsyth } 1544*37da2899SCharles.Forsyth 1545*37da2899SCharles.Forsyth /* compute intersections */ 1546*37da2899SCharles.Forsyth if ( state_bez == Ascending_State ) 1547*37da2899SCharles.Forsyth { 1548*37da2899SCharles.Forsyth if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) 1549*37da2899SCharles.Forsyth goto Fail; 1550*37da2899SCharles.Forsyth } 1551*37da2899SCharles.Forsyth else 1552*37da2899SCharles.Forsyth if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) 1553*37da2899SCharles.Forsyth goto Fail; 1554*37da2899SCharles.Forsyth } 1555*37da2899SCharles.Forsyth 1556*37da2899SCharles.Forsyth } while ( ras.arc >= ras.arcs ); 1557*37da2899SCharles.Forsyth 1558*37da2899SCharles.Forsyth ras.lastX = x4; 1559*37da2899SCharles.Forsyth ras.lastY = y4; 1560*37da2899SCharles.Forsyth 1561*37da2899SCharles.Forsyth return SUCCESS; 1562*37da2899SCharles.Forsyth 1563*37da2899SCharles.Forsyth Fail: 1564*37da2899SCharles.Forsyth return FAILURE; 1565*37da2899SCharles.Forsyth } 1566*37da2899SCharles.Forsyth 1567*37da2899SCharles.Forsyth 1568*37da2899SCharles.Forsyth #undef SWAP_ 1569*37da2899SCharles.Forsyth #define SWAP_( x, y ) do \ 1570*37da2899SCharles.Forsyth { \ 1571*37da2899SCharles.Forsyth Long swap = x; \ 1572*37da2899SCharles.Forsyth \ 1573*37da2899SCharles.Forsyth \ 1574*37da2899SCharles.Forsyth x = y; \ 1575*37da2899SCharles.Forsyth y = swap; \ 1576*37da2899SCharles.Forsyth } while ( 0 ) 1577*37da2899SCharles.Forsyth 1578*37da2899SCharles.Forsyth 1579*37da2899SCharles.Forsyth /*************************************************************************/ 1580*37da2899SCharles.Forsyth /* */ 1581*37da2899SCharles.Forsyth /* <Function> */ 1582*37da2899SCharles.Forsyth /* Decompose_Curve */ 1583*37da2899SCharles.Forsyth /* */ 1584*37da2899SCharles.Forsyth /* <Description> */ 1585*37da2899SCharles.Forsyth /* Scans the outline arays in order to emit individual segments and */ 1586*37da2899SCharles.Forsyth /* Beziers by calling Line_To() and Bezier_To(). It handles all */ 1587*37da2899SCharles.Forsyth /* weird cases, like when the first point is off the curve, or when */ 1588*37da2899SCharles.Forsyth /* there are simply no `on' points in the contour! */ 1589*37da2899SCharles.Forsyth /* */ 1590*37da2899SCharles.Forsyth /* <Input> */ 1591*37da2899SCharles.Forsyth /* first :: The index of the first point in the contour. */ 1592*37da2899SCharles.Forsyth /* */ 1593*37da2899SCharles.Forsyth /* last :: The index of the last point in the contour. */ 1594*37da2899SCharles.Forsyth /* */ 1595*37da2899SCharles.Forsyth /* flipped :: If set, flip the direction of the curve. */ 1596*37da2899SCharles.Forsyth /* */ 1597*37da2899SCharles.Forsyth /* <Return> */ 1598*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE on error. */ 1599*37da2899SCharles.Forsyth /* */ 1600*37da2899SCharles.Forsyth static Bool Decompose_Curve(RAS_ARGS UShort first,UShort last,int flipped)1601*37da2899SCharles.Forsyth Decompose_Curve( RAS_ARGS UShort first, 1602*37da2899SCharles.Forsyth UShort last, 1603*37da2899SCharles.Forsyth int flipped ) 1604*37da2899SCharles.Forsyth { 1605*37da2899SCharles.Forsyth FT_Vector v_last; 1606*37da2899SCharles.Forsyth FT_Vector v_control; 1607*37da2899SCharles.Forsyth FT_Vector v_start; 1608*37da2899SCharles.Forsyth 1609*37da2899SCharles.Forsyth FT_Vector* points; 1610*37da2899SCharles.Forsyth FT_Vector* point; 1611*37da2899SCharles.Forsyth FT_Vector* limit; 1612*37da2899SCharles.Forsyth char* tags; 1613*37da2899SCharles.Forsyth 1614*37da2899SCharles.Forsyth unsigned tag; /* current point's state */ 1615*37da2899SCharles.Forsyth 1616*37da2899SCharles.Forsyth 1617*37da2899SCharles.Forsyth points = ras.outline.points; 1618*37da2899SCharles.Forsyth limit = points + last; 1619*37da2899SCharles.Forsyth 1620*37da2899SCharles.Forsyth v_start.x = SCALED( points[first].x ); 1621*37da2899SCharles.Forsyth v_start.y = SCALED( points[first].y ); 1622*37da2899SCharles.Forsyth v_last.x = SCALED( points[last].x ); 1623*37da2899SCharles.Forsyth v_last.y = SCALED( points[last].y ); 1624*37da2899SCharles.Forsyth 1625*37da2899SCharles.Forsyth if ( flipped ) 1626*37da2899SCharles.Forsyth { 1627*37da2899SCharles.Forsyth SWAP_( v_start.x, v_start.y ); 1628*37da2899SCharles.Forsyth SWAP_( v_last.x, v_last.y ); 1629*37da2899SCharles.Forsyth } 1630*37da2899SCharles.Forsyth 1631*37da2899SCharles.Forsyth v_control = v_start; 1632*37da2899SCharles.Forsyth 1633*37da2899SCharles.Forsyth point = points + first; 1634*37da2899SCharles.Forsyth tags = ras.outline.tags + first; 1635*37da2899SCharles.Forsyth tag = FT_CURVE_TAG( tags[0] ); 1636*37da2899SCharles.Forsyth 1637*37da2899SCharles.Forsyth /* A contour cannot start with a cubic control point! */ 1638*37da2899SCharles.Forsyth if ( tag == FT_CURVE_TAG_CUBIC ) 1639*37da2899SCharles.Forsyth goto Invalid_Outline; 1640*37da2899SCharles.Forsyth 1641*37da2899SCharles.Forsyth /* check first point to determine origin */ 1642*37da2899SCharles.Forsyth if ( tag == FT_CURVE_TAG_CONIC ) 1643*37da2899SCharles.Forsyth { 1644*37da2899SCharles.Forsyth /* first point is conic control. Yes, this happens. */ 1645*37da2899SCharles.Forsyth if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) 1646*37da2899SCharles.Forsyth { 1647*37da2899SCharles.Forsyth /* start at last point if it is on the curve */ 1648*37da2899SCharles.Forsyth v_start = v_last; 1649*37da2899SCharles.Forsyth limit--; 1650*37da2899SCharles.Forsyth } 1651*37da2899SCharles.Forsyth else 1652*37da2899SCharles.Forsyth { 1653*37da2899SCharles.Forsyth /* if both first and last points are conic, */ 1654*37da2899SCharles.Forsyth /* start at their middle and record its position */ 1655*37da2899SCharles.Forsyth /* for closure */ 1656*37da2899SCharles.Forsyth v_start.x = ( v_start.x + v_last.x ) / 2; 1657*37da2899SCharles.Forsyth v_start.y = ( v_start.y + v_last.y ) / 2; 1658*37da2899SCharles.Forsyth 1659*37da2899SCharles.Forsyth v_last = v_start; 1660*37da2899SCharles.Forsyth } 1661*37da2899SCharles.Forsyth point--; 1662*37da2899SCharles.Forsyth tags--; 1663*37da2899SCharles.Forsyth } 1664*37da2899SCharles.Forsyth 1665*37da2899SCharles.Forsyth ras.lastX = v_start.x; 1666*37da2899SCharles.Forsyth ras.lastY = v_start.y; 1667*37da2899SCharles.Forsyth 1668*37da2899SCharles.Forsyth while ( point < limit ) 1669*37da2899SCharles.Forsyth { 1670*37da2899SCharles.Forsyth point++; 1671*37da2899SCharles.Forsyth tags++; 1672*37da2899SCharles.Forsyth 1673*37da2899SCharles.Forsyth tag = FT_CURVE_TAG( tags[0] ); 1674*37da2899SCharles.Forsyth 1675*37da2899SCharles.Forsyth switch ( tag ) 1676*37da2899SCharles.Forsyth { 1677*37da2899SCharles.Forsyth case FT_CURVE_TAG_ON: /* emit a single line_to */ 1678*37da2899SCharles.Forsyth { 1679*37da2899SCharles.Forsyth Long x, y; 1680*37da2899SCharles.Forsyth 1681*37da2899SCharles.Forsyth 1682*37da2899SCharles.Forsyth x = SCALED( point->x ); 1683*37da2899SCharles.Forsyth y = SCALED( point->y ); 1684*37da2899SCharles.Forsyth if ( flipped ) 1685*37da2899SCharles.Forsyth SWAP_( x, y ); 1686*37da2899SCharles.Forsyth 1687*37da2899SCharles.Forsyth if ( Line_To( RAS_VARS x, y ) ) 1688*37da2899SCharles.Forsyth goto Fail; 1689*37da2899SCharles.Forsyth continue; 1690*37da2899SCharles.Forsyth } 1691*37da2899SCharles.Forsyth 1692*37da2899SCharles.Forsyth case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 1693*37da2899SCharles.Forsyth v_control.x = SCALED( point[0].x ); 1694*37da2899SCharles.Forsyth v_control.y = SCALED( point[0].y ); 1695*37da2899SCharles.Forsyth 1696*37da2899SCharles.Forsyth if ( flipped ) 1697*37da2899SCharles.Forsyth SWAP_( v_control.x, v_control.y ); 1698*37da2899SCharles.Forsyth 1699*37da2899SCharles.Forsyth Do_Conic: 1700*37da2899SCharles.Forsyth if ( point < limit ) 1701*37da2899SCharles.Forsyth { 1702*37da2899SCharles.Forsyth FT_Vector v_middle; 1703*37da2899SCharles.Forsyth Long x, y; 1704*37da2899SCharles.Forsyth 1705*37da2899SCharles.Forsyth 1706*37da2899SCharles.Forsyth point++; 1707*37da2899SCharles.Forsyth tags++; 1708*37da2899SCharles.Forsyth tag = FT_CURVE_TAG( tags[0] ); 1709*37da2899SCharles.Forsyth 1710*37da2899SCharles.Forsyth x = SCALED( point[0].x ); 1711*37da2899SCharles.Forsyth y = SCALED( point[0].y ); 1712*37da2899SCharles.Forsyth 1713*37da2899SCharles.Forsyth if ( flipped ) 1714*37da2899SCharles.Forsyth SWAP_( x, y ); 1715*37da2899SCharles.Forsyth 1716*37da2899SCharles.Forsyth if ( tag == FT_CURVE_TAG_ON ) 1717*37da2899SCharles.Forsyth { 1718*37da2899SCharles.Forsyth if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) 1719*37da2899SCharles.Forsyth goto Fail; 1720*37da2899SCharles.Forsyth continue; 1721*37da2899SCharles.Forsyth } 1722*37da2899SCharles.Forsyth 1723*37da2899SCharles.Forsyth if ( tag != FT_CURVE_TAG_CONIC ) 1724*37da2899SCharles.Forsyth goto Invalid_Outline; 1725*37da2899SCharles.Forsyth 1726*37da2899SCharles.Forsyth v_middle.x = ( v_control.x + x ) / 2; 1727*37da2899SCharles.Forsyth v_middle.y = ( v_control.y + y ) / 2; 1728*37da2899SCharles.Forsyth 1729*37da2899SCharles.Forsyth if ( Conic_To( RAS_VARS v_control.x, v_control.y, 1730*37da2899SCharles.Forsyth v_middle.x, v_middle.y ) ) 1731*37da2899SCharles.Forsyth goto Fail; 1732*37da2899SCharles.Forsyth 1733*37da2899SCharles.Forsyth v_control.x = x; 1734*37da2899SCharles.Forsyth v_control.y = y; 1735*37da2899SCharles.Forsyth 1736*37da2899SCharles.Forsyth goto Do_Conic; 1737*37da2899SCharles.Forsyth } 1738*37da2899SCharles.Forsyth 1739*37da2899SCharles.Forsyth if ( Conic_To( RAS_VARS v_control.x, v_control.y, 1740*37da2899SCharles.Forsyth v_start.x, v_start.y ) ) 1741*37da2899SCharles.Forsyth goto Fail; 1742*37da2899SCharles.Forsyth 1743*37da2899SCharles.Forsyth goto Close; 1744*37da2899SCharles.Forsyth 1745*37da2899SCharles.Forsyth default: /* FT_CURVE_TAG_CUBIC */ 1746*37da2899SCharles.Forsyth { 1747*37da2899SCharles.Forsyth Long x1, y1, x2, y2, x3, y3; 1748*37da2899SCharles.Forsyth 1749*37da2899SCharles.Forsyth 1750*37da2899SCharles.Forsyth if ( point + 1 > limit || 1751*37da2899SCharles.Forsyth FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 1752*37da2899SCharles.Forsyth goto Invalid_Outline; 1753*37da2899SCharles.Forsyth 1754*37da2899SCharles.Forsyth point += 2; 1755*37da2899SCharles.Forsyth tags += 2; 1756*37da2899SCharles.Forsyth 1757*37da2899SCharles.Forsyth x1 = SCALED( point[-2].x ); 1758*37da2899SCharles.Forsyth y1 = SCALED( point[-2].y ); 1759*37da2899SCharles.Forsyth x2 = SCALED( point[-1].x ); 1760*37da2899SCharles.Forsyth y2 = SCALED( point[-1].y ); 1761*37da2899SCharles.Forsyth x3 = SCALED( point[ 0].x ); 1762*37da2899SCharles.Forsyth y3 = SCALED( point[ 0].y ); 1763*37da2899SCharles.Forsyth 1764*37da2899SCharles.Forsyth if ( flipped ) 1765*37da2899SCharles.Forsyth { 1766*37da2899SCharles.Forsyth SWAP_( x1, y1 ); 1767*37da2899SCharles.Forsyth SWAP_( x2, y2 ); 1768*37da2899SCharles.Forsyth SWAP_( x3, y3 ); 1769*37da2899SCharles.Forsyth } 1770*37da2899SCharles.Forsyth 1771*37da2899SCharles.Forsyth if ( point <= limit ) 1772*37da2899SCharles.Forsyth { 1773*37da2899SCharles.Forsyth if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) 1774*37da2899SCharles.Forsyth goto Fail; 1775*37da2899SCharles.Forsyth continue; 1776*37da2899SCharles.Forsyth } 1777*37da2899SCharles.Forsyth 1778*37da2899SCharles.Forsyth if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) 1779*37da2899SCharles.Forsyth goto Fail; 1780*37da2899SCharles.Forsyth goto Close; 1781*37da2899SCharles.Forsyth } 1782*37da2899SCharles.Forsyth } 1783*37da2899SCharles.Forsyth } 1784*37da2899SCharles.Forsyth 1785*37da2899SCharles.Forsyth /* close the contour with a line segment */ 1786*37da2899SCharles.Forsyth if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) 1787*37da2899SCharles.Forsyth goto Fail; 1788*37da2899SCharles.Forsyth 1789*37da2899SCharles.Forsyth Close: 1790*37da2899SCharles.Forsyth return SUCCESS; 1791*37da2899SCharles.Forsyth 1792*37da2899SCharles.Forsyth Invalid_Outline: 1793*37da2899SCharles.Forsyth ras.error = Raster_Err_Invalid; 1794*37da2899SCharles.Forsyth 1795*37da2899SCharles.Forsyth Fail: 1796*37da2899SCharles.Forsyth return FAILURE; 1797*37da2899SCharles.Forsyth } 1798*37da2899SCharles.Forsyth 1799*37da2899SCharles.Forsyth 1800*37da2899SCharles.Forsyth /*************************************************************************/ 1801*37da2899SCharles.Forsyth /* */ 1802*37da2899SCharles.Forsyth /* <Function> */ 1803*37da2899SCharles.Forsyth /* Convert_Glyph */ 1804*37da2899SCharles.Forsyth /* */ 1805*37da2899SCharles.Forsyth /* <Description> */ 1806*37da2899SCharles.Forsyth /* Converts a glyph into a series of segments and arcs and makes a */ 1807*37da2899SCharles.Forsyth /* profiles list with them. */ 1808*37da2899SCharles.Forsyth /* */ 1809*37da2899SCharles.Forsyth /* <Input> */ 1810*37da2899SCharles.Forsyth /* flipped :: If set, flip the direction of curve. */ 1811*37da2899SCharles.Forsyth /* */ 1812*37da2899SCharles.Forsyth /* <Return> */ 1813*37da2899SCharles.Forsyth /* SUCCESS on success, FAILURE if any error was encountered during */ 1814*37da2899SCharles.Forsyth /* rendering. */ 1815*37da2899SCharles.Forsyth /* */ 1816*37da2899SCharles.Forsyth static Bool Convert_Glyph(RAS_ARGS int flipped)1817*37da2899SCharles.Forsyth Convert_Glyph( RAS_ARGS int flipped ) 1818*37da2899SCharles.Forsyth { 1819*37da2899SCharles.Forsyth int i; 1820*37da2899SCharles.Forsyth unsigned start; 1821*37da2899SCharles.Forsyth 1822*37da2899SCharles.Forsyth PProfile lastProfile; 1823*37da2899SCharles.Forsyth 1824*37da2899SCharles.Forsyth 1825*37da2899SCharles.Forsyth ras.fProfile = NULL; 1826*37da2899SCharles.Forsyth ras.joint = FALSE; 1827*37da2899SCharles.Forsyth ras.fresh = FALSE; 1828*37da2899SCharles.Forsyth 1829*37da2899SCharles.Forsyth ras.maxBuff = ras.sizeBuff - AlignProfileSize; 1830*37da2899SCharles.Forsyth 1831*37da2899SCharles.Forsyth ras.numTurns = 0; 1832*37da2899SCharles.Forsyth 1833*37da2899SCharles.Forsyth ras.cProfile = (PProfile)ras.top; 1834*37da2899SCharles.Forsyth ras.cProfile->offset = ras.top; 1835*37da2899SCharles.Forsyth ras.num_Profs = 0; 1836*37da2899SCharles.Forsyth 1837*37da2899SCharles.Forsyth start = 0; 1838*37da2899SCharles.Forsyth 1839*37da2899SCharles.Forsyth for ( i = 0; i < ras.outline.n_contours; i++ ) 1840*37da2899SCharles.Forsyth { 1841*37da2899SCharles.Forsyth ras.state = Unknown_State; 1842*37da2899SCharles.Forsyth ras.gProfile = NULL; 1843*37da2899SCharles.Forsyth 1844*37da2899SCharles.Forsyth if ( Decompose_Curve( RAS_VARS (unsigned short)start, 1845*37da2899SCharles.Forsyth ras.outline.contours[i], 1846*37da2899SCharles.Forsyth flipped ) ) 1847*37da2899SCharles.Forsyth return FAILURE; 1848*37da2899SCharles.Forsyth 1849*37da2899SCharles.Forsyth start = ras.outline.contours[i] + 1; 1850*37da2899SCharles.Forsyth 1851*37da2899SCharles.Forsyth /* We must now see whether the extreme arcs join or not */ 1852*37da2899SCharles.Forsyth if ( FRAC( ras.lastY ) == 0 && 1853*37da2899SCharles.Forsyth ras.lastY >= ras.minY && 1854*37da2899SCharles.Forsyth ras.lastY <= ras.maxY ) 1855*37da2899SCharles.Forsyth if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow ) 1856*37da2899SCharles.Forsyth ras.top--; 1857*37da2899SCharles.Forsyth /* Note that ras.gProfile can be nil if the contour was too small */ 1858*37da2899SCharles.Forsyth /* to be drawn. */ 1859*37da2899SCharles.Forsyth 1860*37da2899SCharles.Forsyth lastProfile = ras.cProfile; 1861*37da2899SCharles.Forsyth if ( End_Profile( RAS_VAR ) ) 1862*37da2899SCharles.Forsyth return FAILURE; 1863*37da2899SCharles.Forsyth 1864*37da2899SCharles.Forsyth /* close the `next profile in contour' linked list */ 1865*37da2899SCharles.Forsyth if ( ras.gProfile ) 1866*37da2899SCharles.Forsyth lastProfile->next = ras.gProfile; 1867*37da2899SCharles.Forsyth } 1868*37da2899SCharles.Forsyth 1869*37da2899SCharles.Forsyth if ( Finalize_Profile_Table( RAS_VAR ) ) 1870*37da2899SCharles.Forsyth return FAILURE; 1871*37da2899SCharles.Forsyth 1872*37da2899SCharles.Forsyth return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); 1873*37da2899SCharles.Forsyth } 1874*37da2899SCharles.Forsyth 1875*37da2899SCharles.Forsyth 1876*37da2899SCharles.Forsyth /*************************************************************************/ 1877*37da2899SCharles.Forsyth /*************************************************************************/ 1878*37da2899SCharles.Forsyth /** **/ 1879*37da2899SCharles.Forsyth /** SCAN-LINE SWEEPS AND DRAWING **/ 1880*37da2899SCharles.Forsyth /** **/ 1881*37da2899SCharles.Forsyth /*************************************************************************/ 1882*37da2899SCharles.Forsyth /*************************************************************************/ 1883*37da2899SCharles.Forsyth 1884*37da2899SCharles.Forsyth 1885*37da2899SCharles.Forsyth /*************************************************************************/ 1886*37da2899SCharles.Forsyth /* */ 1887*37da2899SCharles.Forsyth /* Init_Linked */ 1888*37da2899SCharles.Forsyth /* */ 1889*37da2899SCharles.Forsyth /* Initializes an empty linked list. */ 1890*37da2899SCharles.Forsyth /* */ 1891*37da2899SCharles.Forsyth static void Init_Linked(TProfileList * l)1892*37da2899SCharles.Forsyth Init_Linked( TProfileList* l ) 1893*37da2899SCharles.Forsyth { 1894*37da2899SCharles.Forsyth *l = NULL; 1895*37da2899SCharles.Forsyth } 1896*37da2899SCharles.Forsyth 1897*37da2899SCharles.Forsyth 1898*37da2899SCharles.Forsyth /*************************************************************************/ 1899*37da2899SCharles.Forsyth /* */ 1900*37da2899SCharles.Forsyth /* InsNew */ 1901*37da2899SCharles.Forsyth /* */ 1902*37da2899SCharles.Forsyth /* Inserts a new profile in a linked list. */ 1903*37da2899SCharles.Forsyth /* */ 1904*37da2899SCharles.Forsyth static void InsNew(PProfileList list,PProfile profile)1905*37da2899SCharles.Forsyth InsNew( PProfileList list, 1906*37da2899SCharles.Forsyth PProfile profile ) 1907*37da2899SCharles.Forsyth { 1908*37da2899SCharles.Forsyth PProfile *old, current; 1909*37da2899SCharles.Forsyth Long x; 1910*37da2899SCharles.Forsyth 1911*37da2899SCharles.Forsyth 1912*37da2899SCharles.Forsyth old = list; 1913*37da2899SCharles.Forsyth current = *old; 1914*37da2899SCharles.Forsyth x = profile->X; 1915*37da2899SCharles.Forsyth 1916*37da2899SCharles.Forsyth while ( current ) 1917*37da2899SCharles.Forsyth { 1918*37da2899SCharles.Forsyth if ( x < current->X ) 1919*37da2899SCharles.Forsyth break; 1920*37da2899SCharles.Forsyth old = ¤t->link; 1921*37da2899SCharles.Forsyth current = *old; 1922*37da2899SCharles.Forsyth } 1923*37da2899SCharles.Forsyth 1924*37da2899SCharles.Forsyth profile->link = current; 1925*37da2899SCharles.Forsyth *old = profile; 1926*37da2899SCharles.Forsyth } 1927*37da2899SCharles.Forsyth 1928*37da2899SCharles.Forsyth 1929*37da2899SCharles.Forsyth /*************************************************************************/ 1930*37da2899SCharles.Forsyth /* */ 1931*37da2899SCharles.Forsyth /* DelOld */ 1932*37da2899SCharles.Forsyth /* */ 1933*37da2899SCharles.Forsyth /* Removes an old profile from a linked list. */ 1934*37da2899SCharles.Forsyth /* */ 1935*37da2899SCharles.Forsyth static void DelOld(PProfileList list,PProfile profile)1936*37da2899SCharles.Forsyth DelOld( PProfileList list, 1937*37da2899SCharles.Forsyth PProfile profile ) 1938*37da2899SCharles.Forsyth { 1939*37da2899SCharles.Forsyth PProfile *old, current; 1940*37da2899SCharles.Forsyth 1941*37da2899SCharles.Forsyth 1942*37da2899SCharles.Forsyth old = list; 1943*37da2899SCharles.Forsyth current = *old; 1944*37da2899SCharles.Forsyth 1945*37da2899SCharles.Forsyth while ( current ) 1946*37da2899SCharles.Forsyth { 1947*37da2899SCharles.Forsyth if ( current == profile ) 1948*37da2899SCharles.Forsyth { 1949*37da2899SCharles.Forsyth *old = current->link; 1950*37da2899SCharles.Forsyth return; 1951*37da2899SCharles.Forsyth } 1952*37da2899SCharles.Forsyth 1953*37da2899SCharles.Forsyth old = ¤t->link; 1954*37da2899SCharles.Forsyth current = *old; 1955*37da2899SCharles.Forsyth } 1956*37da2899SCharles.Forsyth 1957*37da2899SCharles.Forsyth /* we should never get there, unless the profile was not part of */ 1958*37da2899SCharles.Forsyth /* the list. */ 1959*37da2899SCharles.Forsyth } 1960*37da2899SCharles.Forsyth 1961*37da2899SCharles.Forsyth 1962*37da2899SCharles.Forsyth /*************************************************************************/ 1963*37da2899SCharles.Forsyth /* */ 1964*37da2899SCharles.Forsyth /* Sort */ 1965*37da2899SCharles.Forsyth /* */ 1966*37da2899SCharles.Forsyth /* Sorts a trace list. In 95%, the list is already sorted. We need */ 1967*37da2899SCharles.Forsyth /* an algorithm which is fast in this case. Bubble sort is enough */ 1968*37da2899SCharles.Forsyth /* and simple. */ 1969*37da2899SCharles.Forsyth /* */ 1970*37da2899SCharles.Forsyth static void Sort(PProfileList list)1971*37da2899SCharles.Forsyth Sort( PProfileList list ) 1972*37da2899SCharles.Forsyth { 1973*37da2899SCharles.Forsyth PProfile *old, current, next; 1974*37da2899SCharles.Forsyth 1975*37da2899SCharles.Forsyth 1976*37da2899SCharles.Forsyth /* First, set the new X coordinate of each profile */ 1977*37da2899SCharles.Forsyth current = *list; 1978*37da2899SCharles.Forsyth while ( current ) 1979*37da2899SCharles.Forsyth { 1980*37da2899SCharles.Forsyth current->X = *current->offset; 1981*37da2899SCharles.Forsyth current->offset += current->flow; 1982*37da2899SCharles.Forsyth current->height--; 1983*37da2899SCharles.Forsyth current = current->link; 1984*37da2899SCharles.Forsyth } 1985*37da2899SCharles.Forsyth 1986*37da2899SCharles.Forsyth /* Then sort them */ 1987*37da2899SCharles.Forsyth old = list; 1988*37da2899SCharles.Forsyth current = *old; 1989*37da2899SCharles.Forsyth 1990*37da2899SCharles.Forsyth if ( !current ) 1991*37da2899SCharles.Forsyth return; 1992*37da2899SCharles.Forsyth 1993*37da2899SCharles.Forsyth next = current->link; 1994*37da2899SCharles.Forsyth 1995*37da2899SCharles.Forsyth while ( next ) 1996*37da2899SCharles.Forsyth { 1997*37da2899SCharles.Forsyth if ( current->X <= next->X ) 1998*37da2899SCharles.Forsyth { 1999*37da2899SCharles.Forsyth old = ¤t->link; 2000*37da2899SCharles.Forsyth current = *old; 2001*37da2899SCharles.Forsyth 2002*37da2899SCharles.Forsyth if ( !current ) 2003*37da2899SCharles.Forsyth return; 2004*37da2899SCharles.Forsyth } 2005*37da2899SCharles.Forsyth else 2006*37da2899SCharles.Forsyth { 2007*37da2899SCharles.Forsyth *old = next; 2008*37da2899SCharles.Forsyth current->link = next->link; 2009*37da2899SCharles.Forsyth next->link = current; 2010*37da2899SCharles.Forsyth 2011*37da2899SCharles.Forsyth old = list; 2012*37da2899SCharles.Forsyth current = *old; 2013*37da2899SCharles.Forsyth } 2014*37da2899SCharles.Forsyth 2015*37da2899SCharles.Forsyth next = current->link; 2016*37da2899SCharles.Forsyth } 2017*37da2899SCharles.Forsyth } 2018*37da2899SCharles.Forsyth 2019*37da2899SCharles.Forsyth 2020*37da2899SCharles.Forsyth /*************************************************************************/ 2021*37da2899SCharles.Forsyth /* */ 2022*37da2899SCharles.Forsyth /* Vertical Sweep Procedure Set */ 2023*37da2899SCharles.Forsyth /* */ 2024*37da2899SCharles.Forsyth /* These four routines are used during the vertical black/white sweep */ 2025*37da2899SCharles.Forsyth /* phase by the generic Draw_Sweep() function. */ 2026*37da2899SCharles.Forsyth /* */ 2027*37da2899SCharles.Forsyth /*************************************************************************/ 2028*37da2899SCharles.Forsyth 2029*37da2899SCharles.Forsyth static void Vertical_Sweep_Init(RAS_ARGS Short * min,Short * max)2030*37da2899SCharles.Forsyth Vertical_Sweep_Init( RAS_ARGS Short* min, 2031*37da2899SCharles.Forsyth Short* max ) 2032*37da2899SCharles.Forsyth { 2033*37da2899SCharles.Forsyth Long pitch = ras.target.pitch; 2034*37da2899SCharles.Forsyth 2035*37da2899SCharles.Forsyth FT_UNUSED( max ); 2036*37da2899SCharles.Forsyth 2037*37da2899SCharles.Forsyth 2038*37da2899SCharles.Forsyth ras.traceIncr = (Short)-pitch; 2039*37da2899SCharles.Forsyth ras.traceOfs = -*min * pitch; 2040*37da2899SCharles.Forsyth if ( pitch > 0 ) 2041*37da2899SCharles.Forsyth ras.traceOfs += ( ras.target.rows - 1 ) * pitch; 2042*37da2899SCharles.Forsyth 2043*37da2899SCharles.Forsyth ras.gray_min_x = 0; 2044*37da2899SCharles.Forsyth ras.gray_max_x = 0; 2045*37da2899SCharles.Forsyth } 2046*37da2899SCharles.Forsyth 2047*37da2899SCharles.Forsyth 2048*37da2899SCharles.Forsyth static void Vertical_Sweep_Span(RAS_ARGS Short y,FT_F26Dot6 x1,FT_F26Dot6 x2,PProfile left,PProfile right)2049*37da2899SCharles.Forsyth Vertical_Sweep_Span( RAS_ARGS Short y, 2050*37da2899SCharles.Forsyth FT_F26Dot6 x1, 2051*37da2899SCharles.Forsyth FT_F26Dot6 x2, 2052*37da2899SCharles.Forsyth PProfile left, 2053*37da2899SCharles.Forsyth PProfile right ) 2054*37da2899SCharles.Forsyth { 2055*37da2899SCharles.Forsyth Long e1, e2; 2056*37da2899SCharles.Forsyth int c1, c2; 2057*37da2899SCharles.Forsyth Byte f1, f2; 2058*37da2899SCharles.Forsyth Byte* target; 2059*37da2899SCharles.Forsyth 2060*37da2899SCharles.Forsyth FT_UNUSED( y ); 2061*37da2899SCharles.Forsyth FT_UNUSED( left ); 2062*37da2899SCharles.Forsyth FT_UNUSED( right ); 2063*37da2899SCharles.Forsyth 2064*37da2899SCharles.Forsyth 2065*37da2899SCharles.Forsyth /* Drop-out control */ 2066*37da2899SCharles.Forsyth 2067*37da2899SCharles.Forsyth e1 = TRUNC( CEILING( x1 ) ); 2068*37da2899SCharles.Forsyth 2069*37da2899SCharles.Forsyth if ( x2 - x1 - ras.precision <= ras.precision_jitter ) 2070*37da2899SCharles.Forsyth e2 = e1; 2071*37da2899SCharles.Forsyth else 2072*37da2899SCharles.Forsyth e2 = TRUNC( FLOOR( x2 ) ); 2073*37da2899SCharles.Forsyth 2074*37da2899SCharles.Forsyth if ( e2 >= 0 && e1 < ras.bWidth ) 2075*37da2899SCharles.Forsyth { 2076*37da2899SCharles.Forsyth if ( e1 < 0 ) 2077*37da2899SCharles.Forsyth e1 = 0; 2078*37da2899SCharles.Forsyth if ( e2 >= ras.bWidth ) 2079*37da2899SCharles.Forsyth e2 = ras.bWidth - 1; 2080*37da2899SCharles.Forsyth 2081*37da2899SCharles.Forsyth c1 = (Short)( e1 >> 3 ); 2082*37da2899SCharles.Forsyth c2 = (Short)( e2 >> 3 ); 2083*37da2899SCharles.Forsyth 2084*37da2899SCharles.Forsyth f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); 2085*37da2899SCharles.Forsyth f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); 2086*37da2899SCharles.Forsyth 2087*37da2899SCharles.Forsyth if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1; 2088*37da2899SCharles.Forsyth if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2; 2089*37da2899SCharles.Forsyth 2090*37da2899SCharles.Forsyth target = ras.bTarget + ras.traceOfs + c1; 2091*37da2899SCharles.Forsyth c2 -= c1; 2092*37da2899SCharles.Forsyth 2093*37da2899SCharles.Forsyth if ( c2 > 0 ) 2094*37da2899SCharles.Forsyth { 2095*37da2899SCharles.Forsyth target[0] |= f1; 2096*37da2899SCharles.Forsyth 2097*37da2899SCharles.Forsyth /* memset() is slower than the following code on many platforms. */ 2098*37da2899SCharles.Forsyth /* This is due to the fact that, in the vast majority of cases, */ 2099*37da2899SCharles.Forsyth /* the span length in bytes is relatively small. */ 2100*37da2899SCharles.Forsyth c2--; 2101*37da2899SCharles.Forsyth while ( c2 > 0 ) 2102*37da2899SCharles.Forsyth { 2103*37da2899SCharles.Forsyth *(++target) = 0xFF; 2104*37da2899SCharles.Forsyth c2--; 2105*37da2899SCharles.Forsyth } 2106*37da2899SCharles.Forsyth target[1] |= f2; 2107*37da2899SCharles.Forsyth } 2108*37da2899SCharles.Forsyth else 2109*37da2899SCharles.Forsyth *target |= ( f1 & f2 ); 2110*37da2899SCharles.Forsyth } 2111*37da2899SCharles.Forsyth } 2112*37da2899SCharles.Forsyth 2113*37da2899SCharles.Forsyth 2114*37da2899SCharles.Forsyth static void Vertical_Sweep_Drop(RAS_ARGS Short y,FT_F26Dot6 x1,FT_F26Dot6 x2,PProfile left,PProfile right)2115*37da2899SCharles.Forsyth Vertical_Sweep_Drop( RAS_ARGS Short y, 2116*37da2899SCharles.Forsyth FT_F26Dot6 x1, 2117*37da2899SCharles.Forsyth FT_F26Dot6 x2, 2118*37da2899SCharles.Forsyth PProfile left, 2119*37da2899SCharles.Forsyth PProfile right ) 2120*37da2899SCharles.Forsyth { 2121*37da2899SCharles.Forsyth Long e1, e2; 2122*37da2899SCharles.Forsyth Short c1, f1; 2123*37da2899SCharles.Forsyth 2124*37da2899SCharles.Forsyth 2125*37da2899SCharles.Forsyth /* Drop-out control */ 2126*37da2899SCharles.Forsyth 2127*37da2899SCharles.Forsyth e1 = CEILING( x1 ); 2128*37da2899SCharles.Forsyth e2 = FLOOR ( x2 ); 2129*37da2899SCharles.Forsyth 2130*37da2899SCharles.Forsyth if ( e1 > e2 ) 2131*37da2899SCharles.Forsyth { 2132*37da2899SCharles.Forsyth if ( e1 == e2 + ras.precision ) 2133*37da2899SCharles.Forsyth { 2134*37da2899SCharles.Forsyth switch ( ras.dropOutControl ) 2135*37da2899SCharles.Forsyth { 2136*37da2899SCharles.Forsyth case 1: 2137*37da2899SCharles.Forsyth e1 = e2; 2138*37da2899SCharles.Forsyth break; 2139*37da2899SCharles.Forsyth 2140*37da2899SCharles.Forsyth case 4: 2141*37da2899SCharles.Forsyth e1 = CEILING( (x1 + x2 + 1) / 2 ); 2142*37da2899SCharles.Forsyth break; 2143*37da2899SCharles.Forsyth 2144*37da2899SCharles.Forsyth case 2: 2145*37da2899SCharles.Forsyth case 5: 2146*37da2899SCharles.Forsyth /* Drop-out Control Rule #4 */ 2147*37da2899SCharles.Forsyth 2148*37da2899SCharles.Forsyth /* The spec is not very clear regarding rule #4. It */ 2149*37da2899SCharles.Forsyth /* presents a method that is way too costly to implement */ 2150*37da2899SCharles.Forsyth /* while the general idea seems to get rid of `stubs'. */ 2151*37da2899SCharles.Forsyth /* */ 2152*37da2899SCharles.Forsyth /* Here, we only get rid of stubs recognized if: */ 2153*37da2899SCharles.Forsyth /* */ 2154*37da2899SCharles.Forsyth /* upper stub: */ 2155*37da2899SCharles.Forsyth /* */ 2156*37da2899SCharles.Forsyth /* - P_Left and P_Right are in the same contour */ 2157*37da2899SCharles.Forsyth /* - P_Right is the successor of P_Left in that contour */ 2158*37da2899SCharles.Forsyth /* - y is the top of P_Left and P_Right */ 2159*37da2899SCharles.Forsyth /* */ 2160*37da2899SCharles.Forsyth /* lower stub: */ 2161*37da2899SCharles.Forsyth /* */ 2162*37da2899SCharles.Forsyth /* - P_Left and P_Right are in the same contour */ 2163*37da2899SCharles.Forsyth /* - P_Left is the successor of P_Right in that contour */ 2164*37da2899SCharles.Forsyth /* - y is the bottom of P_Left */ 2165*37da2899SCharles.Forsyth /* */ 2166*37da2899SCharles.Forsyth 2167*37da2899SCharles.Forsyth /* FIXXXME: uncommenting this line solves the disappearing */ 2168*37da2899SCharles.Forsyth /* bit problem in the `7' of verdana 10pts, but */ 2169*37da2899SCharles.Forsyth /* makes a new one in the `C' of arial 14pts */ 2170*37da2899SCharles.Forsyth 2171*37da2899SCharles.Forsyth #if 0 2172*37da2899SCharles.Forsyth if ( x2 - x1 < ras.precision_half ) 2173*37da2899SCharles.Forsyth #endif 2174*37da2899SCharles.Forsyth { 2175*37da2899SCharles.Forsyth /* upper stub test */ 2176*37da2899SCharles.Forsyth if ( left->next == right && left->height <= 0 ) 2177*37da2899SCharles.Forsyth return; 2178*37da2899SCharles.Forsyth 2179*37da2899SCharles.Forsyth /* lower stub test */ 2180*37da2899SCharles.Forsyth if ( right->next == left && left->start == y ) 2181*37da2899SCharles.Forsyth return; 2182*37da2899SCharles.Forsyth } 2183*37da2899SCharles.Forsyth 2184*37da2899SCharles.Forsyth /* check that the rightmost pixel isn't set */ 2185*37da2899SCharles.Forsyth 2186*37da2899SCharles.Forsyth e1 = TRUNC( e1 ); 2187*37da2899SCharles.Forsyth 2188*37da2899SCharles.Forsyth c1 = (Short)( e1 >> 3 ); 2189*37da2899SCharles.Forsyth f1 = (Short)( e1 & 7 ); 2190*37da2899SCharles.Forsyth 2191*37da2899SCharles.Forsyth if ( e1 >= 0 && e1 < ras.bWidth && 2192*37da2899SCharles.Forsyth ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) 2193*37da2899SCharles.Forsyth return; 2194*37da2899SCharles.Forsyth 2195*37da2899SCharles.Forsyth if ( ras.dropOutControl == 2 ) 2196*37da2899SCharles.Forsyth e1 = e2; 2197*37da2899SCharles.Forsyth else 2198*37da2899SCharles.Forsyth e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); 2199*37da2899SCharles.Forsyth 2200*37da2899SCharles.Forsyth break; 2201*37da2899SCharles.Forsyth 2202*37da2899SCharles.Forsyth default: 2203*37da2899SCharles.Forsyth return; /* unsupported mode */ 2204*37da2899SCharles.Forsyth } 2205*37da2899SCharles.Forsyth } 2206*37da2899SCharles.Forsyth else 2207*37da2899SCharles.Forsyth return; 2208*37da2899SCharles.Forsyth } 2209*37da2899SCharles.Forsyth 2210*37da2899SCharles.Forsyth e1 = TRUNC( e1 ); 2211*37da2899SCharles.Forsyth 2212*37da2899SCharles.Forsyth if ( e1 >= 0 && e1 < ras.bWidth ) 2213*37da2899SCharles.Forsyth { 2214*37da2899SCharles.Forsyth c1 = (Short)( e1 >> 3 ); 2215*37da2899SCharles.Forsyth f1 = (Short)( e1 & 7 ); 2216*37da2899SCharles.Forsyth 2217*37da2899SCharles.Forsyth if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1; 2218*37da2899SCharles.Forsyth if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1; 2219*37da2899SCharles.Forsyth 2220*37da2899SCharles.Forsyth ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); 2221*37da2899SCharles.Forsyth } 2222*37da2899SCharles.Forsyth } 2223*37da2899SCharles.Forsyth 2224*37da2899SCharles.Forsyth 2225*37da2899SCharles.Forsyth static void Vertical_Sweep_Step(RAS_ARG)2226*37da2899SCharles.Forsyth Vertical_Sweep_Step( RAS_ARG ) 2227*37da2899SCharles.Forsyth { 2228*37da2899SCharles.Forsyth ras.traceOfs += ras.traceIncr; 2229*37da2899SCharles.Forsyth } 2230*37da2899SCharles.Forsyth 2231*37da2899SCharles.Forsyth 2232*37da2899SCharles.Forsyth /***********************************************************************/ 2233*37da2899SCharles.Forsyth /* */ 2234*37da2899SCharles.Forsyth /* Horizontal Sweep Procedure Set */ 2235*37da2899SCharles.Forsyth /* */ 2236*37da2899SCharles.Forsyth /* These four routines are used during the horizontal black/white */ 2237*37da2899SCharles.Forsyth /* sweep phase by the generic Draw_Sweep() function. */ 2238*37da2899SCharles.Forsyth /* */ 2239*37da2899SCharles.Forsyth /***********************************************************************/ 2240*37da2899SCharles.Forsyth 2241*37da2899SCharles.Forsyth static void Horizontal_Sweep_Init(RAS_ARGS Short * min,Short * max)2242*37da2899SCharles.Forsyth Horizontal_Sweep_Init( RAS_ARGS Short* min, 2243*37da2899SCharles.Forsyth Short* max ) 2244*37da2899SCharles.Forsyth { 2245*37da2899SCharles.Forsyth /* nothing, really */ 2246*37da2899SCharles.Forsyth FT_UNUSED( raster ); 2247*37da2899SCharles.Forsyth FT_UNUSED( min ); 2248*37da2899SCharles.Forsyth FT_UNUSED( max ); 2249*37da2899SCharles.Forsyth } 2250*37da2899SCharles.Forsyth 2251*37da2899SCharles.Forsyth 2252*37da2899SCharles.Forsyth static void Horizontal_Sweep_Span(RAS_ARGS Short y,FT_F26Dot6 x1,FT_F26Dot6 x2,PProfile left,PProfile right)2253*37da2899SCharles.Forsyth Horizontal_Sweep_Span( RAS_ARGS Short y, 2254*37da2899SCharles.Forsyth FT_F26Dot6 x1, 2255*37da2899SCharles.Forsyth FT_F26Dot6 x2, 2256*37da2899SCharles.Forsyth PProfile left, 2257*37da2899SCharles.Forsyth PProfile right ) 2258*37da2899SCharles.Forsyth { 2259*37da2899SCharles.Forsyth Long e1, e2; 2260*37da2899SCharles.Forsyth PByte bits; 2261*37da2899SCharles.Forsyth Byte f1; 2262*37da2899SCharles.Forsyth 2263*37da2899SCharles.Forsyth FT_UNUSED( left ); 2264*37da2899SCharles.Forsyth FT_UNUSED( right ); 2265*37da2899SCharles.Forsyth 2266*37da2899SCharles.Forsyth 2267*37da2899SCharles.Forsyth if ( x2 - x1 < ras.precision ) 2268*37da2899SCharles.Forsyth { 2269*37da2899SCharles.Forsyth e1 = CEILING( x1 ); 2270*37da2899SCharles.Forsyth e2 = FLOOR ( x2 ); 2271*37da2899SCharles.Forsyth 2272*37da2899SCharles.Forsyth if ( e1 == e2 ) 2273*37da2899SCharles.Forsyth { 2274*37da2899SCharles.Forsyth bits = ras.bTarget + ( y >> 3 ); 2275*37da2899SCharles.Forsyth f1 = (Byte)( 0x80 >> ( y & 7 ) ); 2276*37da2899SCharles.Forsyth 2277*37da2899SCharles.Forsyth e1 = TRUNC( e1 ); 2278*37da2899SCharles.Forsyth 2279*37da2899SCharles.Forsyth if ( e1 >= 0 && e1 < ras.target.rows ) 2280*37da2899SCharles.Forsyth { 2281*37da2899SCharles.Forsyth PByte p; 2282*37da2899SCharles.Forsyth 2283*37da2899SCharles.Forsyth 2284*37da2899SCharles.Forsyth p = bits - e1*ras.target.pitch; 2285*37da2899SCharles.Forsyth if ( ras.target.pitch > 0 ) 2286*37da2899SCharles.Forsyth p += ( ras.target.rows - 1 ) * ras.target.pitch; 2287*37da2899SCharles.Forsyth 2288*37da2899SCharles.Forsyth p[0] |= f1; 2289*37da2899SCharles.Forsyth } 2290*37da2899SCharles.Forsyth } 2291*37da2899SCharles.Forsyth } 2292*37da2899SCharles.Forsyth } 2293*37da2899SCharles.Forsyth 2294*37da2899SCharles.Forsyth 2295*37da2899SCharles.Forsyth static void Horizontal_Sweep_Drop(RAS_ARGS Short y,FT_F26Dot6 x1,FT_F26Dot6 x2,PProfile left,PProfile right)2296*37da2899SCharles.Forsyth Horizontal_Sweep_Drop( RAS_ARGS Short y, 2297*37da2899SCharles.Forsyth FT_F26Dot6 x1, 2298*37da2899SCharles.Forsyth FT_F26Dot6 x2, 2299*37da2899SCharles.Forsyth PProfile left, 2300*37da2899SCharles.Forsyth PProfile right ) 2301*37da2899SCharles.Forsyth { 2302*37da2899SCharles.Forsyth Long e1, e2; 2303*37da2899SCharles.Forsyth PByte bits; 2304*37da2899SCharles.Forsyth Byte f1; 2305*37da2899SCharles.Forsyth 2306*37da2899SCharles.Forsyth 2307*37da2899SCharles.Forsyth /* During the horizontal sweep, we only take care of drop-outs */ 2308*37da2899SCharles.Forsyth 2309*37da2899SCharles.Forsyth e1 = CEILING( x1 ); 2310*37da2899SCharles.Forsyth e2 = FLOOR ( x2 ); 2311*37da2899SCharles.Forsyth 2312*37da2899SCharles.Forsyth if ( e1 > e2 ) 2313*37da2899SCharles.Forsyth { 2314*37da2899SCharles.Forsyth if ( e1 == e2 + ras.precision ) 2315*37da2899SCharles.Forsyth { 2316*37da2899SCharles.Forsyth switch ( ras.dropOutControl ) 2317*37da2899SCharles.Forsyth { 2318*37da2899SCharles.Forsyth case 1: 2319*37da2899SCharles.Forsyth e1 = e2; 2320*37da2899SCharles.Forsyth break; 2321*37da2899SCharles.Forsyth 2322*37da2899SCharles.Forsyth case 4: 2323*37da2899SCharles.Forsyth e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); 2324*37da2899SCharles.Forsyth break; 2325*37da2899SCharles.Forsyth 2326*37da2899SCharles.Forsyth case 2: 2327*37da2899SCharles.Forsyth case 5: 2328*37da2899SCharles.Forsyth 2329*37da2899SCharles.Forsyth /* Drop-out Control Rule #4 */ 2330*37da2899SCharles.Forsyth 2331*37da2899SCharles.Forsyth /* The spec is not very clear regarding rule #4. It */ 2332*37da2899SCharles.Forsyth /* presents a method that is way too costly to implement */ 2333*37da2899SCharles.Forsyth /* while the general idea seems to get rid of `stubs'. */ 2334*37da2899SCharles.Forsyth /* */ 2335*37da2899SCharles.Forsyth 2336*37da2899SCharles.Forsyth /* rightmost stub test */ 2337*37da2899SCharles.Forsyth if ( left->next == right && left->height <= 0 ) 2338*37da2899SCharles.Forsyth return; 2339*37da2899SCharles.Forsyth 2340*37da2899SCharles.Forsyth /* leftmost stub test */ 2341*37da2899SCharles.Forsyth if ( right->next == left && left->start == y ) 2342*37da2899SCharles.Forsyth return; 2343*37da2899SCharles.Forsyth 2344*37da2899SCharles.Forsyth /* check that the rightmost pixel isn't set */ 2345*37da2899SCharles.Forsyth 2346*37da2899SCharles.Forsyth e1 = TRUNC( e1 ); 2347*37da2899SCharles.Forsyth 2348*37da2899SCharles.Forsyth bits = ras.bTarget + ( y >> 3 ); 2349*37da2899SCharles.Forsyth f1 = (Byte)( 0x80 >> ( y & 7 ) ); 2350*37da2899SCharles.Forsyth 2351*37da2899SCharles.Forsyth bits -= e1 * ras.target.pitch; 2352*37da2899SCharles.Forsyth if ( ras.target.pitch > 0 ) 2353*37da2899SCharles.Forsyth bits += ( ras.target.rows - 1 ) * ras.target.pitch; 2354*37da2899SCharles.Forsyth 2355*37da2899SCharles.Forsyth if ( e1 >= 0 && 2356*37da2899SCharles.Forsyth e1 < ras.target.rows && 2357*37da2899SCharles.Forsyth *bits & f1 ) 2358*37da2899SCharles.Forsyth return; 2359*37da2899SCharles.Forsyth 2360*37da2899SCharles.Forsyth if ( ras.dropOutControl == 2 ) 2361*37da2899SCharles.Forsyth e1 = e2; 2362*37da2899SCharles.Forsyth else 2363*37da2899SCharles.Forsyth e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); 2364*37da2899SCharles.Forsyth 2365*37da2899SCharles.Forsyth break; 2366*37da2899SCharles.Forsyth 2367*37da2899SCharles.Forsyth default: 2368*37da2899SCharles.Forsyth return; /* unsupported mode */ 2369*37da2899SCharles.Forsyth } 2370*37da2899SCharles.Forsyth } 2371*37da2899SCharles.Forsyth else 2372*37da2899SCharles.Forsyth return; 2373*37da2899SCharles.Forsyth } 2374*37da2899SCharles.Forsyth 2375*37da2899SCharles.Forsyth bits = ras.bTarget + ( y >> 3 ); 2376*37da2899SCharles.Forsyth f1 = (Byte)( 0x80 >> ( y & 7 ) ); 2377*37da2899SCharles.Forsyth 2378*37da2899SCharles.Forsyth e1 = TRUNC( e1 ); 2379*37da2899SCharles.Forsyth 2380*37da2899SCharles.Forsyth if ( e1 >= 0 && e1 < ras.target.rows ) 2381*37da2899SCharles.Forsyth { 2382*37da2899SCharles.Forsyth bits -= e1 * ras.target.pitch; 2383*37da2899SCharles.Forsyth if ( ras.target.pitch > 0 ) 2384*37da2899SCharles.Forsyth bits += ( ras.target.rows - 1 ) * ras.target.pitch; 2385*37da2899SCharles.Forsyth 2386*37da2899SCharles.Forsyth bits[0] |= f1; 2387*37da2899SCharles.Forsyth } 2388*37da2899SCharles.Forsyth } 2389*37da2899SCharles.Forsyth 2390*37da2899SCharles.Forsyth 2391*37da2899SCharles.Forsyth static void Horizontal_Sweep_Step(RAS_ARG)2392*37da2899SCharles.Forsyth Horizontal_Sweep_Step( RAS_ARG ) 2393*37da2899SCharles.Forsyth { 2394*37da2899SCharles.Forsyth /* Nothing, really */ 2395*37da2899SCharles.Forsyth FT_UNUSED( raster ); 2396*37da2899SCharles.Forsyth } 2397*37da2899SCharles.Forsyth 2398*37da2899SCharles.Forsyth 2399*37da2899SCharles.Forsyth #ifdef FT_RASTER_OPTION_ANTI_ALIASING 2400*37da2899SCharles.Forsyth 2401*37da2899SCharles.Forsyth 2402*37da2899SCharles.Forsyth /*************************************************************************/ 2403*37da2899SCharles.Forsyth /* */ 2404*37da2899SCharles.Forsyth /* Vertical Gray Sweep Procedure Set */ 2405*37da2899SCharles.Forsyth /* */ 2406*37da2899SCharles.Forsyth /* These two routines are used during the vertical gray-levels sweep */ 2407*37da2899SCharles.Forsyth /* phase by the generic Draw_Sweep() function. */ 2408*37da2899SCharles.Forsyth /* */ 2409*37da2899SCharles.Forsyth /* NOTES */ 2410*37da2899SCharles.Forsyth /* */ 2411*37da2899SCharles.Forsyth /* - The target pixmap's width *must* be a multiple of 4. */ 2412*37da2899SCharles.Forsyth /* */ 2413*37da2899SCharles.Forsyth /* - You have to use the function Vertical_Sweep_Span() for the gray */ 2414*37da2899SCharles.Forsyth /* span call. */ 2415*37da2899SCharles.Forsyth /* */ 2416*37da2899SCharles.Forsyth /*************************************************************************/ 2417*37da2899SCharles.Forsyth 2418*37da2899SCharles.Forsyth static void Vertical_Gray_Sweep_Init(RAS_ARGS Short * min,Short * max)2419*37da2899SCharles.Forsyth Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, 2420*37da2899SCharles.Forsyth Short* max ) 2421*37da2899SCharles.Forsyth { 2422*37da2899SCharles.Forsyth Long pitch, byte_len; 2423*37da2899SCharles.Forsyth 2424*37da2899SCharles.Forsyth 2425*37da2899SCharles.Forsyth *min = *min & -2; 2426*37da2899SCharles.Forsyth *max = ( *max + 3 ) & -2; 2427*37da2899SCharles.Forsyth 2428*37da2899SCharles.Forsyth ras.traceOfs = 0; 2429*37da2899SCharles.Forsyth pitch = ras.target.pitch; 2430*37da2899SCharles.Forsyth byte_len = -pitch; 2431*37da2899SCharles.Forsyth ras.traceIncr = (Short)byte_len; 2432*37da2899SCharles.Forsyth ras.traceG = ( *min / 2 ) * byte_len; 2433*37da2899SCharles.Forsyth 2434*37da2899SCharles.Forsyth if ( pitch > 0 ) 2435*37da2899SCharles.Forsyth { 2436*37da2899SCharles.Forsyth ras.traceG += ( ras.target.rows - 1 ) * pitch; 2437*37da2899SCharles.Forsyth byte_len = -byte_len; 2438*37da2899SCharles.Forsyth } 2439*37da2899SCharles.Forsyth 2440*37da2899SCharles.Forsyth ras.gray_min_x = (Short)byte_len; 2441*37da2899SCharles.Forsyth ras.gray_max_x = -(Short)byte_len; 2442*37da2899SCharles.Forsyth } 2443*37da2899SCharles.Forsyth 2444*37da2899SCharles.Forsyth 2445*37da2899SCharles.Forsyth static void Vertical_Gray_Sweep_Step(RAS_ARG)2446*37da2899SCharles.Forsyth Vertical_Gray_Sweep_Step( RAS_ARG ) 2447*37da2899SCharles.Forsyth { 2448*37da2899SCharles.Forsyth Int c1, c2; 2449*37da2899SCharles.Forsyth PByte pix, bit, bit2; 2450*37da2899SCharles.Forsyth Int* count = ras.count_table; 2451*37da2899SCharles.Forsyth Byte* grays; 2452*37da2899SCharles.Forsyth 2453*37da2899SCharles.Forsyth 2454*37da2899SCharles.Forsyth ras.traceOfs += ras.gray_width; 2455*37da2899SCharles.Forsyth 2456*37da2899SCharles.Forsyth if ( ras.traceOfs > ras.gray_width ) 2457*37da2899SCharles.Forsyth { 2458*37da2899SCharles.Forsyth pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; 2459*37da2899SCharles.Forsyth grays = ras.grays; 2460*37da2899SCharles.Forsyth 2461*37da2899SCharles.Forsyth if ( ras.gray_max_x >= 0 ) 2462*37da2899SCharles.Forsyth { 2463*37da2899SCharles.Forsyth Long last_pixel = ras.target.width - 1; 2464*37da2899SCharles.Forsyth Int last_cell = last_pixel >> 2; 2465*37da2899SCharles.Forsyth Int last_bit = last_pixel & 3; 2466*37da2899SCharles.Forsyth Bool over = 0; 2467*37da2899SCharles.Forsyth 2468*37da2899SCharles.Forsyth 2469*37da2899SCharles.Forsyth if ( ras.gray_max_x >= last_cell && last_bit != 3 ) 2470*37da2899SCharles.Forsyth { 2471*37da2899SCharles.Forsyth ras.gray_max_x = last_cell - 1; 2472*37da2899SCharles.Forsyth over = 1; 2473*37da2899SCharles.Forsyth } 2474*37da2899SCharles.Forsyth 2475*37da2899SCharles.Forsyth if ( ras.gray_min_x < 0 ) 2476*37da2899SCharles.Forsyth ras.gray_min_x = 0; 2477*37da2899SCharles.Forsyth 2478*37da2899SCharles.Forsyth bit = ras.bTarget + ras.gray_min_x; 2479*37da2899SCharles.Forsyth bit2 = bit + ras.gray_width; 2480*37da2899SCharles.Forsyth 2481*37da2899SCharles.Forsyth c1 = ras.gray_max_x - ras.gray_min_x; 2482*37da2899SCharles.Forsyth 2483*37da2899SCharles.Forsyth while ( c1 >= 0 ) 2484*37da2899SCharles.Forsyth { 2485*37da2899SCharles.Forsyth c2 = count[*bit] + count[*bit2]; 2486*37da2899SCharles.Forsyth 2487*37da2899SCharles.Forsyth if ( c2 ) 2488*37da2899SCharles.Forsyth { 2489*37da2899SCharles.Forsyth pix[0] = grays[(c2 >> 12) & 0x000F]; 2490*37da2899SCharles.Forsyth pix[1] = grays[(c2 >> 8 ) & 0x000F]; 2491*37da2899SCharles.Forsyth pix[2] = grays[(c2 >> 4 ) & 0x000F]; 2492*37da2899SCharles.Forsyth pix[3] = grays[ c2 & 0x000F]; 2493*37da2899SCharles.Forsyth 2494*37da2899SCharles.Forsyth *bit = 0; 2495*37da2899SCharles.Forsyth *bit2 = 0; 2496*37da2899SCharles.Forsyth } 2497*37da2899SCharles.Forsyth 2498*37da2899SCharles.Forsyth bit++; 2499*37da2899SCharles.Forsyth bit2++; 2500*37da2899SCharles.Forsyth pix += 4; 2501*37da2899SCharles.Forsyth c1--; 2502*37da2899SCharles.Forsyth } 2503*37da2899SCharles.Forsyth 2504*37da2899SCharles.Forsyth if ( over ) 2505*37da2899SCharles.Forsyth { 2506*37da2899SCharles.Forsyth c2 = count[*bit] + count[*bit2]; 2507*37da2899SCharles.Forsyth if ( c2 ) 2508*37da2899SCharles.Forsyth { 2509*37da2899SCharles.Forsyth switch ( last_bit ) 2510*37da2899SCharles.Forsyth { 2511*37da2899SCharles.Forsyth case 2: 2512*37da2899SCharles.Forsyth pix[2] = grays[(c2 >> 4 ) & 0x000F]; 2513*37da2899SCharles.Forsyth case 1: 2514*37da2899SCharles.Forsyth pix[1] = grays[(c2 >> 8 ) & 0x000F]; 2515*37da2899SCharles.Forsyth default: 2516*37da2899SCharles.Forsyth pix[0] = grays[(c2 >> 12) & 0x000F]; 2517*37da2899SCharles.Forsyth } 2518*37da2899SCharles.Forsyth 2519*37da2899SCharles.Forsyth *bit = 0; 2520*37da2899SCharles.Forsyth *bit2 = 0; 2521*37da2899SCharles.Forsyth } 2522*37da2899SCharles.Forsyth } 2523*37da2899SCharles.Forsyth } 2524*37da2899SCharles.Forsyth 2525*37da2899SCharles.Forsyth ras.traceOfs = 0; 2526*37da2899SCharles.Forsyth ras.traceG += ras.traceIncr; 2527*37da2899SCharles.Forsyth 2528*37da2899SCharles.Forsyth ras.gray_min_x = 32000; 2529*37da2899SCharles.Forsyth ras.gray_max_x = -32000; 2530*37da2899SCharles.Forsyth } 2531*37da2899SCharles.Forsyth } 2532*37da2899SCharles.Forsyth 2533*37da2899SCharles.Forsyth 2534*37da2899SCharles.Forsyth static void Horizontal_Gray_Sweep_Span(RAS_ARGS Short y,FT_F26Dot6 x1,FT_F26Dot6 x2,PProfile left,PProfile right)2535*37da2899SCharles.Forsyth Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, 2536*37da2899SCharles.Forsyth FT_F26Dot6 x1, 2537*37da2899SCharles.Forsyth FT_F26Dot6 x2, 2538*37da2899SCharles.Forsyth PProfile left, 2539*37da2899SCharles.Forsyth PProfile right ) 2540*37da2899SCharles.Forsyth { 2541*37da2899SCharles.Forsyth /* nothing, really */ 2542*37da2899SCharles.Forsyth FT_UNUSED( raster ); 2543*37da2899SCharles.Forsyth FT_UNUSED( y ); 2544*37da2899SCharles.Forsyth FT_UNUSED( x1 ); 2545*37da2899SCharles.Forsyth FT_UNUSED( x2 ); 2546*37da2899SCharles.Forsyth FT_UNUSED( left ); 2547*37da2899SCharles.Forsyth FT_UNUSED( right ); 2548*37da2899SCharles.Forsyth } 2549*37da2899SCharles.Forsyth 2550*37da2899SCharles.Forsyth 2551*37da2899SCharles.Forsyth static void Horizontal_Gray_Sweep_Drop(RAS_ARGS Short y,FT_F26Dot6 x1,FT_F26Dot6 x2,PProfile left,PProfile right)2552*37da2899SCharles.Forsyth Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, 2553*37da2899SCharles.Forsyth FT_F26Dot6 x1, 2554*37da2899SCharles.Forsyth FT_F26Dot6 x2, 2555*37da2899SCharles.Forsyth PProfile left, 2556*37da2899SCharles.Forsyth PProfile right ) 2557*37da2899SCharles.Forsyth { 2558*37da2899SCharles.Forsyth Long e1, e2; 2559*37da2899SCharles.Forsyth PByte pixel; 2560*37da2899SCharles.Forsyth Byte color; 2561*37da2899SCharles.Forsyth 2562*37da2899SCharles.Forsyth 2563*37da2899SCharles.Forsyth /* During the horizontal sweep, we only take care of drop-outs */ 2564*37da2899SCharles.Forsyth e1 = CEILING( x1 ); 2565*37da2899SCharles.Forsyth e2 = FLOOR ( x2 ); 2566*37da2899SCharles.Forsyth 2567*37da2899SCharles.Forsyth if ( e1 > e2 ) 2568*37da2899SCharles.Forsyth { 2569*37da2899SCharles.Forsyth if ( e1 == e2 + ras.precision ) 2570*37da2899SCharles.Forsyth { 2571*37da2899SCharles.Forsyth switch ( ras.dropOutControl ) 2572*37da2899SCharles.Forsyth { 2573*37da2899SCharles.Forsyth case 1: 2574*37da2899SCharles.Forsyth e1 = e2; 2575*37da2899SCharles.Forsyth break; 2576*37da2899SCharles.Forsyth 2577*37da2899SCharles.Forsyth case 4: 2578*37da2899SCharles.Forsyth e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); 2579*37da2899SCharles.Forsyth break; 2580*37da2899SCharles.Forsyth 2581*37da2899SCharles.Forsyth case 2: 2582*37da2899SCharles.Forsyth case 5: 2583*37da2899SCharles.Forsyth 2584*37da2899SCharles.Forsyth /* Drop-out Control Rule #4 */ 2585*37da2899SCharles.Forsyth 2586*37da2899SCharles.Forsyth /* The spec is not very clear regarding rule #4. It */ 2587*37da2899SCharles.Forsyth /* presents a method that is way too costly to implement */ 2588*37da2899SCharles.Forsyth /* while the general idea seems to get rid of `stubs'. */ 2589*37da2899SCharles.Forsyth /* */ 2590*37da2899SCharles.Forsyth 2591*37da2899SCharles.Forsyth /* rightmost stub test */ 2592*37da2899SCharles.Forsyth if ( left->next == right && left->height <= 0 ) 2593*37da2899SCharles.Forsyth return; 2594*37da2899SCharles.Forsyth 2595*37da2899SCharles.Forsyth /* leftmost stub test */ 2596*37da2899SCharles.Forsyth if ( right->next == left && left->start == y ) 2597*37da2899SCharles.Forsyth return; 2598*37da2899SCharles.Forsyth 2599*37da2899SCharles.Forsyth if ( ras.dropOutControl == 2 ) 2600*37da2899SCharles.Forsyth e1 = e2; 2601*37da2899SCharles.Forsyth else 2602*37da2899SCharles.Forsyth e1 = CEILING( ( x1 + x2 + 1 ) / 2 ); 2603*37da2899SCharles.Forsyth 2604*37da2899SCharles.Forsyth break; 2605*37da2899SCharles.Forsyth 2606*37da2899SCharles.Forsyth default: 2607*37da2899SCharles.Forsyth return; /* unsupported mode */ 2608*37da2899SCharles.Forsyth } 2609*37da2899SCharles.Forsyth } 2610*37da2899SCharles.Forsyth else 2611*37da2899SCharles.Forsyth return; 2612*37da2899SCharles.Forsyth } 2613*37da2899SCharles.Forsyth 2614*37da2899SCharles.Forsyth if ( e1 >= 0 ) 2615*37da2899SCharles.Forsyth { 2616*37da2899SCharles.Forsyth if ( x2 - x1 >= ras.precision_half ) 2617*37da2899SCharles.Forsyth color = ras.grays[2]; 2618*37da2899SCharles.Forsyth else 2619*37da2899SCharles.Forsyth color = ras.grays[1]; 2620*37da2899SCharles.Forsyth 2621*37da2899SCharles.Forsyth e1 = TRUNC( e1 ) / 2; 2622*37da2899SCharles.Forsyth if ( e1 < ras.target.rows ) 2623*37da2899SCharles.Forsyth { 2624*37da2899SCharles.Forsyth pixel = ras.gTarget - e1 * ras.target.pitch + y / 2; 2625*37da2899SCharles.Forsyth if ( ras.target.pitch > 0 ) 2626*37da2899SCharles.Forsyth pixel += ( ras.target.rows - 1 ) * ras.target.pitch; 2627*37da2899SCharles.Forsyth 2628*37da2899SCharles.Forsyth if ( pixel[0] == ras.grays[0] ) 2629*37da2899SCharles.Forsyth pixel[0] = color; 2630*37da2899SCharles.Forsyth } 2631*37da2899SCharles.Forsyth } 2632*37da2899SCharles.Forsyth } 2633*37da2899SCharles.Forsyth 2634*37da2899SCharles.Forsyth 2635*37da2899SCharles.Forsyth #endif /* FT_RASTER_OPTION_ANTI_ALIASING */ 2636*37da2899SCharles.Forsyth 2637*37da2899SCharles.Forsyth 2638*37da2899SCharles.Forsyth /*************************************************************************/ 2639*37da2899SCharles.Forsyth /* */ 2640*37da2899SCharles.Forsyth /* Generic Sweep Drawing routine */ 2641*37da2899SCharles.Forsyth /* */ 2642*37da2899SCharles.Forsyth /*************************************************************************/ 2643*37da2899SCharles.Forsyth 2644*37da2899SCharles.Forsyth static Bool Draw_Sweep(RAS_ARG)2645*37da2899SCharles.Forsyth Draw_Sweep( RAS_ARG ) 2646*37da2899SCharles.Forsyth { 2647*37da2899SCharles.Forsyth Short y, y_change, y_height; 2648*37da2899SCharles.Forsyth 2649*37da2899SCharles.Forsyth PProfile P, Q, P_Left, P_Right; 2650*37da2899SCharles.Forsyth 2651*37da2899SCharles.Forsyth Short min_Y, max_Y, top, bottom, dropouts; 2652*37da2899SCharles.Forsyth 2653*37da2899SCharles.Forsyth Long x1, x2, xs, e1, e2; 2654*37da2899SCharles.Forsyth 2655*37da2899SCharles.Forsyth TProfileList waiting; 2656*37da2899SCharles.Forsyth TProfileList draw_left, draw_right; 2657*37da2899SCharles.Forsyth 2658*37da2899SCharles.Forsyth 2659*37da2899SCharles.Forsyth /* Init empty linked lists */ 2660*37da2899SCharles.Forsyth 2661*37da2899SCharles.Forsyth Init_Linked( &waiting ); 2662*37da2899SCharles.Forsyth 2663*37da2899SCharles.Forsyth Init_Linked( &draw_left ); 2664*37da2899SCharles.Forsyth Init_Linked( &draw_right ); 2665*37da2899SCharles.Forsyth 2666*37da2899SCharles.Forsyth /* first, compute min and max Y */ 2667*37da2899SCharles.Forsyth 2668*37da2899SCharles.Forsyth P = ras.fProfile; 2669*37da2899SCharles.Forsyth max_Y = (Short)TRUNC( ras.minY ); 2670*37da2899SCharles.Forsyth min_Y = (Short)TRUNC( ras.maxY ); 2671*37da2899SCharles.Forsyth 2672*37da2899SCharles.Forsyth while ( P ) 2673*37da2899SCharles.Forsyth { 2674*37da2899SCharles.Forsyth Q = P->link; 2675*37da2899SCharles.Forsyth 2676*37da2899SCharles.Forsyth bottom = (Short)P->start; 2677*37da2899SCharles.Forsyth top = (Short)( P->start + P->height - 1 ); 2678*37da2899SCharles.Forsyth 2679*37da2899SCharles.Forsyth if ( min_Y > bottom ) min_Y = bottom; 2680*37da2899SCharles.Forsyth if ( max_Y < top ) max_Y = top; 2681*37da2899SCharles.Forsyth 2682*37da2899SCharles.Forsyth P->X = 0; 2683*37da2899SCharles.Forsyth InsNew( &waiting, P ); 2684*37da2899SCharles.Forsyth 2685*37da2899SCharles.Forsyth P = Q; 2686*37da2899SCharles.Forsyth } 2687*37da2899SCharles.Forsyth 2688*37da2899SCharles.Forsyth /* Check the Y-turns */ 2689*37da2899SCharles.Forsyth if ( ras.numTurns == 0 ) 2690*37da2899SCharles.Forsyth { 2691*37da2899SCharles.Forsyth ras.error = Raster_Err_Invalid; 2692*37da2899SCharles.Forsyth return FAILURE; 2693*37da2899SCharles.Forsyth } 2694*37da2899SCharles.Forsyth 2695*37da2899SCharles.Forsyth /* Now inits the sweep */ 2696*37da2899SCharles.Forsyth 2697*37da2899SCharles.Forsyth ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); 2698*37da2899SCharles.Forsyth 2699*37da2899SCharles.Forsyth /* Then compute the distance of each profile from min_Y */ 2700*37da2899SCharles.Forsyth 2701*37da2899SCharles.Forsyth P = waiting; 2702*37da2899SCharles.Forsyth 2703*37da2899SCharles.Forsyth while ( P ) 2704*37da2899SCharles.Forsyth { 2705*37da2899SCharles.Forsyth P->countL = (UShort)( P->start - min_Y ); 2706*37da2899SCharles.Forsyth P = P->link; 2707*37da2899SCharles.Forsyth } 2708*37da2899SCharles.Forsyth 2709*37da2899SCharles.Forsyth /* Let's go */ 2710*37da2899SCharles.Forsyth 2711*37da2899SCharles.Forsyth y = min_Y; 2712*37da2899SCharles.Forsyth y_height = 0; 2713*37da2899SCharles.Forsyth 2714*37da2899SCharles.Forsyth if ( ras.numTurns > 0 && 2715*37da2899SCharles.Forsyth ras.sizeBuff[-ras.numTurns] == min_Y ) 2716*37da2899SCharles.Forsyth ras.numTurns--; 2717*37da2899SCharles.Forsyth 2718*37da2899SCharles.Forsyth while ( ras.numTurns > 0 ) 2719*37da2899SCharles.Forsyth { 2720*37da2899SCharles.Forsyth /* look in the waiting list for new activations */ 2721*37da2899SCharles.Forsyth 2722*37da2899SCharles.Forsyth P = waiting; 2723*37da2899SCharles.Forsyth 2724*37da2899SCharles.Forsyth while ( P ) 2725*37da2899SCharles.Forsyth { 2726*37da2899SCharles.Forsyth Q = P->link; 2727*37da2899SCharles.Forsyth P->countL -= y_height; 2728*37da2899SCharles.Forsyth if ( P->countL == 0 ) 2729*37da2899SCharles.Forsyth { 2730*37da2899SCharles.Forsyth DelOld( &waiting, P ); 2731*37da2899SCharles.Forsyth 2732*37da2899SCharles.Forsyth switch ( P->flow ) 2733*37da2899SCharles.Forsyth { 2734*37da2899SCharles.Forsyth case Flow_Up: 2735*37da2899SCharles.Forsyth InsNew( &draw_left, P ); 2736*37da2899SCharles.Forsyth break; 2737*37da2899SCharles.Forsyth 2738*37da2899SCharles.Forsyth case Flow_Down: 2739*37da2899SCharles.Forsyth InsNew( &draw_right, P ); 2740*37da2899SCharles.Forsyth break; 2741*37da2899SCharles.Forsyth } 2742*37da2899SCharles.Forsyth } 2743*37da2899SCharles.Forsyth 2744*37da2899SCharles.Forsyth P = Q; 2745*37da2899SCharles.Forsyth } 2746*37da2899SCharles.Forsyth 2747*37da2899SCharles.Forsyth /* Sort the drawing lists */ 2748*37da2899SCharles.Forsyth 2749*37da2899SCharles.Forsyth Sort( &draw_left ); 2750*37da2899SCharles.Forsyth Sort( &draw_right ); 2751*37da2899SCharles.Forsyth 2752*37da2899SCharles.Forsyth y_change = (Short)ras.sizeBuff[-ras.numTurns--]; 2753*37da2899SCharles.Forsyth y_height = (Short)( y_change - y ); 2754*37da2899SCharles.Forsyth 2755*37da2899SCharles.Forsyth while ( y < y_change ) 2756*37da2899SCharles.Forsyth { 2757*37da2899SCharles.Forsyth /* Let's trace */ 2758*37da2899SCharles.Forsyth 2759*37da2899SCharles.Forsyth dropouts = 0; 2760*37da2899SCharles.Forsyth 2761*37da2899SCharles.Forsyth P_Left = draw_left; 2762*37da2899SCharles.Forsyth P_Right = draw_right; 2763*37da2899SCharles.Forsyth 2764*37da2899SCharles.Forsyth while ( P_Left ) 2765*37da2899SCharles.Forsyth { 2766*37da2899SCharles.Forsyth x1 = P_Left ->X; 2767*37da2899SCharles.Forsyth x2 = P_Right->X; 2768*37da2899SCharles.Forsyth 2769*37da2899SCharles.Forsyth if ( x1 > x2 ) 2770*37da2899SCharles.Forsyth { 2771*37da2899SCharles.Forsyth xs = x1; 2772*37da2899SCharles.Forsyth x1 = x2; 2773*37da2899SCharles.Forsyth x2 = xs; 2774*37da2899SCharles.Forsyth } 2775*37da2899SCharles.Forsyth 2776*37da2899SCharles.Forsyth if ( x2 - x1 <= ras.precision ) 2777*37da2899SCharles.Forsyth { 2778*37da2899SCharles.Forsyth e1 = FLOOR( x1 ); 2779*37da2899SCharles.Forsyth e2 = CEILING( x2 ); 2780*37da2899SCharles.Forsyth 2781*37da2899SCharles.Forsyth if ( ras.dropOutControl != 0 && 2782*37da2899SCharles.Forsyth ( e1 > e2 || e2 == e1 + ras.precision ) ) 2783*37da2899SCharles.Forsyth { 2784*37da2899SCharles.Forsyth /* a drop out was detected */ 2785*37da2899SCharles.Forsyth 2786*37da2899SCharles.Forsyth P_Left ->X = x1; 2787*37da2899SCharles.Forsyth P_Right->X = x2; 2788*37da2899SCharles.Forsyth 2789*37da2899SCharles.Forsyth /* mark profile for drop-out processing */ 2790*37da2899SCharles.Forsyth P_Left->countL = 1; 2791*37da2899SCharles.Forsyth dropouts++; 2792*37da2899SCharles.Forsyth 2793*37da2899SCharles.Forsyth goto Skip_To_Next; 2794*37da2899SCharles.Forsyth } 2795*37da2899SCharles.Forsyth } 2796*37da2899SCharles.Forsyth 2797*37da2899SCharles.Forsyth ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); 2798*37da2899SCharles.Forsyth 2799*37da2899SCharles.Forsyth Skip_To_Next: 2800*37da2899SCharles.Forsyth 2801*37da2899SCharles.Forsyth P_Left = P_Left->link; 2802*37da2899SCharles.Forsyth P_Right = P_Right->link; 2803*37da2899SCharles.Forsyth } 2804*37da2899SCharles.Forsyth 2805*37da2899SCharles.Forsyth /* now perform the dropouts _after_ the span drawing -- */ 2806*37da2899SCharles.Forsyth /* drop-outs processing has been moved out of the loop */ 2807*37da2899SCharles.Forsyth /* for performance tuning */ 2808*37da2899SCharles.Forsyth if ( dropouts > 0 ) 2809*37da2899SCharles.Forsyth goto Scan_DropOuts; 2810*37da2899SCharles.Forsyth 2811*37da2899SCharles.Forsyth Next_Line: 2812*37da2899SCharles.Forsyth 2813*37da2899SCharles.Forsyth ras.Proc_Sweep_Step( RAS_VAR ); 2814*37da2899SCharles.Forsyth 2815*37da2899SCharles.Forsyth y++; 2816*37da2899SCharles.Forsyth 2817*37da2899SCharles.Forsyth if ( y < y_change ) 2818*37da2899SCharles.Forsyth { 2819*37da2899SCharles.Forsyth Sort( &draw_left ); 2820*37da2899SCharles.Forsyth Sort( &draw_right ); 2821*37da2899SCharles.Forsyth } 2822*37da2899SCharles.Forsyth } 2823*37da2899SCharles.Forsyth 2824*37da2899SCharles.Forsyth /* Now finalize the profiles that needs it */ 2825*37da2899SCharles.Forsyth 2826*37da2899SCharles.Forsyth P = draw_left; 2827*37da2899SCharles.Forsyth while ( P ) 2828*37da2899SCharles.Forsyth { 2829*37da2899SCharles.Forsyth Q = P->link; 2830*37da2899SCharles.Forsyth if ( P->height == 0 ) 2831*37da2899SCharles.Forsyth DelOld( &draw_left, P ); 2832*37da2899SCharles.Forsyth P = Q; 2833*37da2899SCharles.Forsyth } 2834*37da2899SCharles.Forsyth 2835*37da2899SCharles.Forsyth P = draw_right; 2836*37da2899SCharles.Forsyth while ( P ) 2837*37da2899SCharles.Forsyth { 2838*37da2899SCharles.Forsyth Q = P->link; 2839*37da2899SCharles.Forsyth if ( P->height == 0 ) 2840*37da2899SCharles.Forsyth DelOld( &draw_right, P ); 2841*37da2899SCharles.Forsyth P = Q; 2842*37da2899SCharles.Forsyth } 2843*37da2899SCharles.Forsyth } 2844*37da2899SCharles.Forsyth 2845*37da2899SCharles.Forsyth /* for gray-scaling, flushes the bitmap scanline cache */ 2846*37da2899SCharles.Forsyth while ( y <= max_Y ) 2847*37da2899SCharles.Forsyth { 2848*37da2899SCharles.Forsyth ras.Proc_Sweep_Step( RAS_VAR ); 2849*37da2899SCharles.Forsyth y++; 2850*37da2899SCharles.Forsyth } 2851*37da2899SCharles.Forsyth 2852*37da2899SCharles.Forsyth return SUCCESS; 2853*37da2899SCharles.Forsyth 2854*37da2899SCharles.Forsyth Scan_DropOuts: 2855*37da2899SCharles.Forsyth 2856*37da2899SCharles.Forsyth P_Left = draw_left; 2857*37da2899SCharles.Forsyth P_Right = draw_right; 2858*37da2899SCharles.Forsyth 2859*37da2899SCharles.Forsyth while ( P_Left ) 2860*37da2899SCharles.Forsyth { 2861*37da2899SCharles.Forsyth if ( P_Left->countL ) 2862*37da2899SCharles.Forsyth { 2863*37da2899SCharles.Forsyth P_Left->countL = 0; 2864*37da2899SCharles.Forsyth #if 0 2865*37da2899SCharles.Forsyth dropouts--; /* -- this is useful when debugging only */ 2866*37da2899SCharles.Forsyth #endif 2867*37da2899SCharles.Forsyth ras.Proc_Sweep_Drop( RAS_VARS y, 2868*37da2899SCharles.Forsyth P_Left->X, 2869*37da2899SCharles.Forsyth P_Right->X, 2870*37da2899SCharles.Forsyth P_Left, 2871*37da2899SCharles.Forsyth P_Right ); 2872*37da2899SCharles.Forsyth } 2873*37da2899SCharles.Forsyth 2874*37da2899SCharles.Forsyth P_Left = P_Left->link; 2875*37da2899SCharles.Forsyth P_Right = P_Right->link; 2876*37da2899SCharles.Forsyth } 2877*37da2899SCharles.Forsyth 2878*37da2899SCharles.Forsyth goto Next_Line; 2879*37da2899SCharles.Forsyth } 2880*37da2899SCharles.Forsyth 2881*37da2899SCharles.Forsyth 2882*37da2899SCharles.Forsyth /*************************************************************************/ 2883*37da2899SCharles.Forsyth /* */ 2884*37da2899SCharles.Forsyth /* <Function> */ 2885*37da2899SCharles.Forsyth /* Render_Single_Pass */ 2886*37da2899SCharles.Forsyth /* */ 2887*37da2899SCharles.Forsyth /* <Description> */ 2888*37da2899SCharles.Forsyth /* Performs one sweep with sub-banding. */ 2889*37da2899SCharles.Forsyth /* */ 2890*37da2899SCharles.Forsyth /* <Input> */ 2891*37da2899SCharles.Forsyth /* flipped :: If set, flip the direction of the outline. */ 2892*37da2899SCharles.Forsyth /* */ 2893*37da2899SCharles.Forsyth /* <Return> */ 2894*37da2899SCharles.Forsyth /* Renderer error code. */ 2895*37da2899SCharles.Forsyth /* */ 2896*37da2899SCharles.Forsyth static int Render_Single_Pass(RAS_ARGS Bool flipped)2897*37da2899SCharles.Forsyth Render_Single_Pass( RAS_ARGS Bool flipped ) 2898*37da2899SCharles.Forsyth { 2899*37da2899SCharles.Forsyth Short i, j, k; 2900*37da2899SCharles.Forsyth 2901*37da2899SCharles.Forsyth 2902*37da2899SCharles.Forsyth while ( ras.band_top >= 0 ) 2903*37da2899SCharles.Forsyth { 2904*37da2899SCharles.Forsyth ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; 2905*37da2899SCharles.Forsyth ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; 2906*37da2899SCharles.Forsyth 2907*37da2899SCharles.Forsyth ras.top = ras.buff; 2908*37da2899SCharles.Forsyth 2909*37da2899SCharles.Forsyth ras.error = Raster_Err_None; 2910*37da2899SCharles.Forsyth 2911*37da2899SCharles.Forsyth if ( Convert_Glyph( RAS_VARS flipped ) ) 2912*37da2899SCharles.Forsyth { 2913*37da2899SCharles.Forsyth if ( ras.error != Raster_Err_Overflow ) 2914*37da2899SCharles.Forsyth return FAILURE; 2915*37da2899SCharles.Forsyth 2916*37da2899SCharles.Forsyth ras.error = Raster_Err_None; 2917*37da2899SCharles.Forsyth 2918*37da2899SCharles.Forsyth /* sub-banding */ 2919*37da2899SCharles.Forsyth 2920*37da2899SCharles.Forsyth #ifdef DEBUG_RASTER 2921*37da2899SCharles.Forsyth ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); 2922*37da2899SCharles.Forsyth #endif 2923*37da2899SCharles.Forsyth 2924*37da2899SCharles.Forsyth i = ras.band_stack[ras.band_top].y_min; 2925*37da2899SCharles.Forsyth j = ras.band_stack[ras.band_top].y_max; 2926*37da2899SCharles.Forsyth 2927*37da2899SCharles.Forsyth k = (Short)( ( i + j ) / 2 ); 2928*37da2899SCharles.Forsyth 2929*37da2899SCharles.Forsyth if ( ras.band_top >= 7 || k < i ) 2930*37da2899SCharles.Forsyth { 2931*37da2899SCharles.Forsyth ras.band_top = 0; 2932*37da2899SCharles.Forsyth ras.error = Raster_Err_Invalid; 2933*37da2899SCharles.Forsyth 2934*37da2899SCharles.Forsyth return ras.error; 2935*37da2899SCharles.Forsyth } 2936*37da2899SCharles.Forsyth 2937*37da2899SCharles.Forsyth ras.band_stack[ras.band_top + 1].y_min = k; 2938*37da2899SCharles.Forsyth ras.band_stack[ras.band_top + 1].y_max = j; 2939*37da2899SCharles.Forsyth 2940*37da2899SCharles.Forsyth ras.band_stack[ras.band_top].y_max = (Short)( k - 1 ); 2941*37da2899SCharles.Forsyth 2942*37da2899SCharles.Forsyth ras.band_top++; 2943*37da2899SCharles.Forsyth } 2944*37da2899SCharles.Forsyth else 2945*37da2899SCharles.Forsyth { 2946*37da2899SCharles.Forsyth if ( ras.fProfile ) 2947*37da2899SCharles.Forsyth if ( Draw_Sweep( RAS_VAR ) ) 2948*37da2899SCharles.Forsyth return ras.error; 2949*37da2899SCharles.Forsyth ras.band_top--; 2950*37da2899SCharles.Forsyth } 2951*37da2899SCharles.Forsyth } 2952*37da2899SCharles.Forsyth 2953*37da2899SCharles.Forsyth return SUCCESS; 2954*37da2899SCharles.Forsyth } 2955*37da2899SCharles.Forsyth 2956*37da2899SCharles.Forsyth 2957*37da2899SCharles.Forsyth /*************************************************************************/ 2958*37da2899SCharles.Forsyth /* */ 2959*37da2899SCharles.Forsyth /* <Function> */ 2960*37da2899SCharles.Forsyth /* Render_Glyph */ 2961*37da2899SCharles.Forsyth /* */ 2962*37da2899SCharles.Forsyth /* <Description> */ 2963*37da2899SCharles.Forsyth /* Renders a glyph in a bitmap. Sub-banding if needed. */ 2964*37da2899SCharles.Forsyth /* */ 2965*37da2899SCharles.Forsyth /* <Return> */ 2966*37da2899SCharles.Forsyth /* FreeType error code. 0 means success. */ 2967*37da2899SCharles.Forsyth /* */ 2968*37da2899SCharles.Forsyth FT_LOCAL_DEF( FT_Error ) Render_Glyph(RAS_ARG)2969*37da2899SCharles.Forsyth Render_Glyph( RAS_ARG ) 2970*37da2899SCharles.Forsyth { 2971*37da2899SCharles.Forsyth FT_Error error; 2972*37da2899SCharles.Forsyth 2973*37da2899SCharles.Forsyth 2974*37da2899SCharles.Forsyth Set_High_Precision( RAS_VARS ras.outline.flags & 2975*37da2899SCharles.Forsyth FT_OUTLINE_HIGH_PRECISION ); 2976*37da2899SCharles.Forsyth ras.scale_shift = ras.precision_shift; 2977*37da2899SCharles.Forsyth ras.dropOutControl = 2; 2978*37da2899SCharles.Forsyth ras.second_pass = (FT_Byte)( !( ras.outline.flags & 2979*37da2899SCharles.Forsyth FT_OUTLINE_SINGLE_PASS ) ); 2980*37da2899SCharles.Forsyth 2981*37da2899SCharles.Forsyth /* Vertical Sweep */ 2982*37da2899SCharles.Forsyth ras.Proc_Sweep_Init = Vertical_Sweep_Init; 2983*37da2899SCharles.Forsyth ras.Proc_Sweep_Span = Vertical_Sweep_Span; 2984*37da2899SCharles.Forsyth ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; 2985*37da2899SCharles.Forsyth ras.Proc_Sweep_Step = Vertical_Sweep_Step; 2986*37da2899SCharles.Forsyth 2987*37da2899SCharles.Forsyth ras.band_top = 0; 2988*37da2899SCharles.Forsyth ras.band_stack[0].y_min = 0; 2989*37da2899SCharles.Forsyth ras.band_stack[0].y_max = (short)( ras.target.rows - 1 ); 2990*37da2899SCharles.Forsyth 2991*37da2899SCharles.Forsyth ras.bWidth = (unsigned short)ras.target.width; 2992*37da2899SCharles.Forsyth ras.bTarget = (Byte*)ras.target.buffer; 2993*37da2899SCharles.Forsyth 2994*37da2899SCharles.Forsyth if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) 2995*37da2899SCharles.Forsyth return error; 2996*37da2899SCharles.Forsyth 2997*37da2899SCharles.Forsyth /* Horizontal Sweep */ 2998*37da2899SCharles.Forsyth if ( ras.second_pass && ras.dropOutControl != 0 ) 2999*37da2899SCharles.Forsyth { 3000*37da2899SCharles.Forsyth ras.Proc_Sweep_Init = Horizontal_Sweep_Init; 3001*37da2899SCharles.Forsyth ras.Proc_Sweep_Span = Horizontal_Sweep_Span; 3002*37da2899SCharles.Forsyth ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; 3003*37da2899SCharles.Forsyth ras.Proc_Sweep_Step = Horizontal_Sweep_Step; 3004*37da2899SCharles.Forsyth 3005*37da2899SCharles.Forsyth ras.band_top = 0; 3006*37da2899SCharles.Forsyth ras.band_stack[0].y_min = 0; 3007*37da2899SCharles.Forsyth ras.band_stack[0].y_max = (short)( ras.target.width - 1 ); 3008*37da2899SCharles.Forsyth 3009*37da2899SCharles.Forsyth if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) 3010*37da2899SCharles.Forsyth return error; 3011*37da2899SCharles.Forsyth } 3012*37da2899SCharles.Forsyth 3013*37da2899SCharles.Forsyth return Raster_Err_Ok; 3014*37da2899SCharles.Forsyth } 3015*37da2899SCharles.Forsyth 3016*37da2899SCharles.Forsyth 3017*37da2899SCharles.Forsyth #ifdef FT_RASTER_OPTION_ANTI_ALIASING 3018*37da2899SCharles.Forsyth 3019*37da2899SCharles.Forsyth 3020*37da2899SCharles.Forsyth /*************************************************************************/ 3021*37da2899SCharles.Forsyth /* */ 3022*37da2899SCharles.Forsyth /* <Function> */ 3023*37da2899SCharles.Forsyth /* Render_Gray_Glyph */ 3024*37da2899SCharles.Forsyth /* */ 3025*37da2899SCharles.Forsyth /* <Description> */ 3026*37da2899SCharles.Forsyth /* Renders a glyph with grayscaling. Sub-banding if needed. */ 3027*37da2899SCharles.Forsyth /* */ 3028*37da2899SCharles.Forsyth /* <Return> */ 3029*37da2899SCharles.Forsyth /* FreeType error code. 0 means success. */ 3030*37da2899SCharles.Forsyth /* */ 3031*37da2899SCharles.Forsyth FT_LOCAL_DEF( FT_Error ) Render_Gray_Glyph(RAS_ARG)3032*37da2899SCharles.Forsyth Render_Gray_Glyph( RAS_ARG ) 3033*37da2899SCharles.Forsyth { 3034*37da2899SCharles.Forsyth Long pixel_width; 3035*37da2899SCharles.Forsyth FT_Error error; 3036*37da2899SCharles.Forsyth 3037*37da2899SCharles.Forsyth 3038*37da2899SCharles.Forsyth Set_High_Precision( RAS_VARS ras.outline.flags & 3039*37da2899SCharles.Forsyth FT_OUTLINE_HIGH_PRECISION ); 3040*37da2899SCharles.Forsyth ras.scale_shift = ras.precision_shift + 1; 3041*37da2899SCharles.Forsyth ras.dropOutControl = 2; 3042*37da2899SCharles.Forsyth ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ); 3043*37da2899SCharles.Forsyth 3044*37da2899SCharles.Forsyth /* Vertical Sweep */ 3045*37da2899SCharles.Forsyth 3046*37da2899SCharles.Forsyth ras.band_top = 0; 3047*37da2899SCharles.Forsyth ras.band_stack[0].y_min = 0; 3048*37da2899SCharles.Forsyth ras.band_stack[0].y_max = 2 * ras.target.rows - 1; 3049*37da2899SCharles.Forsyth 3050*37da2899SCharles.Forsyth ras.bWidth = ras.gray_width; 3051*37da2899SCharles.Forsyth pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); 3052*37da2899SCharles.Forsyth 3053*37da2899SCharles.Forsyth if ( ras.bWidth > pixel_width ) 3054*37da2899SCharles.Forsyth ras.bWidth = pixel_width; 3055*37da2899SCharles.Forsyth 3056*37da2899SCharles.Forsyth ras.bWidth = ras.bWidth * 8; 3057*37da2899SCharles.Forsyth ras.bTarget = (Byte*)ras.gray_lines; 3058*37da2899SCharles.Forsyth ras.gTarget = (Byte*)ras.target.buffer; 3059*37da2899SCharles.Forsyth 3060*37da2899SCharles.Forsyth ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; 3061*37da2899SCharles.Forsyth ras.Proc_Sweep_Span = Vertical_Sweep_Span; 3062*37da2899SCharles.Forsyth ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; 3063*37da2899SCharles.Forsyth ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; 3064*37da2899SCharles.Forsyth 3065*37da2899SCharles.Forsyth error = Render_Single_Pass( RAS_VARS 0 ); 3066*37da2899SCharles.Forsyth if ( error ) 3067*37da2899SCharles.Forsyth return error; 3068*37da2899SCharles.Forsyth 3069*37da2899SCharles.Forsyth /* Horizontal Sweep */ 3070*37da2899SCharles.Forsyth if ( ras.second_pass && ras.dropOutControl != 0 ) 3071*37da2899SCharles.Forsyth { 3072*37da2899SCharles.Forsyth ras.Proc_Sweep_Init = Horizontal_Sweep_Init; 3073*37da2899SCharles.Forsyth ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; 3074*37da2899SCharles.Forsyth ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; 3075*37da2899SCharles.Forsyth ras.Proc_Sweep_Step = Horizontal_Sweep_Step; 3076*37da2899SCharles.Forsyth 3077*37da2899SCharles.Forsyth ras.band_top = 0; 3078*37da2899SCharles.Forsyth ras.band_stack[0].y_min = 0; 3079*37da2899SCharles.Forsyth ras.band_stack[0].y_max = ras.target.width * 2 - 1; 3080*37da2899SCharles.Forsyth 3081*37da2899SCharles.Forsyth error = Render_Single_Pass( RAS_VARS 1 ); 3082*37da2899SCharles.Forsyth if ( error ) 3083*37da2899SCharles.Forsyth return error; 3084*37da2899SCharles.Forsyth } 3085*37da2899SCharles.Forsyth 3086*37da2899SCharles.Forsyth return Raster_Err_Ok; 3087*37da2899SCharles.Forsyth } 3088*37da2899SCharles.Forsyth 3089*37da2899SCharles.Forsyth #else /* !FT_RASTER_OPTION_ANTI_ALIASING */ 3090*37da2899SCharles.Forsyth 3091*37da2899SCharles.Forsyth FT_LOCAL_DEF( FT_Error ) Render_Gray_Glyph(RAS_ARG)3092*37da2899SCharles.Forsyth Render_Gray_Glyph( RAS_ARG ) 3093*37da2899SCharles.Forsyth { 3094*37da2899SCharles.Forsyth FT_UNUSED_RASTER; 3095*37da2899SCharles.Forsyth 3096*37da2899SCharles.Forsyth return Raster_Err_Cannot_Render_Glyph; 3097*37da2899SCharles.Forsyth } 3098*37da2899SCharles.Forsyth 3099*37da2899SCharles.Forsyth #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */ 3100*37da2899SCharles.Forsyth 3101*37da2899SCharles.Forsyth 3102*37da2899SCharles.Forsyth static void ft_black_init(TRaster_Instance * raster)3103*37da2899SCharles.Forsyth ft_black_init( TRaster_Instance* raster ) 3104*37da2899SCharles.Forsyth { 3105*37da2899SCharles.Forsyth FT_UInt n; 3106*37da2899SCharles.Forsyth FT_ULong c; 3107*37da2899SCharles.Forsyth 3108*37da2899SCharles.Forsyth 3109*37da2899SCharles.Forsyth /* setup count table */ 3110*37da2899SCharles.Forsyth for ( n = 0; n < 256; n++ ) 3111*37da2899SCharles.Forsyth { 3112*37da2899SCharles.Forsyth c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 ); 3113*37da2899SCharles.Forsyth 3114*37da2899SCharles.Forsyth c = ( ( c << 6 ) & 0x3000 ) | 3115*37da2899SCharles.Forsyth ( ( c << 4 ) & 0x0300 ) | 3116*37da2899SCharles.Forsyth ( ( c << 2 ) & 0x0030 ) | 3117*37da2899SCharles.Forsyth (c & 0x0003 ); 3118*37da2899SCharles.Forsyth 3119*37da2899SCharles.Forsyth raster->count_table[n] = (UInt)c; 3120*37da2899SCharles.Forsyth } 3121*37da2899SCharles.Forsyth 3122*37da2899SCharles.Forsyth #ifdef FT_RASTER_OPTION_ANTI_ALIASING 3123*37da2899SCharles.Forsyth 3124*37da2899SCharles.Forsyth /* set default 5-levels gray palette */ 3125*37da2899SCharles.Forsyth for ( n = 0; n < 5; n++ ) 3126*37da2899SCharles.Forsyth raster->grays[n] = n * 255 / 4; 3127*37da2899SCharles.Forsyth 3128*37da2899SCharles.Forsyth raster->gray_width = RASTER_GRAY_LINES / 2; 3129*37da2899SCharles.Forsyth 3130*37da2899SCharles.Forsyth #endif 3131*37da2899SCharles.Forsyth } 3132*37da2899SCharles.Forsyth 3133*37da2899SCharles.Forsyth 3134*37da2899SCharles.Forsyth /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ 3135*37da2899SCharles.Forsyth /**** a static object. *****/ 3136*37da2899SCharles.Forsyth 3137*37da2899SCharles.Forsyth 3138*37da2899SCharles.Forsyth #ifdef _STANDALONE_ 3139*37da2899SCharles.Forsyth 3140*37da2899SCharles.Forsyth 3141*37da2899SCharles.Forsyth static int ft_black_new(void * memory,FT_Raster * araster)3142*37da2899SCharles.Forsyth ft_black_new( void* memory, 3143*37da2899SCharles.Forsyth FT_Raster *araster ) 3144*37da2899SCharles.Forsyth { 3145*37da2899SCharles.Forsyth static FT_RasterRec_ the_raster; 3146*37da2899SCharles.Forsyth 3147*37da2899SCharles.Forsyth 3148*37da2899SCharles.Forsyth *araster = &the_raster; 3149*37da2899SCharles.Forsyth FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); 3150*37da2899SCharles.Forsyth ft_black_init( &the_raster ); 3151*37da2899SCharles.Forsyth 3152*37da2899SCharles.Forsyth return 0; 3153*37da2899SCharles.Forsyth } 3154*37da2899SCharles.Forsyth 3155*37da2899SCharles.Forsyth 3156*37da2899SCharles.Forsyth static void ft_black_done(FT_Raster raster)3157*37da2899SCharles.Forsyth ft_black_done( FT_Raster raster ) 3158*37da2899SCharles.Forsyth { 3159*37da2899SCharles.Forsyth /* nothing */ 3160*37da2899SCharles.Forsyth raster->init = 0; 3161*37da2899SCharles.Forsyth } 3162*37da2899SCharles.Forsyth 3163*37da2899SCharles.Forsyth 3164*37da2899SCharles.Forsyth #else /* _STANDALONE_ */ 3165*37da2899SCharles.Forsyth 3166*37da2899SCharles.Forsyth 3167*37da2899SCharles.Forsyth static int ft_black_new(FT_Memory memory,TRaster_Instance ** araster)3168*37da2899SCharles.Forsyth ft_black_new( FT_Memory memory, 3169*37da2899SCharles.Forsyth TRaster_Instance** araster ) 3170*37da2899SCharles.Forsyth { 3171*37da2899SCharles.Forsyth FT_Error error; 3172*37da2899SCharles.Forsyth TRaster_Instance* raster; 3173*37da2899SCharles.Forsyth 3174*37da2899SCharles.Forsyth 3175*37da2899SCharles.Forsyth *araster = 0; 3176*37da2899SCharles.Forsyth if ( !FT_NEW( raster ) ) 3177*37da2899SCharles.Forsyth { 3178*37da2899SCharles.Forsyth raster->memory = memory; 3179*37da2899SCharles.Forsyth ft_black_init( raster ); 3180*37da2899SCharles.Forsyth 3181*37da2899SCharles.Forsyth *araster = raster; 3182*37da2899SCharles.Forsyth } 3183*37da2899SCharles.Forsyth 3184*37da2899SCharles.Forsyth return error; 3185*37da2899SCharles.Forsyth } 3186*37da2899SCharles.Forsyth 3187*37da2899SCharles.Forsyth 3188*37da2899SCharles.Forsyth static void ft_black_done(TRaster_Instance * raster)3189*37da2899SCharles.Forsyth ft_black_done( TRaster_Instance* raster ) 3190*37da2899SCharles.Forsyth { 3191*37da2899SCharles.Forsyth FT_Memory memory = (FT_Memory)raster->memory; 3192*37da2899SCharles.Forsyth FT_FREE( raster ); 3193*37da2899SCharles.Forsyth } 3194*37da2899SCharles.Forsyth 3195*37da2899SCharles.Forsyth 3196*37da2899SCharles.Forsyth #endif /* _STANDALONE_ */ 3197*37da2899SCharles.Forsyth 3198*37da2899SCharles.Forsyth 3199*37da2899SCharles.Forsyth static void ft_black_reset(TRaster_Instance * raster,const char * pool_base,long pool_size)3200*37da2899SCharles.Forsyth ft_black_reset( TRaster_Instance* raster, 3201*37da2899SCharles.Forsyth const char* pool_base, 3202*37da2899SCharles.Forsyth long pool_size ) 3203*37da2899SCharles.Forsyth { 3204*37da2899SCharles.Forsyth if ( raster && pool_base && pool_size >= 4096 ) 3205*37da2899SCharles.Forsyth { 3206*37da2899SCharles.Forsyth /* save the pool */ 3207*37da2899SCharles.Forsyth raster->buff = (PLong)pool_base; 3208*37da2899SCharles.Forsyth raster->sizeBuff = raster->buff + pool_size / sizeof ( Long ); 3209*37da2899SCharles.Forsyth } 3210*37da2899SCharles.Forsyth } 3211*37da2899SCharles.Forsyth 3212*37da2899SCharles.Forsyth 3213*37da2899SCharles.Forsyth static void ft_black_set_mode(TRaster_Instance * raster,unsigned long mode,const char * palette)3214*37da2899SCharles.Forsyth ft_black_set_mode( TRaster_Instance* raster, 3215*37da2899SCharles.Forsyth unsigned long mode, 3216*37da2899SCharles.Forsyth const char* palette ) 3217*37da2899SCharles.Forsyth { 3218*37da2899SCharles.Forsyth #ifdef FT_RASTER_OPTION_ANTI_ALIASING 3219*37da2899SCharles.Forsyth 3220*37da2899SCharles.Forsyth if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) 3221*37da2899SCharles.Forsyth { 3222*37da2899SCharles.Forsyth /* set 5-levels gray palette */ 3223*37da2899SCharles.Forsyth raster->grays[0] = palette[0]; 3224*37da2899SCharles.Forsyth raster->grays[1] = palette[1]; 3225*37da2899SCharles.Forsyth raster->grays[2] = palette[2]; 3226*37da2899SCharles.Forsyth raster->grays[3] = palette[3]; 3227*37da2899SCharles.Forsyth raster->grays[4] = palette[4]; 3228*37da2899SCharles.Forsyth } 3229*37da2899SCharles.Forsyth 3230*37da2899SCharles.Forsyth #else 3231*37da2899SCharles.Forsyth 3232*37da2899SCharles.Forsyth FT_UNUSED( raster ); 3233*37da2899SCharles.Forsyth FT_UNUSED( mode ); 3234*37da2899SCharles.Forsyth FT_UNUSED( palette ); 3235*37da2899SCharles.Forsyth 3236*37da2899SCharles.Forsyth #endif 3237*37da2899SCharles.Forsyth } 3238*37da2899SCharles.Forsyth 3239*37da2899SCharles.Forsyth 3240*37da2899SCharles.Forsyth static int ft_black_render(TRaster_Instance * raster,FT_Raster_Params * params)3241*37da2899SCharles.Forsyth ft_black_render( TRaster_Instance* raster, 3242*37da2899SCharles.Forsyth FT_Raster_Params* params ) 3243*37da2899SCharles.Forsyth { 3244*37da2899SCharles.Forsyth FT_Outline* outline = (FT_Outline*)params->source; 3245*37da2899SCharles.Forsyth FT_Bitmap* target_map = params->target; 3246*37da2899SCharles.Forsyth 3247*37da2899SCharles.Forsyth 3248*37da2899SCharles.Forsyth if ( !raster || !raster->buff || !raster->sizeBuff ) 3249*37da2899SCharles.Forsyth return Raster_Err_Not_Ini; 3250*37da2899SCharles.Forsyth 3251*37da2899SCharles.Forsyth /* return immediately if the outline is empty */ 3252*37da2899SCharles.Forsyth if ( outline->n_points == 0 || outline->n_contours <= 0 ) 3253*37da2899SCharles.Forsyth return Raster_Err_None; 3254*37da2899SCharles.Forsyth 3255*37da2899SCharles.Forsyth if ( !outline || !outline->contours || !outline->points ) 3256*37da2899SCharles.Forsyth return Raster_Err_Invalid; 3257*37da2899SCharles.Forsyth 3258*37da2899SCharles.Forsyth if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) 3259*37da2899SCharles.Forsyth return Raster_Err_Invalid; 3260*37da2899SCharles.Forsyth 3261*37da2899SCharles.Forsyth /* this version of the raster does not support direct rendering, sorry */ 3262*37da2899SCharles.Forsyth if ( params->flags & FT_RASTER_FLAG_DIRECT ) 3263*37da2899SCharles.Forsyth return Raster_Err_Unsupported; 3264*37da2899SCharles.Forsyth 3265*37da2899SCharles.Forsyth if ( !target_map || !target_map->buffer ) 3266*37da2899SCharles.Forsyth return Raster_Err_Invalid; 3267*37da2899SCharles.Forsyth 3268*37da2899SCharles.Forsyth ras.outline = *outline; 3269*37da2899SCharles.Forsyth ras.target = *target_map; 3270*37da2899SCharles.Forsyth 3271*37da2899SCharles.Forsyth return ( ( params->flags & FT_RASTER_FLAG_AA ) 3272*37da2899SCharles.Forsyth ? Render_Gray_Glyph( raster ) 3273*37da2899SCharles.Forsyth : Render_Glyph( raster ) ); 3274*37da2899SCharles.Forsyth } 3275*37da2899SCharles.Forsyth 3276*37da2899SCharles.Forsyth 3277*37da2899SCharles.Forsyth const FT_Raster_Funcs ft_standard_raster = 3278*37da2899SCharles.Forsyth { 3279*37da2899SCharles.Forsyth FT_GLYPH_FORMAT_OUTLINE, 3280*37da2899SCharles.Forsyth (FT_Raster_New_Func) ft_black_new, 3281*37da2899SCharles.Forsyth (FT_Raster_Reset_Func) ft_black_reset, 3282*37da2899SCharles.Forsyth (FT_Raster_Set_Mode_Func)ft_black_set_mode, 3283*37da2899SCharles.Forsyth (FT_Raster_Render_Func) ft_black_render, 3284*37da2899SCharles.Forsyth (FT_Raster_Done_Func) ft_black_done 3285*37da2899SCharles.Forsyth }; 3286*37da2899SCharles.Forsyth 3287*37da2899SCharles.Forsyth 3288*37da2899SCharles.Forsyth /* END */ 3289