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

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 12 years ago

PDF plugin: freetype library updated to version 2.3.8

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