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