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