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