Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / freetype2 / src / raster / ftraster.c
blob8f014740bdabcfa5f11c9cd7b91aa5f8a7abbaf4
1 /***************************************************************************/
2 /* */
3 /* ftraster.c */
4 /* */
5 /* The FreeType glyph rasterizer (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2005, 2007, 2008 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
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 /*************************************************************************/
44 /*************************************************************************/
45 /* */
46 /* This is a rewrite of the FreeType 1.x scan-line converter */
47 /* */
48 /*************************************************************************/
50 #ifdef _STANDALONE_
52 #include "ftmisc.h"
53 #include "ftimage.h"
55 #else /* !_STANDALONE_ */
57 #include <ft2build.h>
58 #include "ftraster.h"
59 #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
61 #endif /* !_STANDALONE_ */
64 /*************************************************************************/
65 /* */
66 /* A simple technical note on how the raster works */
67 /* ----------------------------------------------- */
68 /* */
69 /* Converting an outline into a bitmap is achieved in several steps: */
70 /* */
71 /* 1 - Decomposing the outline into successive `profiles'. Each */
72 /* profile is simply an array of scanline intersections on a given */
73 /* dimension. A profile's main attributes are */
74 /* */
75 /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
76 /* */
77 /* o an array of intersection coordinates for each scanline */
78 /* between `Ymin' and `Ymax'. */
79 /* */
80 /* o a direction, indicating whether it was built going `up' or */
81 /* `down', as this is very important for filling rules. */
82 /* */
83 /* 2 - Sweeping the target map's scanlines in order to compute segment */
84 /* `spans' which are then filled. Additionally, this pass */
85 /* performs drop-out control. */
86 /* */
87 /* The outline data is parsed during step 1 only. The profiles are */
88 /* built from the bottom of the render pool, used as a stack. The */
89 /* following graphics shows the profile list under construction: */
90 /* */
91 /* ____________________________________________________________ _ _ */
92 /* | | | | | */
93 /* | profile | coordinates for | profile | coordinates for |--> */
94 /* | 1 | profile 1 | 2 | profile 2 |--> */
95 /* |_________|___________________|_________|_________________|__ _ _ */
96 /* */
97 /* ^ ^ */
98 /* | | */
99 /* start of render pool top */
100 /* */
101 /* The top of the profile stack is kept in the `top' variable. */
102 /* */
103 /* As you can see, a profile record is pushed on top of the render */
104 /* pool, which is then followed by its coordinates/intersections. If */
105 /* a change of direction is detected in the outline, a new profile is */
106 /* generated until the end of the outline. */
107 /* */
108 /* Note that when all profiles have been generated, the function */
109 /* Finalize_Profile_Table() is used to record, for each profile, its */
110 /* bottom-most scanline as well as the scanline above its upmost */
111 /* boundary. These positions are called `y-turns' because they (sort */
112 /* of) correspond to local extrema. They are stored in a sorted list */
113 /* built from the top of the render pool as a downwards stack: */
114 /* */
115 /* _ _ _______________________________________ */
116 /* | | */
117 /* <--| sorted list of | */
118 /* <--| extrema scanlines | */
119 /* _ _ __________________|____________________| */
120 /* */
121 /* ^ ^ */
122 /* | | */
123 /* maxBuff sizeBuff = end of pool */
124 /* */
125 /* This list is later used during the sweep phase in order to */
126 /* optimize performance (see technical note on the sweep below). */
127 /* */
128 /* Of course, the raster detects whether the two stacks collide and */
129 /* handles the situation properly. */
130 /* */
131 /*************************************************************************/
134 /*************************************************************************/
135 /*************************************************************************/
136 /** **/
137 /** CONFIGURATION MACROS **/
138 /** **/
139 /*************************************************************************/
140 /*************************************************************************/
142 /* define DEBUG_RASTER if you want to compile a debugging version */
143 #define xxxDEBUG_RASTER
145 /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
146 /* 5-levels anti-aliasing */
147 #undef FT_RASTER_OPTION_ANTI_ALIASING
149 /* The size of the two-lines intermediate bitmap used */
150 /* for anti-aliasing, in bytes. */
151 #define RASTER_GRAY_LINES 2048
154 /*************************************************************************/
155 /*************************************************************************/
156 /** **/
157 /** OTHER MACROS (do not change) **/
158 /** **/
159 /*************************************************************************/
160 /*************************************************************************/
162 /*************************************************************************/
163 /* */
164 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
165 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
166 /* messages during execution. */
167 /* */
168 #undef FT_COMPONENT
169 #define FT_COMPONENT trace_raster
172 #ifdef _STANDALONE_
175 /* This macro is used to indicate that a function parameter is unused. */
176 /* Its purpose is simply to reduce compiler warnings. Note also that */
177 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
178 /* ANSI compilers (e.g. LCC). */
179 #define FT_UNUSED( x ) (x) = (x)
181 /* Disable the tracing mechanism for simplicity -- developers can */
182 /* activate it easily by redefining these two macros. */
183 #ifndef FT_ERROR
184 #define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
185 #endif
187 #ifndef FT_TRACE
188 #define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
189 #define FT_TRACE1( x ) do ; while ( 0 ) /* nothing */
190 #define FT_TRACE6( x ) do ; while ( 0 ) /* nothing */
191 #endif
193 #define Raster_Err_None 0
194 #define Raster_Err_Not_Ini -1
195 #define Raster_Err_Overflow -2
196 #define Raster_Err_Neg_Height -3
197 #define Raster_Err_Invalid -4
198 #define Raster_Err_Unsupported -5
200 #define ft_memset memset
202 #else /* _STANDALONE_ */
205 #include FT_INTERNAL_OBJECTS_H
206 #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
208 #include "rasterrs.h"
210 #define Raster_Err_None Raster_Err_Ok
211 #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
212 #define Raster_Err_Overflow Raster_Err_Raster_Overflow
213 #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
214 #define Raster_Err_Invalid Raster_Err_Invalid_Outline
215 #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
218 #endif /* _STANDALONE_ */
221 #ifndef FT_MEM_SET
222 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
223 #endif
225 #ifndef FT_MEM_ZERO
226 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
227 #endif
229 /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
230 /* typically a small value and the result of a*b is known to fit into */
231 /* 32 bits. */
232 #define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
234 /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
235 /* for clipping computations. It simply uses the FT_MulDiv() function */
236 /* defined in `ftcalc.h'. */
237 #define SMulDiv FT_MulDiv
239 /* The rasterizer is a very general purpose component; please leave */
240 /* the following redefinitions there (you never know your target */
241 /* environment). */
243 #ifndef TRUE
244 #define TRUE 1
245 #endif
247 #ifndef FALSE
248 #define FALSE 0
249 #endif
251 #ifndef NULL
252 #define NULL (void*)0
253 #endif
255 #ifndef SUCCESS
256 #define SUCCESS 0
257 #endif
259 #ifndef FAILURE
260 #define FAILURE 1
261 #endif
264 #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
265 /* Setting this constant to more than 32 is a */
266 /* pure waste of space. */
268 #define Pixel_Bits 6 /* fractional bits of *input* coordinates */
271 /*************************************************************************/
272 /*************************************************************************/
273 /** **/
274 /** SIMPLE TYPE DECLARATIONS **/
275 /** **/
276 /*************************************************************************/
277 /*************************************************************************/
279 typedef int Int;
280 typedef unsigned int UInt;
281 typedef short Short;
282 typedef unsigned short UShort, *PUShort;
283 typedef long Long, *PLong;
284 typedef unsigned long ULong;
286 typedef unsigned char Byte, *PByte;
287 typedef char Bool;
290 typedef union Alignment_
292 long l;
293 void* p;
294 void (*f)(void);
296 } Alignment, *PAlignment;
299 typedef struct TPoint_
301 Long x;
302 Long y;
304 } TPoint;
307 typedef enum TFlow_
309 Flow_None = 0,
310 Flow_Up = 1,
311 Flow_Down = -1
313 } TFlow;
316 /* States of each line, arc, and profile */
317 typedef enum TStates_
319 Unknown_State,
320 Ascending_State,
321 Descending_State,
322 Flat_State
324 } TStates;
327 typedef struct TProfile_ TProfile;
328 typedef TProfile* PProfile;
330 struct TProfile_
332 FT_F26Dot6 X; /* current coordinate during sweep */
333 PProfile link; /* link to next profile - various purpose */
334 PLong offset; /* start of profile's data in render pool */
335 int flow; /* Profile orientation: Asc/Descending */
336 long height; /* profile's height in scanlines */
337 long start; /* profile's starting scanline */
339 unsigned countL; /* number of lines to step before this */
340 /* profile becomes drawable */
342 PProfile next; /* next profile in same contour, used */
343 /* during drop-out control */
346 typedef PProfile TProfileList;
347 typedef PProfile* PProfileList;
350 /* Simple record used to implement a stack of bands, required */
351 /* by the sub-banding mechanism */
352 typedef struct TBand_
354 Short y_min; /* band's minimum */
355 Short y_max; /* band's maximum */
357 } TBand;
360 #define AlignProfileSize \
361 ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
364 #ifdef FT_STATIC_RASTER
367 #define RAS_ARGS /* void */
368 #define RAS_ARG /* void */
370 #define RAS_VARS /* void */
371 #define RAS_VAR /* void */
373 #define FT_UNUSED_RASTER do ; while ( 0 )
376 #else /* FT_STATIC_RASTER */
379 #define RAS_ARGS PWorker worker,
380 #define RAS_ARG PWorker worker
382 #define RAS_VARS worker,
383 #define RAS_VAR worker
385 #define FT_UNUSED_RASTER FT_UNUSED( worker )
388 #endif /* FT_STATIC_RASTER */
391 typedef struct TWorker_ TWorker, *PWorker;
394 /* prototypes used for sweep function dispatch */
395 typedef void
396 Function_Sweep_Init( RAS_ARGS Short* min,
397 Short* max );
399 typedef void
400 Function_Sweep_Span( RAS_ARGS Short y,
401 FT_F26Dot6 x1,
402 FT_F26Dot6 x2,
403 PProfile left,
404 PProfile right );
406 typedef void
407 Function_Sweep_Step( RAS_ARG );
410 /* NOTE: These operations are only valid on 2's complement processors */
412 #define FLOOR( x ) ( (x) & -ras.precision )
413 #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
414 #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
415 #define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
416 #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
418 /* Note that I have moved the location of some fields in the */
419 /* structure to ensure that the most used variables are used */
420 /* at the top. Thus, their offset can be coded with less */
421 /* opcodes, and it results in a smaller executable. */
423 struct TWorker_
425 Int precision_bits; /* precision related variables */
426 Int precision;
427 Int precision_half;
428 Long precision_mask;
429 Int precision_shift;
430 Int precision_step;
431 Int precision_jitter;
433 Int scale_shift; /* == precision_shift for bitmaps */
434 /* == precision_shift+1 for pixmaps */
436 PLong buff; /* The profiles buffer */
437 PLong sizeBuff; /* Render pool size */
438 PLong maxBuff; /* Profiles buffer size */
439 PLong top; /* Current cursor in buffer */
441 FT_Error error;
443 Int numTurns; /* number of Y-turns in outline */
445 TPoint* arc; /* current Bezier arc pointer */
447 UShort bWidth; /* target bitmap width */
448 PByte bTarget; /* target bitmap buffer */
449 PByte gTarget; /* target pixmap buffer */
451 Long lastX, lastY, minY, maxY;
453 UShort num_Profs; /* current number of profiles */
455 Bool fresh; /* signals a fresh new profile which */
456 /* 'start' field must be completed */
457 Bool joint; /* signals that the last arc ended */
458 /* exactly on a scanline. Allows */
459 /* removal of doublets */
460 PProfile cProfile; /* current profile */
461 PProfile fProfile; /* head of linked list of profiles */
462 PProfile gProfile; /* contour's first profile in case */
463 /* of impact */
465 TStates state; /* rendering state */
467 FT_Bitmap target; /* description of target bit/pixmap */
468 FT_Outline outline;
470 Long traceOfs; /* current offset in target bitmap */
471 Long traceG; /* current offset in target pixmap */
473 Short traceIncr; /* sweep's increment in target bitmap */
475 Short gray_min_x; /* current min x during gray rendering */
476 Short gray_max_x; /* current max x during gray rendering */
478 /* dispatch variables */
480 Function_Sweep_Init* Proc_Sweep_Init;
481 Function_Sweep_Span* Proc_Sweep_Span;
482 Function_Sweep_Span* Proc_Sweep_Drop;
483 Function_Sweep_Step* Proc_Sweep_Step;
485 Byte dropOutControl; /* current drop_out control method */
487 Bool second_pass; /* indicates whether a horizontal pass */
488 /* should be performed to control */
489 /* drop-out accurately when calling */
490 /* Render_Glyph. Note that there is */
491 /* no horizontal pass during gray */
492 /* rendering. */
494 TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
496 TBand band_stack[16]; /* band stack used for sub-banding */
497 Int band_top; /* band stack top */
499 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
501 Byte* grays;
503 Byte gray_lines[RASTER_GRAY_LINES];
504 /* Intermediate table used to render the */
505 /* graylevels pixmaps. */
506 /* gray_lines is a buffer holding two */
507 /* monochrome scanlines */
509 Short gray_width; /* width in bytes of one monochrome */
510 /* intermediate scanline of gray_lines. */
511 /* Each gray pixel takes 2 bits long there */
513 /* The gray_lines must hold 2 lines, thus with size */
514 /* in bytes of at least `gray_width*2'. */
516 #endif /* FT_RASTER_ANTI_ALIASING */
521 typedef struct TRaster_
523 char* buffer;
524 long buffer_size;
525 void* memory;
526 PWorker worker;
527 Byte grays[5];
528 Short gray_width;
530 } TRaster, *PRaster;
532 #ifdef FT_STATIC_RASTER
534 static TWorker cur_ras;
535 #define ras cur_ras
537 #else
539 #define ras (*worker)
541 #endif /* FT_STATIC_RASTER */
544 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
546 static const char count_table[256] =
548 0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4,
549 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
550 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
551 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
552 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
553 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
554 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
555 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
556 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5,
557 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
558 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
559 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
560 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6,
561 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
562 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7,
563 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 , 5 , 6 , 6 , 7 , 6 , 7 , 7 , 8 };
565 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
569 /*************************************************************************/
570 /*************************************************************************/
571 /** **/
572 /** PROFILES COMPUTATION **/
573 /** **/
574 /*************************************************************************/
575 /*************************************************************************/
578 /*************************************************************************/
579 /* */
580 /* <Function> */
581 /* Set_High_Precision */
582 /* */
583 /* <Description> */
584 /* Sets precision variables according to param flag. */
585 /* */
586 /* <Input> */
587 /* High :: Set to True for high precision (typically for ppem < 18), */
588 /* false otherwise. */
589 /* */
590 static void
591 Set_High_Precision( RAS_ARGS Int High )
593 if ( High )
595 ras.precision_bits = 10;
596 ras.precision_step = 128;
597 ras.precision_jitter = 24;
599 else
601 ras.precision_bits = 6;
602 ras.precision_step = 32;
603 ras.precision_jitter = 2;
606 FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
608 ras.precision = 1 << ras.precision_bits;
609 ras.precision_half = ras.precision / 2;
610 ras.precision_shift = ras.precision_bits - Pixel_Bits;
611 ras.precision_mask = -ras.precision;
615 /*************************************************************************/
616 /* */
617 /* <Function> */
618 /* New_Profile */
619 /* */
620 /* <Description> */
621 /* Creates a new profile in the render pool. */
622 /* */
623 /* <Input> */
624 /* aState :: The state/orientation of the new profile. */
625 /* */
626 /* <Return> */
627 /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
628 /* profile. */
629 /* */
630 static Bool
631 New_Profile( RAS_ARGS TStates aState )
633 if ( !ras.fProfile )
635 ras.cProfile = (PProfile)ras.top;
636 ras.fProfile = ras.cProfile;
637 ras.top += AlignProfileSize;
640 if ( ras.top >= ras.maxBuff )
642 ras.error = Raster_Err_Overflow;
643 return FAILURE;
646 switch ( aState )
648 case Ascending_State:
649 ras.cProfile->flow = Flow_Up;
650 FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
651 break;
653 case Descending_State:
654 ras.cProfile->flow = Flow_Down;
655 FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
656 break;
658 default:
659 FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
660 ras.error = Raster_Err_Invalid;
661 return FAILURE;
664 ras.cProfile->start = 0;
665 ras.cProfile->height = 0;
666 ras.cProfile->offset = ras.top;
667 ras.cProfile->link = (PProfile)0;
668 ras.cProfile->next = (PProfile)0;
670 if ( !ras.gProfile )
671 ras.gProfile = ras.cProfile;
673 ras.state = aState;
674 ras.fresh = TRUE;
675 ras.joint = FALSE;
677 return SUCCESS;
681 /*************************************************************************/
682 /* */
683 /* <Function> */
684 /* End_Profile */
685 /* */
686 /* <Description> */
687 /* Finalizes the current profile. */
688 /* */
689 /* <Return> */
690 /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
691 /* */
692 static Bool
693 End_Profile( RAS_ARG )
695 Long h;
696 PProfile oldProfile;
699 h = (Long)( ras.top - ras.cProfile->offset );
701 if ( h < 0 )
703 FT_ERROR(( "End_Profile: negative height encountered!\n" ));
704 ras.error = Raster_Err_Neg_Height;
705 return FAILURE;
708 if ( h > 0 )
710 FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
711 (long)ras.cProfile, ras.cProfile->start, h ));
713 oldProfile = ras.cProfile;
714 ras.cProfile->height = h;
715 ras.cProfile = (PProfile)ras.top;
717 ras.top += AlignProfileSize;
719 ras.cProfile->height = 0;
720 ras.cProfile->offset = ras.top;
721 oldProfile->next = ras.cProfile;
722 ras.num_Profs++;
725 if ( ras.top >= ras.maxBuff )
727 FT_TRACE1(( "overflow in End_Profile\n" ));
728 ras.error = Raster_Err_Overflow;
729 return FAILURE;
732 ras.joint = FALSE;
734 return SUCCESS;
738 /*************************************************************************/
739 /* */
740 /* <Function> */
741 /* Insert_Y_Turn */
742 /* */
743 /* <Description> */
744 /* Inserts a salient into the sorted list placed on top of the render */
745 /* pool. */
746 /* */
747 /* <Input> */
748 /* New y scanline position. */
749 /* */
750 /* <Return> */
751 /* SUCCESS on success. FAILURE in case of overflow. */
752 /* */
753 static Bool
754 Insert_Y_Turn( RAS_ARGS Int y )
756 PLong y_turns;
757 Int y2, n;
760 n = ras.numTurns - 1;
761 y_turns = ras.sizeBuff - ras.numTurns;
763 /* look for first y value that is <= */
764 while ( n >= 0 && y < y_turns[n] )
765 n--;
767 /* if it is <, simply insert it, ignore if == */
768 if ( n >= 0 && y > y_turns[n] )
769 while ( n >= 0 )
771 y2 = (Int)y_turns[n];
772 y_turns[n] = y;
773 y = y2;
774 n--;
777 if ( n < 0 )
779 ras.maxBuff--;
780 if ( ras.maxBuff <= ras.top )
782 ras.error = Raster_Err_Overflow;
783 return FAILURE;
785 ras.numTurns++;
786 ras.sizeBuff[-ras.numTurns] = y;
789 return SUCCESS;
793 /*************************************************************************/
794 /* */
795 /* <Function> */
796 /* Finalize_Profile_Table */
797 /* */
798 /* <Description> */
799 /* Adjusts all links in the profiles list. */
800 /* */
801 /* <Return> */
802 /* SUCCESS on success. FAILURE in case of overflow. */
803 /* */
804 static Bool
805 Finalize_Profile_Table( RAS_ARG )
807 Int bottom, top;
808 UShort n;
809 PProfile p;
812 n = ras.num_Profs;
814 if ( n > 1 )
816 p = ras.fProfile;
817 while ( n > 0 )
819 if ( n > 1 )
820 p->link = (PProfile)( p->offset + p->height );
821 else
822 p->link = NULL;
824 switch ( p->flow )
826 case Flow_Down:
827 bottom = (Int)( p->start - p->height + 1 );
828 top = (Int)p->start;
829 p->start = bottom;
830 p->offset += p->height - 1;
831 break;
833 case Flow_Up:
834 default:
835 bottom = (Int)p->start;
836 top = (Int)( p->start + p->height - 1 );
839 if ( Insert_Y_Turn( RAS_VARS bottom ) ||
840 Insert_Y_Turn( RAS_VARS top + 1 ) )
841 return FAILURE;
843 p = p->link;
844 n--;
847 else
848 ras.fProfile = NULL;
850 return SUCCESS;
854 /*************************************************************************/
855 /* */
856 /* <Function> */
857 /* Split_Conic */
858 /* */
859 /* <Description> */
860 /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
861 /* stack. */
862 /* */
863 /* <Input> */
864 /* None (subdivided Bezier is taken from the top of the stack). */
865 /* */
866 /* <Note> */
867 /* This routine is the `beef' of this component. It is _the_ inner */
868 /* loop that should be optimized to hell to get the best performance. */
869 /* */
870 static void
871 Split_Conic( TPoint* base )
873 Long a, b;
876 base[4].x = base[2].x;
877 b = base[1].x;
878 a = base[3].x = ( base[2].x + b ) / 2;
879 b = base[1].x = ( base[0].x + b ) / 2;
880 base[2].x = ( a + b ) / 2;
882 base[4].y = base[2].y;
883 b = base[1].y;
884 a = base[3].y = ( base[2].y + b ) / 2;
885 b = base[1].y = ( base[0].y + b ) / 2;
886 base[2].y = ( a + b ) / 2;
888 /* hand optimized. gcc doesn't seem to be too good at common */
889 /* expression substitution and instruction scheduling ;-) */
893 /*************************************************************************/
894 /* */
895 /* <Function> */
896 /* Split_Cubic */
897 /* */
898 /* <Description> */
899 /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
900 /* Bezier stack. */
901 /* */
902 /* <Note> */
903 /* This routine is the `beef' of the component. It is one of _the_ */
904 /* inner loops that should be optimized like hell to get the best */
905 /* performance. */
906 /* */
907 static void
908 Split_Cubic( TPoint* base )
910 Long a, b, c, d;
913 base[6].x = base[3].x;
914 c = base[1].x;
915 d = base[2].x;
916 base[1].x = a = ( base[0].x + c + 1 ) >> 1;
917 base[5].x = b = ( base[3].x + d + 1 ) >> 1;
918 c = ( c + d + 1 ) >> 1;
919 base[2].x = a = ( a + c + 1 ) >> 1;
920 base[4].x = b = ( b + c + 1 ) >> 1;
921 base[3].x = ( a + b + 1 ) >> 1;
923 base[6].y = base[3].y;
924 c = base[1].y;
925 d = base[2].y;
926 base[1].y = a = ( base[0].y + c + 1 ) >> 1;
927 base[5].y = b = ( base[3].y + d + 1 ) >> 1;
928 c = ( c + d + 1 ) >> 1;
929 base[2].y = a = ( a + c + 1 ) >> 1;
930 base[4].y = b = ( b + c + 1 ) >> 1;
931 base[3].y = ( a + b + 1 ) >> 1;
935 /*************************************************************************/
936 /* */
937 /* <Function> */
938 /* Line_Up */
939 /* */
940 /* <Description> */
941 /* Computes the x-coordinates of an ascending line segment and stores */
942 /* them in the render pool. */
943 /* */
944 /* <Input> */
945 /* x1 :: The x-coordinate of the segment's start point. */
946 /* */
947 /* y1 :: The y-coordinate of the segment's start point. */
948 /* */
949 /* x2 :: The x-coordinate of the segment's end point. */
950 /* */
951 /* y2 :: The y-coordinate of the segment's end point. */
952 /* */
953 /* miny :: A lower vertical clipping bound value. */
954 /* */
955 /* maxy :: An upper vertical clipping bound value. */
956 /* */
957 /* <Return> */
958 /* SUCCESS on success, FAILURE on render pool overflow. */
959 /* */
960 static Bool
961 Line_Up( RAS_ARGS Long x1,
962 Long y1,
963 Long x2,
964 Long y2,
965 Long miny,
966 Long maxy )
968 Long Dx, Dy;
969 Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
970 Long Ix, Rx, Ax;
972 PLong top;
975 Dx = x2 - x1;
976 Dy = y2 - y1;
978 if ( Dy <= 0 || y2 < miny || y1 > maxy )
979 return SUCCESS;
981 if ( y1 < miny )
983 /* Take care: miny-y1 can be a very large value; we use */
984 /* a slow MulDiv function to avoid clipping bugs */
985 x1 += SMulDiv( Dx, miny - y1, Dy );
986 e1 = (Int)TRUNC( miny );
987 f1 = 0;
989 else
991 e1 = (Int)TRUNC( y1 );
992 f1 = (Int)FRAC( y1 );
995 if ( y2 > maxy )
997 /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
998 e2 = (Int)TRUNC( maxy );
999 f2 = 0;
1001 else
1003 e2 = (Int)TRUNC( y2 );
1004 f2 = (Int)FRAC( y2 );
1007 if ( f1 > 0 )
1009 if ( e1 == e2 )
1010 return SUCCESS;
1011 else
1013 x1 += FMulDiv( Dx, ras.precision - f1, Dy );
1014 e1 += 1;
1017 else
1018 if ( ras.joint )
1020 ras.top--;
1021 ras.joint = FALSE;
1024 ras.joint = (char)( f2 == 0 );
1026 if ( ras.fresh )
1028 ras.cProfile->start = e1;
1029 ras.fresh = FALSE;
1032 size = e2 - e1 + 1;
1033 if ( ras.top + size >= ras.maxBuff )
1035 ras.error = Raster_Err_Overflow;
1036 return FAILURE;
1039 if ( Dx > 0 )
1041 Ix = ( ras.precision * Dx ) / Dy;
1042 Rx = ( ras.precision * Dx ) % Dy;
1043 Dx = 1;
1045 else
1047 Ix = -( ( ras.precision * -Dx ) / Dy );
1048 Rx = ( ras.precision * -Dx ) % Dy;
1049 Dx = -1;
1052 Ax = -Dy;
1053 top = ras.top;
1055 while ( size > 0 )
1057 *top++ = x1;
1059 x1 += Ix;
1060 Ax += Rx;
1061 if ( Ax >= 0 )
1063 Ax -= Dy;
1064 x1 += Dx;
1066 size--;
1069 ras.top = top;
1070 return SUCCESS;
1074 /*************************************************************************/
1075 /* */
1076 /* <Function> */
1077 /* Line_Down */
1078 /* */
1079 /* <Description> */
1080 /* Computes the x-coordinates of an descending line segment and */
1081 /* stores them in the render pool. */
1082 /* */
1083 /* <Input> */
1084 /* x1 :: The x-coordinate of the segment's start point. */
1085 /* */
1086 /* y1 :: The y-coordinate of the segment's start point. */
1087 /* */
1088 /* x2 :: The x-coordinate of the segment's end point. */
1089 /* */
1090 /* y2 :: The y-coordinate of the segment's end point. */
1091 /* */
1092 /* miny :: A lower vertical clipping bound value. */
1093 /* */
1094 /* maxy :: An upper vertical clipping bound value. */
1095 /* */
1096 /* <Return> */
1097 /* SUCCESS on success, FAILURE on render pool overflow. */
1098 /* */
1099 static Bool
1100 Line_Down( RAS_ARGS Long x1,
1101 Long y1,
1102 Long x2,
1103 Long y2,
1104 Long miny,
1105 Long maxy )
1107 Bool result, fresh;
1110 fresh = ras.fresh;
1112 result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
1114 if ( fresh && !ras.fresh )
1115 ras.cProfile->start = -ras.cProfile->start;
1117 return result;
1121 /* A function type describing the functions used to split Bezier arcs */
1122 typedef void (*TSplitter)( TPoint* base );
1125 /*************************************************************************/
1126 /* */
1127 /* <Function> */
1128 /* Bezier_Up */
1129 /* */
1130 /* <Description> */
1131 /* Computes the x-coordinates of an ascending Bezier arc and stores */
1132 /* them in the render pool. */
1133 /* */
1134 /* <Input> */
1135 /* degree :: The degree of the Bezier arc (either 2 or 3). */
1136 /* */
1137 /* splitter :: The function to split Bezier arcs. */
1138 /* */
1139 /* miny :: A lower vertical clipping bound value. */
1140 /* */
1141 /* maxy :: An upper vertical clipping bound value. */
1142 /* */
1143 /* <Return> */
1144 /* SUCCESS on success, FAILURE on render pool overflow. */
1145 /* */
1146 static Bool
1147 Bezier_Up( RAS_ARGS Int degree,
1148 TSplitter splitter,
1149 Long miny,
1150 Long maxy )
1152 Long y1, y2, e, e2, e0;
1153 Short f1;
1155 TPoint* arc;
1156 TPoint* start_arc;
1158 PLong top;
1161 arc = ras.arc;
1162 y1 = arc[degree].y;
1163 y2 = arc[0].y;
1164 top = ras.top;
1166 if ( y2 < miny || y1 > maxy )
1167 goto Fin;
1169 e2 = FLOOR( y2 );
1171 if ( e2 > maxy )
1172 e2 = maxy;
1174 e0 = miny;
1176 if ( y1 < miny )
1177 e = miny;
1178 else
1180 e = CEILING( y1 );
1181 f1 = (Short)( FRAC( y1 ) );
1182 e0 = e;
1184 if ( f1 == 0 )
1186 if ( ras.joint )
1188 top--;
1189 ras.joint = FALSE;
1192 *top++ = arc[degree].x;
1194 e += ras.precision;
1198 if ( ras.fresh )
1200 ras.cProfile->start = TRUNC( e0 );
1201 ras.fresh = FALSE;
1204 if ( e2 < e )
1205 goto Fin;
1207 if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
1209 ras.top = top;
1210 ras.error = Raster_Err_Overflow;
1211 return FAILURE;
1214 start_arc = arc;
1216 while ( arc >= start_arc && e <= e2 )
1218 ras.joint = FALSE;
1220 y2 = arc[0].y;
1222 if ( y2 > e )
1224 y1 = arc[degree].y;
1225 if ( y2 - y1 >= ras.precision_step )
1227 splitter( arc );
1228 arc += degree;
1230 else
1232 *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
1233 e - y1, y2 - y1 );
1234 arc -= degree;
1235 e += ras.precision;
1238 else
1240 if ( y2 == e )
1242 ras.joint = TRUE;
1243 *top++ = arc[0].x;
1245 e += ras.precision;
1247 arc -= degree;
1251 Fin:
1252 ras.top = top;
1253 ras.arc -= degree;
1254 return SUCCESS;
1258 /*************************************************************************/
1259 /* */
1260 /* <Function> */
1261 /* Bezier_Down */
1262 /* */
1263 /* <Description> */
1264 /* Computes the x-coordinates of an descending Bezier arc and stores */
1265 /* them in the render pool. */
1266 /* */
1267 /* <Input> */
1268 /* degree :: The degree of the Bezier arc (either 2 or 3). */
1269 /* */
1270 /* splitter :: The function to split Bezier arcs. */
1271 /* */
1272 /* miny :: A lower vertical clipping bound value. */
1273 /* */
1274 /* maxy :: An upper vertical clipping bound value. */
1275 /* */
1276 /* <Return> */
1277 /* SUCCESS on success, FAILURE on render pool overflow. */
1278 /* */
1279 static Bool
1280 Bezier_Down( RAS_ARGS Int degree,
1281 TSplitter splitter,
1282 Long miny,
1283 Long maxy )
1285 TPoint* arc = ras.arc;
1286 Bool result, fresh;
1289 arc[0].y = -arc[0].y;
1290 arc[1].y = -arc[1].y;
1291 arc[2].y = -arc[2].y;
1292 if ( degree > 2 )
1293 arc[3].y = -arc[3].y;
1295 fresh = ras.fresh;
1297 result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
1299 if ( fresh && !ras.fresh )
1300 ras.cProfile->start = -ras.cProfile->start;
1302 arc[0].y = -arc[0].y;
1303 return result;
1307 /*************************************************************************/
1308 /* */
1309 /* <Function> */
1310 /* Line_To */
1311 /* */
1312 /* <Description> */
1313 /* Injects a new line segment and adjusts Profiles list. */
1314 /* */
1315 /* <Input> */
1316 /* x :: The x-coordinate of the segment's end point (its start point */
1317 /* is stored in `lastX'). */
1318 /* */
1319 /* y :: The y-coordinate of the segment's end point (its start point */
1320 /* is stored in `lastY'). */
1321 /* */
1322 /* <Return> */
1323 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1324 /* profile. */
1325 /* */
1326 static Bool
1327 Line_To( RAS_ARGS Long x,
1328 Long y )
1330 /* First, detect a change of direction */
1332 switch ( ras.state )
1334 case Unknown_State:
1335 if ( y > ras.lastY )
1337 if ( New_Profile( RAS_VARS Ascending_State ) )
1338 return FAILURE;
1340 else
1342 if ( y < ras.lastY )
1343 if ( New_Profile( RAS_VARS Descending_State ) )
1344 return FAILURE;
1346 break;
1348 case Ascending_State:
1349 if ( y < ras.lastY )
1351 if ( End_Profile( RAS_VAR ) ||
1352 New_Profile( RAS_VARS Descending_State ) )
1353 return FAILURE;
1355 break;
1357 case Descending_State:
1358 if ( y > ras.lastY )
1360 if ( End_Profile( RAS_VAR ) ||
1361 New_Profile( RAS_VARS Ascending_State ) )
1362 return FAILURE;
1364 break;
1366 default:
1370 /* Then compute the lines */
1372 switch ( ras.state )
1374 case Ascending_State:
1375 if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
1376 x, y, ras.minY, ras.maxY ) )
1377 return FAILURE;
1378 break;
1380 case Descending_State:
1381 if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
1382 x, y, ras.minY, ras.maxY ) )
1383 return FAILURE;
1384 break;
1386 default:
1390 ras.lastX = x;
1391 ras.lastY = y;
1393 return SUCCESS;
1397 /*************************************************************************/
1398 /* */
1399 /* <Function> */
1400 /* Conic_To */
1401 /* */
1402 /* <Description> */
1403 /* Injects a new conic arc and adjusts the profile list. */
1404 /* */
1405 /* <Input> */
1406 /* cx :: The x-coordinate of the arc's new control point. */
1407 /* */
1408 /* cy :: The y-coordinate of the arc's new control point. */
1409 /* */
1410 /* x :: The x-coordinate of the arc's end point (its start point is */
1411 /* stored in `lastX'). */
1412 /* */
1413 /* y :: The y-coordinate of the arc's end point (its start point is */
1414 /* stored in `lastY'). */
1415 /* */
1416 /* <Return> */
1417 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1418 /* profile. */
1419 /* */
1420 static Bool
1421 Conic_To( RAS_ARGS Long cx,
1422 Long cy,
1423 Long x,
1424 Long y )
1426 Long y1, y2, y3, x3, ymin, ymax;
1427 TStates state_bez;
1430 ras.arc = ras.arcs;
1431 ras.arc[2].x = ras.lastX;
1432 ras.arc[2].y = ras.lastY;
1433 ras.arc[1].x = cx; ras.arc[1].y = cy;
1434 ras.arc[0].x = x; ras.arc[0].y = y;
1438 y1 = ras.arc[2].y;
1439 y2 = ras.arc[1].y;
1440 y3 = ras.arc[0].y;
1441 x3 = ras.arc[0].x;
1443 /* first, categorize the Bezier arc */
1445 if ( y1 <= y3 )
1447 ymin = y1;
1448 ymax = y3;
1450 else
1452 ymin = y3;
1453 ymax = y1;
1456 if ( y2 < ymin || y2 > ymax )
1458 /* this arc has no given direction, split it! */
1459 Split_Conic( ras.arc );
1460 ras.arc += 2;
1462 else if ( y1 == y3 )
1464 /* this arc is flat, ignore it and pop it from the Bezier stack */
1465 ras.arc -= 2;
1467 else
1469 /* the arc is y-monotonous, either ascending or descending */
1470 /* detect a change of direction */
1471 state_bez = y1 < y3 ? Ascending_State : Descending_State;
1472 if ( ras.state != state_bez )
1474 /* finalize current profile if any */
1475 if ( ras.state != Unknown_State &&
1476 End_Profile( RAS_VAR ) )
1477 goto Fail;
1479 /* create a new profile */
1480 if ( New_Profile( RAS_VARS state_bez ) )
1481 goto Fail;
1484 /* now call the appropriate routine */
1485 if ( state_bez == Ascending_State )
1487 if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1488 goto Fail;
1490 else
1491 if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1492 goto Fail;
1495 } while ( ras.arc >= ras.arcs );
1497 ras.lastX = x3;
1498 ras.lastY = y3;
1500 return SUCCESS;
1502 Fail:
1503 return FAILURE;
1507 /*************************************************************************/
1508 /* */
1509 /* <Function> */
1510 /* Cubic_To */
1511 /* */
1512 /* <Description> */
1513 /* Injects a new cubic arc and adjusts the profile list. */
1514 /* */
1515 /* <Input> */
1516 /* cx1 :: The x-coordinate of the arc's first new control point. */
1517 /* */
1518 /* cy1 :: The y-coordinate of the arc's first new control point. */
1519 /* */
1520 /* cx2 :: The x-coordinate of the arc's second new control point. */
1521 /* */
1522 /* cy2 :: The y-coordinate of the arc's second new control point. */
1523 /* */
1524 /* x :: The x-coordinate of the arc's end point (its start point is */
1525 /* stored in `lastX'). */
1526 /* */
1527 /* y :: The y-coordinate of the arc's end point (its start point is */
1528 /* stored in `lastY'). */
1529 /* */
1530 /* <Return> */
1531 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1532 /* profile. */
1533 /* */
1534 static Bool
1535 Cubic_To( RAS_ARGS Long cx1,
1536 Long cy1,
1537 Long cx2,
1538 Long cy2,
1539 Long x,
1540 Long y )
1542 Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
1543 TStates state_bez;
1546 ras.arc = ras.arcs;
1547 ras.arc[3].x = ras.lastX;
1548 ras.arc[3].y = ras.lastY;
1549 ras.arc[2].x = cx1; ras.arc[2].y = cy1;
1550 ras.arc[1].x = cx2; ras.arc[1].y = cy2;
1551 ras.arc[0].x = x; ras.arc[0].y = y;
1555 y1 = ras.arc[3].y;
1556 y2 = ras.arc[2].y;
1557 y3 = ras.arc[1].y;
1558 y4 = ras.arc[0].y;
1559 x4 = ras.arc[0].x;
1561 /* first, categorize the Bezier arc */
1563 if ( y1 <= y4 )
1565 ymin1 = y1;
1566 ymax1 = y4;
1568 else
1570 ymin1 = y4;
1571 ymax1 = y1;
1574 if ( y2 <= y3 )
1576 ymin2 = y2;
1577 ymax2 = y3;
1579 else
1581 ymin2 = y3;
1582 ymax2 = y2;
1585 if ( ymin2 < ymin1 || ymax2 > ymax1 )
1587 /* this arc has no given direction, split it! */
1588 Split_Cubic( ras.arc );
1589 ras.arc += 3;
1591 else if ( y1 == y4 )
1593 /* this arc is flat, ignore it and pop it from the Bezier stack */
1594 ras.arc -= 3;
1596 else
1598 state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
1600 /* detect a change of direction */
1601 if ( ras.state != state_bez )
1603 if ( ras.state != Unknown_State &&
1604 End_Profile( RAS_VAR ) )
1605 goto Fail;
1607 if ( New_Profile( RAS_VARS state_bez ) )
1608 goto Fail;
1611 /* compute intersections */
1612 if ( state_bez == Ascending_State )
1614 if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1615 goto Fail;
1617 else
1618 if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1619 goto Fail;
1622 } while ( ras.arc >= ras.arcs );
1624 ras.lastX = x4;
1625 ras.lastY = y4;
1627 return SUCCESS;
1629 Fail:
1630 return FAILURE;
1634 #undef SWAP_
1635 #define SWAP_( x, y ) do \
1637 Long swap = x; \
1640 x = y; \
1641 y = swap; \
1642 } while ( 0 )
1645 /*************************************************************************/
1646 /* */
1647 /* <Function> */
1648 /* Decompose_Curve */
1649 /* */
1650 /* <Description> */
1651 /* Scans the outline arrays in order to emit individual segments and */
1652 /* Beziers by calling Line_To() and Bezier_To(). It handles all */
1653 /* weird cases, like when the first point is off the curve, or when */
1654 /* there are simply no `on' points in the contour! */
1655 /* */
1656 /* <Input> */
1657 /* first :: The index of the first point in the contour. */
1658 /* */
1659 /* last :: The index of the last point in the contour. */
1660 /* */
1661 /* flipped :: If set, flip the direction of the curve. */
1662 /* */
1663 /* <Return> */
1664 /* SUCCESS on success, FAILURE on error. */
1665 /* */
1666 static Bool
1667 Decompose_Curve( RAS_ARGS UShort first,
1668 UShort last,
1669 int flipped )
1671 FT_Vector v_last;
1672 FT_Vector v_control;
1673 FT_Vector v_start;
1675 FT_Vector* points;
1676 FT_Vector* point;
1677 FT_Vector* limit;
1678 char* tags;
1680 unsigned tag; /* current point's state */
1683 points = ras.outline.points;
1684 limit = points + last;
1686 v_start.x = SCALED( points[first].x );
1687 v_start.y = SCALED( points[first].y );
1688 v_last.x = SCALED( points[last].x );
1689 v_last.y = SCALED( points[last].y );
1691 if ( flipped )
1693 SWAP_( v_start.x, v_start.y );
1694 SWAP_( v_last.x, v_last.y );
1697 v_control = v_start;
1699 point = points + first;
1700 tags = ras.outline.tags + first;
1701 tag = FT_CURVE_TAG( tags[0] );
1703 /* A contour cannot start with a cubic control point! */
1704 if ( tag == FT_CURVE_TAG_CUBIC )
1705 goto Invalid_Outline;
1707 /* check first point to determine origin */
1708 if ( tag == FT_CURVE_TAG_CONIC )
1710 /* first point is conic control. Yes, this happens. */
1711 if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
1713 /* start at last point if it is on the curve */
1714 v_start = v_last;
1715 limit--;
1717 else
1719 /* if both first and last points are conic, */
1720 /* start at their middle and record its position */
1721 /* for closure */
1722 v_start.x = ( v_start.x + v_last.x ) / 2;
1723 v_start.y = ( v_start.y + v_last.y ) / 2;
1725 v_last = v_start;
1727 point--;
1728 tags--;
1731 ras.lastX = v_start.x;
1732 ras.lastY = v_start.y;
1734 while ( point < limit )
1736 point++;
1737 tags++;
1739 tag = FT_CURVE_TAG( tags[0] );
1741 switch ( tag )
1743 case FT_CURVE_TAG_ON: /* emit a single line_to */
1745 Long x, y;
1748 x = SCALED( point->x );
1749 y = SCALED( point->y );
1750 if ( flipped )
1751 SWAP_( x, y );
1753 if ( Line_To( RAS_VARS x, y ) )
1754 goto Fail;
1755 continue;
1758 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1759 v_control.x = SCALED( point[0].x );
1760 v_control.y = SCALED( point[0].y );
1762 if ( flipped )
1763 SWAP_( v_control.x, v_control.y );
1765 Do_Conic:
1766 if ( point < limit )
1768 FT_Vector v_middle;
1769 Long x, y;
1772 point++;
1773 tags++;
1774 tag = FT_CURVE_TAG( tags[0] );
1776 x = SCALED( point[0].x );
1777 y = SCALED( point[0].y );
1779 if ( flipped )
1780 SWAP_( x, y );
1782 if ( tag == FT_CURVE_TAG_ON )
1784 if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
1785 goto Fail;
1786 continue;
1789 if ( tag != FT_CURVE_TAG_CONIC )
1790 goto Invalid_Outline;
1792 v_middle.x = ( v_control.x + x ) / 2;
1793 v_middle.y = ( v_control.y + y ) / 2;
1795 if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1796 v_middle.x, v_middle.y ) )
1797 goto Fail;
1799 v_control.x = x;
1800 v_control.y = y;
1802 goto Do_Conic;
1805 if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1806 v_start.x, v_start.y ) )
1807 goto Fail;
1809 goto Close;
1811 default: /* FT_CURVE_TAG_CUBIC */
1813 Long x1, y1, x2, y2, x3, y3;
1816 if ( point + 1 > limit ||
1817 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1818 goto Invalid_Outline;
1820 point += 2;
1821 tags += 2;
1823 x1 = SCALED( point[-2].x );
1824 y1 = SCALED( point[-2].y );
1825 x2 = SCALED( point[-1].x );
1826 y2 = SCALED( point[-1].y );
1827 x3 = SCALED( point[ 0].x );
1828 y3 = SCALED( point[ 0].y );
1830 if ( flipped )
1832 SWAP_( x1, y1 );
1833 SWAP_( x2, y2 );
1834 SWAP_( x3, y3 );
1837 if ( point <= limit )
1839 if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
1840 goto Fail;
1841 continue;
1844 if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
1845 goto Fail;
1846 goto Close;
1851 /* close the contour with a line segment */
1852 if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
1853 goto Fail;
1855 Close:
1856 return SUCCESS;
1858 Invalid_Outline:
1859 ras.error = Raster_Err_Invalid;
1861 Fail:
1862 return FAILURE;
1866 /*************************************************************************/
1867 /* */
1868 /* <Function> */
1869 /* Convert_Glyph */
1870 /* */
1871 /* <Description> */
1872 /* Converts a glyph into a series of segments and arcs and makes a */
1873 /* profiles list with them. */
1874 /* */
1875 /* <Input> */
1876 /* flipped :: If set, flip the direction of curve. */
1877 /* */
1878 /* <Return> */
1879 /* SUCCESS on success, FAILURE if any error was encountered during */
1880 /* rendering. */
1881 /* */
1882 static Bool
1883 Convert_Glyph( RAS_ARGS int flipped )
1885 int i;
1886 unsigned start;
1888 PProfile lastProfile;
1891 ras.fProfile = NULL;
1892 ras.joint = FALSE;
1893 ras.fresh = FALSE;
1895 ras.maxBuff = ras.sizeBuff - AlignProfileSize;
1897 ras.numTurns = 0;
1899 ras.cProfile = (PProfile)ras.top;
1900 ras.cProfile->offset = ras.top;
1901 ras.num_Profs = 0;
1903 start = 0;
1905 for ( i = 0; i < ras.outline.n_contours; i++ )
1907 ras.state = Unknown_State;
1908 ras.gProfile = NULL;
1910 if ( Decompose_Curve( RAS_VARS (unsigned short)start,
1911 ras.outline.contours[i],
1912 flipped ) )
1913 return FAILURE;
1915 start = ras.outline.contours[i] + 1;
1917 /* We must now see whether the extreme arcs join or not */
1918 if ( FRAC( ras.lastY ) == 0 &&
1919 ras.lastY >= ras.minY &&
1920 ras.lastY <= ras.maxY )
1921 if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
1922 ras.top--;
1923 /* Note that ras.gProfile can be nil if the contour was too small */
1924 /* to be drawn. */
1926 lastProfile = ras.cProfile;
1927 if ( End_Profile( RAS_VAR ) )
1928 return FAILURE;
1930 /* close the `next profile in contour' linked list */
1931 if ( ras.gProfile )
1932 lastProfile->next = ras.gProfile;
1935 if ( Finalize_Profile_Table( RAS_VAR ) )
1936 return FAILURE;
1938 return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
1942 /*************************************************************************/
1943 /*************************************************************************/
1944 /** **/
1945 /** SCAN-LINE SWEEPS AND DRAWING **/
1946 /** **/
1947 /*************************************************************************/
1948 /*************************************************************************/
1951 /*************************************************************************/
1952 /* */
1953 /* Init_Linked */
1954 /* */
1955 /* Initializes an empty linked list. */
1956 /* */
1957 static void
1958 Init_Linked( TProfileList* l )
1960 *l = NULL;
1964 /*************************************************************************/
1965 /* */
1966 /* InsNew */
1967 /* */
1968 /* Inserts a new profile in a linked list. */
1969 /* */
1970 static void
1971 InsNew( PProfileList list,
1972 PProfile profile )
1974 PProfile *old, current;
1975 Long x;
1978 old = list;
1979 current = *old;
1980 x = profile->X;
1982 while ( current )
1984 if ( x < current->X )
1985 break;
1986 old = &current->link;
1987 current = *old;
1990 profile->link = current;
1991 *old = profile;
1995 /*************************************************************************/
1996 /* */
1997 /* DelOld */
1998 /* */
1999 /* Removes an old profile from a linked list. */
2000 /* */
2001 static void
2002 DelOld( PProfileList list,
2003 PProfile profile )
2005 PProfile *old, current;
2008 old = list;
2009 current = *old;
2011 while ( current )
2013 if ( current == profile )
2015 *old = current->link;
2016 return;
2019 old = &current->link;
2020 current = *old;
2023 /* we should never get there, unless the profile was not part of */
2024 /* the list. */
2028 /*************************************************************************/
2029 /* */
2030 /* Sort */
2031 /* */
2032 /* Sorts a trace list. In 95%, the list is already sorted. We need */
2033 /* an algorithm which is fast in this case. Bubble sort is enough */
2034 /* and simple. */
2035 /* */
2036 static void
2037 Sort( PProfileList list )
2039 PProfile *old, current, next;
2042 /* First, set the new X coordinate of each profile */
2043 current = *list;
2044 while ( current )
2046 current->X = *current->offset;
2047 current->offset += current->flow;
2048 current->height--;
2049 current = current->link;
2052 /* Then sort them */
2053 old = list;
2054 current = *old;
2056 if ( !current )
2057 return;
2059 next = current->link;
2061 while ( next )
2063 if ( current->X <= next->X )
2065 old = &current->link;
2066 current = *old;
2068 if ( !current )
2069 return;
2071 else
2073 *old = next;
2074 current->link = next->link;
2075 next->link = current;
2077 old = list;
2078 current = *old;
2081 next = current->link;
2086 /*************************************************************************/
2087 /* */
2088 /* Vertical Sweep Procedure Set */
2089 /* */
2090 /* These four routines are used during the vertical black/white sweep */
2091 /* phase by the generic Draw_Sweep() function. */
2092 /* */
2093 /*************************************************************************/
2095 static void
2096 Vertical_Sweep_Init( RAS_ARGS Short* min,
2097 Short* max )
2099 Long pitch = ras.target.pitch;
2101 FT_UNUSED( max );
2104 ras.traceIncr = (Short)-pitch;
2105 ras.traceOfs = -*min * pitch;
2106 if ( pitch > 0 )
2107 ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
2109 ras.gray_min_x = 0;
2110 ras.gray_max_x = 0;
2114 static void
2115 Vertical_Sweep_Span( RAS_ARGS Short y,
2116 FT_F26Dot6 x1,
2117 FT_F26Dot6 x2,
2118 PProfile left,
2119 PProfile right )
2121 Long e1, e2;
2122 int c1, c2;
2123 Byte f1, f2;
2124 Byte* target;
2126 FT_UNUSED( y );
2127 FT_UNUSED( left );
2128 FT_UNUSED( right );
2131 /* Drop-out control */
2133 e1 = TRUNC( CEILING( x1 ) );
2135 if ( x2 - x1 - ras.precision <= ras.precision_jitter )
2136 e2 = e1;
2137 else
2138 e2 = TRUNC( FLOOR( x2 ) );
2140 if ( e2 >= 0 && e1 < ras.bWidth )
2142 if ( e1 < 0 )
2143 e1 = 0;
2144 if ( e2 >= ras.bWidth )
2145 e2 = ras.bWidth - 1;
2147 c1 = (Short)( e1 >> 3 );
2148 c2 = (Short)( e2 >> 3 );
2150 f1 = (Byte) ( 0xFF >> ( e1 & 7 ) );
2151 f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
2153 if ( ras.gray_min_x > c1 )
2154 ras.gray_min_x = (short)c1;
2155 if ( ras.gray_max_x < c2 )
2156 ras.gray_max_x = (short)c2;
2158 target = ras.bTarget + ras.traceOfs + c1;
2159 c2 -= c1;
2161 if ( c2 > 0 )
2163 target[0] |= f1;
2165 /* memset() is slower than the following code on many platforms. */
2166 /* This is due to the fact that, in the vast majority of cases, */
2167 /* the span length in bytes is relatively small. */
2168 c2--;
2169 while ( c2 > 0 )
2171 *(++target) = 0xFF;
2172 c2--;
2174 target[1] |= f2;
2176 else
2177 *target |= ( f1 & f2 );
2182 static void
2183 Vertical_Sweep_Drop( RAS_ARGS Short y,
2184 FT_F26Dot6 x1,
2185 FT_F26Dot6 x2,
2186 PProfile left,
2187 PProfile right )
2189 Long e1, e2, pxl;
2190 Short c1, f1;
2193 /* Drop-out control */
2195 /* e2 x2 x1 e1 */
2196 /* */
2197 /* ^ | */
2198 /* | | */
2199 /* +-------------+---------------------+------------+ */
2200 /* | | */
2201 /* | v */
2202 /* */
2203 /* pixel contour contour pixel */
2204 /* center center */
2206 /* drop-out mode scan conversion rules (as defined in OpenType) */
2207 /* --------------------------------------------------------------- */
2208 /* 0 1, 2, 3 */
2209 /* 1 1, 2, 4 */
2210 /* 2 1, 2 */
2211 /* 3 same as mode 2 */
2212 /* 4 1, 2, 5 */
2213 /* 5 1, 2, 6 */
2214 /* 6, 7 same as mode 2 */
2216 e1 = CEILING( x1 );
2217 e2 = FLOOR ( x2 );
2218 pxl = e1;
2220 if ( e1 > e2 )
2222 if ( e1 == e2 + ras.precision )
2224 switch ( ras.dropOutControl )
2226 case 0: /* simple drop-outs including stubs */
2227 pxl = e2;
2228 break;
2230 case 4: /* smart drop-outs including stubs */
2231 pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
2232 break;
2234 case 1: /* simple drop-outs excluding stubs */
2235 case 5: /* smart drop-outs excluding stubs */
2237 /* Drop-out Control Rules #4 and #6 */
2239 /* The spec is not very clear regarding those rules. It */
2240 /* presents a method that is way too costly to implement */
2241 /* while the general idea seems to get rid of `stubs'. */
2242 /* */
2243 /* Here, we only get rid of stubs recognized if: */
2244 /* */
2245 /* upper stub: */
2246 /* */
2247 /* - P_Left and P_Right are in the same contour */
2248 /* - P_Right is the successor of P_Left in that contour */
2249 /* - y is the top of P_Left and P_Right */
2250 /* */
2251 /* lower stub: */
2252 /* */
2253 /* - P_Left and P_Right are in the same contour */
2254 /* - P_Left is the successor of P_Right in that contour */
2255 /* - y is the bottom of P_Left */
2256 /* */
2258 /* FIXXXME: uncommenting this line solves the disappearing */
2259 /* bit problem in the `7' of verdana 10pts, but */
2260 /* makes a new one in the `C' of arial 14pts */
2261 #if 0
2262 if ( x2 - x1 < ras.precision_half )
2263 #endif
2265 /* upper stub test */
2266 if ( left->next == right && left->height <= 0 )
2267 return;
2269 /* lower stub test */
2270 if ( right->next == left && left->start == y )
2271 return;
2274 if ( ras.dropOutControl == 1 )
2275 pxl = e2;
2276 else
2277 pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
2278 break;
2280 default: /* modes 2, 3, 6, 7 */
2281 return; /* no drop-out control */
2284 /* check that the other pixel isn't set */
2285 e1 = pxl == e1 ? e2 : e1;
2287 e1 = TRUNC( e1 );
2289 c1 = (Short)( e1 >> 3 );
2290 f1 = (Short)( e1 & 7 );
2292 if ( e1 >= 0 && e1 < ras.bWidth &&
2293 ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
2294 return;
2296 else
2297 return;
2300 e1 = TRUNC( pxl );
2302 if ( e1 >= 0 && e1 < ras.bWidth )
2304 c1 = (Short)( e1 >> 3 );
2305 f1 = (Short)( e1 & 7 );
2307 if ( ras.gray_min_x > c1 )
2308 ras.gray_min_x = c1;
2309 if ( ras.gray_max_x < c1 )
2310 ras.gray_max_x = c1;
2312 ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
2317 static void
2318 Vertical_Sweep_Step( RAS_ARG )
2320 ras.traceOfs += ras.traceIncr;
2324 /***********************************************************************/
2325 /* */
2326 /* Horizontal Sweep Procedure Set */
2327 /* */
2328 /* These four routines are used during the horizontal black/white */
2329 /* sweep phase by the generic Draw_Sweep() function. */
2330 /* */
2331 /***********************************************************************/
2333 static void
2334 Horizontal_Sweep_Init( RAS_ARGS Short* min,
2335 Short* max )
2337 /* nothing, really */
2338 FT_UNUSED_RASTER;
2339 FT_UNUSED( min );
2340 FT_UNUSED( max );
2344 static void
2345 Horizontal_Sweep_Span( RAS_ARGS Short y,
2346 FT_F26Dot6 x1,
2347 FT_F26Dot6 x2,
2348 PProfile left,
2349 PProfile right )
2351 Long e1, e2;
2352 PByte bits;
2353 Byte f1;
2355 FT_UNUSED( left );
2356 FT_UNUSED( right );
2359 if ( x2 - x1 < ras.precision )
2361 e1 = CEILING( x1 );
2362 e2 = FLOOR ( x2 );
2364 if ( e1 == e2 )
2366 bits = ras.bTarget + ( y >> 3 );
2367 f1 = (Byte)( 0x80 >> ( y & 7 ) );
2369 e1 = TRUNC( e1 );
2371 if ( e1 >= 0 && e1 < ras.target.rows )
2373 PByte p;
2376 p = bits - e1*ras.target.pitch;
2377 if ( ras.target.pitch > 0 )
2378 p += ( ras.target.rows - 1 ) * ras.target.pitch;
2380 p[0] |= f1;
2387 static void
2388 Horizontal_Sweep_Drop( RAS_ARGS Short y,
2389 FT_F26Dot6 x1,
2390 FT_F26Dot6 x2,
2391 PProfile left,
2392 PProfile right )
2394 Long e1, e2, pxl;
2395 PByte bits;
2396 Byte f1;
2399 /* During the horizontal sweep, we only take care of drop-outs */
2401 /* e1 + <-- pixel center */
2402 /* | */
2403 /* x1 ---+--> <-- contour */
2404 /* | */
2405 /* | */
2406 /* x2 <--+--- <-- contour */
2407 /* | */
2408 /* | */
2409 /* e2 + <-- pixel center */
2411 e1 = CEILING( x1 );
2412 e2 = FLOOR ( x2 );
2413 pxl = e1;
2415 if ( e1 > e2 )
2417 if ( e1 == e2 + ras.precision )
2419 switch ( ras.dropOutControl )
2421 case 0: /* simple drop-outs including stubs */
2422 pxl = e2;
2423 break;
2425 case 4: /* smart drop-outs including stubs */
2426 pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
2427 break;
2429 case 1: /* simple drop-outs excluding stubs */
2430 case 5: /* smart drop-outs excluding stubs */
2431 /* see Vertical_Sweep_Drop for details */
2433 /* rightmost stub test */
2434 if ( left->next == right && left->height <= 0 )
2435 return;
2437 /* leftmost stub test */
2438 if ( right->next == left && left->start == y )
2439 return;
2441 if ( ras.dropOutControl == 1 )
2442 pxl = e2;
2443 else
2444 pxl = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
2445 break;
2447 default: /* modes 2, 3, 6, 7 */
2448 return; /* no drop-out control */
2451 /* check that the other pixel isn't set */
2452 e1 = pxl == e1 ? e2 : e1;
2454 e1 = TRUNC( e1 );
2456 bits = ras.bTarget + ( y >> 3 );
2457 f1 = (Byte)( 0x80 >> ( y & 7 ) );
2459 bits -= e1 * ras.target.pitch;
2460 if ( ras.target.pitch > 0 )
2461 bits += ( ras.target.rows - 1 ) * ras.target.pitch;
2463 if ( e1 >= 0 &&
2464 e1 < ras.target.rows &&
2465 *bits & f1 )
2466 return;
2468 else
2469 return;
2472 bits = ras.bTarget + ( y >> 3 );
2473 f1 = (Byte)( 0x80 >> ( y & 7 ) );
2475 e1 = TRUNC( pxl );
2477 if ( e1 >= 0 && e1 < ras.target.rows )
2479 bits -= e1 * ras.target.pitch;
2480 if ( ras.target.pitch > 0 )
2481 bits += ( ras.target.rows - 1 ) * ras.target.pitch;
2483 bits[0] |= f1;
2488 static void
2489 Horizontal_Sweep_Step( RAS_ARG )
2491 /* Nothing, really */
2492 FT_UNUSED_RASTER;
2496 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
2499 /*************************************************************************/
2500 /* */
2501 /* Vertical Gray Sweep Procedure Set */
2502 /* */
2503 /* These two routines are used during the vertical gray-levels sweep */
2504 /* phase by the generic Draw_Sweep() function. */
2505 /* */
2506 /* NOTES */
2507 /* */
2508 /* - The target pixmap's width *must* be a multiple of 4. */
2509 /* */
2510 /* - You have to use the function Vertical_Sweep_Span() for the gray */
2511 /* span call. */
2512 /* */
2513 /*************************************************************************/
2515 static void
2516 Vertical_Gray_Sweep_Init( RAS_ARGS Short* min,
2517 Short* max )
2519 Long pitch, byte_len;
2522 *min = *min & -2;
2523 *max = ( *max + 3 ) & -2;
2525 ras.traceOfs = 0;
2526 pitch = ras.target.pitch;
2527 byte_len = -pitch;
2528 ras.traceIncr = (Short)byte_len;
2529 ras.traceG = ( *min / 2 ) * byte_len;
2531 if ( pitch > 0 )
2533 ras.traceG += ( ras.target.rows - 1 ) * pitch;
2534 byte_len = -byte_len;
2537 ras.gray_min_x = (Short)byte_len;
2538 ras.gray_max_x = -(Short)byte_len;
2542 static void
2543 Vertical_Gray_Sweep_Step( RAS_ARG )
2545 Int c1, c2;
2546 PByte pix, bit, bit2;
2547 char* count = (char*)count_table;
2548 Byte* grays;
2551 ras.traceOfs += ras.gray_width;
2553 if ( ras.traceOfs > ras.gray_width )
2555 pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
2556 grays = ras.grays;
2558 if ( ras.gray_max_x >= 0 )
2560 Long last_pixel = ras.target.width - 1;
2561 Int last_cell = last_pixel >> 2;
2562 Int last_bit = last_pixel & 3;
2563 Bool over = 0;
2566 if ( ras.gray_max_x >= last_cell && last_bit != 3 )
2568 ras.gray_max_x = last_cell - 1;
2569 over = 1;
2572 if ( ras.gray_min_x < 0 )
2573 ras.gray_min_x = 0;
2575 bit = ras.bTarget + ras.gray_min_x;
2576 bit2 = bit + ras.gray_width;
2578 c1 = ras.gray_max_x - ras.gray_min_x;
2580 while ( c1 >= 0 )
2582 c2 = count[*bit] + count[*bit2];
2584 if ( c2 )
2586 pix[0] = grays[(c2 >> 12) & 0x000F];
2587 pix[1] = grays[(c2 >> 8 ) & 0x000F];
2588 pix[2] = grays[(c2 >> 4 ) & 0x000F];
2589 pix[3] = grays[ c2 & 0x000F];
2591 *bit = 0;
2592 *bit2 = 0;
2595 bit++;
2596 bit2++;
2597 pix += 4;
2598 c1--;
2601 if ( over )
2603 c2 = count[*bit] + count[*bit2];
2604 if ( c2 )
2606 switch ( last_bit )
2608 case 2:
2609 pix[2] = grays[(c2 >> 4 ) & 0x000F];
2610 case 1:
2611 pix[1] = grays[(c2 >> 8 ) & 0x000F];
2612 default:
2613 pix[0] = grays[(c2 >> 12) & 0x000F];
2616 *bit = 0;
2617 *bit2 = 0;
2622 ras.traceOfs = 0;
2623 ras.traceG += ras.traceIncr;
2625 ras.gray_min_x = 32000;
2626 ras.gray_max_x = -32000;
2631 static void
2632 Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
2633 FT_F26Dot6 x1,
2634 FT_F26Dot6 x2,
2635 PProfile left,
2636 PProfile right )
2638 /* nothing, really */
2639 FT_UNUSED_RASTER;
2640 FT_UNUSED( y );
2641 FT_UNUSED( x1 );
2642 FT_UNUSED( x2 );
2643 FT_UNUSED( left );
2644 FT_UNUSED( right );
2648 static void
2649 Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
2650 FT_F26Dot6 x1,
2651 FT_F26Dot6 x2,
2652 PProfile left,
2653 PProfile right )
2655 Long e1, e2;
2656 PByte pixel;
2657 Byte color;
2660 /* During the horizontal sweep, we only take care of drop-outs */
2662 e1 = CEILING( x1 );
2663 e2 = FLOOR ( x2 );
2665 if ( e1 > e2 )
2667 if ( e1 == e2 + ras.precision )
2669 switch ( ras.dropOutControl )
2671 case 0: /* simple drop-outs including stubs */
2672 e1 = e2;
2673 break;
2675 case 4: /* smart drop-outs including stubs */
2676 e1 = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
2677 break;
2679 case 1: /* simple drop-outs excluding stubs */
2680 case 5: /* smart drop-outs excluding stubs */
2681 /* see Vertical_Sweep_Drop for details */
2683 /* rightmost stub test */
2684 if ( left->next == right && left->height <= 0 )
2685 return;
2687 /* leftmost stub test */
2688 if ( right->next == left && left->start == y )
2689 return;
2691 if ( ras.dropOutControl == 1 )
2692 e1 = e2;
2693 else
2694 e1 = FLOOR( ( x1 + x2 + 1 ) / 2 + ras.precision_half );
2696 break;
2698 default: /* modes 2, 3, 6, 7 */
2699 return; /* no drop-out control */
2702 else
2703 return;
2706 if ( e1 >= 0 )
2708 if ( x2 - x1 >= ras.precision_half )
2709 color = ras.grays[2];
2710 else
2711 color = ras.grays[1];
2713 e1 = TRUNC( e1 ) / 2;
2714 if ( e1 < ras.target.rows )
2716 pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
2717 if ( ras.target.pitch > 0 )
2718 pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
2720 if ( pixel[0] == ras.grays[0] )
2721 pixel[0] = color;
2727 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
2730 /*************************************************************************/
2731 /* */
2732 /* Generic Sweep Drawing routine */
2733 /* */
2734 /*************************************************************************/
2736 static Bool
2737 Draw_Sweep( RAS_ARG )
2739 Short y, y_change, y_height;
2741 PProfile P, Q, P_Left, P_Right;
2743 Short min_Y, max_Y, top, bottom, dropouts;
2745 Long x1, x2, xs, e1, e2;
2747 TProfileList waiting;
2748 TProfileList draw_left, draw_right;
2751 /* Init empty linked lists */
2753 Init_Linked( &waiting );
2755 Init_Linked( &draw_left );
2756 Init_Linked( &draw_right );
2758 /* first, compute min and max Y */
2760 P = ras.fProfile;
2761 max_Y = (Short)TRUNC( ras.minY );
2762 min_Y = (Short)TRUNC( ras.maxY );
2764 while ( P )
2766 Q = P->link;
2768 bottom = (Short)P->start;
2769 top = (Short)( P->start + P->height - 1 );
2771 if ( min_Y > bottom )
2772 min_Y = bottom;
2773 if ( max_Y < top )
2774 max_Y = top;
2776 P->X = 0;
2777 InsNew( &waiting, P );
2779 P = Q;
2782 /* Check the Y-turns */
2783 if ( ras.numTurns == 0 )
2785 ras.error = Raster_Err_Invalid;
2786 return FAILURE;
2789 /* Now inits the sweep */
2791 ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
2793 /* Then compute the distance of each profile from min_Y */
2795 P = waiting;
2797 while ( P )
2799 P->countL = (UShort)( P->start - min_Y );
2800 P = P->link;
2803 /* Let's go */
2805 y = min_Y;
2806 y_height = 0;
2808 if ( ras.numTurns > 0 &&
2809 ras.sizeBuff[-ras.numTurns] == min_Y )
2810 ras.numTurns--;
2812 while ( ras.numTurns > 0 )
2814 /* look in the waiting list for new activations */
2816 P = waiting;
2818 while ( P )
2820 Q = P->link;
2821 P->countL -= y_height;
2822 if ( P->countL == 0 )
2824 DelOld( &waiting, P );
2826 switch ( P->flow )
2828 case Flow_Up:
2829 InsNew( &draw_left, P );
2830 break;
2832 case Flow_Down:
2833 InsNew( &draw_right, P );
2834 break;
2838 P = Q;
2841 /* Sort the drawing lists */
2843 Sort( &draw_left );
2844 Sort( &draw_right );
2846 y_change = (Short)ras.sizeBuff[-ras.numTurns--];
2847 y_height = (Short)( y_change - y );
2849 while ( y < y_change )
2851 /* Let's trace */
2853 dropouts = 0;
2855 P_Left = draw_left;
2856 P_Right = draw_right;
2858 while ( P_Left )
2860 x1 = P_Left ->X;
2861 x2 = P_Right->X;
2863 if ( x1 > x2 )
2865 xs = x1;
2866 x1 = x2;
2867 x2 = xs;
2870 if ( x2 - x1 <= ras.precision )
2872 e1 = FLOOR( x1 );
2873 e2 = CEILING( x2 );
2875 if ( e1 > e2 || e2 == e1 + ras.precision )
2877 if ( ras.dropOutControl != 2 )
2879 /* a drop out was detected */
2881 P_Left ->X = x1;
2882 P_Right->X = x2;
2884 /* mark profile for drop-out processing */
2885 P_Left->countL = 1;
2886 dropouts++;
2889 goto Skip_To_Next;
2893 ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
2895 Skip_To_Next:
2897 P_Left = P_Left->link;
2898 P_Right = P_Right->link;
2901 /* now perform the dropouts _after_ the span drawing -- */
2902 /* drop-outs processing has been moved out of the loop */
2903 /* for performance tuning */
2904 if ( dropouts > 0 )
2905 goto Scan_DropOuts;
2907 Next_Line:
2909 ras.Proc_Sweep_Step( RAS_VAR );
2911 y++;
2913 if ( y < y_change )
2915 Sort( &draw_left );
2916 Sort( &draw_right );
2920 /* Now finalize the profiles that needs it */
2922 P = draw_left;
2923 while ( P )
2925 Q = P->link;
2926 if ( P->height == 0 )
2927 DelOld( &draw_left, P );
2928 P = Q;
2931 P = draw_right;
2932 while ( P )
2934 Q = P->link;
2935 if ( P->height == 0 )
2936 DelOld( &draw_right, P );
2937 P = Q;
2941 /* for gray-scaling, flushes the bitmap scanline cache */
2942 while ( y <= max_Y )
2944 ras.Proc_Sweep_Step( RAS_VAR );
2945 y++;
2948 return SUCCESS;
2950 Scan_DropOuts:
2952 P_Left = draw_left;
2953 P_Right = draw_right;
2955 while ( P_Left )
2957 if ( P_Left->countL )
2959 P_Left->countL = 0;
2960 #if 0
2961 dropouts--; /* -- this is useful when debugging only */
2962 #endif
2963 ras.Proc_Sweep_Drop( RAS_VARS y,
2964 P_Left->X,
2965 P_Right->X,
2966 P_Left,
2967 P_Right );
2970 P_Left = P_Left->link;
2971 P_Right = P_Right->link;
2974 goto Next_Line;
2978 /*************************************************************************/
2979 /* */
2980 /* <Function> */
2981 /* Render_Single_Pass */
2982 /* */
2983 /* <Description> */
2984 /* Performs one sweep with sub-banding. */
2985 /* */
2986 /* <Input> */
2987 /* flipped :: If set, flip the direction of the outline. */
2988 /* */
2989 /* <Return> */
2990 /* Renderer error code. */
2991 /* */
2992 static int
2993 Render_Single_Pass( RAS_ARGS Bool flipped )
2995 Short i, j, k;
2998 while ( ras.band_top >= 0 )
3000 ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
3001 ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
3003 ras.top = ras.buff;
3005 ras.error = Raster_Err_None;
3007 if ( Convert_Glyph( RAS_VARS flipped ) )
3009 if ( ras.error != Raster_Err_Overflow )
3010 return FAILURE;
3012 ras.error = Raster_Err_None;
3014 /* sub-banding */
3016 #ifdef DEBUG_RASTER
3017 ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
3018 #endif
3020 i = ras.band_stack[ras.band_top].y_min;
3021 j = ras.band_stack[ras.band_top].y_max;
3023 k = (Short)( ( i + j ) / 2 );
3025 if ( ras.band_top >= 7 || k < i )
3027 ras.band_top = 0;
3028 ras.error = Raster_Err_Invalid;
3030 return ras.error;
3033 ras.band_stack[ras.band_top + 1].y_min = k;
3034 ras.band_stack[ras.band_top + 1].y_max = j;
3036 ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
3038 ras.band_top++;
3040 else
3042 if ( ras.fProfile )
3043 if ( Draw_Sweep( RAS_VAR ) )
3044 return ras.error;
3045 ras.band_top--;
3049 return SUCCESS;
3053 /*************************************************************************/
3054 /* */
3055 /* <Function> */
3056 /* Render_Glyph */
3057 /* */
3058 /* <Description> */
3059 /* Renders a glyph in a bitmap. Sub-banding if needed. */
3060 /* */
3061 /* <Return> */
3062 /* FreeType error code. 0 means success. */
3063 /* */
3064 FT_LOCAL_DEF( FT_Error )
3065 Render_Glyph( RAS_ARG )
3067 FT_Error error;
3070 Set_High_Precision( RAS_VARS ras.outline.flags &
3071 FT_OUTLINE_HIGH_PRECISION );
3072 ras.scale_shift = ras.precision_shift;
3074 if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
3075 ras.dropOutControl = 2;
3076 else
3078 if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
3079 ras.dropOutControl = 4;
3080 else
3081 ras.dropOutControl = 0;
3083 if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
3084 ras.dropOutControl += 1;
3087 ras.second_pass = (FT_Byte)( !( ras.outline.flags &
3088 FT_OUTLINE_SINGLE_PASS ) );
3090 /* Vertical Sweep */
3091 ras.Proc_Sweep_Init = Vertical_Sweep_Init;
3092 ras.Proc_Sweep_Span = Vertical_Sweep_Span;
3093 ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
3094 ras.Proc_Sweep_Step = Vertical_Sweep_Step;
3096 ras.band_top = 0;
3097 ras.band_stack[0].y_min = 0;
3098 ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
3100 ras.bWidth = (unsigned short)ras.target.width;
3101 ras.bTarget = (Byte*)ras.target.buffer;
3103 if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
3104 return error;
3106 /* Horizontal Sweep */
3107 if ( ras.second_pass && ras.dropOutControl != 2 )
3109 ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
3110 ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
3111 ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
3112 ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
3114 ras.band_top = 0;
3115 ras.band_stack[0].y_min = 0;
3116 ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
3118 if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
3119 return error;
3122 return Raster_Err_None;
3126 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3129 /*************************************************************************/
3130 /* */
3131 /* <Function> */
3132 /* Render_Gray_Glyph */
3133 /* */
3134 /* <Description> */
3135 /* Renders a glyph with grayscaling. Sub-banding if needed. */
3136 /* */
3137 /* <Return> */
3138 /* FreeType error code. 0 means success. */
3139 /* */
3140 FT_LOCAL_DEF( FT_Error )
3141 Render_Gray_Glyph( RAS_ARG )
3143 Long pixel_width;
3144 FT_Error error;
3147 Set_High_Precision( RAS_VARS ras.outline.flags &
3148 FT_OUTLINE_HIGH_PRECISION );
3149 ras.scale_shift = ras.precision_shift + 1;
3151 if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS )
3152 ras.dropOutControl = 2;
3153 else
3155 if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS )
3156 ras.dropOutControl = 4;
3157 else
3158 ras.dropOutControl = 0;
3160 if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) )
3161 ras.dropOutControl += 1;
3164 ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
3166 /* Vertical Sweep */
3168 ras.band_top = 0;
3169 ras.band_stack[0].y_min = 0;
3170 ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
3172 ras.bWidth = ras.gray_width;
3173 pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
3175 if ( ras.bWidth > pixel_width )
3176 ras.bWidth = pixel_width;
3178 ras.bWidth = ras.bWidth * 8;
3179 ras.bTarget = (Byte*)ras.gray_lines;
3180 ras.gTarget = (Byte*)ras.target.buffer;
3182 ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
3183 ras.Proc_Sweep_Span = Vertical_Sweep_Span;
3184 ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
3185 ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
3187 error = Render_Single_Pass( RAS_VARS 0 );
3188 if ( error )
3189 return error;
3191 /* Horizontal Sweep */
3192 if ( ras.second_pass && ras.dropOutControl != 2 )
3194 ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
3195 ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
3196 ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
3197 ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
3199 ras.band_top = 0;
3200 ras.band_stack[0].y_min = 0;
3201 ras.band_stack[0].y_max = ras.target.width * 2 - 1;
3203 error = Render_Single_Pass( RAS_VARS 1 );
3204 if ( error )
3205 return error;
3208 return Raster_Err_None;
3211 #else /* !FT_RASTER_OPTION_ANTI_ALIASING */
3213 FT_LOCAL_DEF( FT_Error )
3214 Render_Gray_Glyph( RAS_ARG )
3216 FT_UNUSED_RASTER;
3218 return Raster_Err_Unsupported;
3221 #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
3224 static void
3225 ft_black_init( PRaster raster )
3227 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3228 FT_UInt n;
3231 /* set default 5-levels gray palette */
3232 for ( n = 0; n < 5; n++ )
3233 raster->grays[n] = n * 255 / 4;
3235 raster->gray_width = RASTER_GRAY_LINES / 2;
3237 #else
3238 FT_UNUSED( raster );
3239 #endif
3243 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
3244 /**** a static object. *****/
3247 #ifdef _STANDALONE_
3250 static int
3251 ft_black_new( void* memory,
3252 FT_Raster *araster )
3254 static TRaster the_raster;
3257 *araster = (FT_Raster)&the_raster;
3258 FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
3259 ft_black_init( &the_raster );
3261 return 0;
3265 static void
3266 ft_black_done( FT_Raster raster )
3268 /* nothing */
3269 FT_UNUSED( raster );
3273 #else /* _STANDALONE_ */
3276 static int
3277 ft_black_new( FT_Memory memory,
3278 PRaster *araster )
3280 FT_Error error;
3281 PRaster raster;
3284 *araster = 0;
3285 if ( !FT_NEW( raster ) )
3287 raster->memory = memory;
3288 ft_black_init( raster );
3290 *araster = raster;
3293 return error;
3297 static void
3298 ft_black_done( PRaster raster )
3300 FT_Memory memory = (FT_Memory)raster->memory;
3301 FT_FREE( raster );
3305 #endif /* _STANDALONE_ */
3308 static void
3309 ft_black_reset( PRaster raster,
3310 char* pool_base,
3311 long pool_size )
3313 if ( raster )
3315 if ( pool_base && pool_size >= (long)sizeof(TWorker) + 2048 )
3317 PWorker worker = (PWorker)pool_base;
3320 raster->buffer = pool_base + ( (sizeof ( *worker ) + 7 ) & ~7 );
3321 raster->buffer_size = ( ( pool_base + pool_size ) -
3322 (char*)raster->buffer ) / sizeof ( Long );
3323 raster->worker = worker;
3325 else
3327 raster->buffer = NULL;
3328 raster->buffer_size = 0;
3329 raster->worker = NULL;
3335 static void
3336 ft_black_set_mode( PRaster raster,
3337 unsigned long mode,
3338 const char* palette )
3340 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3342 if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
3344 /* set 5-levels gray palette */
3345 raster->grays[0] = palette[0];
3346 raster->grays[1] = palette[1];
3347 raster->grays[2] = palette[2];
3348 raster->grays[3] = palette[3];
3349 raster->grays[4] = palette[4];
3352 #else
3354 FT_UNUSED( raster );
3355 FT_UNUSED( mode );
3356 FT_UNUSED( palette );
3358 #endif
3362 static int
3363 ft_black_render( PRaster raster,
3364 const FT_Raster_Params* params )
3366 const FT_Outline* outline = (const FT_Outline*)params->source;
3367 const FT_Bitmap* target_map = params->target;
3368 PWorker worker;
3371 if ( !raster || !raster->buffer || !raster->buffer_size )
3372 return Raster_Err_Not_Ini;
3374 if ( !outline )
3375 return Raster_Err_Invalid;
3377 /* return immediately if the outline is empty */
3378 if ( outline->n_points == 0 || outline->n_contours <= 0 )
3379 return Raster_Err_None;
3381 if ( !outline->contours || !outline->points )
3382 return Raster_Err_Invalid;
3384 if ( outline->n_points !=
3385 outline->contours[outline->n_contours - 1] + 1 )
3386 return Raster_Err_Invalid;
3388 worker = raster->worker;
3390 /* this version of the raster does not support direct rendering, sorry */
3391 if ( params->flags & FT_RASTER_FLAG_DIRECT )
3392 return Raster_Err_Unsupported;
3394 if ( !target_map )
3395 return Raster_Err_Invalid;
3397 /* nothing to do */
3398 if ( !target_map->width || !target_map->rows )
3399 return Raster_Err_None;
3401 if ( !target_map->buffer )
3402 return Raster_Err_Invalid;
3404 ras.outline = *outline;
3405 ras.target = *target_map;
3407 worker->buff = (PLong) raster->buffer;
3408 worker->sizeBuff = worker->buff +
3409 raster->buffer_size / sizeof ( Long );
3410 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3411 worker->grays = raster->grays;
3412 worker->gray_width = raster->gray_width;
3413 #endif
3415 return ( ( params->flags & FT_RASTER_FLAG_AA )
3416 ? Render_Gray_Glyph( RAS_VAR )
3417 : Render_Glyph( RAS_VAR ) );
3421 const FT_Raster_Funcs ft_standard_raster =
3423 FT_GLYPH_FORMAT_OUTLINE,
3424 (FT_Raster_New_Func) ft_black_new,
3425 (FT_Raster_Reset_Func) ft_black_reset,
3426 (FT_Raster_Set_Mode_Func)ft_black_set_mode,
3427 (FT_Raster_Render_Func) ft_black_render,
3428 (FT_Raster_Done_Func) ft_black_done
3432 /* END */