1 /***************************************************************************/
5 /* The FreeType glyph rasterizer (body). */
7 /* Copyright 1996-2001, 2002 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
18 /*************************************************************************/
20 /* This is a rewrite of the FreeType 1.x scan-line converter */
22 /*************************************************************************/
27 #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
30 /*************************************************************************/
32 /* A simple technical note on how the raster works */
33 /* ----------------------------------------------- */
35 /* Converting an outline into a bitmap is achieved in several steps: */
37 /* 1 - Decomposing the outline into successive `profiles'. Each */
38 /* profile is simply an array of scanline intersections on a given */
39 /* dimension. A profile's main attributes are */
41 /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
43 /* o an array of intersection coordinates for each scanline */
44 /* between `Ymin' and `Ymax'. */
46 /* o a direction, indicating whether it was built going `up' or */
47 /* `down', as this is very important for filling rules. */
49 /* 2 - Sweeping the target map's scanlines in order to compute segment */
50 /* `spans' which are then filled. Additionally, this pass */
51 /* performs drop-out control. */
53 /* The outline data is parsed during step 1 only. The profiles are */
54 /* built from the bottom of the render pool, used as a stack. The */
55 /* following graphics shows the profile list under construction: */
57 /* ____________________________________________________________ _ _ */
59 /* | profile | coordinates for | profile | coordinates for |--> */
60 /* | 1 | profile 1 | 2 | profile 2 |--> */
61 /* |_________|___________________|_________|_________________|__ _ _ */
65 /* start of render pool top */
67 /* The top of the profile stack is kept in the `top' variable. */
69 /* As you can see, a profile record is pushed on top of the render */
70 /* pool, which is then followed by its coordinates/intersections. If */
71 /* a change of direction is detected in the outline, a new profile is */
72 /* generated until the end of the outline. */
74 /* Note that when all profiles have been generated, the function */
75 /* Finalize_Profile_Table() is used to record, for each profile, its */
76 /* bottom-most scanline as well as the scanline above its upmost */
77 /* boundary. These positions are called `y-turns' because they (sort */
78 /* of) correspond to local extrema. They are stored in a sorted list */
79 /* built from the top of the render pool as a downwards stack: */
81 /* _ _ _______________________________________ */
83 /* <--| sorted list of | */
84 /* <--| extrema scanlines | */
85 /* _ _ __________________|____________________| */
89 /* maxBuff sizeBuff = end of pool */
91 /* This list is later used during the sweep phase in order to */
92 /* optimize performance (see technical note on the sweep below). */
94 /* Of course, the raster detects whether the two stacks collide and */
95 /* handles the situation propertly. */
97 /*************************************************************************/
100 /*************************************************************************/
101 /*************************************************************************/
103 /** CONFIGURATION MACROS **/
105 /*************************************************************************/
106 /*************************************************************************/
108 /* define DEBUG_RASTER if you want to compile a debugging version */
109 #define xxxDEBUG_RASTER
111 /* The default render pool size in bytes */
112 #define RASTER_RENDER_POOL 8192
114 /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
115 /* 5-levels anti-aliasing */
116 #ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS
117 #define FT_RASTER_OPTION_ANTI_ALIASING
120 /* The size of the two-lines intermediate bitmap used */
121 /* for anti-aliasing, in bytes. */
122 #define RASTER_GRAY_LINES 2048
125 /*************************************************************************/
126 /*************************************************************************/
128 /** OTHER MACROS (do not change) **/
130 /*************************************************************************/
131 /*************************************************************************/
133 /*************************************************************************/
135 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
136 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
137 /* messages during execution. */
140 #define FT_COMPONENT trace_raster
146 /* This macro is used to indicate that a function parameter is unused. */
147 /* Its purpose is simply to reduce compiler warnings. Note also that */
148 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
149 /* ANSI compilers (e.g. LCC). */
150 #define FT_UNUSED( x ) (x) = (x)
152 /* Disable the tracing mechanism for simplicity -- developers can */
153 /* activate it easily by redefining these two macros. */
155 #define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
159 #define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
162 #define Raster_Err_None 0
163 #define Raster_Err_Not_Ini -1
164 #define Raster_Err_Overflow -2
165 #define Raster_Err_Neg_Height -3
166 #define Raster_Err_Invalid -4
167 #define Raster_Err_Unsupported -5
170 #else /* _STANDALONE_ */
173 #include FT_INTERNAL_OBJECTS_H
174 #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
176 #include "rasterrs.h"
178 #define Raster_Err_None Raster_Err_Ok
179 #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
180 #define Raster_Err_Overflow Raster_Err_Raster_Overflow
181 #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
182 #define Raster_Err_Invalid Raster_Err_Invalid_Outline
183 #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
186 #endif /* _STANDALONE_ */
190 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
194 /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
195 /* typically a small value and the result of a*b is known to fit into */
197 #define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
199 /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
200 /* for clipping computations. It simply uses the FT_MulDiv() function */
201 /* defined in `ftcalc.h'. */
202 #define SMulDiv FT_MulDiv
204 /* The rasterizer is a very general purpose component; please leave */
205 /* the following redefinitions there (you never know your target */
217 #define NULL (void*)0
229 #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
230 /* Setting this constant to more than 32 is a */
231 /* pure waste of space. */
233 #define Pixel_Bits 6 /* fractional bits of *input* coordinates */
236 /*************************************************************************/
237 /*************************************************************************/
239 /** SIMPLE TYPE DECLARATIONS **/
241 /*************************************************************************/
242 /*************************************************************************/
245 typedef unsigned int UInt;
247 typedef unsigned short UShort, *PUShort;
248 typedef long Long, *PLong;
249 typedef unsigned long ULong;
251 typedef unsigned char Byte, *PByte;
254 typedef struct TPoint_
271 /* States of each line, arc, and profile */
272 typedef enum TStates_
282 typedef struct TProfile_ TProfile;
283 typedef TProfile* PProfile;
287 FT_F26Dot6 X; /* current coordinate during sweep */
288 PProfile link; /* link to next profile - various purpose */
289 PLong offset; /* start of profile's data in render pool */
290 int flow; /* Profile orientation: Asc/Descending */
291 long height; /* profile's height in scanlines */
292 long start; /* profile's starting scanline */
294 unsigned countL; /* number of lines to step before this */
295 /* profile becomes drawable */
297 PProfile next; /* next profile in same contour, used */
298 /* during drop-out control */
301 typedef PProfile TProfileList;
302 typedef PProfile* PProfileList;
305 /* Simple record used to implement a stack of bands, required */
306 /* by the sub-banding mechanism */
307 typedef struct TBand_
309 Short y_min; /* band's minimum */
310 Short y_max; /* band's maximum */
315 #define AlignProfileSize \
316 ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) )
319 #ifdef TT_STATIC_RASTER
322 #define RAS_ARGS /* void */
323 #define RAS_ARG /* void */
325 #define RAS_VARS /* void */
326 #define RAS_VAR /* void */
328 #define FT_UNUSED_RASTER do ; while ( 0 )
331 #else /* TT_STATIC_RASTER */
334 #define RAS_ARGS TRaster_Instance* raster,
335 #define RAS_ARG TRaster_Instance* raster
337 #define RAS_VARS raster,
338 #define RAS_VAR raster
340 #define FT_UNUSED_RASTER FT_UNUSED( raster )
343 #endif /* TT_STATIC_RASTER */
346 typedef struct TRaster_Instance_ TRaster_Instance;
349 /* prototypes used for sweep function dispatch */
351 Function_Sweep_Init( RAS_ARGS Short* min,
355 Function_Sweep_Span( RAS_ARGS Short y,
362 Function_Sweep_Step( RAS_ARG );
365 /* NOTE: These operations are only valid on 2's complement processors */
367 #define FLOOR( x ) ( (x) & -ras.precision )
368 #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
369 #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
370 #define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
371 #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
373 /* Note that I have moved the location of some fields in the */
374 /* structure to ensure that the most used variables are used */
375 /* at the top. Thus, their offset can be coded with less */
376 /* opcodes, and it results in a smaller executable. */
378 struct TRaster_Instance_
380 Int precision_bits; /* precision related variables */
386 Int precision_jitter;
388 Int scale_shift; /* == precision_shift for bitmaps */
389 /* == precision_shift+1 for pixmaps */
391 PLong buff; /* The profiles buffer */
392 PLong sizeBuff; /* Render pool size */
393 PLong maxBuff; /* Profiles buffer size */
394 PLong top; /* Current cursor in buffer */
398 Int numTurns; /* number of Y-turns in outline */
400 TPoint* arc; /* current Bezier arc pointer */
402 UShort bWidth; /* target bitmap width */
403 PByte bTarget; /* target bitmap buffer */
404 PByte gTarget; /* target pixmap buffer */
406 Long lastX, lastY, minY, maxY;
408 UShort num_Profs; /* current number of profiles */
410 Bool fresh; /* signals a fresh new profile which */
411 /* 'start' field must be completed */
412 Bool joint; /* signals that the last arc ended */
413 /* exactly on a scanline. Allows */
414 /* removal of doublets */
415 PProfile cProfile; /* current profile */
416 PProfile fProfile; /* head of linked list of profiles */
417 PProfile gProfile; /* contour's first profile in case */
420 TStates state; /* rendering state */
422 FT_Bitmap target; /* description of target bit/pixmap */
425 Long traceOfs; /* current offset in target bitmap */
426 Long traceG; /* current offset in target pixmap */
428 Short traceIncr; /* sweep's increment in target bitmap */
430 Short gray_min_x; /* current min x during gray rendering */
431 Short gray_max_x; /* current max x during gray rendering */
433 /* dispatch variables */
435 Function_Sweep_Init* Proc_Sweep_Init;
436 Function_Sweep_Span* Proc_Sweep_Span;
437 Function_Sweep_Span* Proc_Sweep_Drop;
438 Function_Sweep_Step* Proc_Sweep_Step;
440 Byte dropOutControl; /* current drop_out control method */
442 Bool second_pass; /* indicates wether a horizontal pass */
443 /* should be performed to control */
444 /* drop-out accurately when calling */
445 /* Render_Glyph. Note that there is */
446 /* no horizontal pass during gray */
449 TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
451 TBand band_stack[16]; /* band stack used for sub-banding */
452 Int band_top; /* band stack top */
454 Int count_table[256]; /* Look-up table used to quickly count */
455 /* set bits in a gray 2x2 cell */
459 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
461 Byte grays[5]; /* Palette of gray levels used for */
464 Byte gray_lines[RASTER_GRAY_LINES];
465 /* Intermediate table used to render the */
466 /* graylevels pixmaps. */
467 /* gray_lines is a buffer holding two */
468 /* monochrome scanlines */
470 Short gray_width; /* width in bytes of one monochrome */
471 /* intermediate scanline of gray_lines. */
472 /* Each gray pixel takes 2 bits long there */
474 /* The gray_lines must hold 2 lines, thus with size */
475 /* in bytes of at least `gray_width*2'. */
477 #endif /* FT_RASTER_ANTI_ALIASING */
480 PByte flags; /* current flags table */
481 PUShort outs; /* current outlines table */
484 UShort nPoints; /* number of points in current glyph */
485 Short nContours; /* number of contours in current glyph */
491 #ifdef FT_CONFIG_OPTION_STATIC_RASTER
493 static TRaster_Instance cur_ras;
498 #define ras (*raster)
500 #endif /* FT_CONFIG_OPTION_STATIC_RASTER */
503 /*************************************************************************/
504 /*************************************************************************/
506 /** PROFILES COMPUTATION **/
508 /*************************************************************************/
509 /*************************************************************************/
512 /*************************************************************************/
515 /* Set_High_Precision */
518 /* Sets precision variables according to param flag. */
521 /* High :: Set to True for high precision (typically for ppem < 18), */
522 /* false otherwise. */
525 Set_High_Precision( RAS_ARGS Int High )
529 ras.precision_bits = 10;
530 ras.precision_step = 128;
531 ras.precision_jitter = 24;
535 ras.precision_bits = 6;
536 ras.precision_step = 32;
537 ras.precision_jitter = 2;
540 FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
542 ras.precision = 1 << ras.precision_bits;
543 ras.precision_half = ras.precision / 2;
544 ras.precision_shift = ras.precision_bits - Pixel_Bits;
545 ras.precision_mask = -ras.precision;
549 /*************************************************************************/
555 /* Creates a new profile in the render pool. */
558 /* aState :: The state/orientation of the new profile. */
561 /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
565 New_Profile( RAS_ARGS TStates aState )
569 ras.cProfile = (PProfile)ras.top;
570 ras.fProfile = ras.cProfile;
571 ras.top += AlignProfileSize;
574 if ( ras.top >= ras.maxBuff )
576 ras.error = Raster_Err_Overflow;
582 case Ascending_State:
583 ras.cProfile->flow = Flow_Up;
584 FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
587 case Descending_State:
588 ras.cProfile->flow = Flow_Down;
589 FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
593 FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
594 ras.error = Raster_Err_Invalid;
598 ras.cProfile->start = 0;
599 ras.cProfile->height = 0;
600 ras.cProfile->offset = ras.top;
601 ras.cProfile->link = (PProfile)0;
602 ras.cProfile->next = (PProfile)0;
605 ras.gProfile = ras.cProfile;
615 /*************************************************************************/
621 /* Finalizes the current profile. */
624 /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
627 End_Profile( RAS_ARG )
633 h = (Long)( ras.top - ras.cProfile->offset );
637 FT_ERROR(( "End_Profile: negative height encountered!\n" ));
638 ras.error = Raster_Err_Neg_Height;
644 FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
645 (long)ras.cProfile, ras.cProfile->start, h ));
647 oldProfile = ras.cProfile;
648 ras.cProfile->height = h;
649 ras.cProfile = (PProfile)ras.top;
651 ras.top += AlignProfileSize;
653 ras.cProfile->height = 0;
654 ras.cProfile->offset = ras.top;
655 oldProfile->next = ras.cProfile;
659 if ( ras.top >= ras.maxBuff )
661 FT_TRACE1(( "overflow in End_Profile\n" ));
662 ras.error = Raster_Err_Overflow;
672 /*************************************************************************/
678 /* Inserts a salient into the sorted list placed on top of the render */
682 /* New y scanline position. */
685 /* SUCCESS on success. FAILURE in case of overflow. */
688 Insert_Y_Turn( RAS_ARGS Int y )
694 n = ras.numTurns - 1;
695 y_turns = ras.sizeBuff - ras.numTurns;
697 /* look for first y value that is <= */
698 while ( n >= 0 && y < y_turns[n] )
701 /* if it is <, simply insert it, ignore if == */
702 if ( n >= 0 && y > y_turns[n] )
705 y2 = (Int)y_turns[n];
713 if ( ras.maxBuff <= ras.top )
715 ras.error = Raster_Err_Overflow;
720 ras.sizeBuff[-ras.numTurns] = y;
727 /*************************************************************************/
730 /* Finalize_Profile_Table */
733 /* Adjusts all links in the profiles list. */
736 /* SUCCESS on success. FAILURE in case of overflow. */
739 Finalize_Profile_Table( RAS_ARG )
754 p->link = (PProfile)( p->offset + p->height );
761 bottom = (Int)( p->start - p->height + 1 );
764 p->offset += p->height - 1;
769 bottom = (Int)p->start;
770 top = (Int)( p->start + p->height - 1 );
773 if ( Insert_Y_Turn( RAS_VARS bottom ) ||
774 Insert_Y_Turn( RAS_VARS top + 1 ) )
788 /*************************************************************************/
794 /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
798 /* None (subdivided Bezier is taken from the top of the stack). */
801 /* This routine is the `beef' of this component. It is _the_ inner */
802 /* loop that should be optimized to hell to get the best performance. */
805 Split_Conic( TPoint* base )
810 base[4].x = base[2].x;
812 a = base[3].x = ( base[2].x + b ) / 2;
813 b = base[1].x = ( base[0].x + b ) / 2;
814 base[2].x = ( a + b ) / 2;
816 base[4].y = base[2].y;
818 a = base[3].y = ( base[2].y + b ) / 2;
819 b = base[1].y = ( base[0].y + b ) / 2;
820 base[2].y = ( a + b ) / 2;
822 /* hand optimized. gcc doesn't seem to be too good at common */
823 /* expression substitution and instruction scheduling ;-) */
827 /*************************************************************************/
833 /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
837 /* This routine is the `beef' of the component. It is one of _the_ */
838 /* inner loops that should be optimized like hell to get the best */
842 Split_Cubic( TPoint* base )
847 base[6].x = base[3].x;
850 base[1].x = a = ( base[0].x + c + 1 ) >> 1;
851 base[5].x = b = ( base[3].x + d + 1 ) >> 1;
852 c = ( c + d + 1 ) >> 1;
853 base[2].x = a = ( a + c + 1 ) >> 1;
854 base[4].x = b = ( b + c + 1 ) >> 1;
855 base[3].x = ( a + b + 1 ) >> 1;
857 base[6].y = base[3].y;
860 base[1].y = a = ( base[0].y + c + 1 ) >> 1;
861 base[5].y = b = ( base[3].y + d + 1 ) >> 1;
862 c = ( c + d + 1 ) >> 1;
863 base[2].y = a = ( a + c + 1 ) >> 1;
864 base[4].y = b = ( b + c + 1 ) >> 1;
865 base[3].y = ( a + b + 1 ) >> 1;
869 /*************************************************************************/
875 /* Computes the x-coordinates of an ascending line segment and stores */
876 /* them in the render pool. */
879 /* x1 :: The x-coordinate of the segment's start point. */
881 /* y1 :: The y-coordinate of the segment's start point. */
883 /* x2 :: The x-coordinate of the segment's end point. */
885 /* y2 :: The y-coordinate of the segment's end point. */
887 /* miny :: A lower vertical clipping bound value. */
889 /* maxy :: An upper vertical clipping bound value. */
892 /* SUCCESS on success, FAILURE on render pool overflow. */
895 Line_Up( RAS_ARGS Long x1,
903 Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
912 if ( Dy <= 0 || y2 < miny || y1 > maxy )
917 /* Take care: miny-y1 can be a very large value; we use */
918 /* a slow MulDiv function to avoid clipping bugs */
919 x1 += SMulDiv( Dx, miny - y1, Dy );
925 e1 = (Int)TRUNC( y1 );
926 f1 = (Int)FRAC( y1 );
931 /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
932 e2 = (Int)TRUNC( maxy );
937 e2 = (Int)TRUNC( y2 );
938 f2 = (Int)FRAC( y2 );
947 x1 += FMulDiv( Dx, ras.precision - f1, Dy );
958 ras.joint = (char)( f2 == 0 );
962 ras.cProfile->start = e1;
967 if ( ras.top + size >= ras.maxBuff )
969 ras.error = Raster_Err_Overflow;
975 Ix = ( ras.precision * Dx ) / Dy;
976 Rx = ( ras.precision * Dx ) % Dy;
981 Ix = -( ( ras.precision * -Dx ) / Dy );
982 Rx = ( ras.precision * -Dx ) % Dy;
1008 /*************************************************************************/
1014 /* Computes the x-coordinates of an descending line segment and */
1015 /* stores them in the render pool. */
1018 /* x1 :: The x-coordinate of the segment's start point. */
1020 /* y1 :: The y-coordinate of the segment's start point. */
1022 /* x2 :: The x-coordinate of the segment's end point. */
1024 /* y2 :: The y-coordinate of the segment's end point. */
1026 /* miny :: A lower vertical clipping bound value. */
1028 /* maxy :: An upper vertical clipping bound value. */
1031 /* SUCCESS on success, FAILURE on render pool overflow. */
1034 Line_Down( RAS_ARGS Long x1,
1046 result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
1048 if ( fresh && !ras.fresh )
1049 ras.cProfile->start = -ras.cProfile->start;
1055 /* A function type describing the functions used to split Bezier arcs */
1056 typedef void (*TSplitter)( TPoint* base );
1059 /*************************************************************************/
1065 /* Computes the x-coordinates of an ascending Bezier arc and stores */
1066 /* them in the render pool. */
1069 /* degree :: The degree of the Bezier arc (either 2 or 3). */
1071 /* splitter :: The function to split Bezier arcs. */
1073 /* miny :: A lower vertical clipping bound value. */
1075 /* maxy :: An upper vertical clipping bound value. */
1078 /* SUCCESS on success, FAILURE on render pool overflow. */
1081 Bezier_Up( RAS_ARGS Int degree,
1086 Long y1, y2, e, e2, e0;
1100 if ( y2 < miny || y1 > maxy )
1115 f1 = (Short)( FRAC( y1 ) );
1126 *top++ = arc[degree].x;
1134 ras.cProfile->start = TRUNC( e0 );
1141 if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
1144 ras.error = Raster_Err_Overflow;
1150 while ( arc >= start_arc && e <= e2 )
1159 if ( y2 - y1 >= ras.precision_step )
1166 *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
1192 /*************************************************************************/
1198 /* Computes the x-coordinates of an descending Bezier arc and stores */
1199 /* them in the render pool. */
1202 /* degree :: The degree of the Bezier arc (either 2 or 3). */
1204 /* splitter :: The function to split Bezier arcs. */
1206 /* miny :: A lower vertical clipping bound value. */
1208 /* maxy :: An upper vertical clipping bound value. */
1211 /* SUCCESS on success, FAILURE on render pool overflow. */
1214 Bezier_Down( RAS_ARGS Int degree,
1219 TPoint* arc = ras.arc;
1223 arc[0].y = -arc[0].y;
1224 arc[1].y = -arc[1].y;
1225 arc[2].y = -arc[2].y;
1227 arc[3].y = -arc[3].y;
1231 result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
1233 if ( fresh && !ras.fresh )
1234 ras.cProfile->start = -ras.cProfile->start;
1236 arc[0].y = -arc[0].y;
1241 /*************************************************************************/
1247 /* Injects a new line segment and adjusts Profiles list. */
1250 /* x :: The x-coordinate of the segment's end point (its start point */
1251 /* is stored in `LastX'). */
1253 /* y :: The y-coordinate of the segment's end point (its start point */
1254 /* is stored in `LastY'). */
1257 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1261 Line_To( RAS_ARGS Long x,
1264 /* First, detect a change of direction */
1266 switch ( ras.state )
1269 if ( y > ras.lastY )
1271 if ( New_Profile( RAS_VARS Ascending_State ) )
1276 if ( y < ras.lastY )
1277 if ( New_Profile( RAS_VARS Descending_State ) )
1282 case Ascending_State:
1283 if ( y < ras.lastY )
1285 if ( End_Profile( RAS_VAR ) ||
1286 New_Profile( RAS_VARS Descending_State ) )
1291 case Descending_State:
1292 if ( y > ras.lastY )
1294 if ( End_Profile( RAS_VAR ) ||
1295 New_Profile( RAS_VARS Ascending_State ) )
1304 /* Then compute the lines */
1306 switch ( ras.state )
1308 case Ascending_State:
1309 if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
1310 x, y, ras.minY, ras.maxY ) )
1314 case Descending_State:
1315 if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
1316 x, y, ras.minY, ras.maxY ) )
1331 /*************************************************************************/
1337 /* Injects a new conic arc and adjusts the profile list. */
1340 /* cx :: The x-coordinate of the arc's new control point. */
1342 /* cy :: The y-coordinate of the arc's new control point. */
1344 /* x :: The x-coordinate of the arc's end point (its start point is */
1345 /* stored in `LastX'). */
1347 /* y :: The y-coordinate of the arc's end point (its start point is */
1348 /* stored in `LastY'). */
1351 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1355 Conic_To( RAS_ARGS Long cx,
1360 Long y1, y2, y3, x3, ymin, ymax;
1365 ras.arc[2].x = ras.lastX;
1366 ras.arc[2].y = ras.lastY;
1367 ras.arc[1].x = cx; ras.arc[1].y = cy;
1368 ras.arc[0].x = x; ras.arc[0].y = y;
1377 /* first, categorize the Bezier arc */
1390 if ( y2 < ymin || y2 > ymax )
1392 /* this arc has no given direction, split it! */
1393 Split_Conic( ras.arc );
1396 else if ( y1 == y3 )
1398 /* this arc is flat, ignore it and pop it from the Bezier stack */
1403 /* the arc is y-monotonous, either ascending or descending */
1404 /* detect a change of direction */
1405 state_bez = y1 < y3 ? Ascending_State : Descending_State;
1406 if ( ras.state != state_bez )
1408 /* finalize current profile if any */
1409 if ( ras.state != Unknown_State &&
1410 End_Profile( RAS_VAR ) )
1413 /* create a new profile */
1414 if ( New_Profile( RAS_VARS state_bez ) )
1418 /* now call the appropriate routine */
1419 if ( state_bez == Ascending_State )
1421 if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1425 if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1429 } while ( ras.arc >= ras.arcs );
1441 /*************************************************************************/
1447 /* Injects a new cubic arc and adjusts the profile list. */
1450 /* cx1 :: The x-coordinate of the arc's first new control point. */
1452 /* cy1 :: The y-coordinate of the arc's first new control point. */
1454 /* cx2 :: The x-coordinate of the arc's second new control point. */
1456 /* cy2 :: The y-coordinate of the arc's second new control point. */
1458 /* x :: The x-coordinate of the arc's end point (its start point is */
1459 /* stored in `LastX'). */
1461 /* y :: The y-coordinate of the arc's end point (its start point is */
1462 /* stored in `LastY'). */
1465 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1469 Cubic_To( RAS_ARGS Long cx1,
1476 Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
1481 ras.arc[3].x = ras.lastX;
1482 ras.arc[3].y = ras.lastY;
1483 ras.arc[2].x = cx1; ras.arc[2].y = cy1;
1484 ras.arc[1].x = cx2; ras.arc[1].y = cy2;
1485 ras.arc[0].x = x; ras.arc[0].y = y;
1495 /* first, categorize the Bezier arc */
1519 if ( ymin2 < ymin1 || ymax2 > ymax1 )
1521 /* this arc has no given direction, split it! */
1522 Split_Cubic( ras.arc );
1525 else if ( y1 == y4 )
1527 /* this arc is flat, ignore it and pop it from the Bezier stack */
1532 state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
1534 /* detect a change of direction */
1535 if ( ras.state != state_bez )
1537 if ( ras.state != Unknown_State &&
1538 End_Profile( RAS_VAR ) )
1541 if ( New_Profile( RAS_VARS state_bez ) )
1545 /* compute intersections */
1546 if ( state_bez == Ascending_State )
1548 if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1552 if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1556 } while ( ras.arc >= ras.arcs );
1569 #define SWAP_( x, y ) do \
1579 /*************************************************************************/
1582 /* Decompose_Curve */
1585 /* Scans the outline arays in order to emit individual segments and */
1586 /* Beziers by calling Line_To() and Bezier_To(). It handles all */
1587 /* weird cases, like when the first point is off the curve, or when */
1588 /* there are simply no `on' points in the contour! */
1591 /* first :: The index of the first point in the contour. */
1593 /* last :: The index of the last point in the contour. */
1595 /* flipped :: If set, flip the direction of the curve. */
1598 /* SUCCESS on success, FAILURE on error. */
1601 Decompose_Curve( RAS_ARGS UShort first,
1606 FT_Vector v_control;
1614 unsigned tag; /* current point's state */
1617 points = ras.outline.points;
1618 limit = points + last;
1620 v_start.x = SCALED( points[first].x );
1621 v_start.y = SCALED( points[first].y );
1622 v_last.x = SCALED( points[last].x );
1623 v_last.y = SCALED( points[last].y );
1627 SWAP_( v_start.x, v_start.y );
1628 SWAP_( v_last.x, v_last.y );
1631 v_control = v_start;
1633 point = points + first;
1634 tags = ras.outline.tags + first;
1635 tag = FT_CURVE_TAG( tags[0] );
1637 /* A contour cannot start with a cubic control point! */
1638 if ( tag == FT_CURVE_TAG_CUBIC )
1639 goto Invalid_Outline;
1641 /* check first point to determine origin */
1642 if ( tag == FT_CURVE_TAG_CONIC )
1644 /* first point is conic control. Yes, this happens. */
1645 if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
1647 /* start at last point if it is on the curve */
1653 /* if both first and last points are conic, */
1654 /* start at their middle and record its position */
1656 v_start.x = ( v_start.x + v_last.x ) / 2;
1657 v_start.y = ( v_start.y + v_last.y ) / 2;
1665 ras.lastX = v_start.x;
1666 ras.lastY = v_start.y;
1668 while ( point < limit )
1673 tag = FT_CURVE_TAG( tags[0] );
1677 case FT_CURVE_TAG_ON: /* emit a single line_to */
1682 x = SCALED( point->x );
1683 y = SCALED( point->y );
1687 if ( Line_To( RAS_VARS x, y ) )
1692 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1693 v_control.x = SCALED( point[0].x );
1694 v_control.y = SCALED( point[0].y );
1697 SWAP_( v_control.x, v_control.y );
1700 if ( point < limit )
1708 tag = FT_CURVE_TAG( tags[0] );
1710 x = SCALED( point[0].x );
1711 y = SCALED( point[0].y );
1716 if ( tag == FT_CURVE_TAG_ON )
1718 if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
1723 if ( tag != FT_CURVE_TAG_CONIC )
1724 goto Invalid_Outline;
1726 v_middle.x = ( v_control.x + x ) / 2;
1727 v_middle.y = ( v_control.y + y ) / 2;
1729 if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1730 v_middle.x, v_middle.y ) )
1739 if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1740 v_start.x, v_start.y ) )
1745 default: /* FT_CURVE_TAG_CUBIC */
1747 Long x1, y1, x2, y2, x3, y3;
1750 if ( point + 1 > limit ||
1751 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1752 goto Invalid_Outline;
1757 x1 = SCALED( point[-2].x );
1758 y1 = SCALED( point[-2].y );
1759 x2 = SCALED( point[-1].x );
1760 y2 = SCALED( point[-1].y );
1761 x3 = SCALED( point[ 0].x );
1762 y3 = SCALED( point[ 0].y );
1771 if ( point <= limit )
1773 if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
1778 if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
1785 /* close the contour with a line segment */
1786 if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
1793 ras.error = Raster_Err_Invalid;
1800 /*************************************************************************/
1806 /* Converts a glyph into a series of segments and arcs and makes a */
1807 /* profiles list with them. */
1810 /* flipped :: If set, flip the direction of curve. */
1813 /* SUCCESS on success, FAILURE if any error was encountered during */
1817 Convert_Glyph( RAS_ARGS int flipped )
1822 PProfile lastProfile;
1825 ras.fProfile = NULL;
1829 ras.maxBuff = ras.sizeBuff - AlignProfileSize;
1833 ras.cProfile = (PProfile)ras.top;
1834 ras.cProfile->offset = ras.top;
1839 for ( i = 0; i < ras.outline.n_contours; i++ )
1841 ras.state = Unknown_State;
1842 ras.gProfile = NULL;
1844 if ( Decompose_Curve( RAS_VARS (unsigned short)start,
1845 ras.outline.contours[i],
1849 start = ras.outline.contours[i] + 1;
1851 /* We must now see whether the extreme arcs join or not */
1852 if ( FRAC( ras.lastY ) == 0 &&
1853 ras.lastY >= ras.minY &&
1854 ras.lastY <= ras.maxY )
1855 if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
1857 /* Note that ras.gProfile can be nil if the contour was too small */
1860 lastProfile = ras.cProfile;
1861 if ( End_Profile( RAS_VAR ) )
1864 /* close the `next profile in contour' linked list */
1866 lastProfile->next = ras.gProfile;
1869 if ( Finalize_Profile_Table( RAS_VAR ) )
1872 return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
1876 /*************************************************************************/
1877 /*************************************************************************/
1879 /** SCAN-LINE SWEEPS AND DRAWING **/
1881 /*************************************************************************/
1882 /*************************************************************************/
1885 /*************************************************************************/
1889 /* Initializes an empty linked list. */
1892 Init_Linked( TProfileList* l )
1898 /*************************************************************************/
1902 /* Inserts a new profile in a linked list. */
1905 InsNew( PProfileList list,
1908 PProfile *old, current;
1918 if ( x < current->X )
1920 old = ¤t->link;
1924 profile->link = current;
1929 /*************************************************************************/
1933 /* Removes an old profile from a linked list. */
1936 DelOld( PProfileList list,
1939 PProfile *old, current;
1947 if ( current == profile )
1949 *old = current->link;
1953 old = ¤t->link;
1957 /* we should never get there, unless the profile was not part of */
1962 /*************************************************************************/
1966 /* Sorts a trace list. In 95%, the list is already sorted. We need */
1967 /* an algorithm which is fast in this case. Bubble sort is enough */
1971 Sort( PProfileList list )
1973 PProfile *old, current, next;
1976 /* First, set the new X coordinate of each profile */
1980 current->X = *current->offset;
1981 current->offset += current->flow;
1983 current = current->link;
1986 /* Then sort them */
1993 next = current->link;
1997 if ( current->X <= next->X )
1999 old = ¤t->link;
2008 current->link = next->link;
2009 next->link = current;
2015 next = current->link;
2020 /*************************************************************************/
2022 /* Vertical Sweep Procedure Set */
2024 /* These four routines are used during the vertical black/white sweep */
2025 /* phase by the generic Draw_Sweep() function. */
2027 /*************************************************************************/
2030 Vertical_Sweep_Init( RAS_ARGS Short* min,
2033 Long pitch = ras.target.pitch;
2038 ras.traceIncr = (Short)-pitch;
2039 ras.traceOfs = -*min * pitch;
2041 ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
2049 Vertical_Sweep_Span( RAS_ARGS Short y,
2065 /* Drop-out control */
2067 e1 = TRUNC( CEILING( x1 ) );
2069 if ( x2 - x1 - ras.precision <= ras.precision_jitter )
2072 e2 = TRUNC( FLOOR( x2 ) );
2074 if ( e2 >= 0 && e1 < ras.bWidth )
2078 if ( e2 >= ras.bWidth )
2079 e2 = ras.bWidth - 1;
2081 c1 = (Short)( e1 >> 3 );
2082 c2 = (Short)( e2 >> 3 );
2084 f1 = (Byte) ( 0xFF >> ( e1 & 7 ) );
2085 f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
2087 if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1;
2088 if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2;
2090 target = ras.bTarget + ras.traceOfs + c1;
2097 /* memset() is slower than the following code on many platforms. */
2098 /* This is due to the fact that, in the vast majority of cases, */
2099 /* the span length in bytes is relatively small. */
2109 *target |= ( f1 & f2 );
2115 Vertical_Sweep_Drop( RAS_ARGS Short y,
2125 /* Drop-out control */
2132 if ( e1 == e2 + ras.precision )
2134 switch ( ras.dropOutControl )
2141 e1 = CEILING( (x1 + x2 + 1) / 2 );
2146 /* Drop-out Control Rule #4 */
2148 /* The spec is not very clear regarding rule #4. It */
2149 /* presents a method that is way too costly to implement */
2150 /* while the general idea seems to get rid of `stubs'. */
2152 /* Here, we only get rid of stubs recognized if: */
2156 /* - P_Left and P_Right are in the same contour */
2157 /* - P_Right is the successor of P_Left in that contour */
2158 /* - y is the top of P_Left and P_Right */
2162 /* - P_Left and P_Right are in the same contour */
2163 /* - P_Left is the successor of P_Right in that contour */
2164 /* - y is the bottom of P_Left */
2167 /* FIXXXME: uncommenting this line solves the disappearing */
2168 /* bit problem in the `7' of verdana 10pts, but */
2169 /* makes a new one in the `C' of arial 14pts */
2172 if ( x2 - x1 < ras.precision_half )
2175 /* upper stub test */
2176 if ( left->next == right && left->height <= 0 )
2179 /* lower stub test */
2180 if ( right->next == left && left->start == y )
2184 /* check that the rightmost pixel isn't set */
2188 c1 = (Short)( e1 >> 3 );
2189 f1 = (Short)( e1 & 7 );
2191 if ( e1 >= 0 && e1 < ras.bWidth &&
2192 ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
2195 if ( ras.dropOutControl == 2 )
2198 e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2203 return; /* unsupported mode */
2212 if ( e1 >= 0 && e1 < ras.bWidth )
2214 c1 = (Short)( e1 >> 3 );
2215 f1 = (Short)( e1 & 7 );
2217 if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
2218 if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
2220 ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
2226 Vertical_Sweep_Step( RAS_ARG )
2228 ras.traceOfs += ras.traceIncr;
2232 /***********************************************************************/
2234 /* Horizontal Sweep Procedure Set */
2236 /* These four routines are used during the horizontal black/white */
2237 /* sweep phase by the generic Draw_Sweep() function. */
2239 /***********************************************************************/
2242 Horizontal_Sweep_Init( RAS_ARGS Short* min,
2245 /* nothing, really */
2246 FT_UNUSED( raster );
2253 Horizontal_Sweep_Span( RAS_ARGS Short y,
2267 if ( x2 - x1 < ras.precision )
2274 bits = ras.bTarget + ( y >> 3 );
2275 f1 = (Byte)( 0x80 >> ( y & 7 ) );
2279 if ( e1 >= 0 && e1 < ras.target.rows )
2284 p = bits - e1*ras.target.pitch;
2285 if ( ras.target.pitch > 0 )
2286 p += ( ras.target.rows - 1 ) * ras.target.pitch;
2296 Horizontal_Sweep_Drop( RAS_ARGS Short y,
2307 /* During the horizontal sweep, we only take care of drop-outs */
2314 if ( e1 == e2 + ras.precision )
2316 switch ( ras.dropOutControl )
2323 e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2329 /* Drop-out Control Rule #4 */
2331 /* The spec is not very clear regarding rule #4. It */
2332 /* presents a method that is way too costly to implement */
2333 /* while the general idea seems to get rid of `stubs'. */
2336 /* rightmost stub test */
2337 if ( left->next == right && left->height <= 0 )
2340 /* leftmost stub test */
2341 if ( right->next == left && left->start == y )
2344 /* check that the rightmost pixel isn't set */
2348 bits = ras.bTarget + ( y >> 3 );
2349 f1 = (Byte)( 0x80 >> ( y & 7 ) );
2351 bits -= e1 * ras.target.pitch;
2352 if ( ras.target.pitch > 0 )
2353 bits += ( ras.target.rows - 1 ) * ras.target.pitch;
2356 e1 < ras.target.rows &&
2360 if ( ras.dropOutControl == 2 )
2363 e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2368 return; /* unsupported mode */
2375 bits = ras.bTarget + ( y >> 3 );
2376 f1 = (Byte)( 0x80 >> ( y & 7 ) );
2380 if ( e1 >= 0 && e1 < ras.target.rows )
2382 bits -= e1 * ras.target.pitch;
2383 if ( ras.target.pitch > 0 )
2384 bits += ( ras.target.rows - 1 ) * ras.target.pitch;
2392 Horizontal_Sweep_Step( RAS_ARG )
2394 /* Nothing, really */
2395 FT_UNUSED( raster );
2399 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
2402 /*************************************************************************/
2404 /* Vertical Gray Sweep Procedure Set */
2406 /* These two routines are used during the vertical gray-levels sweep */
2407 /* phase by the generic Draw_Sweep() function. */
2411 /* - The target pixmap's width *must* be a multiple of 4. */
2413 /* - You have to use the function Vertical_Sweep_Span() for the gray */
2416 /*************************************************************************/
2419 Vertical_Gray_Sweep_Init( RAS_ARGS Short* min,
2422 Long pitch, byte_len;
2426 *max = ( *max + 3 ) & -2;
2429 pitch = ras.target.pitch;
2431 ras.traceIncr = (Short)byte_len;
2432 ras.traceG = ( *min / 2 ) * byte_len;
2436 ras.traceG += ( ras.target.rows - 1 ) * pitch;
2437 byte_len = -byte_len;
2440 ras.gray_min_x = (Short)byte_len;
2441 ras.gray_max_x = -(Short)byte_len;
2446 Vertical_Gray_Sweep_Step( RAS_ARG )
2449 PByte pix, bit, bit2;
2450 Int* count = ras.count_table;
2454 ras.traceOfs += ras.gray_width;
2456 if ( ras.traceOfs > ras.gray_width )
2458 pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
2461 if ( ras.gray_max_x >= 0 )
2463 Long last_pixel = ras.target.width - 1;
2464 Int last_cell = last_pixel >> 2;
2465 Int last_bit = last_pixel & 3;
2469 if ( ras.gray_max_x >= last_cell && last_bit != 3 )
2471 ras.gray_max_x = last_cell - 1;
2475 if ( ras.gray_min_x < 0 )
2478 bit = ras.bTarget + ras.gray_min_x;
2479 bit2 = bit + ras.gray_width;
2481 c1 = ras.gray_max_x - ras.gray_min_x;
2485 c2 = count[*bit] + count[*bit2];
2489 pix[0] = grays[(c2 >> 12) & 0x000F];
2490 pix[1] = grays[(c2 >> 8 ) & 0x000F];
2491 pix[2] = grays[(c2 >> 4 ) & 0x000F];
2492 pix[3] = grays[ c2 & 0x000F];
2506 c2 = count[*bit] + count[*bit2];
2512 pix[2] = grays[(c2 >> 4 ) & 0x000F];
2514 pix[1] = grays[(c2 >> 8 ) & 0x000F];
2516 pix[0] = grays[(c2 >> 12) & 0x000F];
2526 ras.traceG += ras.traceIncr;
2528 ras.gray_min_x = 32000;
2529 ras.gray_max_x = -32000;
2535 Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
2541 /* nothing, really */
2542 FT_UNUSED( raster );
2552 Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
2563 /* During the horizontal sweep, we only take care of drop-outs */
2569 if ( e1 == e2 + ras.precision )
2571 switch ( ras.dropOutControl )
2578 e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2584 /* Drop-out Control Rule #4 */
2586 /* The spec is not very clear regarding rule #4. It */
2587 /* presents a method that is way too costly to implement */
2588 /* while the general idea seems to get rid of `stubs'. */
2591 /* rightmost stub test */
2592 if ( left->next == right && left->height <= 0 )
2595 /* leftmost stub test */
2596 if ( right->next == left && left->start == y )
2599 if ( ras.dropOutControl == 2 )
2602 e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2607 return; /* unsupported mode */
2616 if ( x2 - x1 >= ras.precision_half )
2617 color = ras.grays[2];
2619 color = ras.grays[1];
2621 e1 = TRUNC( e1 ) / 2;
2622 if ( e1 < ras.target.rows )
2624 pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
2625 if ( ras.target.pitch > 0 )
2626 pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
2628 if ( pixel[0] == ras.grays[0] )
2635 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
2638 /*************************************************************************/
2640 /* Generic Sweep Drawing routine */
2642 /*************************************************************************/
2645 Draw_Sweep( RAS_ARG )
2647 Short y, y_change, y_height;
2649 PProfile P, Q, P_Left, P_Right;
2651 Short min_Y, max_Y, top, bottom, dropouts;
2653 Long x1, x2, xs, e1, e2;
2655 TProfileList waiting;
2656 TProfileList draw_left, draw_right;
2659 /* Init empty linked lists */
2661 Init_Linked( &waiting );
2663 Init_Linked( &draw_left );
2664 Init_Linked( &draw_right );
2666 /* first, compute min and max Y */
2669 max_Y = (Short)TRUNC( ras.minY );
2670 min_Y = (Short)TRUNC( ras.maxY );
2676 bottom = (Short)P->start;
2677 top = (Short)( P->start + P->height - 1 );
2679 if ( min_Y > bottom ) min_Y = bottom;
2680 if ( max_Y < top ) max_Y = top;
2683 InsNew( &waiting, P );
2688 /* Check the Y-turns */
2689 if ( ras.numTurns == 0 )
2691 ras.error = Raster_Err_Invalid;
2695 /* Now inits the sweep */
2697 ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
2699 /* Then compute the distance of each profile from min_Y */
2705 P->countL = (UShort)( P->start - min_Y );
2714 if ( ras.numTurns > 0 &&
2715 ras.sizeBuff[-ras.numTurns] == min_Y )
2718 while ( ras.numTurns > 0 )
2720 /* look in the waiting list for new activations */
2727 P->countL -= y_height;
2728 if ( P->countL == 0 )
2730 DelOld( &waiting, P );
2735 InsNew( &draw_left, P );
2739 InsNew( &draw_right, P );
2747 /* Sort the drawing lists */
2750 Sort( &draw_right );
2752 y_change = (Short)ras.sizeBuff[-ras.numTurns--];
2753 y_height = (Short)( y_change - y );
2755 while ( y < y_change )
2762 P_Right = draw_right;
2776 if ( x2 - x1 <= ras.precision )
2781 if ( ras.dropOutControl != 0 &&
2782 ( e1 > e2 || e2 == e1 + ras.precision ) )
2784 /* a drop out was detected */
2789 /* mark profile for drop-out processing */
2797 ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
2801 P_Left = P_Left->link;
2802 P_Right = P_Right->link;
2805 /* now perform the dropouts _after_ the span drawing -- */
2806 /* drop-outs processing has been moved out of the loop */
2807 /* for performance tuning */
2813 ras.Proc_Sweep_Step( RAS_VAR );
2820 Sort( &draw_right );
2824 /* Now finalize the profiles that needs it */
2830 if ( P->height == 0 )
2831 DelOld( &draw_left, P );
2839 if ( P->height == 0 )
2840 DelOld( &draw_right, P );
2845 /* for gray-scaling, flushes the bitmap scanline cache */
2846 while ( y <= max_Y )
2848 ras.Proc_Sweep_Step( RAS_VAR );
2857 P_Right = draw_right;
2861 if ( P_Left->countL )
2865 dropouts--; /* -- this is useful when debugging only */
2867 ras.Proc_Sweep_Drop( RAS_VARS y,
2874 P_Left = P_Left->link;
2875 P_Right = P_Right->link;
2882 /*************************************************************************/
2885 /* Render_Single_Pass */
2888 /* Performs one sweep with sub-banding. */
2891 /* flipped :: If set, flip the direction of the outline. */
2894 /* Renderer error code. */
2897 Render_Single_Pass( RAS_ARGS Bool flipped )
2902 while ( ras.band_top >= 0 )
2904 ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
2905 ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
2909 ras.error = Raster_Err_None;
2911 if ( Convert_Glyph( RAS_VARS flipped ) )
2913 if ( ras.error != Raster_Err_Overflow )
2916 ras.error = Raster_Err_None;
2921 ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
2924 i = ras.band_stack[ras.band_top].y_min;
2925 j = ras.band_stack[ras.band_top].y_max;
2927 k = (Short)( ( i + j ) / 2 );
2929 if ( ras.band_top >= 7 || k < i )
2932 ras.error = Raster_Err_Invalid;
2937 ras.band_stack[ras.band_top + 1].y_min = k;
2938 ras.band_stack[ras.band_top + 1].y_max = j;
2940 ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
2947 if ( Draw_Sweep( RAS_VAR ) )
2957 /*************************************************************************/
2963 /* Renders a glyph in a bitmap. Sub-banding if needed. */
2966 /* FreeType error code. 0 means success. */
2968 FT_LOCAL_DEF( FT_Error )
2969 Render_Glyph( RAS_ARG )
2974 Set_High_Precision( RAS_VARS ras.outline.flags &
2975 FT_OUTLINE_HIGH_PRECISION );
2976 ras.scale_shift = ras.precision_shift;
2977 ras.dropOutControl = 2;
2978 ras.second_pass = (FT_Byte)( !( ras.outline.flags &
2979 FT_OUTLINE_SINGLE_PASS ) );
2981 /* Vertical Sweep */
2982 ras.Proc_Sweep_Init = Vertical_Sweep_Init;
2983 ras.Proc_Sweep_Span = Vertical_Sweep_Span;
2984 ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
2985 ras.Proc_Sweep_Step = Vertical_Sweep_Step;
2988 ras.band_stack[0].y_min = 0;
2989 ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
2991 ras.bWidth = (unsigned short)ras.target.width;
2992 ras.bTarget = (Byte*)ras.target.buffer;
2994 if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
2997 /* Horizontal Sweep */
2998 if ( ras.second_pass && ras.dropOutControl != 0 )
3000 ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
3001 ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
3002 ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
3003 ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
3006 ras.band_stack[0].y_min = 0;
3007 ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
3009 if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
3013 return Raster_Err_Ok;
3017 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3020 /*************************************************************************/
3023 /* Render_Gray_Glyph */
3026 /* Renders a glyph with grayscaling. Sub-banding if needed. */
3029 /* FreeType error code. 0 means success. */
3031 FT_LOCAL_DEF( FT_Error )
3032 Render_Gray_Glyph( RAS_ARG )
3038 Set_High_Precision( RAS_VARS ras.outline.flags &
3039 FT_OUTLINE_HIGH_PRECISION );
3040 ras.scale_shift = ras.precision_shift + 1;
3041 ras.dropOutControl = 2;
3042 ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
3044 /* Vertical Sweep */
3047 ras.band_stack[0].y_min = 0;
3048 ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
3050 ras.bWidth = ras.gray_width;
3051 pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
3053 if ( ras.bWidth > pixel_width )
3054 ras.bWidth = pixel_width;
3056 ras.bWidth = ras.bWidth * 8;
3057 ras.bTarget = (Byte*)ras.gray_lines;
3058 ras.gTarget = (Byte*)ras.target.buffer;
3060 ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
3061 ras.Proc_Sweep_Span = Vertical_Sweep_Span;
3062 ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
3063 ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
3065 error = Render_Single_Pass( RAS_VARS 0 );
3069 /* Horizontal Sweep */
3070 if ( ras.second_pass && ras.dropOutControl != 0 )
3072 ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
3073 ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
3074 ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
3075 ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
3078 ras.band_stack[0].y_min = 0;
3079 ras.band_stack[0].y_max = ras.target.width * 2 - 1;
3081 error = Render_Single_Pass( RAS_VARS 1 );
3086 return Raster_Err_Ok;
3089 #else /* !FT_RASTER_OPTION_ANTI_ALIASING */
3091 FT_LOCAL_DEF( FT_Error )
3092 Render_Gray_Glyph( RAS_ARG )
3096 return Raster_Err_Cannot_Render_Glyph;
3099 #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
3103 ft_black_init( TRaster_Instance* raster )
3109 /* setup count table */
3110 for ( n = 0; n < 256; n++ )
3112 c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
3114 c = ( ( c << 6 ) & 0x3000 ) |
3115 ( ( c << 4 ) & 0x0300 ) |
3116 ( ( c << 2 ) & 0x0030 ) |
3119 raster->count_table[n] = (UInt)c;
3122 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3124 /* set default 5-levels gray palette */
3125 for ( n = 0; n < 5; n++ )
3126 raster->grays[n] = n * 255 / 4;
3128 raster->gray_width = RASTER_GRAY_LINES / 2;
3134 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
3135 /**** a static object. *****/
3142 ft_black_new( void* memory,
3143 FT_Raster *araster )
3145 static FT_RasterRec_ the_raster;
3148 *araster = &the_raster;
3149 FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
3150 ft_black_init( &the_raster );
3157 ft_black_done( FT_Raster raster )
3164 #else /* _STANDALONE_ */
3168 ft_black_new( FT_Memory memory,
3169 TRaster_Instance** araster )
3172 TRaster_Instance* raster;
3176 if ( !FT_NEW( raster ) )
3178 raster->memory = memory;
3179 ft_black_init( raster );
3189 ft_black_done( TRaster_Instance* raster )
3191 FT_Memory memory = (FT_Memory)raster->memory;
3196 #endif /* _STANDALONE_ */
3200 ft_black_reset( TRaster_Instance* raster,
3201 const char* pool_base,
3204 if ( raster && pool_base && pool_size >= 4096 )
3207 raster->buff = (PLong)pool_base;
3208 raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
3214 ft_black_set_mode( TRaster_Instance* raster,
3216 const char* palette )
3218 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3220 if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
3222 /* set 5-levels gray palette */
3223 raster->grays[0] = palette[0];
3224 raster->grays[1] = palette[1];
3225 raster->grays[2] = palette[2];
3226 raster->grays[3] = palette[3];
3227 raster->grays[4] = palette[4];
3232 FT_UNUSED( raster );
3234 FT_UNUSED( palette );
3241 ft_black_render( TRaster_Instance* raster,
3242 FT_Raster_Params* params )
3244 FT_Outline* outline = (FT_Outline*)params->source;
3245 FT_Bitmap* target_map = params->target;
3248 if ( !raster || !raster->buff || !raster->sizeBuff )
3249 return Raster_Err_Not_Ini;
3251 /* return immediately if the outline is empty */
3252 if ( outline->n_points == 0 || outline->n_contours <= 0 )
3253 return Raster_Err_None;
3255 if ( !outline || !outline->contours || !outline->points )
3256 return Raster_Err_Invalid;
3258 if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
3259 return Raster_Err_Invalid;
3261 /* this version of the raster does not support direct rendering, sorry */
3262 if ( params->flags & FT_RASTER_FLAG_DIRECT )
3263 return Raster_Err_Unsupported;
3265 if ( !target_map || !target_map->buffer )
3266 return Raster_Err_Invalid;
3268 ras.outline = *outline;
3269 ras.target = *target_map;
3271 return ( ( params->flags & FT_RASTER_FLAG_AA )
3272 ? Render_Gray_Glyph( raster )
3273 : Render_Glyph( raster ) );
3277 const FT_Raster_Funcs ft_standard_raster =
3279 FT_GLYPH_FORMAT_OUTLINE,
3280 (FT_Raster_New_Func) ft_black_new,
3281 (FT_Raster_Reset_Func) ft_black_reset,
3282 (FT_Raster_Set_Mode_Func)ft_black_set_mode,
3283 (FT_Raster_Render_Func) ft_black_render,
3284 (FT_Raster_Done_Func) ft_black_done