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