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