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