~ubuntu-branches/ubuntu/wily/hedgewars/wily

« back to all changes in this revision

Viewing changes to misc/libfreetype/src/raster/ftraster.c

  • Committer: Package Import Robot
  • Author(s): Dmitry E. Oboukhov
  • Date: 2011-09-23 10:16:55 UTC
  • mfrom: (1.2.11 upstream)
  • Revision ID: package-import@ubuntu.com-20110923101655-3977th2gc5n0a3pv
Tags: 0.9.16-1
* New upstream version.
 + Downloadable content! Simply click to install any content.
   New voices, hats, maps, themes, translations, music, scripts...
   Hedgewars is now more customisable than ever before! As time goes
   by we will be soliciting community content to feature on this page,
   so remember to check it from time to time. If you decide you want
   to go back to standard Hedgewars, just remove the Data directory
   from your Hedgewars config directory.
 + 3-D rendering! Diorama-like rendering of the game in a variety
   of 3D modes. Let us know which ones work best for you, we didn't
   really have the equipment to test them all.
 + Resizable game window.
 + New utilities! The Time Box will remove one of your hedgehogs
   from the game for a while, protecting from attack until it returns,
   somewhere else on the map. Land spray will allow you to build bridges,
   seal up holes, or just make life unpleasant for your enemies.
 + New single player: Bamboo Thicket, That Sinking Feeling, Newton and
   the Tree and multi-player: The Specialists, Space Invaders,
   Racer - scripts! And a ton more script hooks for scripters
 + New twists on old weapons. Drill strike, seduction and fire have
   been adjusted. Defective mines have been added, rope can attach to
   hogs/crates/barrels again, grenades now have variable bounce (use
   precise key + 1-5). Portal gun is now more usable in flight and
   all game actions are a lot faster.
 + New theme - Golf, dozens of new community hats and a new
   localised Default voice, Ukranian.

Show diffs side-by-side

added added

removed removed

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