Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

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