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