xref: /inferno-os/libfreetype/ftgrays.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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