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