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