1*37da2899SCharles.Forsyth /***************************************************************************/ 2*37da2899SCharles.Forsyth /* */ 3*37da2899SCharles.Forsyth /* ftgrays.c */ 4*37da2899SCharles.Forsyth /* */ 5*37da2899SCharles.Forsyth /* A new `perfect' anti-aliasing renderer (body). */ 6*37da2899SCharles.Forsyth /* */ 7*37da2899SCharles.Forsyth /* Copyright 2000-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 file can be compiled without the rest of the FreeType engine, by */ 21*37da2899SCharles.Forsyth /* defining the _STANDALONE_ macro when compiling it. You also need to */ 22*37da2899SCharles.Forsyth /* put the files `ftgrays.h' and `ftimage.h' into the current */ 23*37da2899SCharles.Forsyth /* compilation directory. Typically, you could do something like */ 24*37da2899SCharles.Forsyth /* */ 25*37da2899SCharles.Forsyth /* - copy `src/smooth/ftgrays.c' (this file) to your current directory */ 26*37da2899SCharles.Forsyth /* */ 27*37da2899SCharles.Forsyth /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */ 28*37da2899SCharles.Forsyth /* same directory */ 29*37da2899SCharles.Forsyth /* */ 30*37da2899SCharles.Forsyth /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ 31*37da2899SCharles.Forsyth /* */ 32*37da2899SCharles.Forsyth /* cc -c -D_STANDALONE_ ftgrays.c */ 33*37da2899SCharles.Forsyth /* */ 34*37da2899SCharles.Forsyth /* The renderer can be initialized with a call to */ 35*37da2899SCharles.Forsyth /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */ 36*37da2899SCharles.Forsyth /* with a call to `ft_gray_raster.raster_render'. */ 37*37da2899SCharles.Forsyth /* */ 38*37da2899SCharles.Forsyth /* See the comments and documentation in the file `ftimage.h' for more */ 39*37da2899SCharles.Forsyth /* details on how the raster works. */ 40*37da2899SCharles.Forsyth /* */ 41*37da2899SCharles.Forsyth /*************************************************************************/ 42*37da2899SCharles.Forsyth 43*37da2899SCharles.Forsyth /*************************************************************************/ 44*37da2899SCharles.Forsyth /* */ 45*37da2899SCharles.Forsyth /* This is a new anti-aliasing scan-converter for FreeType 2. The */ 46*37da2899SCharles.Forsyth /* algorithm used here is _very_ different from the one in the standard */ 47*37da2899SCharles.Forsyth /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ 48*37da2899SCharles.Forsyth /* coverage of the outline on each pixel cell. */ 49*37da2899SCharles.Forsyth /* */ 50*37da2899SCharles.Forsyth /* It is based on ideas that I initially found in Raph Levien's */ 51*37da2899SCharles.Forsyth /* excellent LibArt graphics library (see http://www.levien.com/libart */ 52*37da2899SCharles.Forsyth /* for more information, though the web pages do not tell anything */ 53*37da2899SCharles.Forsyth /* about the renderer; you'll have to dive into the source code to */ 54*37da2899SCharles.Forsyth /* understand how it works). */ 55*37da2899SCharles.Forsyth /* */ 56*37da2899SCharles.Forsyth /* Note, however, that this is a _very_ different implementation */ 57*37da2899SCharles.Forsyth /* compared to Raph's. Coverage information is stored in a very */ 58*37da2899SCharles.Forsyth /* different way, and I don't use sorted vector paths. Also, it doesn't */ 59*37da2899SCharles.Forsyth /* use floating point values. */ 60*37da2899SCharles.Forsyth /* */ 61*37da2899SCharles.Forsyth /* This renderer has the following advantages: */ 62*37da2899SCharles.Forsyth /* */ 63*37da2899SCharles.Forsyth /* - It doesn't need an intermediate bitmap. Instead, one can supply a */ 64*37da2899SCharles.Forsyth /* callback function that will be called by the renderer to draw gray */ 65*37da2899SCharles.Forsyth /* spans on any target surface. You can thus do direct composition on */ 66*37da2899SCharles.Forsyth /* any kind of bitmap, provided that you give the renderer the right */ 67*37da2899SCharles.Forsyth /* callback. */ 68*37da2899SCharles.Forsyth /* */ 69*37da2899SCharles.Forsyth /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ 70*37da2899SCharles.Forsyth /* each pixel cell. */ 71*37da2899SCharles.Forsyth /* */ 72*37da2899SCharles.Forsyth /* - It performs a single pass on the outline (the `standard' FT2 */ 73*37da2899SCharles.Forsyth /* renderer makes two passes). */ 74*37da2899SCharles.Forsyth /* */ 75*37da2899SCharles.Forsyth /* - It can easily be modified to render to _any_ number of gray levels */ 76*37da2899SCharles.Forsyth /* cheaply. */ 77*37da2899SCharles.Forsyth /* */ 78*37da2899SCharles.Forsyth /* - For small (< 20) pixel sizes, it is faster than the standard */ 79*37da2899SCharles.Forsyth /* renderer. */ 80*37da2899SCharles.Forsyth /* */ 81*37da2899SCharles.Forsyth /*************************************************************************/ 82*37da2899SCharles.Forsyth 83*37da2899SCharles.Forsyth 84*37da2899SCharles.Forsyth 85*37da2899SCharles.Forsyth /* experimental support for gamma correction within the rasterizer */ 86*37da2899SCharles.Forsyth #define xxxGRAYS_USE_GAMMA 87*37da2899SCharles.Forsyth 88*37da2899SCharles.Forsyth 89*37da2899SCharles.Forsyth /*************************************************************************/ 90*37da2899SCharles.Forsyth /* */ 91*37da2899SCharles.Forsyth /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 92*37da2899SCharles.Forsyth /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 93*37da2899SCharles.Forsyth /* messages during execution. */ 94*37da2899SCharles.Forsyth /* */ 95*37da2899SCharles.Forsyth #undef FT_COMPONENT 96*37da2899SCharles.Forsyth #define FT_COMPONENT trace_smooth 97*37da2899SCharles.Forsyth 98*37da2899SCharles.Forsyth 99*37da2899SCharles.Forsyth #define ErrRaster_MemoryOverflow -4 100*37da2899SCharles.Forsyth 101*37da2899SCharles.Forsyth 102*37da2899SCharles.Forsyth #ifdef _STANDALONE_ 103*37da2899SCharles.Forsyth 104*37da2899SCharles.Forsyth #include <string.h> /* for ft_memcpy() */ 105*37da2899SCharles.Forsyth #include <setjmp.h> 106*37da2899SCharles.Forsyth #include <limits.h> 107*37da2899SCharles.Forsyth #define FT_UINT_MAX UINT_MAX 108*37da2899SCharles.Forsyth 109*37da2899SCharles.Forsyth #define ft_memset memset 110*37da2899SCharles.Forsyth 111*37da2899SCharles.Forsyth #define ft_setjmp setjmp 112*37da2899SCharles.Forsyth #define ft_longjmp longjmp 113*37da2899SCharles.Forsyth #define ft_jmp_buf jmp_buf 114*37da2899SCharles.Forsyth 115*37da2899SCharles.Forsyth 116*37da2899SCharles.Forsyth #define ErrRaster_Invalid_Mode -2 117*37da2899SCharles.Forsyth #define ErrRaster_Invalid_Outline -1 118*37da2899SCharles.Forsyth 119*37da2899SCharles.Forsyth #define FT_BEGIN_HEADER 120*37da2899SCharles.Forsyth #define FT_END_HEADER 121*37da2899SCharles.Forsyth 122*37da2899SCharles.Forsyth #include "ftimage.h" 123*37da2899SCharles.Forsyth #include "ftgrays.h" 124*37da2899SCharles.Forsyth 125*37da2899SCharles.Forsyth /* This macro is used to indicate that a function parameter is unused. */ 126*37da2899SCharles.Forsyth /* Its purpose is simply to reduce compiler warnings. Note also that */ 127*37da2899SCharles.Forsyth /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 128*37da2899SCharles.Forsyth /* ANSI compilers (e.g. LCC). */ 129*37da2899SCharles.Forsyth #define FT_UNUSED( x ) (x) = (x) 130*37da2899SCharles.Forsyth 131*37da2899SCharles.Forsyth /* Disable the tracing mechanism for simplicity -- developers can */ 132*37da2899SCharles.Forsyth /* activate it easily by redefining these two macros. */ 133*37da2899SCharles.Forsyth #ifndef FT_ERROR 134*37da2899SCharles.Forsyth #define FT_ERROR( x ) do ; while ( 0 ) /* nothing */ 135*37da2899SCharles.Forsyth #endif 136*37da2899SCharles.Forsyth 137*37da2899SCharles.Forsyth #ifndef FT_TRACE 138*37da2899SCharles.Forsyth #define FT_TRACE( x ) do ; while ( 0 ) /* nothing */ 139*37da2899SCharles.Forsyth #endif 140*37da2899SCharles.Forsyth 141*37da2899SCharles.Forsyth 142*37da2899SCharles.Forsyth #else /* _STANDALONE_ */ 143*37da2899SCharles.Forsyth 144*37da2899SCharles.Forsyth 145*37da2899SCharles.Forsyth #include <ft2build.h> 146*37da2899SCharles.Forsyth #include "ftgrays.h" 147*37da2899SCharles.Forsyth #include FT_INTERNAL_OBJECTS_H 148*37da2899SCharles.Forsyth #include FT_INTERNAL_DEBUG_H 149*37da2899SCharles.Forsyth #include FT_OUTLINE_H 150*37da2899SCharles.Forsyth 151*37da2899SCharles.Forsyth #include "ftsmerrs.h" 152*37da2899SCharles.Forsyth 153*37da2899SCharles.Forsyth #define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph 154*37da2899SCharles.Forsyth #define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline 155*37da2899SCharles.Forsyth 156*37da2899SCharles.Forsyth 157*37da2899SCharles.Forsyth #endif /* _STANDALONE_ */ 158*37da2899SCharles.Forsyth 159*37da2899SCharles.Forsyth 160*37da2899SCharles.Forsyth #ifndef FT_MEM_SET 161*37da2899SCharles.Forsyth #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) 162*37da2899SCharles.Forsyth #endif 163*37da2899SCharles.Forsyth 164*37da2899SCharles.Forsyth #ifndef FT_MEM_ZERO 165*37da2899SCharles.Forsyth #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) 166*37da2899SCharles.Forsyth #endif 167*37da2899SCharles.Forsyth 168*37da2899SCharles.Forsyth /* define this to dump debugging information */ 169*37da2899SCharles.Forsyth #define xxxDEBUG_GRAYS 170*37da2899SCharles.Forsyth 171*37da2899SCharles.Forsyth /* as usual, for the speed hungry :-) */ 172*37da2899SCharles.Forsyth 173*37da2899SCharles.Forsyth #ifndef FT_STATIC_RASTER 174*37da2899SCharles.Forsyth 175*37da2899SCharles.Forsyth 176*37da2899SCharles.Forsyth #define RAS_ARG PRaster raster 177*37da2899SCharles.Forsyth #define RAS_ARG_ PRaster raster, 178*37da2899SCharles.Forsyth 179*37da2899SCharles.Forsyth #define RAS_VAR raster 180*37da2899SCharles.Forsyth #define RAS_VAR_ raster, 181*37da2899SCharles.Forsyth 182*37da2899SCharles.Forsyth #define ras (*raster) 183*37da2899SCharles.Forsyth 184*37da2899SCharles.Forsyth 185*37da2899SCharles.Forsyth #else /* FT_STATIC_RASTER */ 186*37da2899SCharles.Forsyth 187*37da2899SCharles.Forsyth 188*37da2899SCharles.Forsyth #define RAS_ARG /* empty */ 189*37da2899SCharles.Forsyth #define RAS_ARG_ /* empty */ 190*37da2899SCharles.Forsyth #define RAS_VAR /* empty */ 191*37da2899SCharles.Forsyth #define RAS_VAR_ /* empty */ 192*37da2899SCharles.Forsyth 193*37da2899SCharles.Forsyth static TRaster ras; 194*37da2899SCharles.Forsyth 195*37da2899SCharles.Forsyth 196*37da2899SCharles.Forsyth #endif /* FT_STATIC_RASTER */ 197*37da2899SCharles.Forsyth 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsyth /* must be at least 6 bits! */ 200*37da2899SCharles.Forsyth #define PIXEL_BITS 8 201*37da2899SCharles.Forsyth 202*37da2899SCharles.Forsyth #define ONE_PIXEL ( 1L << PIXEL_BITS ) 203*37da2899SCharles.Forsyth #define PIXEL_MASK ( -1L << PIXEL_BITS ) 204*37da2899SCharles.Forsyth #define TRUNC( x ) ( (TCoord)((x) >> PIXEL_BITS) ) 205*37da2899SCharles.Forsyth #define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) 206*37da2899SCharles.Forsyth #define FLOOR( x ) ( (x) & -ONE_PIXEL ) 207*37da2899SCharles.Forsyth #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) 208*37da2899SCharles.Forsyth #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) 209*37da2899SCharles.Forsyth 210*37da2899SCharles.Forsyth #if PIXEL_BITS >= 6 211*37da2899SCharles.Forsyth #define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) 212*37da2899SCharles.Forsyth #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) 213*37da2899SCharles.Forsyth #else 214*37da2899SCharles.Forsyth #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) 215*37da2899SCharles.Forsyth #define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) 216*37da2899SCharles.Forsyth #endif 217*37da2899SCharles.Forsyth 218*37da2899SCharles.Forsyth /* Define this if you want to use a more compact storage scheme. This */ 219*37da2899SCharles.Forsyth /* increases the number of cells available in the render pool but slows */ 220*37da2899SCharles.Forsyth /* down the rendering a bit. It is useful if you have a really tiny */ 221*37da2899SCharles.Forsyth /* render pool. */ 222*37da2899SCharles.Forsyth #undef GRAYS_COMPACT 223*37da2899SCharles.Forsyth 224*37da2899SCharles.Forsyth 225*37da2899SCharles.Forsyth /*************************************************************************/ 226*37da2899SCharles.Forsyth /* */ 227*37da2899SCharles.Forsyth /* TYPE DEFINITIONS */ 228*37da2899SCharles.Forsyth /* */ 229*37da2899SCharles.Forsyth 230*37da2899SCharles.Forsyth /* don't change the following types to FT_Int or FT_Pos, since we might */ 231*37da2899SCharles.Forsyth /* need to define them to "float" or "double" when experimenting with */ 232*37da2899SCharles.Forsyth /* new algorithms */ 233*37da2899SCharles.Forsyth 234*37da2899SCharles.Forsyth typedef int TCoord; /* integer scanline/pixel coordinate */ 235*37da2899SCharles.Forsyth typedef long TPos; /* sub-pixel coordinate */ 236*37da2899SCharles.Forsyth 237*37da2899SCharles.Forsyth /* determine the type used to store cell areas. This normally takes at */ 238*37da2899SCharles.Forsyth /* least PIXEL_BYTES*2 + 1. On 16-bit systems, we need to use `long' */ 239*37da2899SCharles.Forsyth /* instead of `int', otherwise bad things happen */ 240*37da2899SCharles.Forsyth 241*37da2899SCharles.Forsyth #if PIXEL_BITS <= 7 242*37da2899SCharles.Forsyth 243*37da2899SCharles.Forsyth typedef int TArea; 244*37da2899SCharles.Forsyth 245*37da2899SCharles.Forsyth #else /* PIXEL_BITS >= 8 */ 246*37da2899SCharles.Forsyth 247*37da2899SCharles.Forsyth /* approximately determine the size of integers using an ANSI-C header */ 248*37da2899SCharles.Forsyth #if FT_UINT_MAX == 0xFFFFU 249*37da2899SCharles.Forsyth typedef long TArea; 250*37da2899SCharles.Forsyth #else 251*37da2899SCharles.Forsyth typedef int TArea; 252*37da2899SCharles.Forsyth #endif 253*37da2899SCharles.Forsyth 254*37da2899SCharles.Forsyth #endif /* PIXEL_BITS >= 8 */ 255*37da2899SCharles.Forsyth 256*37da2899SCharles.Forsyth 257*37da2899SCharles.Forsyth /* maximal number of gray spans in a call to the span callback */ 258*37da2899SCharles.Forsyth #define FT_MAX_GRAY_SPANS 32 259*37da2899SCharles.Forsyth 260*37da2899SCharles.Forsyth 261*37da2899SCharles.Forsyth #ifdef GRAYS_COMPACT 262*37da2899SCharles.Forsyth 263*37da2899SCharles.Forsyth typedef struct TCell_ 264*37da2899SCharles.Forsyth { 265*37da2899SCharles.Forsyth short x : 14; 266*37da2899SCharles.Forsyth short y : 14; 267*37da2899SCharles.Forsyth int cover : PIXEL_BITS + 2; 268*37da2899SCharles.Forsyth int area : PIXEL_BITS * 2 + 2; 269*37da2899SCharles.Forsyth 270*37da2899SCharles.Forsyth } TCell, *PCell; 271*37da2899SCharles.Forsyth 272*37da2899SCharles.Forsyth #else /* GRAYS_COMPACT */ 273*37da2899SCharles.Forsyth 274*37da2899SCharles.Forsyth typedef struct TCell_ 275*37da2899SCharles.Forsyth { 276*37da2899SCharles.Forsyth TCoord x; 277*37da2899SCharles.Forsyth TCoord y; 278*37da2899SCharles.Forsyth int cover; 279*37da2899SCharles.Forsyth TArea area; 280*37da2899SCharles.Forsyth 281*37da2899SCharles.Forsyth } TCell, *PCell; 282*37da2899SCharles.Forsyth 283*37da2899SCharles.Forsyth #endif /* GRAYS_COMPACT */ 284*37da2899SCharles.Forsyth 285*37da2899SCharles.Forsyth 286*37da2899SCharles.Forsyth typedef struct TRaster_ 287*37da2899SCharles.Forsyth { 288*37da2899SCharles.Forsyth PCell cells; 289*37da2899SCharles.Forsyth int max_cells; 290*37da2899SCharles.Forsyth int num_cells; 291*37da2899SCharles.Forsyth 292*37da2899SCharles.Forsyth TPos min_ex, max_ex; 293*37da2899SCharles.Forsyth TPos min_ey, max_ey; 294*37da2899SCharles.Forsyth 295*37da2899SCharles.Forsyth TArea area; 296*37da2899SCharles.Forsyth int cover; 297*37da2899SCharles.Forsyth int invalid; 298*37da2899SCharles.Forsyth 299*37da2899SCharles.Forsyth TCoord ex, ey; 300*37da2899SCharles.Forsyth TCoord cx, cy; 301*37da2899SCharles.Forsyth TPos x, y; 302*37da2899SCharles.Forsyth 303*37da2899SCharles.Forsyth TPos last_ey; 304*37da2899SCharles.Forsyth 305*37da2899SCharles.Forsyth FT_Vector bez_stack[32 * 3 + 1]; 306*37da2899SCharles.Forsyth int lev_stack[32]; 307*37da2899SCharles.Forsyth 308*37da2899SCharles.Forsyth FT_Outline outline; 309*37da2899SCharles.Forsyth FT_Bitmap target; 310*37da2899SCharles.Forsyth FT_BBox clip_box; 311*37da2899SCharles.Forsyth 312*37da2899SCharles.Forsyth FT_Span gray_spans[FT_MAX_GRAY_SPANS]; 313*37da2899SCharles.Forsyth int num_gray_spans; 314*37da2899SCharles.Forsyth 315*37da2899SCharles.Forsyth FT_Raster_Span_Func render_span; 316*37da2899SCharles.Forsyth void* render_span_data; 317*37da2899SCharles.Forsyth int span_y; 318*37da2899SCharles.Forsyth 319*37da2899SCharles.Forsyth int band_size; 320*37da2899SCharles.Forsyth int band_shoot; 321*37da2899SCharles.Forsyth int conic_level; 322*37da2899SCharles.Forsyth int cubic_level; 323*37da2899SCharles.Forsyth 324*37da2899SCharles.Forsyth void* memory; 325*37da2899SCharles.Forsyth ft_jmp_buf jump_buffer; 326*37da2899SCharles.Forsyth 327*37da2899SCharles.Forsyth #ifdef GRAYS_USE_GAMMA 328*37da2899SCharles.Forsyth unsigned char gamma[257]; 329*37da2899SCharles.Forsyth #endif 330*37da2899SCharles.Forsyth 331*37da2899SCharles.Forsyth } TRaster, *PRaster; 332*37da2899SCharles.Forsyth 333*37da2899SCharles.Forsyth 334*37da2899SCharles.Forsyth /*************************************************************************/ 335*37da2899SCharles.Forsyth /* */ 336*37da2899SCharles.Forsyth /* Initialize the cells table. */ 337*37da2899SCharles.Forsyth /* */ 338*37da2899SCharles.Forsyth static void gray_init_cells(RAS_ARG_ void * buffer,long byte_size)339*37da2899SCharles.Forsyth gray_init_cells( RAS_ARG_ void* buffer, 340*37da2899SCharles.Forsyth long byte_size ) 341*37da2899SCharles.Forsyth { 342*37da2899SCharles.Forsyth ras.cells = (PCell)buffer; 343*37da2899SCharles.Forsyth ras.max_cells = byte_size / sizeof ( TCell ); 344*37da2899SCharles.Forsyth ras.num_cells = 0; 345*37da2899SCharles.Forsyth ras.area = 0; 346*37da2899SCharles.Forsyth ras.cover = 0; 347*37da2899SCharles.Forsyth ras.invalid = 1; 348*37da2899SCharles.Forsyth } 349*37da2899SCharles.Forsyth 350*37da2899SCharles.Forsyth 351*37da2899SCharles.Forsyth /*************************************************************************/ 352*37da2899SCharles.Forsyth /* */ 353*37da2899SCharles.Forsyth /* Compute the outline bounding box. */ 354*37da2899SCharles.Forsyth /* */ 355*37da2899SCharles.Forsyth static void gray_compute_cbox(RAS_ARG)356*37da2899SCharles.Forsyth gray_compute_cbox( RAS_ARG ) 357*37da2899SCharles.Forsyth { 358*37da2899SCharles.Forsyth FT_Outline* outline = &ras.outline; 359*37da2899SCharles.Forsyth FT_Vector* vec = outline->points; 360*37da2899SCharles.Forsyth FT_Vector* limit = vec + outline->n_points; 361*37da2899SCharles.Forsyth 362*37da2899SCharles.Forsyth 363*37da2899SCharles.Forsyth if ( outline->n_points <= 0 ) 364*37da2899SCharles.Forsyth { 365*37da2899SCharles.Forsyth ras.min_ex = ras.max_ex = 0; 366*37da2899SCharles.Forsyth ras.min_ey = ras.max_ey = 0; 367*37da2899SCharles.Forsyth return; 368*37da2899SCharles.Forsyth } 369*37da2899SCharles.Forsyth 370*37da2899SCharles.Forsyth ras.min_ex = ras.max_ex = vec->x; 371*37da2899SCharles.Forsyth ras.min_ey = ras.max_ey = vec->y; 372*37da2899SCharles.Forsyth 373*37da2899SCharles.Forsyth vec++; 374*37da2899SCharles.Forsyth 375*37da2899SCharles.Forsyth for ( ; vec < limit; vec++ ) 376*37da2899SCharles.Forsyth { 377*37da2899SCharles.Forsyth TPos x = vec->x; 378*37da2899SCharles.Forsyth TPos y = vec->y; 379*37da2899SCharles.Forsyth 380*37da2899SCharles.Forsyth 381*37da2899SCharles.Forsyth if ( x < ras.min_ex ) ras.min_ex = x; 382*37da2899SCharles.Forsyth if ( x > ras.max_ex ) ras.max_ex = x; 383*37da2899SCharles.Forsyth if ( y < ras.min_ey ) ras.min_ey = y; 384*37da2899SCharles.Forsyth if ( y > ras.max_ey ) ras.max_ey = y; 385*37da2899SCharles.Forsyth } 386*37da2899SCharles.Forsyth 387*37da2899SCharles.Forsyth /* truncate the bounding box to integer pixels */ 388*37da2899SCharles.Forsyth ras.min_ex = ras.min_ex >> 6; 389*37da2899SCharles.Forsyth ras.min_ey = ras.min_ey >> 6; 390*37da2899SCharles.Forsyth ras.max_ex = ( ras.max_ex + 63 ) >> 6; 391*37da2899SCharles.Forsyth ras.max_ey = ( ras.max_ey + 63 ) >> 6; 392*37da2899SCharles.Forsyth } 393*37da2899SCharles.Forsyth 394*37da2899SCharles.Forsyth 395*37da2899SCharles.Forsyth /*************************************************************************/ 396*37da2899SCharles.Forsyth /* */ 397*37da2899SCharles.Forsyth /* Record the current cell in the table. */ 398*37da2899SCharles.Forsyth /* */ 399*37da2899SCharles.Forsyth static void gray_record_cell(RAS_ARG)400*37da2899SCharles.Forsyth gray_record_cell( RAS_ARG ) 401*37da2899SCharles.Forsyth { 402*37da2899SCharles.Forsyth PCell cell; 403*37da2899SCharles.Forsyth 404*37da2899SCharles.Forsyth 405*37da2899SCharles.Forsyth if ( !ras.invalid && ( ras.area | ras.cover ) ) 406*37da2899SCharles.Forsyth { 407*37da2899SCharles.Forsyth if ( ras.num_cells >= ras.max_cells ) 408*37da2899SCharles.Forsyth ft_longjmp( ras.jump_buffer, 1 ); 409*37da2899SCharles.Forsyth 410*37da2899SCharles.Forsyth cell = ras.cells + ras.num_cells++; 411*37da2899SCharles.Forsyth cell->x = (TCoord)(ras.ex - ras.min_ex); 412*37da2899SCharles.Forsyth cell->y = (TCoord)(ras.ey - ras.min_ey); 413*37da2899SCharles.Forsyth cell->area = ras.area; 414*37da2899SCharles.Forsyth cell->cover = ras.cover; 415*37da2899SCharles.Forsyth } 416*37da2899SCharles.Forsyth } 417*37da2899SCharles.Forsyth 418*37da2899SCharles.Forsyth 419*37da2899SCharles.Forsyth /*************************************************************************/ 420*37da2899SCharles.Forsyth /* */ 421*37da2899SCharles.Forsyth /* Set the current cell to a new position. */ 422*37da2899SCharles.Forsyth /* */ 423*37da2899SCharles.Forsyth static void gray_set_cell(RAS_ARG_ TCoord ex,TCoord ey)424*37da2899SCharles.Forsyth gray_set_cell( RAS_ARG_ TCoord ex, 425*37da2899SCharles.Forsyth TCoord ey ) 426*37da2899SCharles.Forsyth { 427*37da2899SCharles.Forsyth int invalid, record, clean; 428*37da2899SCharles.Forsyth 429*37da2899SCharles.Forsyth 430*37da2899SCharles.Forsyth /* Move the cell pointer to a new position. We set the `invalid' */ 431*37da2899SCharles.Forsyth /* flag to indicate that the cell isn't part of those we're interested */ 432*37da2899SCharles.Forsyth /* in during the render phase. This means that: */ 433*37da2899SCharles.Forsyth /* */ 434*37da2899SCharles.Forsyth /* . the new vertical position must be within min_ey..max_ey-1. */ 435*37da2899SCharles.Forsyth /* . the new horizontal position must be strictly less than max_ex */ 436*37da2899SCharles.Forsyth /* */ 437*37da2899SCharles.Forsyth /* Note that if a cell is to the left of the clipping region, it is */ 438*37da2899SCharles.Forsyth /* actually set to the (min_ex-1) horizontal position. */ 439*37da2899SCharles.Forsyth 440*37da2899SCharles.Forsyth record = 0; 441*37da2899SCharles.Forsyth clean = 1; 442*37da2899SCharles.Forsyth 443*37da2899SCharles.Forsyth invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex ); 444*37da2899SCharles.Forsyth if ( !invalid ) 445*37da2899SCharles.Forsyth { 446*37da2899SCharles.Forsyth /* All cells that are on the left of the clipping region go to the */ 447*37da2899SCharles.Forsyth /* min_ex - 1 horizontal position. */ 448*37da2899SCharles.Forsyth if ( ex < ras.min_ex ) 449*37da2899SCharles.Forsyth ex = (TCoord)(ras.min_ex - 1); 450*37da2899SCharles.Forsyth 451*37da2899SCharles.Forsyth /* if our position is new, then record the previous cell */ 452*37da2899SCharles.Forsyth if ( ex != ras.ex || ey != ras.ey ) 453*37da2899SCharles.Forsyth record = 1; 454*37da2899SCharles.Forsyth else 455*37da2899SCharles.Forsyth clean = ras.invalid; /* do not clean if we didn't move from */ 456*37da2899SCharles.Forsyth /* a valid cell */ 457*37da2899SCharles.Forsyth } 458*37da2899SCharles.Forsyth 459*37da2899SCharles.Forsyth /* record the previous cell if needed (i.e., if we changed the cell */ 460*37da2899SCharles.Forsyth /* position, of changed the `invalid' flag) */ 461*37da2899SCharles.Forsyth if ( ras.invalid != invalid || record ) 462*37da2899SCharles.Forsyth gray_record_cell( RAS_VAR ); 463*37da2899SCharles.Forsyth 464*37da2899SCharles.Forsyth if ( clean ) 465*37da2899SCharles.Forsyth { 466*37da2899SCharles.Forsyth ras.area = 0; 467*37da2899SCharles.Forsyth ras.cover = 0; 468*37da2899SCharles.Forsyth } 469*37da2899SCharles.Forsyth 470*37da2899SCharles.Forsyth ras.invalid = invalid; 471*37da2899SCharles.Forsyth ras.ex = ex; 472*37da2899SCharles.Forsyth ras.ey = ey; 473*37da2899SCharles.Forsyth } 474*37da2899SCharles.Forsyth 475*37da2899SCharles.Forsyth 476*37da2899SCharles.Forsyth /*************************************************************************/ 477*37da2899SCharles.Forsyth /* */ 478*37da2899SCharles.Forsyth /* Start a new contour at a given cell. */ 479*37da2899SCharles.Forsyth /* */ 480*37da2899SCharles.Forsyth static void gray_start_cell(RAS_ARG_ TCoord ex,TCoord ey)481*37da2899SCharles.Forsyth gray_start_cell( RAS_ARG_ TCoord ex, 482*37da2899SCharles.Forsyth TCoord ey ) 483*37da2899SCharles.Forsyth { 484*37da2899SCharles.Forsyth if ( ex < ras.min_ex ) 485*37da2899SCharles.Forsyth ex = (TCoord)(ras.min_ex - 1); 486*37da2899SCharles.Forsyth 487*37da2899SCharles.Forsyth ras.area = 0; 488*37da2899SCharles.Forsyth ras.cover = 0; 489*37da2899SCharles.Forsyth ras.ex = ex; 490*37da2899SCharles.Forsyth ras.ey = ey; 491*37da2899SCharles.Forsyth ras.last_ey = SUBPIXELS( ey ); 492*37da2899SCharles.Forsyth ras.invalid = 0; 493*37da2899SCharles.Forsyth 494*37da2899SCharles.Forsyth gray_set_cell( RAS_VAR_ ex, ey ); 495*37da2899SCharles.Forsyth } 496*37da2899SCharles.Forsyth 497*37da2899SCharles.Forsyth 498*37da2899SCharles.Forsyth /*************************************************************************/ 499*37da2899SCharles.Forsyth /* */ 500*37da2899SCharles.Forsyth /* Render a scanline as one or more cells. */ 501*37da2899SCharles.Forsyth /* */ 502*37da2899SCharles.Forsyth static void gray_render_scanline(RAS_ARG_ TCoord ey,TPos x1,TCoord y1,TPos x2,TCoord y2)503*37da2899SCharles.Forsyth gray_render_scanline( RAS_ARG_ TCoord ey, 504*37da2899SCharles.Forsyth TPos x1, 505*37da2899SCharles.Forsyth TCoord y1, 506*37da2899SCharles.Forsyth TPos x2, 507*37da2899SCharles.Forsyth TCoord y2 ) 508*37da2899SCharles.Forsyth { 509*37da2899SCharles.Forsyth TCoord ex1, ex2, fx1, fx2, delta; 510*37da2899SCharles.Forsyth long p, first, dx; 511*37da2899SCharles.Forsyth int incr, lift, mod, rem; 512*37da2899SCharles.Forsyth 513*37da2899SCharles.Forsyth 514*37da2899SCharles.Forsyth dx = x2 - x1; 515*37da2899SCharles.Forsyth 516*37da2899SCharles.Forsyth ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */ 517*37da2899SCharles.Forsyth ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */ 518*37da2899SCharles.Forsyth fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); 519*37da2899SCharles.Forsyth fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); 520*37da2899SCharles.Forsyth 521*37da2899SCharles.Forsyth /* trivial case. Happens often */ 522*37da2899SCharles.Forsyth if ( y1 == y2 ) 523*37da2899SCharles.Forsyth { 524*37da2899SCharles.Forsyth gray_set_cell( RAS_VAR_ ex2, ey ); 525*37da2899SCharles.Forsyth return; 526*37da2899SCharles.Forsyth } 527*37da2899SCharles.Forsyth 528*37da2899SCharles.Forsyth /* everything is located in a single cell. That is easy! */ 529*37da2899SCharles.Forsyth /* */ 530*37da2899SCharles.Forsyth if ( ex1 == ex2 ) 531*37da2899SCharles.Forsyth { 532*37da2899SCharles.Forsyth delta = y2 - y1; 533*37da2899SCharles.Forsyth ras.area += (TArea)( fx1 + fx2 ) * delta; 534*37da2899SCharles.Forsyth ras.cover += delta; 535*37da2899SCharles.Forsyth return; 536*37da2899SCharles.Forsyth } 537*37da2899SCharles.Forsyth 538*37da2899SCharles.Forsyth /* ok, we'll have to render a run of adjacent cells on the same */ 539*37da2899SCharles.Forsyth /* scanline... */ 540*37da2899SCharles.Forsyth /* */ 541*37da2899SCharles.Forsyth p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); 542*37da2899SCharles.Forsyth first = ONE_PIXEL; 543*37da2899SCharles.Forsyth incr = 1; 544*37da2899SCharles.Forsyth 545*37da2899SCharles.Forsyth if ( dx < 0 ) 546*37da2899SCharles.Forsyth { 547*37da2899SCharles.Forsyth p = fx1 * ( y2 - y1 ); 548*37da2899SCharles.Forsyth first = 0; 549*37da2899SCharles.Forsyth incr = -1; 550*37da2899SCharles.Forsyth dx = -dx; 551*37da2899SCharles.Forsyth } 552*37da2899SCharles.Forsyth 553*37da2899SCharles.Forsyth delta = (TCoord)( p / dx ); 554*37da2899SCharles.Forsyth mod = (TCoord)( p % dx ); 555*37da2899SCharles.Forsyth if ( mod < 0 ) 556*37da2899SCharles.Forsyth { 557*37da2899SCharles.Forsyth delta--; 558*37da2899SCharles.Forsyth mod += (TCoord)dx; 559*37da2899SCharles.Forsyth } 560*37da2899SCharles.Forsyth 561*37da2899SCharles.Forsyth ras.area += (TArea)( fx1 + first ) * delta; 562*37da2899SCharles.Forsyth ras.cover += delta; 563*37da2899SCharles.Forsyth 564*37da2899SCharles.Forsyth ex1 += incr; 565*37da2899SCharles.Forsyth gray_set_cell( RAS_VAR_ ex1, ey ); 566*37da2899SCharles.Forsyth y1 += delta; 567*37da2899SCharles.Forsyth 568*37da2899SCharles.Forsyth if ( ex1 != ex2 ) 569*37da2899SCharles.Forsyth { 570*37da2899SCharles.Forsyth p = ONE_PIXEL * ( y2 - y1 + delta ); 571*37da2899SCharles.Forsyth lift = (TCoord)( p / dx ); 572*37da2899SCharles.Forsyth rem = (TCoord)( p % dx ); 573*37da2899SCharles.Forsyth if ( rem < 0 ) 574*37da2899SCharles.Forsyth { 575*37da2899SCharles.Forsyth lift--; 576*37da2899SCharles.Forsyth rem += (TCoord)dx; 577*37da2899SCharles.Forsyth } 578*37da2899SCharles.Forsyth 579*37da2899SCharles.Forsyth mod -= dx; 580*37da2899SCharles.Forsyth 581*37da2899SCharles.Forsyth while ( ex1 != ex2 ) 582*37da2899SCharles.Forsyth { 583*37da2899SCharles.Forsyth delta = lift; 584*37da2899SCharles.Forsyth mod += rem; 585*37da2899SCharles.Forsyth if ( mod >= 0 ) 586*37da2899SCharles.Forsyth { 587*37da2899SCharles.Forsyth mod -= (TCoord)dx; 588*37da2899SCharles.Forsyth delta++; 589*37da2899SCharles.Forsyth } 590*37da2899SCharles.Forsyth 591*37da2899SCharles.Forsyth ras.area += (TArea)ONE_PIXEL * delta; 592*37da2899SCharles.Forsyth ras.cover += delta; 593*37da2899SCharles.Forsyth y1 += delta; 594*37da2899SCharles.Forsyth ex1 += incr; 595*37da2899SCharles.Forsyth gray_set_cell( RAS_VAR_ ex1, ey ); 596*37da2899SCharles.Forsyth } 597*37da2899SCharles.Forsyth } 598*37da2899SCharles.Forsyth 599*37da2899SCharles.Forsyth delta = y2 - y1; 600*37da2899SCharles.Forsyth ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta; 601*37da2899SCharles.Forsyth ras.cover += delta; 602*37da2899SCharles.Forsyth } 603*37da2899SCharles.Forsyth 604*37da2899SCharles.Forsyth 605*37da2899SCharles.Forsyth /*************************************************************************/ 606*37da2899SCharles.Forsyth /* */ 607*37da2899SCharles.Forsyth /* Render a given line as a series of scanlines. */ 608*37da2899SCharles.Forsyth /* */ 609*37da2899SCharles.Forsyth static void gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)610*37da2899SCharles.Forsyth gray_render_line( RAS_ARG_ TPos to_x, 611*37da2899SCharles.Forsyth TPos to_y ) 612*37da2899SCharles.Forsyth { 613*37da2899SCharles.Forsyth TCoord ey1, ey2, fy1, fy2; 614*37da2899SCharles.Forsyth TPos dx, dy, x, x2; 615*37da2899SCharles.Forsyth long p, first; 616*37da2899SCharles.Forsyth int delta, rem, mod, lift, incr; 617*37da2899SCharles.Forsyth 618*37da2899SCharles.Forsyth 619*37da2899SCharles.Forsyth ey1 = TRUNC( ras.last_ey ); 620*37da2899SCharles.Forsyth ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ 621*37da2899SCharles.Forsyth fy1 = (TCoord)( ras.y - ras.last_ey ); 622*37da2899SCharles.Forsyth fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); 623*37da2899SCharles.Forsyth 624*37da2899SCharles.Forsyth dx = to_x - ras.x; 625*37da2899SCharles.Forsyth dy = to_y - ras.y; 626*37da2899SCharles.Forsyth 627*37da2899SCharles.Forsyth /* XXX: we should do something about the trivial case where dx == 0, */ 628*37da2899SCharles.Forsyth /* as it happens very often! */ 629*37da2899SCharles.Forsyth 630*37da2899SCharles.Forsyth /* perform vertical clipping */ 631*37da2899SCharles.Forsyth { 632*37da2899SCharles.Forsyth TCoord min, max; 633*37da2899SCharles.Forsyth 634*37da2899SCharles.Forsyth 635*37da2899SCharles.Forsyth min = ey1; 636*37da2899SCharles.Forsyth max = ey2; 637*37da2899SCharles.Forsyth if ( ey1 > ey2 ) 638*37da2899SCharles.Forsyth { 639*37da2899SCharles.Forsyth min = ey2; 640*37da2899SCharles.Forsyth max = ey1; 641*37da2899SCharles.Forsyth } 642*37da2899SCharles.Forsyth if ( min >= ras.max_ey || max < ras.min_ey ) 643*37da2899SCharles.Forsyth goto End; 644*37da2899SCharles.Forsyth } 645*37da2899SCharles.Forsyth 646*37da2899SCharles.Forsyth /* everything is on a single scanline */ 647*37da2899SCharles.Forsyth if ( ey1 == ey2 ) 648*37da2899SCharles.Forsyth { 649*37da2899SCharles.Forsyth gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); 650*37da2899SCharles.Forsyth goto End; 651*37da2899SCharles.Forsyth } 652*37da2899SCharles.Forsyth 653*37da2899SCharles.Forsyth /* vertical line - avoid calling gray_render_scanline */ 654*37da2899SCharles.Forsyth incr = 1; 655*37da2899SCharles.Forsyth 656*37da2899SCharles.Forsyth if ( dx == 0 ) 657*37da2899SCharles.Forsyth { 658*37da2899SCharles.Forsyth TCoord ex = TRUNC( ras.x ); 659*37da2899SCharles.Forsyth TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); 660*37da2899SCharles.Forsyth TPos area; 661*37da2899SCharles.Forsyth 662*37da2899SCharles.Forsyth 663*37da2899SCharles.Forsyth first = ONE_PIXEL; 664*37da2899SCharles.Forsyth if ( dy < 0 ) 665*37da2899SCharles.Forsyth { 666*37da2899SCharles.Forsyth first = 0; 667*37da2899SCharles.Forsyth incr = -1; 668*37da2899SCharles.Forsyth } 669*37da2899SCharles.Forsyth 670*37da2899SCharles.Forsyth delta = (int)( first - fy1 ); 671*37da2899SCharles.Forsyth ras.area += (TArea)two_fx * delta; 672*37da2899SCharles.Forsyth ras.cover += delta; 673*37da2899SCharles.Forsyth ey1 += incr; 674*37da2899SCharles.Forsyth 675*37da2899SCharles.Forsyth gray_set_cell( raster, ex, ey1 ); 676*37da2899SCharles.Forsyth 677*37da2899SCharles.Forsyth delta = (int)( first + first - ONE_PIXEL ); 678*37da2899SCharles.Forsyth area = (TArea)two_fx * delta; 679*37da2899SCharles.Forsyth while ( ey1 != ey2 ) 680*37da2899SCharles.Forsyth { 681*37da2899SCharles.Forsyth ras.area += area; 682*37da2899SCharles.Forsyth ras.cover += delta; 683*37da2899SCharles.Forsyth ey1 += incr; 684*37da2899SCharles.Forsyth gray_set_cell( raster, ex, ey1 ); 685*37da2899SCharles.Forsyth } 686*37da2899SCharles.Forsyth 687*37da2899SCharles.Forsyth delta = (int)( fy2 - ONE_PIXEL + first ); 688*37da2899SCharles.Forsyth ras.area += (TArea)two_fx * delta; 689*37da2899SCharles.Forsyth ras.cover += delta; 690*37da2899SCharles.Forsyth goto End; 691*37da2899SCharles.Forsyth } 692*37da2899SCharles.Forsyth 693*37da2899SCharles.Forsyth /* ok, we have to render several scanlines */ 694*37da2899SCharles.Forsyth p = ( ONE_PIXEL - fy1 ) * dx; 695*37da2899SCharles.Forsyth first = ONE_PIXEL; 696*37da2899SCharles.Forsyth incr = 1; 697*37da2899SCharles.Forsyth 698*37da2899SCharles.Forsyth if ( dy < 0 ) 699*37da2899SCharles.Forsyth { 700*37da2899SCharles.Forsyth p = fy1 * dx; 701*37da2899SCharles.Forsyth first = 0; 702*37da2899SCharles.Forsyth incr = -1; 703*37da2899SCharles.Forsyth dy = -dy; 704*37da2899SCharles.Forsyth } 705*37da2899SCharles.Forsyth 706*37da2899SCharles.Forsyth delta = (int)( p / dy ); 707*37da2899SCharles.Forsyth mod = (int)( p % dy ); 708*37da2899SCharles.Forsyth if ( mod < 0 ) 709*37da2899SCharles.Forsyth { 710*37da2899SCharles.Forsyth delta--; 711*37da2899SCharles.Forsyth mod += (TCoord)dy; 712*37da2899SCharles.Forsyth } 713*37da2899SCharles.Forsyth 714*37da2899SCharles.Forsyth x = ras.x + delta; 715*37da2899SCharles.Forsyth gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); 716*37da2899SCharles.Forsyth 717*37da2899SCharles.Forsyth ey1 += incr; 718*37da2899SCharles.Forsyth gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 719*37da2899SCharles.Forsyth 720*37da2899SCharles.Forsyth if ( ey1 != ey2 ) 721*37da2899SCharles.Forsyth { 722*37da2899SCharles.Forsyth p = ONE_PIXEL * dx; 723*37da2899SCharles.Forsyth lift = (int)( p / dy ); 724*37da2899SCharles.Forsyth rem = (int)( p % dy ); 725*37da2899SCharles.Forsyth if ( rem < 0 ) 726*37da2899SCharles.Forsyth { 727*37da2899SCharles.Forsyth lift--; 728*37da2899SCharles.Forsyth rem += (int)dy; 729*37da2899SCharles.Forsyth } 730*37da2899SCharles.Forsyth mod -= (int)dy; 731*37da2899SCharles.Forsyth 732*37da2899SCharles.Forsyth while ( ey1 != ey2 ) 733*37da2899SCharles.Forsyth { 734*37da2899SCharles.Forsyth delta = lift; 735*37da2899SCharles.Forsyth mod += rem; 736*37da2899SCharles.Forsyth if ( mod >= 0 ) 737*37da2899SCharles.Forsyth { 738*37da2899SCharles.Forsyth mod -= (int)dy; 739*37da2899SCharles.Forsyth delta++; 740*37da2899SCharles.Forsyth } 741*37da2899SCharles.Forsyth 742*37da2899SCharles.Forsyth x2 = x + delta; 743*37da2899SCharles.Forsyth gray_render_scanline( RAS_VAR_ ey1, x, 744*37da2899SCharles.Forsyth (TCoord)( ONE_PIXEL - first ), x2, 745*37da2899SCharles.Forsyth (TCoord)first ); 746*37da2899SCharles.Forsyth x = x2; 747*37da2899SCharles.Forsyth 748*37da2899SCharles.Forsyth ey1 += incr; 749*37da2899SCharles.Forsyth gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 750*37da2899SCharles.Forsyth } 751*37da2899SCharles.Forsyth } 752*37da2899SCharles.Forsyth 753*37da2899SCharles.Forsyth gray_render_scanline( RAS_VAR_ ey1, x, 754*37da2899SCharles.Forsyth (TCoord)( ONE_PIXEL - first ), to_x, 755*37da2899SCharles.Forsyth fy2 ); 756*37da2899SCharles.Forsyth 757*37da2899SCharles.Forsyth End: 758*37da2899SCharles.Forsyth ras.x = to_x; 759*37da2899SCharles.Forsyth ras.y = to_y; 760*37da2899SCharles.Forsyth ras.last_ey = SUBPIXELS( ey2 ); 761*37da2899SCharles.Forsyth } 762*37da2899SCharles.Forsyth 763*37da2899SCharles.Forsyth 764*37da2899SCharles.Forsyth static void gray_split_conic(FT_Vector * base)765*37da2899SCharles.Forsyth gray_split_conic( FT_Vector* base ) 766*37da2899SCharles.Forsyth { 767*37da2899SCharles.Forsyth TPos a, b; 768*37da2899SCharles.Forsyth 769*37da2899SCharles.Forsyth 770*37da2899SCharles.Forsyth base[4].x = base[2].x; 771*37da2899SCharles.Forsyth b = base[1].x; 772*37da2899SCharles.Forsyth a = base[3].x = ( base[2].x + b ) / 2; 773*37da2899SCharles.Forsyth b = base[1].x = ( base[0].x + b ) / 2; 774*37da2899SCharles.Forsyth base[2].x = ( a + b ) / 2; 775*37da2899SCharles.Forsyth 776*37da2899SCharles.Forsyth base[4].y = base[2].y; 777*37da2899SCharles.Forsyth b = base[1].y; 778*37da2899SCharles.Forsyth a = base[3].y = ( base[2].y + b ) / 2; 779*37da2899SCharles.Forsyth b = base[1].y = ( base[0].y + b ) / 2; 780*37da2899SCharles.Forsyth base[2].y = ( a + b ) / 2; 781*37da2899SCharles.Forsyth } 782*37da2899SCharles.Forsyth 783*37da2899SCharles.Forsyth 784*37da2899SCharles.Forsyth static void gray_render_conic(RAS_ARG_ FT_Vector * control,FT_Vector * to)785*37da2899SCharles.Forsyth gray_render_conic( RAS_ARG_ FT_Vector* control, 786*37da2899SCharles.Forsyth FT_Vector* to ) 787*37da2899SCharles.Forsyth { 788*37da2899SCharles.Forsyth TPos dx, dy; 789*37da2899SCharles.Forsyth int top, level; 790*37da2899SCharles.Forsyth int* levels; 791*37da2899SCharles.Forsyth FT_Vector* arc; 792*37da2899SCharles.Forsyth 793*37da2899SCharles.Forsyth 794*37da2899SCharles.Forsyth dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 ); 795*37da2899SCharles.Forsyth if ( dx < 0 ) 796*37da2899SCharles.Forsyth dx = -dx; 797*37da2899SCharles.Forsyth dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 ); 798*37da2899SCharles.Forsyth if ( dy < 0 ) 799*37da2899SCharles.Forsyth dy = -dy; 800*37da2899SCharles.Forsyth if ( dx < dy ) 801*37da2899SCharles.Forsyth dx = dy; 802*37da2899SCharles.Forsyth 803*37da2899SCharles.Forsyth level = 1; 804*37da2899SCharles.Forsyth dx = dx / ras.conic_level; 805*37da2899SCharles.Forsyth while ( dx > 0 ) 806*37da2899SCharles.Forsyth { 807*37da2899SCharles.Forsyth dx >>= 2; 808*37da2899SCharles.Forsyth level++; 809*37da2899SCharles.Forsyth } 810*37da2899SCharles.Forsyth 811*37da2899SCharles.Forsyth /* a shortcut to speed things up */ 812*37da2899SCharles.Forsyth if ( level <= 1 ) 813*37da2899SCharles.Forsyth { 814*37da2899SCharles.Forsyth /* we compute the mid-point directly in order to avoid */ 815*37da2899SCharles.Forsyth /* calling gray_split_conic() */ 816*37da2899SCharles.Forsyth TPos to_x, to_y, mid_x, mid_y; 817*37da2899SCharles.Forsyth 818*37da2899SCharles.Forsyth 819*37da2899SCharles.Forsyth to_x = UPSCALE( to->x ); 820*37da2899SCharles.Forsyth to_y = UPSCALE( to->y ); 821*37da2899SCharles.Forsyth mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4; 822*37da2899SCharles.Forsyth mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4; 823*37da2899SCharles.Forsyth 824*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ mid_x, mid_y ); 825*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ to_x, to_y ); 826*37da2899SCharles.Forsyth return; 827*37da2899SCharles.Forsyth } 828*37da2899SCharles.Forsyth 829*37da2899SCharles.Forsyth arc = ras.bez_stack; 830*37da2899SCharles.Forsyth levels = ras.lev_stack; 831*37da2899SCharles.Forsyth top = 0; 832*37da2899SCharles.Forsyth levels[0] = level; 833*37da2899SCharles.Forsyth 834*37da2899SCharles.Forsyth arc[0].x = UPSCALE( to->x ); 835*37da2899SCharles.Forsyth arc[0].y = UPSCALE( to->y ); 836*37da2899SCharles.Forsyth arc[1].x = UPSCALE( control->x ); 837*37da2899SCharles.Forsyth arc[1].y = UPSCALE( control->y ); 838*37da2899SCharles.Forsyth arc[2].x = ras.x; 839*37da2899SCharles.Forsyth arc[2].y = ras.y; 840*37da2899SCharles.Forsyth 841*37da2899SCharles.Forsyth while ( top >= 0 ) 842*37da2899SCharles.Forsyth { 843*37da2899SCharles.Forsyth level = levels[top]; 844*37da2899SCharles.Forsyth if ( level > 1 ) 845*37da2899SCharles.Forsyth { 846*37da2899SCharles.Forsyth /* check that the arc crosses the current band */ 847*37da2899SCharles.Forsyth TPos min, max, y; 848*37da2899SCharles.Forsyth 849*37da2899SCharles.Forsyth 850*37da2899SCharles.Forsyth min = max = arc[0].y; 851*37da2899SCharles.Forsyth 852*37da2899SCharles.Forsyth y = arc[1].y; 853*37da2899SCharles.Forsyth if ( y < min ) min = y; 854*37da2899SCharles.Forsyth if ( y > max ) max = y; 855*37da2899SCharles.Forsyth 856*37da2899SCharles.Forsyth y = arc[2].y; 857*37da2899SCharles.Forsyth if ( y < min ) min = y; 858*37da2899SCharles.Forsyth if ( y > max ) max = y; 859*37da2899SCharles.Forsyth 860*37da2899SCharles.Forsyth if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) 861*37da2899SCharles.Forsyth goto Draw; 862*37da2899SCharles.Forsyth 863*37da2899SCharles.Forsyth gray_split_conic( arc ); 864*37da2899SCharles.Forsyth arc += 2; 865*37da2899SCharles.Forsyth top++; 866*37da2899SCharles.Forsyth levels[top] = levels[top - 1] = level - 1; 867*37da2899SCharles.Forsyth continue; 868*37da2899SCharles.Forsyth } 869*37da2899SCharles.Forsyth 870*37da2899SCharles.Forsyth Draw: 871*37da2899SCharles.Forsyth { 872*37da2899SCharles.Forsyth TPos to_x, to_y, mid_x, mid_y; 873*37da2899SCharles.Forsyth 874*37da2899SCharles.Forsyth 875*37da2899SCharles.Forsyth to_x = arc[0].x; 876*37da2899SCharles.Forsyth to_y = arc[0].y; 877*37da2899SCharles.Forsyth mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4; 878*37da2899SCharles.Forsyth mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4; 879*37da2899SCharles.Forsyth 880*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ mid_x, mid_y ); 881*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ to_x, to_y ); 882*37da2899SCharles.Forsyth 883*37da2899SCharles.Forsyth top--; 884*37da2899SCharles.Forsyth arc -= 2; 885*37da2899SCharles.Forsyth } 886*37da2899SCharles.Forsyth } 887*37da2899SCharles.Forsyth return; 888*37da2899SCharles.Forsyth } 889*37da2899SCharles.Forsyth 890*37da2899SCharles.Forsyth 891*37da2899SCharles.Forsyth static void gray_split_cubic(FT_Vector * base)892*37da2899SCharles.Forsyth gray_split_cubic( FT_Vector* base ) 893*37da2899SCharles.Forsyth { 894*37da2899SCharles.Forsyth TPos a, b, c, d; 895*37da2899SCharles.Forsyth 896*37da2899SCharles.Forsyth 897*37da2899SCharles.Forsyth base[6].x = base[3].x; 898*37da2899SCharles.Forsyth c = base[1].x; 899*37da2899SCharles.Forsyth d = base[2].x; 900*37da2899SCharles.Forsyth base[1].x = a = ( base[0].x + c ) / 2; 901*37da2899SCharles.Forsyth base[5].x = b = ( base[3].x + d ) / 2; 902*37da2899SCharles.Forsyth c = ( c + d ) / 2; 903*37da2899SCharles.Forsyth base[2].x = a = ( a + c ) / 2; 904*37da2899SCharles.Forsyth base[4].x = b = ( b + c ) / 2; 905*37da2899SCharles.Forsyth base[3].x = ( a + b ) / 2; 906*37da2899SCharles.Forsyth 907*37da2899SCharles.Forsyth base[6].y = base[3].y; 908*37da2899SCharles.Forsyth c = base[1].y; 909*37da2899SCharles.Forsyth d = base[2].y; 910*37da2899SCharles.Forsyth base[1].y = a = ( base[0].y + c ) / 2; 911*37da2899SCharles.Forsyth base[5].y = b = ( base[3].y + d ) / 2; 912*37da2899SCharles.Forsyth c = ( c + d ) / 2; 913*37da2899SCharles.Forsyth base[2].y = a = ( a + c ) / 2; 914*37da2899SCharles.Forsyth base[4].y = b = ( b + c ) / 2; 915*37da2899SCharles.Forsyth base[3].y = ( a + b ) / 2; 916*37da2899SCharles.Forsyth } 917*37da2899SCharles.Forsyth 918*37da2899SCharles.Forsyth 919*37da2899SCharles.Forsyth static void gray_render_cubic(RAS_ARG_ FT_Vector * control1,FT_Vector * control2,FT_Vector * to)920*37da2899SCharles.Forsyth gray_render_cubic( RAS_ARG_ FT_Vector* control1, 921*37da2899SCharles.Forsyth FT_Vector* control2, 922*37da2899SCharles.Forsyth FT_Vector* to ) 923*37da2899SCharles.Forsyth { 924*37da2899SCharles.Forsyth TPos dx, dy, da, db; 925*37da2899SCharles.Forsyth int top, level; 926*37da2899SCharles.Forsyth int* levels; 927*37da2899SCharles.Forsyth FT_Vector* arc; 928*37da2899SCharles.Forsyth 929*37da2899SCharles.Forsyth 930*37da2899SCharles.Forsyth dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 ); 931*37da2899SCharles.Forsyth if ( dx < 0 ) 932*37da2899SCharles.Forsyth dx = -dx; 933*37da2899SCharles.Forsyth dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 ); 934*37da2899SCharles.Forsyth if ( dy < 0 ) 935*37da2899SCharles.Forsyth dy = -dy; 936*37da2899SCharles.Forsyth if ( dx < dy ) 937*37da2899SCharles.Forsyth dx = dy; 938*37da2899SCharles.Forsyth da = dx; 939*37da2899SCharles.Forsyth 940*37da2899SCharles.Forsyth dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x ); 941*37da2899SCharles.Forsyth if ( dx < 0 ) 942*37da2899SCharles.Forsyth dx = -dx; 943*37da2899SCharles.Forsyth dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y ); 944*37da2899SCharles.Forsyth if ( dy < 0 ) 945*37da2899SCharles.Forsyth dy = -dy; 946*37da2899SCharles.Forsyth if ( dx < dy ) 947*37da2899SCharles.Forsyth dx = dy; 948*37da2899SCharles.Forsyth db = dx; 949*37da2899SCharles.Forsyth 950*37da2899SCharles.Forsyth level = 1; 951*37da2899SCharles.Forsyth da = da / ras.cubic_level; 952*37da2899SCharles.Forsyth db = db / ras.conic_level; 953*37da2899SCharles.Forsyth while ( da > 0 || db > 0 ) 954*37da2899SCharles.Forsyth { 955*37da2899SCharles.Forsyth da >>= 2; 956*37da2899SCharles.Forsyth db >>= 3; 957*37da2899SCharles.Forsyth level++; 958*37da2899SCharles.Forsyth } 959*37da2899SCharles.Forsyth 960*37da2899SCharles.Forsyth if ( level <= 1 ) 961*37da2899SCharles.Forsyth { 962*37da2899SCharles.Forsyth TPos to_x, to_y, mid_x, mid_y; 963*37da2899SCharles.Forsyth 964*37da2899SCharles.Forsyth 965*37da2899SCharles.Forsyth to_x = UPSCALE( to->x ); 966*37da2899SCharles.Forsyth to_y = UPSCALE( to->y ); 967*37da2899SCharles.Forsyth mid_x = ( ras.x + to_x + 968*37da2899SCharles.Forsyth 3 * UPSCALE( control1->x + control2->x ) ) / 8; 969*37da2899SCharles.Forsyth mid_y = ( ras.y + to_y + 970*37da2899SCharles.Forsyth 3 * UPSCALE( control1->y + control2->y ) ) / 8; 971*37da2899SCharles.Forsyth 972*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ mid_x, mid_y ); 973*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ to_x, to_y ); 974*37da2899SCharles.Forsyth return; 975*37da2899SCharles.Forsyth } 976*37da2899SCharles.Forsyth 977*37da2899SCharles.Forsyth arc = ras.bez_stack; 978*37da2899SCharles.Forsyth arc[0].x = UPSCALE( to->x ); 979*37da2899SCharles.Forsyth arc[0].y = UPSCALE( to->y ); 980*37da2899SCharles.Forsyth arc[1].x = UPSCALE( control2->x ); 981*37da2899SCharles.Forsyth arc[1].y = UPSCALE( control2->y ); 982*37da2899SCharles.Forsyth arc[2].x = UPSCALE( control1->x ); 983*37da2899SCharles.Forsyth arc[2].y = UPSCALE( control1->y ); 984*37da2899SCharles.Forsyth arc[3].x = ras.x; 985*37da2899SCharles.Forsyth arc[3].y = ras.y; 986*37da2899SCharles.Forsyth 987*37da2899SCharles.Forsyth levels = ras.lev_stack; 988*37da2899SCharles.Forsyth top = 0; 989*37da2899SCharles.Forsyth levels[0] = level; 990*37da2899SCharles.Forsyth 991*37da2899SCharles.Forsyth while ( top >= 0 ) 992*37da2899SCharles.Forsyth { 993*37da2899SCharles.Forsyth level = levels[top]; 994*37da2899SCharles.Forsyth if ( level > 1 ) 995*37da2899SCharles.Forsyth { 996*37da2899SCharles.Forsyth /* check that the arc crosses the current band */ 997*37da2899SCharles.Forsyth TPos min, max, y; 998*37da2899SCharles.Forsyth 999*37da2899SCharles.Forsyth 1000*37da2899SCharles.Forsyth min = max = arc[0].y; 1001*37da2899SCharles.Forsyth y = arc[1].y; 1002*37da2899SCharles.Forsyth if ( y < min ) min = y; 1003*37da2899SCharles.Forsyth if ( y > max ) max = y; 1004*37da2899SCharles.Forsyth y = arc[2].y; 1005*37da2899SCharles.Forsyth if ( y < min ) min = y; 1006*37da2899SCharles.Forsyth if ( y > max ) max = y; 1007*37da2899SCharles.Forsyth y = arc[3].y; 1008*37da2899SCharles.Forsyth if ( y < min ) min = y; 1009*37da2899SCharles.Forsyth if ( y > max ) max = y; 1010*37da2899SCharles.Forsyth if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) 1011*37da2899SCharles.Forsyth goto Draw; 1012*37da2899SCharles.Forsyth gray_split_cubic( arc ); 1013*37da2899SCharles.Forsyth arc += 3; 1014*37da2899SCharles.Forsyth top ++; 1015*37da2899SCharles.Forsyth levels[top] = levels[top - 1] = level - 1; 1016*37da2899SCharles.Forsyth continue; 1017*37da2899SCharles.Forsyth } 1018*37da2899SCharles.Forsyth 1019*37da2899SCharles.Forsyth Draw: 1020*37da2899SCharles.Forsyth { 1021*37da2899SCharles.Forsyth TPos to_x, to_y, mid_x, mid_y; 1022*37da2899SCharles.Forsyth 1023*37da2899SCharles.Forsyth 1024*37da2899SCharles.Forsyth to_x = arc[0].x; 1025*37da2899SCharles.Forsyth to_y = arc[0].y; 1026*37da2899SCharles.Forsyth mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8; 1027*37da2899SCharles.Forsyth mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8; 1028*37da2899SCharles.Forsyth 1029*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ mid_x, mid_y ); 1030*37da2899SCharles.Forsyth gray_render_line( RAS_VAR_ to_x, to_y ); 1031*37da2899SCharles.Forsyth top --; 1032*37da2899SCharles.Forsyth arc -= 3; 1033*37da2899SCharles.Forsyth } 1034*37da2899SCharles.Forsyth } 1035*37da2899SCharles.Forsyth return; 1036*37da2899SCharles.Forsyth } 1037*37da2899SCharles.Forsyth 1038*37da2899SCharles.Forsyth 1039*37da2899SCharles.Forsyth /* a macro comparing two cell pointers. Returns true if a <= b. */ 1040*37da2899SCharles.Forsyth #if 1 1041*37da2899SCharles.Forsyth 1042*37da2899SCharles.Forsyth #define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x ) 1043*37da2899SCharles.Forsyth #define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) ) 1044*37da2899SCharles.Forsyth 1045*37da2899SCharles.Forsyth #else /* 1 */ 1046*37da2899SCharles.Forsyth 1047*37da2899SCharles.Forsyth #define LESS_THAN( a, b ) ( (a)->y < (b)->y || \ 1048*37da2899SCharles.Forsyth ( (a)->y == (b)->y && (a)->x < (b)->x ) ) 1049*37da2899SCharles.Forsyth 1050*37da2899SCharles.Forsyth #endif /* 1 */ 1051*37da2899SCharles.Forsyth 1052*37da2899SCharles.Forsyth #define SWAP_CELLS( a, b, temp ) do \ 1053*37da2899SCharles.Forsyth { \ 1054*37da2899SCharles.Forsyth temp = *(a); \ 1055*37da2899SCharles.Forsyth *(a) = *(b); \ 1056*37da2899SCharles.Forsyth *(b) = temp; \ 1057*37da2899SCharles.Forsyth } while ( 0 ) 1058*37da2899SCharles.Forsyth #define DEBUG_SORT 1059*37da2899SCharles.Forsyth #define QUICK_SORT 1060*37da2899SCharles.Forsyth 1061*37da2899SCharles.Forsyth #ifdef SHELL_SORT 1062*37da2899SCharles.Forsyth 1063*37da2899SCharles.Forsyth /* a simple shell sort algorithm that works directly on our */ 1064*37da2899SCharles.Forsyth /* cells table */ 1065*37da2899SCharles.Forsyth static void gray_shell_sort(PCell cells,int count)1066*37da2899SCharles.Forsyth gray_shell_sort ( PCell cells, 1067*37da2899SCharles.Forsyth int count ) 1068*37da2899SCharles.Forsyth { 1069*37da2899SCharles.Forsyth PCell i, j, limit = cells + count; 1070*37da2899SCharles.Forsyth TCell temp; 1071*37da2899SCharles.Forsyth int gap; 1072*37da2899SCharles.Forsyth 1073*37da2899SCharles.Forsyth 1074*37da2899SCharles.Forsyth /* compute initial gap */ 1075*37da2899SCharles.Forsyth for ( gap = 0; ++gap < count; gap *= 3 ) 1076*37da2899SCharles.Forsyth ; 1077*37da2899SCharles.Forsyth 1078*37da2899SCharles.Forsyth while ( gap /= 3 ) 1079*37da2899SCharles.Forsyth { 1080*37da2899SCharles.Forsyth for ( i = cells + gap; i < limit; i++ ) 1081*37da2899SCharles.Forsyth { 1082*37da2899SCharles.Forsyth for ( j = i - gap; ; j -= gap ) 1083*37da2899SCharles.Forsyth { 1084*37da2899SCharles.Forsyth PCell k = j + gap; 1085*37da2899SCharles.Forsyth 1086*37da2899SCharles.Forsyth 1087*37da2899SCharles.Forsyth if ( LESS_THAN( j, k ) ) 1088*37da2899SCharles.Forsyth break; 1089*37da2899SCharles.Forsyth 1090*37da2899SCharles.Forsyth SWAP_CELLS( j, k, temp ); 1091*37da2899SCharles.Forsyth 1092*37da2899SCharles.Forsyth if ( j < cells + gap ) 1093*37da2899SCharles.Forsyth break; 1094*37da2899SCharles.Forsyth } 1095*37da2899SCharles.Forsyth } 1096*37da2899SCharles.Forsyth } 1097*37da2899SCharles.Forsyth } 1098*37da2899SCharles.Forsyth 1099*37da2899SCharles.Forsyth #endif /* SHELL_SORT */ 1100*37da2899SCharles.Forsyth 1101*37da2899SCharles.Forsyth 1102*37da2899SCharles.Forsyth #ifdef QUICK_SORT 1103*37da2899SCharles.Forsyth 1104*37da2899SCharles.Forsyth /* This is a non-recursive quicksort that directly process our cells */ 1105*37da2899SCharles.Forsyth /* array. It should be faster than calling the stdlib qsort(), and we */ 1106*37da2899SCharles.Forsyth /* can even tailor our insertion threshold... */ 1107*37da2899SCharles.Forsyth 1108*37da2899SCharles.Forsyth #define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */ 1109*37da2899SCharles.Forsyth /* through a normal insertion sort */ 1110*37da2899SCharles.Forsyth 1111*37da2899SCharles.Forsyth static void gray_quick_sort(PCell cells,int count)1112*37da2899SCharles.Forsyth gray_quick_sort( PCell cells, 1113*37da2899SCharles.Forsyth int count ) 1114*37da2899SCharles.Forsyth { 1115*37da2899SCharles.Forsyth PCell stack[40]; /* should be enough ;-) */ 1116*37da2899SCharles.Forsyth PCell* top; /* top of stack */ 1117*37da2899SCharles.Forsyth PCell base, limit; 1118*37da2899SCharles.Forsyth TCell temp; 1119*37da2899SCharles.Forsyth 1120*37da2899SCharles.Forsyth 1121*37da2899SCharles.Forsyth limit = cells + count; 1122*37da2899SCharles.Forsyth base = cells; 1123*37da2899SCharles.Forsyth top = stack; 1124*37da2899SCharles.Forsyth 1125*37da2899SCharles.Forsyth for (;;) 1126*37da2899SCharles.Forsyth { 1127*37da2899SCharles.Forsyth int len = (int)( limit - base ); 1128*37da2899SCharles.Forsyth PCell i, j, pivot; 1129*37da2899SCharles.Forsyth 1130*37da2899SCharles.Forsyth 1131*37da2899SCharles.Forsyth if ( len > QSORT_THRESHOLD ) 1132*37da2899SCharles.Forsyth { 1133*37da2899SCharles.Forsyth /* we use base + len/2 as the pivot */ 1134*37da2899SCharles.Forsyth pivot = base + len / 2; 1135*37da2899SCharles.Forsyth SWAP_CELLS( base, pivot, temp ); 1136*37da2899SCharles.Forsyth 1137*37da2899SCharles.Forsyth i = base + 1; 1138*37da2899SCharles.Forsyth j = limit - 1; 1139*37da2899SCharles.Forsyth 1140*37da2899SCharles.Forsyth /* now ensure that *i <= *base <= *j */ 1141*37da2899SCharles.Forsyth if ( LESS_THAN( j, i ) ) 1142*37da2899SCharles.Forsyth SWAP_CELLS( i, j, temp ); 1143*37da2899SCharles.Forsyth 1144*37da2899SCharles.Forsyth if ( LESS_THAN( base, i ) ) 1145*37da2899SCharles.Forsyth SWAP_CELLS( base, i, temp ); 1146*37da2899SCharles.Forsyth 1147*37da2899SCharles.Forsyth if ( LESS_THAN( j, base ) ) 1148*37da2899SCharles.Forsyth SWAP_CELLS( base, j, temp ); 1149*37da2899SCharles.Forsyth 1150*37da2899SCharles.Forsyth for (;;) 1151*37da2899SCharles.Forsyth { 1152*37da2899SCharles.Forsyth do i++; while ( LESS_THAN( i, base ) ); 1153*37da2899SCharles.Forsyth do j--; while ( LESS_THAN( base, j ) ); 1154*37da2899SCharles.Forsyth 1155*37da2899SCharles.Forsyth if ( i > j ) 1156*37da2899SCharles.Forsyth break; 1157*37da2899SCharles.Forsyth 1158*37da2899SCharles.Forsyth SWAP_CELLS( i, j, temp ); 1159*37da2899SCharles.Forsyth } 1160*37da2899SCharles.Forsyth 1161*37da2899SCharles.Forsyth SWAP_CELLS( base, j, temp ); 1162*37da2899SCharles.Forsyth 1163*37da2899SCharles.Forsyth /* now, push the largest sub-array */ 1164*37da2899SCharles.Forsyth if ( j - base > limit - i ) 1165*37da2899SCharles.Forsyth { 1166*37da2899SCharles.Forsyth top[0] = base; 1167*37da2899SCharles.Forsyth top[1] = j; 1168*37da2899SCharles.Forsyth base = i; 1169*37da2899SCharles.Forsyth } 1170*37da2899SCharles.Forsyth else 1171*37da2899SCharles.Forsyth { 1172*37da2899SCharles.Forsyth top[0] = i; 1173*37da2899SCharles.Forsyth top[1] = limit; 1174*37da2899SCharles.Forsyth limit = j; 1175*37da2899SCharles.Forsyth } 1176*37da2899SCharles.Forsyth top += 2; 1177*37da2899SCharles.Forsyth } 1178*37da2899SCharles.Forsyth else 1179*37da2899SCharles.Forsyth { 1180*37da2899SCharles.Forsyth /* the sub-array is small, perform insertion sort */ 1181*37da2899SCharles.Forsyth j = base; 1182*37da2899SCharles.Forsyth i = j + 1; 1183*37da2899SCharles.Forsyth 1184*37da2899SCharles.Forsyth for ( ; i < limit; j = i, i++ ) 1185*37da2899SCharles.Forsyth { 1186*37da2899SCharles.Forsyth for ( ; LESS_THAN( j + 1, j ); j-- ) 1187*37da2899SCharles.Forsyth { 1188*37da2899SCharles.Forsyth SWAP_CELLS( j + 1, j, temp ); 1189*37da2899SCharles.Forsyth if ( j == base ) 1190*37da2899SCharles.Forsyth break; 1191*37da2899SCharles.Forsyth } 1192*37da2899SCharles.Forsyth } 1193*37da2899SCharles.Forsyth if ( top > stack ) 1194*37da2899SCharles.Forsyth { 1195*37da2899SCharles.Forsyth top -= 2; 1196*37da2899SCharles.Forsyth base = top[0]; 1197*37da2899SCharles.Forsyth limit = top[1]; 1198*37da2899SCharles.Forsyth } 1199*37da2899SCharles.Forsyth else 1200*37da2899SCharles.Forsyth break; 1201*37da2899SCharles.Forsyth } 1202*37da2899SCharles.Forsyth } 1203*37da2899SCharles.Forsyth } 1204*37da2899SCharles.Forsyth 1205*37da2899SCharles.Forsyth #endif /* QUICK_SORT */ 1206*37da2899SCharles.Forsyth 1207*37da2899SCharles.Forsyth 1208*37da2899SCharles.Forsyth #ifdef DEBUG_GRAYS 1209*37da2899SCharles.Forsyth #ifdef DEBUG_SORT 1210*37da2899SCharles.Forsyth 1211*37da2899SCharles.Forsyth static int gray_check_sort(PCell cells,int count)1212*37da2899SCharles.Forsyth gray_check_sort( PCell cells, 1213*37da2899SCharles.Forsyth int count ) 1214*37da2899SCharles.Forsyth { 1215*37da2899SCharles.Forsyth PCell p, q; 1216*37da2899SCharles.Forsyth 1217*37da2899SCharles.Forsyth 1218*37da2899SCharles.Forsyth for ( p = cells + count - 2; p >= cells; p-- ) 1219*37da2899SCharles.Forsyth { 1220*37da2899SCharles.Forsyth q = p + 1; 1221*37da2899SCharles.Forsyth if ( !LESS_THAN( p, q ) ) 1222*37da2899SCharles.Forsyth return 0; 1223*37da2899SCharles.Forsyth } 1224*37da2899SCharles.Forsyth return 1; 1225*37da2899SCharles.Forsyth } 1226*37da2899SCharles.Forsyth 1227*37da2899SCharles.Forsyth #endif /* DEBUG_SORT */ 1228*37da2899SCharles.Forsyth #endif /* DEBUG_GRAYS */ 1229*37da2899SCharles.Forsyth 1230*37da2899SCharles.Forsyth 1231*37da2899SCharles.Forsyth static int gray_move_to(FT_Vector * to,FT_Raster raster)1232*37da2899SCharles.Forsyth gray_move_to( FT_Vector* to, 1233*37da2899SCharles.Forsyth FT_Raster raster ) 1234*37da2899SCharles.Forsyth { 1235*37da2899SCharles.Forsyth TPos x, y; 1236*37da2899SCharles.Forsyth 1237*37da2899SCharles.Forsyth 1238*37da2899SCharles.Forsyth /* record current cell, if any */ 1239*37da2899SCharles.Forsyth gray_record_cell( (PRaster)raster ); 1240*37da2899SCharles.Forsyth 1241*37da2899SCharles.Forsyth /* start to a new position */ 1242*37da2899SCharles.Forsyth x = UPSCALE( to->x ); 1243*37da2899SCharles.Forsyth y = UPSCALE( to->y ); 1244*37da2899SCharles.Forsyth 1245*37da2899SCharles.Forsyth gray_start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) ); 1246*37da2899SCharles.Forsyth 1247*37da2899SCharles.Forsyth ((PRaster)raster)->x = x; 1248*37da2899SCharles.Forsyth ((PRaster)raster)->y = y; 1249*37da2899SCharles.Forsyth return 0; 1250*37da2899SCharles.Forsyth } 1251*37da2899SCharles.Forsyth 1252*37da2899SCharles.Forsyth 1253*37da2899SCharles.Forsyth static int gray_line_to(FT_Vector * to,FT_Raster raster)1254*37da2899SCharles.Forsyth gray_line_to( FT_Vector* to, 1255*37da2899SCharles.Forsyth FT_Raster raster ) 1256*37da2899SCharles.Forsyth { 1257*37da2899SCharles.Forsyth gray_render_line( (PRaster)raster, 1258*37da2899SCharles.Forsyth UPSCALE( to->x ), UPSCALE( to->y ) ); 1259*37da2899SCharles.Forsyth return 0; 1260*37da2899SCharles.Forsyth } 1261*37da2899SCharles.Forsyth 1262*37da2899SCharles.Forsyth 1263*37da2899SCharles.Forsyth static int gray_conic_to(FT_Vector * control,FT_Vector * to,FT_Raster raster)1264*37da2899SCharles.Forsyth gray_conic_to( FT_Vector* control, 1265*37da2899SCharles.Forsyth FT_Vector* to, 1266*37da2899SCharles.Forsyth FT_Raster raster ) 1267*37da2899SCharles.Forsyth { 1268*37da2899SCharles.Forsyth gray_render_conic( (PRaster)raster, control, to ); 1269*37da2899SCharles.Forsyth return 0; 1270*37da2899SCharles.Forsyth } 1271*37da2899SCharles.Forsyth 1272*37da2899SCharles.Forsyth 1273*37da2899SCharles.Forsyth static int gray_cubic_to(FT_Vector * control1,FT_Vector * control2,FT_Vector * to,FT_Raster raster)1274*37da2899SCharles.Forsyth gray_cubic_to( FT_Vector* control1, 1275*37da2899SCharles.Forsyth FT_Vector* control2, 1276*37da2899SCharles.Forsyth FT_Vector* to, 1277*37da2899SCharles.Forsyth FT_Raster raster ) 1278*37da2899SCharles.Forsyth { 1279*37da2899SCharles.Forsyth gray_render_cubic( (PRaster)raster, control1, control2, to ); 1280*37da2899SCharles.Forsyth return 0; 1281*37da2899SCharles.Forsyth } 1282*37da2899SCharles.Forsyth 1283*37da2899SCharles.Forsyth 1284*37da2899SCharles.Forsyth static void gray_render_span(int y,int count,FT_Span * spans,PRaster raster)1285*37da2899SCharles.Forsyth gray_render_span( int y, 1286*37da2899SCharles.Forsyth int count, 1287*37da2899SCharles.Forsyth FT_Span* spans, 1288*37da2899SCharles.Forsyth PRaster raster ) 1289*37da2899SCharles.Forsyth { 1290*37da2899SCharles.Forsyth unsigned char* p; 1291*37da2899SCharles.Forsyth FT_Bitmap* map = &raster->target; 1292*37da2899SCharles.Forsyth 1293*37da2899SCharles.Forsyth 1294*37da2899SCharles.Forsyth /* first of all, compute the scanline offset */ 1295*37da2899SCharles.Forsyth p = (unsigned char*)map->buffer - y * map->pitch; 1296*37da2899SCharles.Forsyth if ( map->pitch >= 0 ) 1297*37da2899SCharles.Forsyth p += ( map->rows - 1 ) * map->pitch; 1298*37da2899SCharles.Forsyth 1299*37da2899SCharles.Forsyth for ( ; count > 0; count--, spans++ ) 1300*37da2899SCharles.Forsyth { 1301*37da2899SCharles.Forsyth unsigned char coverage = spans->coverage; 1302*37da2899SCharles.Forsyth 1303*37da2899SCharles.Forsyth 1304*37da2899SCharles.Forsyth #ifdef GRAYS_USE_GAMMA 1305*37da2899SCharles.Forsyth coverage = raster->gamma[coverage]; 1306*37da2899SCharles.Forsyth #endif 1307*37da2899SCharles.Forsyth 1308*37da2899SCharles.Forsyth if ( coverage ) 1309*37da2899SCharles.Forsyth #if 1 1310*37da2899SCharles.Forsyth FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len ); 1311*37da2899SCharles.Forsyth #else /* 1 */ 1312*37da2899SCharles.Forsyth { 1313*37da2899SCharles.Forsyth q = p + spans->x; 1314*37da2899SCharles.Forsyth limit = q + spans->len; 1315*37da2899SCharles.Forsyth for ( ; q < limit; q++ ) 1316*37da2899SCharles.Forsyth q[0] = (unsigned char)coverage; 1317*37da2899SCharles.Forsyth } 1318*37da2899SCharles.Forsyth #endif /* 1 */ 1319*37da2899SCharles.Forsyth } 1320*37da2899SCharles.Forsyth } 1321*37da2899SCharles.Forsyth 1322*37da2899SCharles.Forsyth 1323*37da2899SCharles.Forsyth #ifdef DEBUG_GRAYS 1324*37da2899SCharles.Forsyth 1325*37da2899SCharles.Forsyth #include <stdio.h> 1326*37da2899SCharles.Forsyth 1327*37da2899SCharles.Forsyth static void gray_dump_cells(RAS_ARG)1328*37da2899SCharles.Forsyth gray_dump_cells( RAS_ARG ) 1329*37da2899SCharles.Forsyth { 1330*37da2899SCharles.Forsyth PCell cell, limit; 1331*37da2899SCharles.Forsyth int y = -1; 1332*37da2899SCharles.Forsyth 1333*37da2899SCharles.Forsyth 1334*37da2899SCharles.Forsyth cell = ras.cells; 1335*37da2899SCharles.Forsyth limit = cell + ras.num_cells; 1336*37da2899SCharles.Forsyth 1337*37da2899SCharles.Forsyth for ( ; cell < limit; cell++ ) 1338*37da2899SCharles.Forsyth { 1339*37da2899SCharles.Forsyth if ( cell->y != y ) 1340*37da2899SCharles.Forsyth { 1341*37da2899SCharles.Forsyth fprintf( stderr, "\n%2d: ", cell->y ); 1342*37da2899SCharles.Forsyth y = cell->y; 1343*37da2899SCharles.Forsyth } 1344*37da2899SCharles.Forsyth fprintf( stderr, "[%d %d %d]", 1345*37da2899SCharles.Forsyth cell->x, cell->area, cell->cover ); 1346*37da2899SCharles.Forsyth } 1347*37da2899SCharles.Forsyth fprintf(stderr, "\n" ); 1348*37da2899SCharles.Forsyth } 1349*37da2899SCharles.Forsyth 1350*37da2899SCharles.Forsyth #endif /* DEBUG_GRAYS */ 1351*37da2899SCharles.Forsyth 1352*37da2899SCharles.Forsyth 1353*37da2899SCharles.Forsyth static void gray_hline(RAS_ARG_ TCoord x,TCoord y,TPos area,int acount)1354*37da2899SCharles.Forsyth gray_hline( RAS_ARG_ TCoord x, 1355*37da2899SCharles.Forsyth TCoord y, 1356*37da2899SCharles.Forsyth TPos area, 1357*37da2899SCharles.Forsyth int acount ) 1358*37da2899SCharles.Forsyth { 1359*37da2899SCharles.Forsyth FT_Span* span; 1360*37da2899SCharles.Forsyth int count; 1361*37da2899SCharles.Forsyth int coverage; 1362*37da2899SCharles.Forsyth 1363*37da2899SCharles.Forsyth 1364*37da2899SCharles.Forsyth /* compute the coverage line's coverage, depending on the */ 1365*37da2899SCharles.Forsyth /* outline fill rule */ 1366*37da2899SCharles.Forsyth /* */ 1367*37da2899SCharles.Forsyth /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ 1368*37da2899SCharles.Forsyth /* */ 1369*37da2899SCharles.Forsyth coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); 1370*37da2899SCharles.Forsyth /* use range 0..256 */ 1371*37da2899SCharles.Forsyth if ( coverage < 0 ) 1372*37da2899SCharles.Forsyth coverage = -coverage; 1373*37da2899SCharles.Forsyth 1374*37da2899SCharles.Forsyth if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) 1375*37da2899SCharles.Forsyth { 1376*37da2899SCharles.Forsyth coverage &= 511; 1377*37da2899SCharles.Forsyth 1378*37da2899SCharles.Forsyth if ( coverage > 256 ) 1379*37da2899SCharles.Forsyth coverage = 512 - coverage; 1380*37da2899SCharles.Forsyth else if ( coverage == 256 ) 1381*37da2899SCharles.Forsyth coverage = 255; 1382*37da2899SCharles.Forsyth } 1383*37da2899SCharles.Forsyth else 1384*37da2899SCharles.Forsyth { 1385*37da2899SCharles.Forsyth /* normal non-zero winding rule */ 1386*37da2899SCharles.Forsyth if ( coverage >= 256 ) 1387*37da2899SCharles.Forsyth coverage = 255; 1388*37da2899SCharles.Forsyth } 1389*37da2899SCharles.Forsyth 1390*37da2899SCharles.Forsyth y += (TCoord)ras.min_ey; 1391*37da2899SCharles.Forsyth x += (TCoord)ras.min_ex; 1392*37da2899SCharles.Forsyth 1393*37da2899SCharles.Forsyth if ( coverage ) 1394*37da2899SCharles.Forsyth { 1395*37da2899SCharles.Forsyth /* see if we can add this span to the current list */ 1396*37da2899SCharles.Forsyth count = ras.num_gray_spans; 1397*37da2899SCharles.Forsyth span = ras.gray_spans + count - 1; 1398*37da2899SCharles.Forsyth if ( count > 0 && 1399*37da2899SCharles.Forsyth ras.span_y == y && 1400*37da2899SCharles.Forsyth (int)span->x + span->len == (int)x && 1401*37da2899SCharles.Forsyth span->coverage == coverage ) 1402*37da2899SCharles.Forsyth { 1403*37da2899SCharles.Forsyth span->len = (unsigned short)( span->len + acount ); 1404*37da2899SCharles.Forsyth return; 1405*37da2899SCharles.Forsyth } 1406*37da2899SCharles.Forsyth 1407*37da2899SCharles.Forsyth if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) 1408*37da2899SCharles.Forsyth { 1409*37da2899SCharles.Forsyth if ( ras.render_span && count > 0 ) 1410*37da2899SCharles.Forsyth ras.render_span( ras.span_y, count, ras.gray_spans, 1411*37da2899SCharles.Forsyth ras.render_span_data ); 1412*37da2899SCharles.Forsyth /* ras.render_span( span->y, ras.gray_spans, count ); */ 1413*37da2899SCharles.Forsyth 1414*37da2899SCharles.Forsyth #ifdef DEBUG_GRAYS 1415*37da2899SCharles.Forsyth 1416*37da2899SCharles.Forsyth if ( ras.span_y >= 0 ) 1417*37da2899SCharles.Forsyth { 1418*37da2899SCharles.Forsyth int n; 1419*37da2899SCharles.Forsyth 1420*37da2899SCharles.Forsyth 1421*37da2899SCharles.Forsyth fprintf( stderr, "y=%3d ", ras.span_y ); 1422*37da2899SCharles.Forsyth span = ras.gray_spans; 1423*37da2899SCharles.Forsyth for ( n = 0; n < count; n++, span++ ) 1424*37da2899SCharles.Forsyth fprintf( stderr, "[%d..%d]:%02x ", 1425*37da2899SCharles.Forsyth span->x, span->x + span->len - 1, span->coverage ); 1426*37da2899SCharles.Forsyth fprintf( stderr, "\n" ); 1427*37da2899SCharles.Forsyth } 1428*37da2899SCharles.Forsyth 1429*37da2899SCharles.Forsyth #endif /* DEBUG_GRAYS */ 1430*37da2899SCharles.Forsyth 1431*37da2899SCharles.Forsyth ras.num_gray_spans = 0; 1432*37da2899SCharles.Forsyth ras.span_y = y; 1433*37da2899SCharles.Forsyth 1434*37da2899SCharles.Forsyth count = 0; 1435*37da2899SCharles.Forsyth span = ras.gray_spans; 1436*37da2899SCharles.Forsyth } 1437*37da2899SCharles.Forsyth else 1438*37da2899SCharles.Forsyth span++; 1439*37da2899SCharles.Forsyth 1440*37da2899SCharles.Forsyth /* add a gray span to the current list */ 1441*37da2899SCharles.Forsyth span->x = (short)x; 1442*37da2899SCharles.Forsyth span->len = (unsigned short)acount; 1443*37da2899SCharles.Forsyth span->coverage = (unsigned char)coverage; 1444*37da2899SCharles.Forsyth ras.num_gray_spans++; 1445*37da2899SCharles.Forsyth } 1446*37da2899SCharles.Forsyth } 1447*37da2899SCharles.Forsyth 1448*37da2899SCharles.Forsyth 1449*37da2899SCharles.Forsyth static void gray_sweep(RAS_ARG_ FT_Bitmap * target)1450*37da2899SCharles.Forsyth gray_sweep( RAS_ARG_ FT_Bitmap* target ) 1451*37da2899SCharles.Forsyth { 1452*37da2899SCharles.Forsyth TCoord x, y, cover; 1453*37da2899SCharles.Forsyth TArea area; 1454*37da2899SCharles.Forsyth PCell start, cur, limit; 1455*37da2899SCharles.Forsyth 1456*37da2899SCharles.Forsyth FT_UNUSED( target ); 1457*37da2899SCharles.Forsyth 1458*37da2899SCharles.Forsyth 1459*37da2899SCharles.Forsyth if ( ras.num_cells == 0 ) 1460*37da2899SCharles.Forsyth return; 1461*37da2899SCharles.Forsyth 1462*37da2899SCharles.Forsyth cur = ras.cells; 1463*37da2899SCharles.Forsyth limit = cur + ras.num_cells; 1464*37da2899SCharles.Forsyth 1465*37da2899SCharles.Forsyth cover = 0; 1466*37da2899SCharles.Forsyth ras.span_y = -1; 1467*37da2899SCharles.Forsyth ras.num_gray_spans = 0; 1468*37da2899SCharles.Forsyth 1469*37da2899SCharles.Forsyth for (;;) 1470*37da2899SCharles.Forsyth { 1471*37da2899SCharles.Forsyth start = cur; 1472*37da2899SCharles.Forsyth y = start->y; 1473*37da2899SCharles.Forsyth x = start->x; 1474*37da2899SCharles.Forsyth 1475*37da2899SCharles.Forsyth area = start->area; 1476*37da2899SCharles.Forsyth cover += start->cover; 1477*37da2899SCharles.Forsyth 1478*37da2899SCharles.Forsyth /* accumulate all start cells */ 1479*37da2899SCharles.Forsyth for (;;) 1480*37da2899SCharles.Forsyth { 1481*37da2899SCharles.Forsyth ++cur; 1482*37da2899SCharles.Forsyth if ( cur >= limit || cur->y != start->y || cur->x != start->x ) 1483*37da2899SCharles.Forsyth break; 1484*37da2899SCharles.Forsyth 1485*37da2899SCharles.Forsyth area += cur->area; 1486*37da2899SCharles.Forsyth cover += cur->cover; 1487*37da2899SCharles.Forsyth } 1488*37da2899SCharles.Forsyth 1489*37da2899SCharles.Forsyth /* if the start cell has a non-null area, we must draw an */ 1490*37da2899SCharles.Forsyth /* individual gray pixel there */ 1491*37da2899SCharles.Forsyth if ( area && x >= 0 ) 1492*37da2899SCharles.Forsyth { 1493*37da2899SCharles.Forsyth gray_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 ); 1494*37da2899SCharles.Forsyth x++; 1495*37da2899SCharles.Forsyth } 1496*37da2899SCharles.Forsyth 1497*37da2899SCharles.Forsyth if ( x < 0 ) 1498*37da2899SCharles.Forsyth x = 0; 1499*37da2899SCharles.Forsyth 1500*37da2899SCharles.Forsyth if ( cur < limit && start->y == cur->y ) 1501*37da2899SCharles.Forsyth { 1502*37da2899SCharles.Forsyth /* draw a gray span between the start cell and the current one */ 1503*37da2899SCharles.Forsyth if ( cur->x > x ) 1504*37da2899SCharles.Forsyth gray_hline( RAS_VAR_ x, y, 1505*37da2899SCharles.Forsyth cover * ( ONE_PIXEL * 2 ), cur->x - x ); 1506*37da2899SCharles.Forsyth } 1507*37da2899SCharles.Forsyth else 1508*37da2899SCharles.Forsyth { 1509*37da2899SCharles.Forsyth /* draw a gray span until the end of the clipping region */ 1510*37da2899SCharles.Forsyth if ( cover && x < ras.max_ex - ras.min_ex ) 1511*37da2899SCharles.Forsyth gray_hline( RAS_VAR_ x, y, 1512*37da2899SCharles.Forsyth cover * ( ONE_PIXEL * 2 ), 1513*37da2899SCharles.Forsyth (int)( ras.max_ex - x - ras.min_ex ) ); 1514*37da2899SCharles.Forsyth cover = 0; 1515*37da2899SCharles.Forsyth } 1516*37da2899SCharles.Forsyth 1517*37da2899SCharles.Forsyth if ( cur >= limit ) 1518*37da2899SCharles.Forsyth break; 1519*37da2899SCharles.Forsyth } 1520*37da2899SCharles.Forsyth 1521*37da2899SCharles.Forsyth if ( ras.render_span && ras.num_gray_spans > 0 ) 1522*37da2899SCharles.Forsyth ras.render_span( ras.span_y, ras.num_gray_spans, 1523*37da2899SCharles.Forsyth ras.gray_spans, ras.render_span_data ); 1524*37da2899SCharles.Forsyth 1525*37da2899SCharles.Forsyth #ifdef DEBUG_GRAYS 1526*37da2899SCharles.Forsyth 1527*37da2899SCharles.Forsyth { 1528*37da2899SCharles.Forsyth int n; 1529*37da2899SCharles.Forsyth FT_Span* span; 1530*37da2899SCharles.Forsyth 1531*37da2899SCharles.Forsyth 1532*37da2899SCharles.Forsyth fprintf( stderr, "y=%3d ", ras.span_y ); 1533*37da2899SCharles.Forsyth span = ras.gray_spans; 1534*37da2899SCharles.Forsyth for ( n = 0; n < ras.num_gray_spans; n++, span++ ) 1535*37da2899SCharles.Forsyth fprintf( stderr, "[%d..%d]:%02x ", 1536*37da2899SCharles.Forsyth span->x, span->x + span->len - 1, span->coverage ); 1537*37da2899SCharles.Forsyth fprintf( stderr, "\n" ); 1538*37da2899SCharles.Forsyth } 1539*37da2899SCharles.Forsyth 1540*37da2899SCharles.Forsyth #endif /* DEBUG_GRAYS */ 1541*37da2899SCharles.Forsyth 1542*37da2899SCharles.Forsyth } 1543*37da2899SCharles.Forsyth 1544*37da2899SCharles.Forsyth 1545*37da2899SCharles.Forsyth #ifdef _STANDALONE_ 1546*37da2899SCharles.Forsyth 1547*37da2899SCharles.Forsyth /*************************************************************************/ 1548*37da2899SCharles.Forsyth /* */ 1549*37da2899SCharles.Forsyth /* The following function should only compile in stand_alone mode, */ 1550*37da2899SCharles.Forsyth /* i.e., when building this component without the rest of FreeType. */ 1551*37da2899SCharles.Forsyth /* */ 1552*37da2899SCharles.Forsyth /*************************************************************************/ 1553*37da2899SCharles.Forsyth 1554*37da2899SCharles.Forsyth /*************************************************************************/ 1555*37da2899SCharles.Forsyth /* */ 1556*37da2899SCharles.Forsyth /* <Function> */ 1557*37da2899SCharles.Forsyth /* FT_Outline_Decompose */ 1558*37da2899SCharles.Forsyth /* */ 1559*37da2899SCharles.Forsyth /* <Description> */ 1560*37da2899SCharles.Forsyth /* Walks over an outline's structure to decompose it into individual */ 1561*37da2899SCharles.Forsyth /* segments and Bezier arcs. This function is also able to emit */ 1562*37da2899SCharles.Forsyth /* `move to' and `close to' operations to indicate the start and end */ 1563*37da2899SCharles.Forsyth /* of new contours in the outline. */ 1564*37da2899SCharles.Forsyth /* */ 1565*37da2899SCharles.Forsyth /* <Input> */ 1566*37da2899SCharles.Forsyth /* outline :: A pointer to the source target. */ 1567*37da2899SCharles.Forsyth /* */ 1568*37da2899SCharles.Forsyth /* func_interface :: A table of `emitters', i.e,. function pointers */ 1569*37da2899SCharles.Forsyth /* called during decomposition to indicate path */ 1570*37da2899SCharles.Forsyth /* operations. */ 1571*37da2899SCharles.Forsyth /* */ 1572*37da2899SCharles.Forsyth /* user :: A typeless pointer which is passed to each */ 1573*37da2899SCharles.Forsyth /* emitter during the decomposition. It can be */ 1574*37da2899SCharles.Forsyth /* used to store the state during the */ 1575*37da2899SCharles.Forsyth /* decomposition. */ 1576*37da2899SCharles.Forsyth /* */ 1577*37da2899SCharles.Forsyth /* <Return> */ 1578*37da2899SCharles.Forsyth /* Error code. 0 means sucess. */ 1579*37da2899SCharles.Forsyth /* */ 1580*37da2899SCharles.Forsyth static FT_Outline_Decompose(FT_Outline * outline,const FT_Outline_Funcs * func_interface,void * user)1581*37da2899SCharles.Forsyth int FT_Outline_Decompose( FT_Outline* outline, 1582*37da2899SCharles.Forsyth const FT_Outline_Funcs* func_interface, 1583*37da2899SCharles.Forsyth void* user ) 1584*37da2899SCharles.Forsyth { 1585*37da2899SCharles.Forsyth #undef SCALED 1586*37da2899SCharles.Forsyth #if 0 1587*37da2899SCharles.Forsyth #define SCALED( x ) ( ( (x) << shift ) - delta ) 1588*37da2899SCharles.Forsyth #else 1589*37da2899SCharles.Forsyth #define SCALED( x ) (x) 1590*37da2899SCharles.Forsyth #endif 1591*37da2899SCharles.Forsyth 1592*37da2899SCharles.Forsyth FT_Vector v_last; 1593*37da2899SCharles.Forsyth FT_Vector v_control; 1594*37da2899SCharles.Forsyth FT_Vector v_start; 1595*37da2899SCharles.Forsyth 1596*37da2899SCharles.Forsyth FT_Vector* point; 1597*37da2899SCharles.Forsyth FT_Vector* limit; 1598*37da2899SCharles.Forsyth char* tags; 1599*37da2899SCharles.Forsyth 1600*37da2899SCharles.Forsyth int n; /* index of contour in outline */ 1601*37da2899SCharles.Forsyth int first; /* index of first point in contour */ 1602*37da2899SCharles.Forsyth int error; 1603*37da2899SCharles.Forsyth char tag; /* current point's state */ 1604*37da2899SCharles.Forsyth 1605*37da2899SCharles.Forsyth #if 0 1606*37da2899SCharles.Forsyth int shift = func_interface->shift; 1607*37da2899SCharles.Forsyth TPos delta = func_interface->delta; 1608*37da2899SCharles.Forsyth #endif 1609*37da2899SCharles.Forsyth 1610*37da2899SCharles.Forsyth 1611*37da2899SCharles.Forsyth first = 0; 1612*37da2899SCharles.Forsyth 1613*37da2899SCharles.Forsyth for ( n = 0; n < outline->n_contours; n++ ) 1614*37da2899SCharles.Forsyth { 1615*37da2899SCharles.Forsyth int last; /* index of last point in contour */ 1616*37da2899SCharles.Forsyth 1617*37da2899SCharles.Forsyth 1618*37da2899SCharles.Forsyth last = outline->contours[n]; 1619*37da2899SCharles.Forsyth limit = outline->points + last; 1620*37da2899SCharles.Forsyth 1621*37da2899SCharles.Forsyth v_start = outline->points[first]; 1622*37da2899SCharles.Forsyth v_last = outline->points[last]; 1623*37da2899SCharles.Forsyth 1624*37da2899SCharles.Forsyth v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); 1625*37da2899SCharles.Forsyth v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); 1626*37da2899SCharles.Forsyth 1627*37da2899SCharles.Forsyth v_control = v_start; 1628*37da2899SCharles.Forsyth 1629*37da2899SCharles.Forsyth point = outline->points + first; 1630*37da2899SCharles.Forsyth tags = outline->tags + first; 1631*37da2899SCharles.Forsyth tag = FT_CURVE_TAG( tags[0] ); 1632*37da2899SCharles.Forsyth 1633*37da2899SCharles.Forsyth /* A contour cannot start with a cubic control point! */ 1634*37da2899SCharles.Forsyth if ( tag == FT_CURVE_TAG_CUBIC ) 1635*37da2899SCharles.Forsyth goto Invalid_Outline; 1636*37da2899SCharles.Forsyth 1637*37da2899SCharles.Forsyth /* check first point to determine origin */ 1638*37da2899SCharles.Forsyth if ( tag == FT_CURVE_TAG_CONIC ) 1639*37da2899SCharles.Forsyth { 1640*37da2899SCharles.Forsyth /* first point is conic control. Yes, this happens. */ 1641*37da2899SCharles.Forsyth if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 1642*37da2899SCharles.Forsyth { 1643*37da2899SCharles.Forsyth /* start at last point if it is on the curve */ 1644*37da2899SCharles.Forsyth v_start = v_last; 1645*37da2899SCharles.Forsyth limit--; 1646*37da2899SCharles.Forsyth } 1647*37da2899SCharles.Forsyth else 1648*37da2899SCharles.Forsyth { 1649*37da2899SCharles.Forsyth /* if both first and last points are conic, */ 1650*37da2899SCharles.Forsyth /* start at their middle and record its position */ 1651*37da2899SCharles.Forsyth /* for closure */ 1652*37da2899SCharles.Forsyth v_start.x = ( v_start.x + v_last.x ) / 2; 1653*37da2899SCharles.Forsyth v_start.y = ( v_start.y + v_last.y ) / 2; 1654*37da2899SCharles.Forsyth 1655*37da2899SCharles.Forsyth v_last = v_start; 1656*37da2899SCharles.Forsyth } 1657*37da2899SCharles.Forsyth point--; 1658*37da2899SCharles.Forsyth tags--; 1659*37da2899SCharles.Forsyth } 1660*37da2899SCharles.Forsyth 1661*37da2899SCharles.Forsyth error = func_interface->move_to( &v_start, user ); 1662*37da2899SCharles.Forsyth if ( error ) 1663*37da2899SCharles.Forsyth goto Exit; 1664*37da2899SCharles.Forsyth 1665*37da2899SCharles.Forsyth while ( point < limit ) 1666*37da2899SCharles.Forsyth { 1667*37da2899SCharles.Forsyth point++; 1668*37da2899SCharles.Forsyth tags++; 1669*37da2899SCharles.Forsyth 1670*37da2899SCharles.Forsyth tag = FT_CURVE_TAG( tags[0] ); 1671*37da2899SCharles.Forsyth switch ( tag ) 1672*37da2899SCharles.Forsyth { 1673*37da2899SCharles.Forsyth case FT_CURVE_TAG_ON: /* emit a single line_to */ 1674*37da2899SCharles.Forsyth { 1675*37da2899SCharles.Forsyth FT_Vector vec; 1676*37da2899SCharles.Forsyth 1677*37da2899SCharles.Forsyth 1678*37da2899SCharles.Forsyth vec.x = SCALED( point->x ); 1679*37da2899SCharles.Forsyth vec.y = SCALED( point->y ); 1680*37da2899SCharles.Forsyth 1681*37da2899SCharles.Forsyth error = func_interface->line_to( &vec, user ); 1682*37da2899SCharles.Forsyth if ( error ) 1683*37da2899SCharles.Forsyth goto Exit; 1684*37da2899SCharles.Forsyth continue; 1685*37da2899SCharles.Forsyth } 1686*37da2899SCharles.Forsyth 1687*37da2899SCharles.Forsyth case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 1688*37da2899SCharles.Forsyth { 1689*37da2899SCharles.Forsyth v_control.x = SCALED( point->x ); 1690*37da2899SCharles.Forsyth v_control.y = SCALED( point->y ); 1691*37da2899SCharles.Forsyth 1692*37da2899SCharles.Forsyth Do_Conic: 1693*37da2899SCharles.Forsyth if ( point < limit ) 1694*37da2899SCharles.Forsyth { 1695*37da2899SCharles.Forsyth FT_Vector vec; 1696*37da2899SCharles.Forsyth FT_Vector v_middle; 1697*37da2899SCharles.Forsyth 1698*37da2899SCharles.Forsyth 1699*37da2899SCharles.Forsyth point++; 1700*37da2899SCharles.Forsyth tags++; 1701*37da2899SCharles.Forsyth tag = FT_CURVE_TAG( tags[0] ); 1702*37da2899SCharles.Forsyth 1703*37da2899SCharles.Forsyth vec.x = SCALED( point->x ); 1704*37da2899SCharles.Forsyth vec.y = SCALED( point->y ); 1705*37da2899SCharles.Forsyth 1706*37da2899SCharles.Forsyth if ( tag == FT_CURVE_TAG_ON ) 1707*37da2899SCharles.Forsyth { 1708*37da2899SCharles.Forsyth error = func_interface->conic_to( &v_control, &vec, user ); 1709*37da2899SCharles.Forsyth if ( error ) 1710*37da2899SCharles.Forsyth goto Exit; 1711*37da2899SCharles.Forsyth continue; 1712*37da2899SCharles.Forsyth } 1713*37da2899SCharles.Forsyth 1714*37da2899SCharles.Forsyth if ( tag != FT_CURVE_TAG_CONIC ) 1715*37da2899SCharles.Forsyth goto Invalid_Outline; 1716*37da2899SCharles.Forsyth 1717*37da2899SCharles.Forsyth v_middle.x = ( v_control.x + vec.x ) / 2; 1718*37da2899SCharles.Forsyth v_middle.y = ( v_control.y + vec.y ) / 2; 1719*37da2899SCharles.Forsyth 1720*37da2899SCharles.Forsyth error = func_interface->conic_to( &v_control, &v_middle, user ); 1721*37da2899SCharles.Forsyth if ( error ) 1722*37da2899SCharles.Forsyth goto Exit; 1723*37da2899SCharles.Forsyth 1724*37da2899SCharles.Forsyth v_control = vec; 1725*37da2899SCharles.Forsyth goto Do_Conic; 1726*37da2899SCharles.Forsyth } 1727*37da2899SCharles.Forsyth 1728*37da2899SCharles.Forsyth error = func_interface->conic_to( &v_control, &v_start, user ); 1729*37da2899SCharles.Forsyth goto Close; 1730*37da2899SCharles.Forsyth } 1731*37da2899SCharles.Forsyth 1732*37da2899SCharles.Forsyth default: /* FT_CURVE_TAG_CUBIC */ 1733*37da2899SCharles.Forsyth { 1734*37da2899SCharles.Forsyth FT_Vector vec1, vec2; 1735*37da2899SCharles.Forsyth 1736*37da2899SCharles.Forsyth 1737*37da2899SCharles.Forsyth if ( point + 1 > limit || 1738*37da2899SCharles.Forsyth FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 1739*37da2899SCharles.Forsyth goto Invalid_Outline; 1740*37da2899SCharles.Forsyth 1741*37da2899SCharles.Forsyth point += 2; 1742*37da2899SCharles.Forsyth tags += 2; 1743*37da2899SCharles.Forsyth 1744*37da2899SCharles.Forsyth vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); 1745*37da2899SCharles.Forsyth vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); 1746*37da2899SCharles.Forsyth 1747*37da2899SCharles.Forsyth if ( point <= limit ) 1748*37da2899SCharles.Forsyth { 1749*37da2899SCharles.Forsyth FT_Vector vec; 1750*37da2899SCharles.Forsyth 1751*37da2899SCharles.Forsyth 1752*37da2899SCharles.Forsyth vec.x = SCALED( point->x ); 1753*37da2899SCharles.Forsyth vec.y = SCALED( point->y ); 1754*37da2899SCharles.Forsyth 1755*37da2899SCharles.Forsyth error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); 1756*37da2899SCharles.Forsyth if ( error ) 1757*37da2899SCharles.Forsyth goto Exit; 1758*37da2899SCharles.Forsyth continue; 1759*37da2899SCharles.Forsyth } 1760*37da2899SCharles.Forsyth 1761*37da2899SCharles.Forsyth error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); 1762*37da2899SCharles.Forsyth goto Close; 1763*37da2899SCharles.Forsyth } 1764*37da2899SCharles.Forsyth } 1765*37da2899SCharles.Forsyth } 1766*37da2899SCharles.Forsyth 1767*37da2899SCharles.Forsyth /* close the contour with a line segment */ 1768*37da2899SCharles.Forsyth error = func_interface->line_to( &v_start, user ); 1769*37da2899SCharles.Forsyth 1770*37da2899SCharles.Forsyth Close: 1771*37da2899SCharles.Forsyth if ( error ) 1772*37da2899SCharles.Forsyth goto Exit; 1773*37da2899SCharles.Forsyth 1774*37da2899SCharles.Forsyth first = last + 1; 1775*37da2899SCharles.Forsyth } 1776*37da2899SCharles.Forsyth 1777*37da2899SCharles.Forsyth return 0; 1778*37da2899SCharles.Forsyth 1779*37da2899SCharles.Forsyth Exit: 1780*37da2899SCharles.Forsyth return error; 1781*37da2899SCharles.Forsyth 1782*37da2899SCharles.Forsyth Invalid_Outline: 1783*37da2899SCharles.Forsyth return ErrRaster_Invalid_Outline; 1784*37da2899SCharles.Forsyth } 1785*37da2899SCharles.Forsyth 1786*37da2899SCharles.Forsyth #endif /* _STANDALONE_ */ 1787*37da2899SCharles.Forsyth 1788*37da2899SCharles.Forsyth 1789*37da2899SCharles.Forsyth typedef struct TBand_ 1790*37da2899SCharles.Forsyth { 1791*37da2899SCharles.Forsyth TPos min, max; 1792*37da2899SCharles.Forsyth 1793*37da2899SCharles.Forsyth } TBand; 1794*37da2899SCharles.Forsyth 1795*37da2899SCharles.Forsyth 1796*37da2899SCharles.Forsyth static int gray_convert_glyph_inner(RAS_ARG)1797*37da2899SCharles.Forsyth gray_convert_glyph_inner( RAS_ARG ) 1798*37da2899SCharles.Forsyth { 1799*37da2899SCharles.Forsyth static 1800*37da2899SCharles.Forsyth const FT_Outline_Funcs func_interface = 1801*37da2899SCharles.Forsyth { 1802*37da2899SCharles.Forsyth (FT_Outline_MoveTo_Func) gray_move_to, 1803*37da2899SCharles.Forsyth (FT_Outline_LineTo_Func) gray_line_to, 1804*37da2899SCharles.Forsyth (FT_Outline_ConicTo_Func)gray_conic_to, 1805*37da2899SCharles.Forsyth (FT_Outline_CubicTo_Func)gray_cubic_to, 1806*37da2899SCharles.Forsyth 0, 1807*37da2899SCharles.Forsyth 0 1808*37da2899SCharles.Forsyth }; 1809*37da2899SCharles.Forsyth 1810*37da2899SCharles.Forsyth volatile int error = 0; 1811*37da2899SCharles.Forsyth 1812*37da2899SCharles.Forsyth if ( ft_setjmp( ras.jump_buffer ) == 0 ) 1813*37da2899SCharles.Forsyth { 1814*37da2899SCharles.Forsyth error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); 1815*37da2899SCharles.Forsyth gray_record_cell( RAS_VAR ); 1816*37da2899SCharles.Forsyth } 1817*37da2899SCharles.Forsyth else 1818*37da2899SCharles.Forsyth { 1819*37da2899SCharles.Forsyth error = ErrRaster_MemoryOverflow; 1820*37da2899SCharles.Forsyth } 1821*37da2899SCharles.Forsyth 1822*37da2899SCharles.Forsyth return error; 1823*37da2899SCharles.Forsyth } 1824*37da2899SCharles.Forsyth 1825*37da2899SCharles.Forsyth 1826*37da2899SCharles.Forsyth static int gray_convert_glyph(RAS_ARG)1827*37da2899SCharles.Forsyth gray_convert_glyph( RAS_ARG ) 1828*37da2899SCharles.Forsyth { 1829*37da2899SCharles.Forsyth TBand bands[40]; 1830*37da2899SCharles.Forsyth volatile TBand* band; 1831*37da2899SCharles.Forsyth volatile int n, num_bands; 1832*37da2899SCharles.Forsyth volatile TPos min, max, max_y; 1833*37da2899SCharles.Forsyth FT_BBox* clip; 1834*37da2899SCharles.Forsyth 1835*37da2899SCharles.Forsyth 1836*37da2899SCharles.Forsyth /* Set up state in the raster object */ 1837*37da2899SCharles.Forsyth gray_compute_cbox( RAS_VAR ); 1838*37da2899SCharles.Forsyth 1839*37da2899SCharles.Forsyth /* clip to target bitmap, exit if nothing to do */ 1840*37da2899SCharles.Forsyth clip = &ras.clip_box; 1841*37da2899SCharles.Forsyth 1842*37da2899SCharles.Forsyth if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || 1843*37da2899SCharles.Forsyth ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) 1844*37da2899SCharles.Forsyth return 0; 1845*37da2899SCharles.Forsyth 1846*37da2899SCharles.Forsyth if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; 1847*37da2899SCharles.Forsyth if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; 1848*37da2899SCharles.Forsyth 1849*37da2899SCharles.Forsyth if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; 1850*37da2899SCharles.Forsyth if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; 1851*37da2899SCharles.Forsyth 1852*37da2899SCharles.Forsyth /* simple heuristic used to speed-up the bezier decomposition -- see */ 1853*37da2899SCharles.Forsyth /* the code in gray_render_conic() and gray_render_cubic() for more */ 1854*37da2899SCharles.Forsyth /* details */ 1855*37da2899SCharles.Forsyth ras.conic_level = 32; 1856*37da2899SCharles.Forsyth ras.cubic_level = 16; 1857*37da2899SCharles.Forsyth 1858*37da2899SCharles.Forsyth { 1859*37da2899SCharles.Forsyth int level = 0; 1860*37da2899SCharles.Forsyth 1861*37da2899SCharles.Forsyth 1862*37da2899SCharles.Forsyth if ( ras.max_ex > 24 || ras.max_ey > 24 ) 1863*37da2899SCharles.Forsyth level++; 1864*37da2899SCharles.Forsyth if ( ras.max_ex > 120 || ras.max_ey > 120 ) 1865*37da2899SCharles.Forsyth level++; 1866*37da2899SCharles.Forsyth 1867*37da2899SCharles.Forsyth ras.conic_level <<= level; 1868*37da2899SCharles.Forsyth ras.cubic_level <<= level; 1869*37da2899SCharles.Forsyth } 1870*37da2899SCharles.Forsyth 1871*37da2899SCharles.Forsyth /* setup vertical bands */ 1872*37da2899SCharles.Forsyth num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); 1873*37da2899SCharles.Forsyth if ( num_bands == 0 ) num_bands = 1; 1874*37da2899SCharles.Forsyth if ( num_bands >= 39 ) num_bands = 39; 1875*37da2899SCharles.Forsyth 1876*37da2899SCharles.Forsyth ras.band_shoot = 0; 1877*37da2899SCharles.Forsyth 1878*37da2899SCharles.Forsyth min = ras.min_ey; 1879*37da2899SCharles.Forsyth max_y = ras.max_ey; 1880*37da2899SCharles.Forsyth 1881*37da2899SCharles.Forsyth for ( n = 0; n < num_bands; n++, min = max ) 1882*37da2899SCharles.Forsyth { 1883*37da2899SCharles.Forsyth max = min + ras.band_size; 1884*37da2899SCharles.Forsyth if ( n == num_bands - 1 || max > max_y ) 1885*37da2899SCharles.Forsyth max = max_y; 1886*37da2899SCharles.Forsyth 1887*37da2899SCharles.Forsyth bands[0].min = min; 1888*37da2899SCharles.Forsyth bands[0].max = max; 1889*37da2899SCharles.Forsyth band = bands; 1890*37da2899SCharles.Forsyth 1891*37da2899SCharles.Forsyth while ( band >= bands ) 1892*37da2899SCharles.Forsyth { 1893*37da2899SCharles.Forsyth TPos bottom, top, middle; 1894*37da2899SCharles.Forsyth int error; 1895*37da2899SCharles.Forsyth 1896*37da2899SCharles.Forsyth 1897*37da2899SCharles.Forsyth ras.num_cells = 0; 1898*37da2899SCharles.Forsyth ras.invalid = 1; 1899*37da2899SCharles.Forsyth ras.min_ey = band->min; 1900*37da2899SCharles.Forsyth ras.max_ey = band->max; 1901*37da2899SCharles.Forsyth 1902*37da2899SCharles.Forsyth #if 1 1903*37da2899SCharles.Forsyth error = gray_convert_glyph_inner( RAS_VAR ); 1904*37da2899SCharles.Forsyth #else 1905*37da2899SCharles.Forsyth error = FT_Outline_Decompose( outline, &func_interface, &ras ) || 1906*37da2899SCharles.Forsyth gray_record_cell( RAS_VAR ); 1907*37da2899SCharles.Forsyth #endif 1908*37da2899SCharles.Forsyth 1909*37da2899SCharles.Forsyth if ( !error ) 1910*37da2899SCharles.Forsyth { 1911*37da2899SCharles.Forsyth #ifdef SHELL_SORT 1912*37da2899SCharles.Forsyth gray_shell_sort( ras.cells, ras.num_cells ); 1913*37da2899SCharles.Forsyth #else 1914*37da2899SCharles.Forsyth gray_quick_sort( ras.cells, ras.num_cells ); 1915*37da2899SCharles.Forsyth #endif 1916*37da2899SCharles.Forsyth 1917*37da2899SCharles.Forsyth #ifdef DEBUG_GRAYS 1918*37da2899SCharles.Forsyth gray_check_sort( ras.cells, ras.num_cells ); 1919*37da2899SCharles.Forsyth gray_dump_cells( RAS_VAR ); 1920*37da2899SCharles.Forsyth #endif 1921*37da2899SCharles.Forsyth 1922*37da2899SCharles.Forsyth gray_sweep( RAS_VAR_ &ras.target ); 1923*37da2899SCharles.Forsyth band--; 1924*37da2899SCharles.Forsyth continue; 1925*37da2899SCharles.Forsyth } 1926*37da2899SCharles.Forsyth else if ( error != ErrRaster_MemoryOverflow ) 1927*37da2899SCharles.Forsyth return 1; 1928*37da2899SCharles.Forsyth 1929*37da2899SCharles.Forsyth /* render pool overflow, we will reduce the render band by half */ 1930*37da2899SCharles.Forsyth bottom = band->min; 1931*37da2899SCharles.Forsyth top = band->max; 1932*37da2899SCharles.Forsyth middle = bottom + ( ( top - bottom ) >> 1 ); 1933*37da2899SCharles.Forsyth 1934*37da2899SCharles.Forsyth /* waoow! This is too complex for a single scanline, something */ 1935*37da2899SCharles.Forsyth /* must be really rotten here! */ 1936*37da2899SCharles.Forsyth if ( middle == bottom ) 1937*37da2899SCharles.Forsyth { 1938*37da2899SCharles.Forsyth #ifdef DEBUG_GRAYS 1939*37da2899SCharles.Forsyth fprintf( stderr, "Rotten glyph!\n" ); 1940*37da2899SCharles.Forsyth #endif 1941*37da2899SCharles.Forsyth return 1; 1942*37da2899SCharles.Forsyth } 1943*37da2899SCharles.Forsyth 1944*37da2899SCharles.Forsyth if ( bottom-top >= ras.band_size ) 1945*37da2899SCharles.Forsyth ras.band_shoot++; 1946*37da2899SCharles.Forsyth 1947*37da2899SCharles.Forsyth band[1].min = bottom; 1948*37da2899SCharles.Forsyth band[1].max = middle; 1949*37da2899SCharles.Forsyth band[0].min = middle; 1950*37da2899SCharles.Forsyth band[0].max = top; 1951*37da2899SCharles.Forsyth band++; 1952*37da2899SCharles.Forsyth } 1953*37da2899SCharles.Forsyth } 1954*37da2899SCharles.Forsyth 1955*37da2899SCharles.Forsyth if ( ras.band_shoot > 8 && ras.band_size > 16 ) 1956*37da2899SCharles.Forsyth ras.band_size = ras.band_size / 2; 1957*37da2899SCharles.Forsyth 1958*37da2899SCharles.Forsyth return 0; 1959*37da2899SCharles.Forsyth } 1960*37da2899SCharles.Forsyth 1961*37da2899SCharles.Forsyth 1962*37da2899SCharles.Forsyth extern int gray_raster_render(PRaster raster,FT_Raster_Params * params)1963*37da2899SCharles.Forsyth gray_raster_render( PRaster raster, 1964*37da2899SCharles.Forsyth FT_Raster_Params* params ) 1965*37da2899SCharles.Forsyth { 1966*37da2899SCharles.Forsyth FT_Outline* outline = (FT_Outline*)params->source; 1967*37da2899SCharles.Forsyth FT_Bitmap* target_map = params->target; 1968*37da2899SCharles.Forsyth 1969*37da2899SCharles.Forsyth 1970*37da2899SCharles.Forsyth if ( !raster || !raster->cells || !raster->max_cells ) 1971*37da2899SCharles.Forsyth return -1; 1972*37da2899SCharles.Forsyth 1973*37da2899SCharles.Forsyth /* return immediately if the outline is empty */ 1974*37da2899SCharles.Forsyth if ( outline->n_points == 0 || outline->n_contours <= 0 ) 1975*37da2899SCharles.Forsyth return 0; 1976*37da2899SCharles.Forsyth 1977*37da2899SCharles.Forsyth if ( !outline || !outline->contours || !outline->points ) 1978*37da2899SCharles.Forsyth return ErrRaster_Invalid_Outline; 1979*37da2899SCharles.Forsyth 1980*37da2899SCharles.Forsyth if ( outline->n_points != 1981*37da2899SCharles.Forsyth outline->contours[outline->n_contours - 1] + 1 ) 1982*37da2899SCharles.Forsyth return ErrRaster_Invalid_Outline; 1983*37da2899SCharles.Forsyth 1984*37da2899SCharles.Forsyth /* if direct mode is not set, we must have a target bitmap */ 1985*37da2899SCharles.Forsyth if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 && 1986*37da2899SCharles.Forsyth ( !target_map || !target_map->buffer ) ) 1987*37da2899SCharles.Forsyth return -1; 1988*37da2899SCharles.Forsyth 1989*37da2899SCharles.Forsyth /* this version does not support monochrome rendering */ 1990*37da2899SCharles.Forsyth if ( !( params->flags & FT_RASTER_FLAG_AA ) ) 1991*37da2899SCharles.Forsyth return ErrRaster_Invalid_Mode; 1992*37da2899SCharles.Forsyth 1993*37da2899SCharles.Forsyth /* compute clipping box */ 1994*37da2899SCharles.Forsyth if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 ) 1995*37da2899SCharles.Forsyth { 1996*37da2899SCharles.Forsyth /* compute clip box from target pixmap */ 1997*37da2899SCharles.Forsyth ras.clip_box.xMin = 0; 1998*37da2899SCharles.Forsyth ras.clip_box.yMin = 0; 1999*37da2899SCharles.Forsyth ras.clip_box.xMax = target_map->width; 2000*37da2899SCharles.Forsyth ras.clip_box.yMax = target_map->rows; 2001*37da2899SCharles.Forsyth } 2002*37da2899SCharles.Forsyth else if ( params->flags & FT_RASTER_FLAG_CLIP ) 2003*37da2899SCharles.Forsyth { 2004*37da2899SCharles.Forsyth ras.clip_box = params->clip_box; 2005*37da2899SCharles.Forsyth } 2006*37da2899SCharles.Forsyth else 2007*37da2899SCharles.Forsyth { 2008*37da2899SCharles.Forsyth ras.clip_box.xMin = -32768L; 2009*37da2899SCharles.Forsyth ras.clip_box.yMin = -32768L; 2010*37da2899SCharles.Forsyth ras.clip_box.xMax = 32767L; 2011*37da2899SCharles.Forsyth ras.clip_box.yMax = 32767L; 2012*37da2899SCharles.Forsyth } 2013*37da2899SCharles.Forsyth 2014*37da2899SCharles.Forsyth ras.outline = *outline; 2015*37da2899SCharles.Forsyth ras.num_cells = 0; 2016*37da2899SCharles.Forsyth ras.invalid = 1; 2017*37da2899SCharles.Forsyth 2018*37da2899SCharles.Forsyth if ( target_map ) 2019*37da2899SCharles.Forsyth ras.target = *target_map; 2020*37da2899SCharles.Forsyth 2021*37da2899SCharles.Forsyth ras.render_span = (FT_Raster_Span_Func)gray_render_span; 2022*37da2899SCharles.Forsyth ras.render_span_data = &ras; 2023*37da2899SCharles.Forsyth 2024*37da2899SCharles.Forsyth if ( params->flags & FT_RASTER_FLAG_DIRECT ) 2025*37da2899SCharles.Forsyth { 2026*37da2899SCharles.Forsyth ras.render_span = (FT_Raster_Span_Func)params->gray_spans; 2027*37da2899SCharles.Forsyth ras.render_span_data = params->user; 2028*37da2899SCharles.Forsyth } 2029*37da2899SCharles.Forsyth 2030*37da2899SCharles.Forsyth return gray_convert_glyph( (PRaster)raster ); 2031*37da2899SCharles.Forsyth } 2032*37da2899SCharles.Forsyth 2033*37da2899SCharles.Forsyth 2034*37da2899SCharles.Forsyth /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ 2035*37da2899SCharles.Forsyth /**** a static object. *****/ 2036*37da2899SCharles.Forsyth 2037*37da2899SCharles.Forsyth #ifdef GRAYS_USE_GAMMA 2038*37da2899SCharles.Forsyth 2039*37da2899SCharles.Forsyth /* initialize the "gamma" table. Yes, this is really a crummy function */ 2040*37da2899SCharles.Forsyth /* but the results look pretty good for something that simple. */ 2041*37da2899SCharles.Forsyth /* */ 2042*37da2899SCharles.Forsyth #define M_MAX 255 2043*37da2899SCharles.Forsyth #define M_X 128 2044*37da2899SCharles.Forsyth #define M_Y 192 2045*37da2899SCharles.Forsyth 2046*37da2899SCharles.Forsyth static void grays_init_gamma(PRaster raster)2047*37da2899SCharles.Forsyth grays_init_gamma( PRaster raster ) 2048*37da2899SCharles.Forsyth { 2049*37da2899SCharles.Forsyth unsigned int x, a; 2050*37da2899SCharles.Forsyth 2051*37da2899SCharles.Forsyth 2052*37da2899SCharles.Forsyth for ( x = 0; x < 256; x++ ) 2053*37da2899SCharles.Forsyth { 2054*37da2899SCharles.Forsyth if ( x <= M_X ) 2055*37da2899SCharles.Forsyth a = ( x * M_Y + M_X / 2) / M_X; 2056*37da2899SCharles.Forsyth else 2057*37da2899SCharles.Forsyth a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) + 2058*37da2899SCharles.Forsyth ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X ); 2059*37da2899SCharles.Forsyth 2060*37da2899SCharles.Forsyth raster->gamma[x] = (unsigned char)a; 2061*37da2899SCharles.Forsyth } 2062*37da2899SCharles.Forsyth } 2063*37da2899SCharles.Forsyth 2064*37da2899SCharles.Forsyth #endif /* GRAYS_USE_GAMMA */ 2065*37da2899SCharles.Forsyth 2066*37da2899SCharles.Forsyth #ifdef _STANDALONE_ 2067*37da2899SCharles.Forsyth 2068*37da2899SCharles.Forsyth static int gray_raster_new(void * memory,FT_Raster * araster)2069*37da2899SCharles.Forsyth gray_raster_new( void* memory, 2070*37da2899SCharles.Forsyth FT_Raster* araster ) 2071*37da2899SCharles.Forsyth { 2072*37da2899SCharles.Forsyth static TRaster the_raster; 2073*37da2899SCharles.Forsyth 2074*37da2899SCharles.Forsyth FT_UNUSED( memory ); 2075*37da2899SCharles.Forsyth 2076*37da2899SCharles.Forsyth 2077*37da2899SCharles.Forsyth *araster = (FT_Raster)&the_raster; 2078*37da2899SCharles.Forsyth FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); 2079*37da2899SCharles.Forsyth 2080*37da2899SCharles.Forsyth #ifdef GRAYS_USE_GAMMA 2081*37da2899SCharles.Forsyth grays_init_gamma( (PRaster)*araster ); 2082*37da2899SCharles.Forsyth #endif 2083*37da2899SCharles.Forsyth 2084*37da2899SCharles.Forsyth return 0; 2085*37da2899SCharles.Forsyth } 2086*37da2899SCharles.Forsyth 2087*37da2899SCharles.Forsyth 2088*37da2899SCharles.Forsyth static void gray_raster_done(FT_Raster raster)2089*37da2899SCharles.Forsyth gray_raster_done( FT_Raster raster ) 2090*37da2899SCharles.Forsyth { 2091*37da2899SCharles.Forsyth /* nothing */ 2092*37da2899SCharles.Forsyth FT_UNUSED( raster ); 2093*37da2899SCharles.Forsyth } 2094*37da2899SCharles.Forsyth 2095*37da2899SCharles.Forsyth #else /* _STANDALONE_ */ 2096*37da2899SCharles.Forsyth 2097*37da2899SCharles.Forsyth static int gray_raster_new(FT_Memory memory,FT_Raster * araster)2098*37da2899SCharles.Forsyth gray_raster_new( FT_Memory memory, 2099*37da2899SCharles.Forsyth FT_Raster* araster ) 2100*37da2899SCharles.Forsyth { 2101*37da2899SCharles.Forsyth FT_Error error; 2102*37da2899SCharles.Forsyth PRaster raster; 2103*37da2899SCharles.Forsyth 2104*37da2899SCharles.Forsyth 2105*37da2899SCharles.Forsyth *araster = 0; 2106*37da2899SCharles.Forsyth if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) ) 2107*37da2899SCharles.Forsyth { 2108*37da2899SCharles.Forsyth raster->memory = memory; 2109*37da2899SCharles.Forsyth *araster = (FT_Raster)raster; 2110*37da2899SCharles.Forsyth 2111*37da2899SCharles.Forsyth #ifdef GRAYS_USE_GAMMA 2112*37da2899SCharles.Forsyth grays_init_gamma( raster ); 2113*37da2899SCharles.Forsyth #endif 2114*37da2899SCharles.Forsyth } 2115*37da2899SCharles.Forsyth 2116*37da2899SCharles.Forsyth return error; 2117*37da2899SCharles.Forsyth } 2118*37da2899SCharles.Forsyth 2119*37da2899SCharles.Forsyth 2120*37da2899SCharles.Forsyth static void gray_raster_done(FT_Raster raster)2121*37da2899SCharles.Forsyth gray_raster_done( FT_Raster raster ) 2122*37da2899SCharles.Forsyth { 2123*37da2899SCharles.Forsyth FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; 2124*37da2899SCharles.Forsyth 2125*37da2899SCharles.Forsyth 2126*37da2899SCharles.Forsyth FT_FREE( raster ); 2127*37da2899SCharles.Forsyth } 2128*37da2899SCharles.Forsyth 2129*37da2899SCharles.Forsyth #endif /* _STANDALONE_ */ 2130*37da2899SCharles.Forsyth 2131*37da2899SCharles.Forsyth 2132*37da2899SCharles.Forsyth static void gray_raster_reset(FT_Raster raster,const char * pool_base,long pool_size)2133*37da2899SCharles.Forsyth gray_raster_reset( FT_Raster raster, 2134*37da2899SCharles.Forsyth const char* pool_base, 2135*37da2899SCharles.Forsyth long pool_size ) 2136*37da2899SCharles.Forsyth { 2137*37da2899SCharles.Forsyth PRaster rast = (PRaster)raster; 2138*37da2899SCharles.Forsyth 2139*37da2899SCharles.Forsyth 2140*37da2899SCharles.Forsyth if ( raster && pool_base && pool_size >= 4096 ) 2141*37da2899SCharles.Forsyth gray_init_cells( rast, (char*)pool_base, pool_size ); 2142*37da2899SCharles.Forsyth 2143*37da2899SCharles.Forsyth rast->band_size = (int)( ( pool_size / sizeof ( TCell ) ) / 8 ); 2144*37da2899SCharles.Forsyth } 2145*37da2899SCharles.Forsyth 2146*37da2899SCharles.Forsyth 2147*37da2899SCharles.Forsyth const FT_Raster_Funcs ft_grays_raster = 2148*37da2899SCharles.Forsyth { 2149*37da2899SCharles.Forsyth FT_GLYPH_FORMAT_OUTLINE, 2150*37da2899SCharles.Forsyth 2151*37da2899SCharles.Forsyth (FT_Raster_New_Func) gray_raster_new, 2152*37da2899SCharles.Forsyth (FT_Raster_Reset_Func) gray_raster_reset, 2153*37da2899SCharles.Forsyth (FT_Raster_Set_Mode_Func)0, 2154*37da2899SCharles.Forsyth (FT_Raster_Render_Func) gray_raster_render, 2155*37da2899SCharles.Forsyth (FT_Raster_Done_Func) gray_raster_done 2156*37da2899SCharles.Forsyth }; 2157*37da2899SCharles.Forsyth 2158*37da2899SCharles.Forsyth 2159*37da2899SCharles.Forsyth /* END */ 2160