source: trunk/poppler/freetype2/src/raster/ftraster.c @ 251

Last change on this file since 251 was 251, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.5

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