~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/freetype/src/raster/ftraster.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

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