Upload tizen 2.0 beta source
[framework/graphics/freetype.git] / src / raster / ftraster.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 )
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 )
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 )
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
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
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
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
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
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
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
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
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 */