1 /***************************************************************************/
5 /* The FreeType glyph rasterizer (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2005, 2007, 2008, 2009, 2010 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 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 */
25 /* - copy `src/raster/ftraster.c' (this file) to your current directory */
27 /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' */
28 /* to your current directory */
30 /* - compile `ftraster' with the _STANDALONE_ macro defined, as in */
32 /* cc -c -D_STANDALONE_ ftraster.c */
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'. */
38 /* See the comments and documentation in the file `ftimage.h' for more */
39 /* details on how the raster works. */
41 /*************************************************************************/
44 /*************************************************************************/
46 /* This is a rewrite of the FreeType 1.x scan-line converter */
48 /*************************************************************************/
52 #define FT_CONFIG_STANDARD_LIBRARY_H <stdlib.h>
54 #include <string.h> /* for memset */
59 #else /* !_STANDALONE_ */
63 #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
67 #endif /* !_STANDALONE_ */
70 /*************************************************************************/
72 /* A simple technical note on how the raster works */
73 /* ----------------------------------------------- */
75 /* Converting an outline into a bitmap is achieved in several steps: */
77 /* 1 - Decomposing the outline into successive `profiles'. Each */
78 /* profile is simply an array of scanline intersections on a given */
79 /* dimension. A profile's main attributes are */
81 /* o its scanline position boundaries, i.e. `Ymin' and `Ymax' */
83 /* o an array of intersection coordinates for each scanline */
84 /* between `Ymin' and `Ymax' */
86 /* o a direction, indicating whether it was built going `up' or */
87 /* `down', as this is very important for filling rules */
89 /* o its drop-out mode */
91 /* 2 - Sweeping the target map's scanlines in order to compute segment */
92 /* `spans' which are then filled. Additionally, this pass */
93 /* performs drop-out control. */
95 /* The outline data is parsed during step 1 only. The profiles are */
96 /* built from the bottom of the render pool, used as a stack. The */
97 /* following graphics shows the profile list under construction: */
99 /* __________________________________________________________ _ _ */
101 /* | profile | coordinates for | profile | coordinates for |--> */
102 /* | 1 | profile 1 | 2 | profile 2 |--> */
103 /* |_________|_________________|_________|_________________|__ _ _ */
107 /* start of render pool top */
109 /* The top of the profile stack is kept in the `top' variable. */
111 /* As you can see, a profile record is pushed on top of the render */
112 /* pool, which is then followed by its coordinates/intersections. If */
113 /* a change of direction is detected in the outline, a new profile is */
114 /* generated until the end of the outline. */
116 /* Note that when all profiles have been generated, the function */
117 /* Finalize_Profile_Table() is used to record, for each profile, its */
118 /* bottom-most scanline as well as the scanline above its upmost */
119 /* boundary. These positions are called `y-turns' because they (sort */
120 /* of) correspond to local extrema. They are stored in a sorted list */
121 /* built from the top of the render pool as a downwards stack: */
123 /* _ _ _______________________________________ */
125 /* <--| sorted list of | */
126 /* <--| extrema scanlines | */
127 /* _ _ __________________|____________________| */
131 /* maxBuff sizeBuff = end of pool */
133 /* This list is later used during the sweep phase in order to */
134 /* optimize performance (see technical note on the sweep below). */
136 /* Of course, the raster detects whether the two stacks collide and */
137 /* handles the situation properly. */
139 /*************************************************************************/
142 /*************************************************************************/
143 /*************************************************************************/
145 /** CONFIGURATION MACROS **/
147 /*************************************************************************/
148 /*************************************************************************/
150 /* define DEBUG_RASTER if you want to compile a debugging version */
151 /* #define DEBUG_RASTER */
153 /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */
154 /* 5-levels anti-aliasing */
155 /* #define FT_RASTER_OPTION_ANTI_ALIASING */
157 /* The size of the two-lines intermediate bitmap used */
158 /* for anti-aliasing, in bytes. */
159 #define RASTER_GRAY_LINES 2048
162 /*************************************************************************/
163 /*************************************************************************/
165 /** OTHER MACROS (do not change) **/
167 /*************************************************************************/
168 /*************************************************************************/
170 /*************************************************************************/
172 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
173 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
174 /* messages during execution. */
177 #define FT_COMPONENT trace_raster
183 /* This macro is used to indicate that a function parameter is unused. */
184 /* Its purpose is simply to reduce compiler warnings. Note also that */
185 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
186 /* ANSI compilers (e.g. LCC). */
187 #define FT_UNUSED( x ) (x) = (x)
189 /* Disable the tracing mechanism for simplicity -- developers can */
190 /* activate it easily by redefining these two macros. */
192 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
196 #define FT_TRACE( x ) do { } while ( 0 ) /* nothing */
197 #define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */
198 #define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */
201 #define Raster_Err_None 0
202 #define Raster_Err_Not_Ini -1
203 #define Raster_Err_Overflow -2
204 #define Raster_Err_Neg_Height -3
205 #define Raster_Err_Invalid -4
206 #define Raster_Err_Unsupported -5
208 #define ft_memset memset
210 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \
211 raster_reset_, raster_set_mode_, \
212 raster_render_, raster_done_ ) \
213 const FT_Raster_Funcs class_ = \
223 #else /* !_STANDALONE_ */
226 #include FT_INTERNAL_OBJECTS_H
227 #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
229 #include "rasterrs.h"
231 #define Raster_Err_None Raster_Err_Ok
232 #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
233 #define Raster_Err_Overflow Raster_Err_Raster_Overflow
234 #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
235 #define Raster_Err_Invalid Raster_Err_Invalid_Outline
236 #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
239 #endif /* !_STANDALONE_ */
243 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
247 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
250 /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
251 /* typically a small value and the result of a*b is known to fit into */
253 #define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
255 /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
256 /* for clipping computations. It simply uses the FT_MulDiv() function */
257 /* defined in `ftcalc.h'. */
258 #define SMulDiv FT_MulDiv
260 /* The rasterizer is a very general purpose component; please leave */
261 /* the following redefinitions there (you never know your target */
273 #define NULL (void*)0
285 #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
286 /* Setting this constant to more than 32 is a */
287 /* pure waste of space. */
289 #define Pixel_Bits 6 /* fractional bits of *input* coordinates */
292 /*************************************************************************/
293 /*************************************************************************/
295 /** SIMPLE TYPE DECLARATIONS **/
297 /*************************************************************************/
298 /*************************************************************************/
301 typedef unsigned int UInt
;
303 typedef unsigned short UShort
, *PUShort
;
304 typedef long Long
, *PLong
;
306 typedef unsigned char Byte
, *PByte
;
310 typedef union Alignment_
316 } Alignment
, *PAlignment
;
319 typedef struct TPoint_
327 /* values for the `flags' bit field */
329 #define Overshoot_Top 0x10
330 #define Overshoot_Bottom 0x20
333 /* States of each line, arc, and profile */
334 typedef enum TStates_
344 typedef struct TProfile_ TProfile
;
345 typedef TProfile
* PProfile
;
349 FT_F26Dot6 X
; /* current coordinate during sweep */
350 PProfile link
; /* link to next profile (various purposes) */
351 PLong offset
; /* start of profile's data in render pool */
352 unsigned flags
; /* Bit 0-2: drop-out mode */
353 /* Bit 3: profile orientation (up/down) */
354 /* Bit 4: is top profile? */
355 /* Bit 5: is bottom profile? */
356 long height
; /* profile's height in scanlines */
357 long start
; /* profile's starting scanline */
359 unsigned countL
; /* number of lines to step before this */
360 /* profile becomes drawable */
362 PProfile next
; /* next profile in same contour, used */
363 /* during drop-out control */
366 typedef PProfile TProfileList
;
367 typedef PProfile
* PProfileList
;
370 /* Simple record used to implement a stack of bands, required */
371 /* by the sub-banding mechanism */
372 typedef struct TBand_
374 Short y_min
; /* band's minimum */
375 Short y_max
; /* band's maximum */
380 #define AlignProfileSize \
381 ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
384 #ifdef FT_STATIC_RASTER
387 #define RAS_ARGS /* void */
388 #define RAS_ARG /* void */
390 #define RAS_VARS /* void */
391 #define RAS_VAR /* void */
393 #define FT_UNUSED_RASTER do { } while ( 0 )
396 #else /* !FT_STATIC_RASTER */
399 #define RAS_ARGS PWorker worker,
400 #define RAS_ARG PWorker worker
402 #define RAS_VARS worker,
403 #define RAS_VAR worker
405 #define FT_UNUSED_RASTER FT_UNUSED( worker )
408 #endif /* !FT_STATIC_RASTER */
411 typedef struct TWorker_ TWorker
, *PWorker
;
414 /* prototypes used for sweep function dispatch */
416 Function_Sweep_Init( RAS_ARGS Short
* min
,
420 Function_Sweep_Span( RAS_ARGS Short y
,
427 Function_Sweep_Step( RAS_ARG
);
430 /* NOTE: These operations are only valid on 2's complement processors */
432 #define FLOOR( x ) ( (x) & -ras.precision )
433 #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
434 #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
435 #define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
436 #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
438 #define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half )
439 #define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half )
441 /* The most used variables are positioned at the top of the structure. */
442 /* Thus, their offset can be coded with less opcodes, resulting in a */
443 /* smaller executable. */
447 Int precision_bits
; /* precision related variables */
452 Int precision_jitter
;
454 Int scale_shift
; /* == precision_shift for bitmaps */
455 /* == precision_shift+1 for pixmaps */
457 PLong buff
; /* The profiles buffer */
458 PLong sizeBuff
; /* Render pool size */
459 PLong maxBuff
; /* Profiles buffer size */
460 PLong top
; /* Current cursor in buffer */
464 Int numTurns
; /* number of Y-turns in outline */
466 TPoint
* arc
; /* current Bezier arc pointer */
468 UShort bWidth
; /* target bitmap width */
469 PByte bTarget
; /* target bitmap buffer */
470 PByte gTarget
; /* target pixmap buffer */
475 UShort num_Profs
; /* current number of profiles */
477 Bool fresh
; /* signals a fresh new profile which */
478 /* `start' field must be completed */
479 Bool joint
; /* signals that the last arc ended */
480 /* exactly on a scanline. Allows */
481 /* removal of doublets */
482 PProfile cProfile
; /* current profile */
483 PProfile fProfile
; /* head of linked list of profiles */
484 PProfile gProfile
; /* contour's first profile in case */
487 TStates state
; /* rendering state */
489 FT_Bitmap target
; /* description of target bit/pixmap */
492 Long traceOfs
; /* current offset in target bitmap */
493 Long traceG
; /* current offset in target pixmap */
495 Short traceIncr
; /* sweep's increment in target bitmap */
497 Short gray_min_x
; /* current min x during gray rendering */
498 Short gray_max_x
; /* current max x during gray rendering */
500 /* dispatch variables */
502 Function_Sweep_Init
* Proc_Sweep_Init
;
503 Function_Sweep_Span
* Proc_Sweep_Span
;
504 Function_Sweep_Span
* Proc_Sweep_Drop
;
505 Function_Sweep_Step
* Proc_Sweep_Step
;
507 Byte dropOutControl
; /* current drop_out control method */
509 Bool second_pass
; /* indicates whether a horizontal pass */
510 /* should be performed to control */
511 /* drop-out accurately when calling */
512 /* Render_Glyph. Note that there is */
513 /* no horizontal pass during gray */
516 TPoint arcs
[3 * MaxBezier
+ 1]; /* The Bezier stack */
518 TBand band_stack
[16]; /* band stack used for sub-banding */
519 Int band_top
; /* band stack top */
521 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
525 Byte gray_lines
[RASTER_GRAY_LINES
];
526 /* Intermediate table used to render the */
527 /* graylevels pixmaps. */
528 /* gray_lines is a buffer holding two */
529 /* monochrome scanlines */
531 Short gray_width
; /* width in bytes of one monochrome */
532 /* intermediate scanline of gray_lines. */
533 /* Each gray pixel takes 2 bits long there */
535 /* The gray_lines must hold 2 lines, thus with size */
536 /* in bytes of at least `gray_width*2'. */
538 #endif /* FT_RASTER_ANTI_ALIASING */
543 typedef struct TRaster_
554 #ifdef FT_STATIC_RASTER
556 static TWorker cur_ras
;
559 #else /* !FT_STATIC_RASTER */
561 #define ras (*worker)
563 #endif /* !FT_STATIC_RASTER */
566 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
568 /* A lookup table used to quickly count set bits in four gray 2x2 */
569 /* cells. The values of the table have been produced with the */
570 /* following code: */
572 /* for ( i = 0; i < 256; i++ ) */
577 /* for ( c = 0; c < 4; c++ ) */
581 /* if ( j & 0x80 ) l++; */
582 /* if ( j & 0x40 ) l++; */
584 /* j = ( j << 2 ) & 0xFF; */
586 /* printf( "0x%04X", l ); */
590 static const short count_table
[256] =
592 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
593 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
594 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
595 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
596 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
597 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
598 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
599 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
600 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
601 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
602 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
603 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
604 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
605 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
606 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
607 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
608 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
609 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
610 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
611 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
612 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
613 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
614 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
615 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
616 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
617 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
618 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
619 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
620 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
621 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
622 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
623 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
626 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
630 /*************************************************************************/
631 /*************************************************************************/
633 /** PROFILES COMPUTATION **/
635 /*************************************************************************/
636 /*************************************************************************/
639 /*************************************************************************/
642 /* Set_High_Precision */
645 /* Set precision variables according to param flag. */
648 /* High :: Set to True for high precision (typically for ppem < 18), */
649 /* false otherwise. */
652 Set_High_Precision( RAS_ARGS Int High
)
656 ras
.precision_bits
= 12;
657 ras
.precision_step
= 256;
658 ras
.precision_jitter
= 50;
662 ras
.precision_bits
= 6;
663 ras
.precision_step
= 32;
664 ras
.precision_jitter
= 2;
667 FT_TRACE6(( "Set_High_Precision(%s)\n", High
? "true" : "false" ));
669 ras
.precision
= 1 << ras
.precision_bits
;
670 ras
.precision_half
= ras
.precision
/ 2;
671 ras
.precision_shift
= ras
.precision_bits
- Pixel_Bits
;
675 /*************************************************************************/
681 /* Create a new profile in the render pool. */
684 /* aState :: The state/orientation of the new profile. */
686 /* overshoot :: Whether the profile's unrounded start position */
687 /* differs by at least a half pixel. */
690 /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
694 New_Profile( RAS_ARGS TStates aState
,
699 ras
.cProfile
= (PProfile
)ras
.top
;
700 ras
.fProfile
= ras
.cProfile
;
701 ras
.top
+= AlignProfileSize
;
704 if ( ras
.top
>= ras
.maxBuff
)
706 ras
.error
= Raster_Err_Overflow
;
710 ras
.cProfile
->flags
= 0;
711 ras
.cProfile
->start
= 0;
712 ras
.cProfile
->height
= 0;
713 ras
.cProfile
->offset
= ras
.top
;
714 ras
.cProfile
->link
= (PProfile
)0;
715 ras
.cProfile
->next
= (PProfile
)0;
716 ras
.cProfile
->flags
= ras
.dropOutControl
;
720 case Ascending_State
:
721 ras
.cProfile
->flags
|= Flow_Up
;
723 ras
.cProfile
->flags
|= Overshoot_Bottom
;
725 FT_TRACE6(( "New ascending profile = %p\n", ras
.cProfile
));
728 case Descending_State
:
730 ras
.cProfile
->flags
|= Overshoot_Top
;
731 FT_TRACE6(( "New descending profile = %p\n", ras
.cProfile
));
735 FT_ERROR(( "New_Profile: invalid profile direction\n" ));
736 ras
.error
= Raster_Err_Invalid
;
741 ras
.gProfile
= ras
.cProfile
;
751 /*************************************************************************/
757 /* Finalize the current profile. */
760 /* overshoot :: Whether the profile's unrounded end position differs */
761 /* by at least a half pixel. */
764 /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
767 End_Profile( RAS_ARGS Bool overshoot
)
773 h
= (Long
)( ras
.top
- ras
.cProfile
->offset
);
777 FT_ERROR(( "End_Profile: negative height encountered\n" ));
778 ras
.error
= Raster_Err_Neg_Height
;
784 FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n",
785 ras
.cProfile
, ras
.cProfile
->start
, h
));
787 ras
.cProfile
->height
= h
;
790 if ( ras
.cProfile
->flags
& Flow_Up
)
791 ras
.cProfile
->flags
|= Overshoot_Top
;
793 ras
.cProfile
->flags
|= Overshoot_Bottom
;
796 oldProfile
= ras
.cProfile
;
797 ras
.cProfile
= (PProfile
)ras
.top
;
799 ras
.top
+= AlignProfileSize
;
801 ras
.cProfile
->height
= 0;
802 ras
.cProfile
->offset
= ras
.top
;
804 oldProfile
->next
= ras
.cProfile
;
808 if ( ras
.top
>= ras
.maxBuff
)
810 FT_TRACE1(( "overflow in End_Profile\n" ));
811 ras
.error
= Raster_Err_Overflow
;
821 /*************************************************************************/
827 /* Insert a salient into the sorted list placed on top of the render */
831 /* New y scanline position. */
834 /* SUCCESS on success. FAILURE in case of overflow. */
837 Insert_Y_Turn( RAS_ARGS Int y
)
843 n
= ras
.numTurns
- 1;
844 y_turns
= ras
.sizeBuff
- ras
.numTurns
;
846 /* look for first y value that is <= */
847 while ( n
>= 0 && y
< y_turns
[n
] )
850 /* if it is <, simply insert it, ignore if == */
851 if ( n
>= 0 && y
> y_turns
[n
] )
854 y2
= (Int
)y_turns
[n
];
863 if ( ras
.maxBuff
<= ras
.top
)
865 ras
.error
= Raster_Err_Overflow
;
869 ras
.sizeBuff
[-ras
.numTurns
] = y
;
876 /*************************************************************************/
879 /* Finalize_Profile_Table */
882 /* Adjust all links in the profiles list. */
885 /* SUCCESS on success. FAILURE in case of overflow. */
888 Finalize_Profile_Table( RAS_ARG
)
903 p
->link
= (PProfile
)( p
->offset
+ p
->height
);
907 if ( p
->flags
& Flow_Up
)
909 bottom
= (Int
)p
->start
;
910 top
= (Int
)( p
->start
+ p
->height
- 1 );
914 bottom
= (Int
)( p
->start
- p
->height
+ 1 );
917 p
->offset
+= p
->height
- 1;
920 if ( Insert_Y_Turn( RAS_VARS bottom
) ||
921 Insert_Y_Turn( RAS_VARS top
+ 1 ) )
935 /*************************************************************************/
941 /* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */
945 /* None (subdivided Bezier is taken from the top of the stack). */
948 /* This routine is the `beef' of this component. It is _the_ inner */
949 /* loop that should be optimized to hell to get the best performance. */
952 Split_Conic( TPoint
* base
)
957 base
[4].x
= base
[2].x
;
959 a
= base
[3].x
= ( base
[2].x
+ b
) / 2;
960 b
= base
[1].x
= ( base
[0].x
+ b
) / 2;
961 base
[2].x
= ( a
+ b
) / 2;
963 base
[4].y
= base
[2].y
;
965 a
= base
[3].y
= ( base
[2].y
+ b
) / 2;
966 b
= base
[1].y
= ( base
[0].y
+ b
) / 2;
967 base
[2].y
= ( a
+ b
) / 2;
969 /* hand optimized. gcc doesn't seem to be too good at common */
970 /* expression substitution and instruction scheduling ;-) */
974 /*************************************************************************/
980 /* Subdivide a third-order Bezier arc into two joint sub-arcs in the */
984 /* This routine is the `beef' of the component. It is one of _the_ */
985 /* inner loops that should be optimized like hell to get the best */
989 Split_Cubic( TPoint
* base
)
994 base
[6].x
= base
[3].x
;
997 base
[1].x
= a
= ( base
[0].x
+ c
+ 1 ) >> 1;
998 base
[5].x
= b
= ( base
[3].x
+ d
+ 1 ) >> 1;
999 c
= ( c
+ d
+ 1 ) >> 1;
1000 base
[2].x
= a
= ( a
+ c
+ 1 ) >> 1;
1001 base
[4].x
= b
= ( b
+ c
+ 1 ) >> 1;
1002 base
[3].x
= ( a
+ b
+ 1 ) >> 1;
1004 base
[6].y
= base
[3].y
;
1007 base
[1].y
= a
= ( base
[0].y
+ c
+ 1 ) >> 1;
1008 base
[5].y
= b
= ( base
[3].y
+ d
+ 1 ) >> 1;
1009 c
= ( c
+ d
+ 1 ) >> 1;
1010 base
[2].y
= a
= ( a
+ c
+ 1 ) >> 1;
1011 base
[4].y
= b
= ( b
+ c
+ 1 ) >> 1;
1012 base
[3].y
= ( a
+ b
+ 1 ) >> 1;
1016 /*************************************************************************/
1022 /* Compute the x-coordinates of an ascending line segment and store */
1023 /* them in the render pool. */
1026 /* x1 :: The x-coordinate of the segment's start point. */
1028 /* y1 :: The y-coordinate of the segment's start point. */
1030 /* x2 :: The x-coordinate of the segment's end point. */
1032 /* y2 :: The y-coordinate of the segment's end point. */
1034 /* miny :: A lower vertical clipping bound value. */
1036 /* maxy :: An upper vertical clipping bound value. */
1039 /* SUCCESS on success, FAILURE on render pool overflow. */
1042 Line_Up( RAS_ARGS Long x1
,
1050 Int e1
, e2
, f1
, f2
, size
; /* XXX: is `Short' sufficient? */
1059 if ( Dy
<= 0 || y2
< miny
|| y1
> maxy
)
1064 /* Take care: miny-y1 can be a very large value; we use */
1065 /* a slow MulDiv function to avoid clipping bugs */
1066 x1
+= SMulDiv( Dx
, miny
- y1
, Dy
);
1067 e1
= (Int
)TRUNC( miny
);
1072 e1
= (Int
)TRUNC( y1
);
1073 f1
= (Int
)FRAC( y1
);
1078 /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
1079 e2
= (Int
)TRUNC( maxy
);
1084 e2
= (Int
)TRUNC( y2
);
1085 f2
= (Int
)FRAC( y2
);
1094 x1
+= SMulDiv( Dx
, ras
.precision
- f1
, Dy
);
1105 ras
.joint
= (char)( f2
== 0 );
1109 ras
.cProfile
->start
= e1
;
1114 if ( ras
.top
+ size
>= ras
.maxBuff
)
1116 ras
.error
= Raster_Err_Overflow
;
1122 Ix
= SMulDiv( ras
.precision
, Dx
, Dy
);
1123 Rx
= ( ras
.precision
* Dx
) % Dy
;
1128 Ix
= SMulDiv( ras
.precision
, -Dx
, Dy
) * -1;
1129 Rx
= ( ras
.precision
* -Dx
) % Dy
;
1155 /*************************************************************************/
1161 /* Compute the x-coordinates of an descending line segment and store */
1162 /* them in the render pool. */
1165 /* x1 :: The x-coordinate of the segment's start point. */
1167 /* y1 :: The y-coordinate of the segment's start point. */
1169 /* x2 :: The x-coordinate of the segment's end point. */
1171 /* y2 :: The y-coordinate of the segment's end point. */
1173 /* miny :: A lower vertical clipping bound value. */
1175 /* maxy :: An upper vertical clipping bound value. */
1178 /* SUCCESS on success, FAILURE on render pool overflow. */
1181 Line_Down( RAS_ARGS Long x1
,
1193 result
= Line_Up( RAS_VARS x1
, -y1
, x2
, -y2
, -maxy
, -miny
);
1195 if ( fresh
&& !ras
.fresh
)
1196 ras
.cProfile
->start
= -ras
.cProfile
->start
;
1202 /* A function type describing the functions used to split Bezier arcs */
1203 typedef void (*TSplitter
)( TPoint
* base
);
1206 /*************************************************************************/
1212 /* Compute the x-coordinates of an ascending Bezier arc and store */
1213 /* them in the render pool. */
1216 /* degree :: The degree of the Bezier arc (either 2 or 3). */
1218 /* splitter :: The function to split Bezier arcs. */
1220 /* miny :: A lower vertical clipping bound value. */
1222 /* maxy :: An upper vertical clipping bound value. */
1225 /* SUCCESS on success, FAILURE on render pool overflow. */
1228 Bezier_Up( RAS_ARGS Int degree
,
1233 Long y1
, y2
, e
, e2
, e0
;
1247 if ( y2
< miny
|| y1
> maxy
)
1262 f1
= (Short
)( FRAC( y1
) );
1273 *top
++ = arc
[degree
].x
;
1281 ras
.cProfile
->start
= TRUNC( e0
);
1288 if ( ( top
+ TRUNC( e2
- e
) + 1 ) >= ras
.maxBuff
)
1291 ras
.error
= Raster_Err_Overflow
;
1297 while ( arc
>= start_arc
&& e
<= e2
)
1306 if ( y2
- y1
>= ras
.precision_step
)
1313 *top
++ = arc
[degree
].x
+ FMulDiv( arc
[0].x
- arc
[degree
].x
,
1339 /*************************************************************************/
1345 /* Compute the x-coordinates of an descending Bezier arc and store */
1346 /* them in the render pool. */
1349 /* degree :: The degree of the Bezier arc (either 2 or 3). */
1351 /* splitter :: The function to split Bezier arcs. */
1353 /* miny :: A lower vertical clipping bound value. */
1355 /* maxy :: An upper vertical clipping bound value. */
1358 /* SUCCESS on success, FAILURE on render pool overflow. */
1361 Bezier_Down( RAS_ARGS Int degree
,
1366 TPoint
* arc
= ras
.arc
;
1370 arc
[0].y
= -arc
[0].y
;
1371 arc
[1].y
= -arc
[1].y
;
1372 arc
[2].y
= -arc
[2].y
;
1374 arc
[3].y
= -arc
[3].y
;
1378 result
= Bezier_Up( RAS_VARS degree
, splitter
, -maxy
, -miny
);
1380 if ( fresh
&& !ras
.fresh
)
1381 ras
.cProfile
->start
= -ras
.cProfile
->start
;
1383 arc
[0].y
= -arc
[0].y
;
1388 /*************************************************************************/
1394 /* Inject a new line segment and adjust the Profiles list. */
1397 /* x :: The x-coordinate of the segment's end point (its start point */
1398 /* is stored in `lastX'). */
1400 /* y :: The y-coordinate of the segment's end point (its start point */
1401 /* is stored in `lastY'). */
1404 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1408 Line_To( RAS_ARGS Long x
,
1411 /* First, detect a change of direction */
1413 switch ( ras
.state
)
1416 if ( y
> ras
.lastY
)
1418 if ( New_Profile( RAS_VARS Ascending_State
,
1419 IS_BOTTOM_OVERSHOOT( ras
.lastY
) ) )
1424 if ( y
< ras
.lastY
)
1425 if ( New_Profile( RAS_VARS Descending_State
,
1426 IS_TOP_OVERSHOOT( ras
.lastY
) ) )
1431 case Ascending_State
:
1432 if ( y
< ras
.lastY
)
1434 if ( End_Profile( RAS_VARS
IS_TOP_OVERSHOOT( ras
.lastY
) ) ||
1435 New_Profile( RAS_VARS Descending_State
,
1436 IS_TOP_OVERSHOOT( ras
.lastY
) ) )
1441 case Descending_State
:
1442 if ( y
> ras
.lastY
)
1444 if ( End_Profile( RAS_VARS
IS_BOTTOM_OVERSHOOT( ras
.lastY
) ) ||
1445 New_Profile( RAS_VARS Ascending_State
,
1446 IS_BOTTOM_OVERSHOOT( ras
.lastY
) ) )
1455 /* Then compute the lines */
1457 switch ( ras
.state
)
1459 case Ascending_State
:
1460 if ( Line_Up( RAS_VARS ras
.lastX
, ras
.lastY
,
1461 x
, y
, ras
.minY
, ras
.maxY
) )
1465 case Descending_State
:
1466 if ( Line_Down( RAS_VARS ras
.lastX
, ras
.lastY
,
1467 x
, y
, ras
.minY
, ras
.maxY
) )
1482 /*************************************************************************/
1488 /* Inject a new conic arc and adjust the profile list. */
1491 /* cx :: The x-coordinate of the arc's new control point. */
1493 /* cy :: The y-coordinate of the arc's new control point. */
1495 /* x :: The x-coordinate of the arc's end point (its start point is */
1496 /* stored in `lastX'). */
1498 /* y :: The y-coordinate of the arc's end point (its start point is */
1499 /* stored in `lastY'). */
1502 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1506 Conic_To( RAS_ARGS Long cx
,
1511 Long y1
, y2
, y3
, x3
, ymin
, ymax
;
1516 ras
.arc
[2].x
= ras
.lastX
;
1517 ras
.arc
[2].y
= ras
.lastY
;
1530 /* first, categorize the Bezier arc */
1543 if ( y2
< ymin
|| y2
> ymax
)
1545 /* this arc has no given direction, split it! */
1546 Split_Conic( ras
.arc
);
1549 else if ( y1
== y3
)
1551 /* this arc is flat, ignore it and pop it from the Bezier stack */
1556 /* the arc is y-monotonous, either ascending or descending */
1557 /* detect a change of direction */
1558 state_bez
= y1
< y3
? Ascending_State
: Descending_State
;
1559 if ( ras
.state
!= state_bez
)
1561 Bool o
= state_bez
== Ascending_State
? IS_BOTTOM_OVERSHOOT( y1
)
1562 : IS_TOP_OVERSHOOT( y1
);
1565 /* finalize current profile if any */
1566 if ( ras
.state
!= Unknown_State
&&
1567 End_Profile( RAS_VARS o
) )
1570 /* create a new profile */
1571 if ( New_Profile( RAS_VARS state_bez
, o
) )
1575 /* now call the appropriate routine */
1576 if ( state_bez
== Ascending_State
)
1578 if ( Bezier_Up( RAS_VARS
2, Split_Conic
, ras
.minY
, ras
.maxY
) )
1582 if ( Bezier_Down( RAS_VARS
2, Split_Conic
, ras
.minY
, ras
.maxY
) )
1586 } while ( ras
.arc
>= ras
.arcs
);
1598 /*************************************************************************/
1604 /* Inject a new cubic arc and adjust the profile list. */
1607 /* cx1 :: The x-coordinate of the arc's first new control point. */
1609 /* cy1 :: The y-coordinate of the arc's first new control point. */
1611 /* cx2 :: The x-coordinate of the arc's second new control point. */
1613 /* cy2 :: The y-coordinate of the arc's second new control point. */
1615 /* x :: The x-coordinate of the arc's end point (its start point is */
1616 /* stored in `lastX'). */
1618 /* y :: The y-coordinate of the arc's end point (its start point is */
1619 /* stored in `lastY'). */
1622 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1626 Cubic_To( RAS_ARGS Long cx1
,
1633 Long y1
, y2
, y3
, y4
, x4
, ymin1
, ymax1
, ymin2
, ymax2
;
1638 ras
.arc
[3].x
= ras
.lastX
;
1639 ras
.arc
[3].y
= ras
.lastY
;
1655 /* first, categorize the Bezier arc */
1679 if ( ymin2
< ymin1
|| ymax2
> ymax1
)
1681 /* this arc has no given direction, split it! */
1682 Split_Cubic( ras
.arc
);
1685 else if ( y1
== y4
)
1687 /* this arc is flat, ignore it and pop it from the Bezier stack */
1692 state_bez
= ( y1
<= y4
) ? Ascending_State
: Descending_State
;
1694 /* detect a change of direction */
1695 if ( ras
.state
!= state_bez
)
1697 Bool o
= state_bez
== Ascending_State
? IS_BOTTOM_OVERSHOOT( y1
)
1698 : IS_TOP_OVERSHOOT( y1
);
1701 /* finalize current profile if any */
1702 if ( ras
.state
!= Unknown_State
&&
1703 End_Profile( RAS_VARS o
) )
1706 if ( New_Profile( RAS_VARS state_bez
, o
) )
1710 /* compute intersections */
1711 if ( state_bez
== Ascending_State
)
1713 if ( Bezier_Up( RAS_VARS
3, Split_Cubic
, ras
.minY
, ras
.maxY
) )
1717 if ( Bezier_Down( RAS_VARS
3, Split_Cubic
, ras
.minY
, ras
.maxY
) )
1721 } while ( ras
.arc
>= ras
.arcs
);
1734 #define SWAP_( x, y ) do \
1744 /*************************************************************************/
1747 /* Decompose_Curve */
1750 /* Scan the outline arrays in order to emit individual segments and */
1751 /* Beziers by calling Line_To() and Bezier_To(). It handles all */
1752 /* weird cases, like when the first point is off the curve, or when */
1753 /* there are simply no `on' points in the contour! */
1756 /* first :: The index of the first point in the contour. */
1758 /* last :: The index of the last point in the contour. */
1760 /* flipped :: If set, flip the direction of the curve. */
1763 /* SUCCESS on success, FAILURE on error. */
1766 Decompose_Curve( RAS_ARGS UShort first
,
1771 FT_Vector v_control
;
1779 unsigned tag
; /* current point's state */
1782 points
= ras
.outline
.points
;
1783 limit
= points
+ last
;
1785 v_start
.x
= SCALED( points
[first
].x
);
1786 v_start
.y
= SCALED( points
[first
].y
);
1787 v_last
.x
= SCALED( points
[last
].x
);
1788 v_last
.y
= SCALED( points
[last
].y
);
1792 SWAP_( v_start
.x
, v_start
.y
);
1793 SWAP_( v_last
.x
, v_last
.y
);
1796 v_control
= v_start
;
1798 point
= points
+ first
;
1799 tags
= ras
.outline
.tags
+ first
;
1801 /* set scan mode if necessary */
1802 if ( tags
[0] & FT_CURVE_TAG_HAS_SCANMODE
)
1803 ras
.dropOutControl
= (Byte
)tags
[0] >> 5;
1805 tag
= FT_CURVE_TAG( tags
[0] );
1807 /* A contour cannot start with a cubic control point! */
1808 if ( tag
== FT_CURVE_TAG_CUBIC
)
1809 goto Invalid_Outline
;
1811 /* check first point to determine origin */
1812 if ( tag
== FT_CURVE_TAG_CONIC
)
1814 /* first point is conic control. Yes, this happens. */
1815 if ( FT_CURVE_TAG( ras
.outline
.tags
[last
] ) == FT_CURVE_TAG_ON
)
1817 /* start at last point if it is on the curve */
1823 /* if both first and last points are conic, */
1824 /* start at their middle and record its position */
1826 v_start
.x
= ( v_start
.x
+ v_last
.x
) / 2;
1827 v_start
.y
= ( v_start
.y
+ v_last
.y
) / 2;
1835 ras
.lastX
= v_start
.x
;
1836 ras
.lastY
= v_start
.y
;
1838 while ( point
< limit
)
1843 tag
= FT_CURVE_TAG( tags
[0] );
1847 case FT_CURVE_TAG_ON
: /* emit a single line_to */
1852 x
= SCALED( point
->x
);
1853 y
= SCALED( point
->y
);
1857 if ( Line_To( RAS_VARS x
, y
) )
1862 case FT_CURVE_TAG_CONIC
: /* consume conic arcs */
1863 v_control
.x
= SCALED( point
[0].x
);
1864 v_control
.y
= SCALED( point
[0].y
);
1867 SWAP_( v_control
.x
, v_control
.y
);
1870 if ( point
< limit
)
1878 tag
= FT_CURVE_TAG( tags
[0] );
1880 x
= SCALED( point
[0].x
);
1881 y
= SCALED( point
[0].y
);
1886 if ( tag
== FT_CURVE_TAG_ON
)
1888 if ( Conic_To( RAS_VARS v_control
.x
, v_control
.y
, x
, y
) )
1893 if ( tag
!= FT_CURVE_TAG_CONIC
)
1894 goto Invalid_Outline
;
1896 v_middle
.x
= ( v_control
.x
+ x
) / 2;
1897 v_middle
.y
= ( v_control
.y
+ y
) / 2;
1899 if ( Conic_To( RAS_VARS v_control
.x
, v_control
.y
,
1900 v_middle
.x
, v_middle
.y
) )
1909 if ( Conic_To( RAS_VARS v_control
.x
, v_control
.y
,
1910 v_start
.x
, v_start
.y
) )
1915 default: /* FT_CURVE_TAG_CUBIC */
1917 Long x1
, y1
, x2
, y2
, x3
, y3
;
1920 if ( point
+ 1 > limit
||
1921 FT_CURVE_TAG( tags
[1] ) != FT_CURVE_TAG_CUBIC
)
1922 goto Invalid_Outline
;
1927 x1
= SCALED( point
[-2].x
);
1928 y1
= SCALED( point
[-2].y
);
1929 x2
= SCALED( point
[-1].x
);
1930 y2
= SCALED( point
[-1].y
);
1938 if ( point
<= limit
)
1940 x3
= SCALED( point
[0].x
);
1941 y3
= SCALED( point
[0].y
);
1946 if ( Cubic_To( RAS_VARS x1
, y1
, x2
, y2
, x3
, y3
) )
1951 if ( Cubic_To( RAS_VARS x1
, y1
, x2
, y2
, v_start
.x
, v_start
.y
) )
1958 /* close the contour with a line segment */
1959 if ( Line_To( RAS_VARS v_start
.x
, v_start
.y
) )
1966 ras
.error
= Raster_Err_Invalid
;
1973 /*************************************************************************/
1979 /* Convert a glyph into a series of segments and arcs and make a */
1980 /* profiles list with them. */
1983 /* flipped :: If set, flip the direction of curve. */
1986 /* SUCCESS on success, FAILURE if any error was encountered during */
1990 Convert_Glyph( RAS_ARGS
int flipped
)
1995 PProfile lastProfile
;
1998 ras
.fProfile
= NULL
;
2002 ras
.maxBuff
= ras
.sizeBuff
- AlignProfileSize
;
2006 ras
.cProfile
= (PProfile
)ras
.top
;
2007 ras
.cProfile
->offset
= ras
.top
;
2012 for ( i
= 0; i
< ras
.outline
.n_contours
; i
++ )
2017 ras
.state
= Unknown_State
;
2018 ras
.gProfile
= NULL
;
2020 if ( Decompose_Curve( RAS_VARS (unsigned short)start
,
2021 ras
.outline
.contours
[i
],
2025 start
= ras
.outline
.contours
[i
] + 1;
2027 /* we must now check whether the extreme arcs join or not */
2028 if ( FRAC( ras
.lastY
) == 0 &&
2029 ras
.lastY
>= ras
.minY
&&
2030 ras
.lastY
<= ras
.maxY
)
2031 if ( ras
.gProfile
&&
2032 ( ras
.gProfile
->flags
& Flow_Up
) ==
2033 ( ras
.cProfile
->flags
& Flow_Up
) )
2035 /* Note that ras.gProfile can be nil if the contour was too small */
2038 lastProfile
= ras
.cProfile
;
2039 if ( ras
.cProfile
->flags
& Flow_Up
)
2040 o
= IS_TOP_OVERSHOOT( ras
.lastY
);
2042 o
= IS_BOTTOM_OVERSHOOT( ras
.lastY
);
2043 if ( End_Profile( RAS_VARS o
) )
2046 /* close the `next profile in contour' linked list */
2048 lastProfile
->next
= ras
.gProfile
;
2051 if ( Finalize_Profile_Table( RAS_VAR
) )
2054 return (Bool
)( ras
.top
< ras
.maxBuff
? SUCCESS
: FAILURE
);
2058 /*************************************************************************/
2059 /*************************************************************************/
2061 /** SCAN-LINE SWEEPS AND DRAWING **/
2063 /*************************************************************************/
2064 /*************************************************************************/
2067 /*************************************************************************/
2071 /* Initializes an empty linked list. */
2074 Init_Linked( TProfileList
* l
)
2080 /*************************************************************************/
2084 /* Inserts a new profile in a linked list. */
2087 InsNew( PProfileList list
,
2090 PProfile
*old
, current
;
2100 if ( x
< current
->X
)
2102 old
= ¤t
->link
;
2106 profile
->link
= current
;
2111 /*************************************************************************/
2115 /* Removes an old profile from a linked list. */
2118 DelOld( PProfileList list
,
2121 PProfile
*old
, current
;
2129 if ( current
== profile
)
2131 *old
= current
->link
;
2135 old
= ¤t
->link
;
2139 /* we should never get there, unless the profile was not part of */
2144 /*************************************************************************/
2148 /* Sorts a trace list. In 95%, the list is already sorted. We need */
2149 /* an algorithm which is fast in this case. Bubble sort is enough */
2153 Sort( PProfileList list
)
2155 PProfile
*old
, current
, next
;
2158 /* First, set the new X coordinate of each profile */
2162 current
->X
= *current
->offset
;
2163 current
->offset
+= current
->flags
& Flow_Up
? 1 : -1;
2165 current
= current
->link
;
2168 /* Then sort them */
2175 next
= current
->link
;
2179 if ( current
->X
<= next
->X
)
2181 old
= ¤t
->link
;
2190 current
->link
= next
->link
;
2191 next
->link
= current
;
2197 next
= current
->link
;
2202 /*************************************************************************/
2204 /* Vertical Sweep Procedure Set */
2206 /* These four routines are used during the vertical black/white sweep */
2207 /* phase by the generic Draw_Sweep() function. */
2209 /*************************************************************************/
2212 Vertical_Sweep_Init( RAS_ARGS Short
* min
,
2215 Long pitch
= ras
.target
.pitch
;
2220 ras
.traceIncr
= (Short
)-pitch
;
2221 ras
.traceOfs
= -*min
* pitch
;
2223 ras
.traceOfs
+= ( ras
.target
.rows
- 1 ) * pitch
;
2231 Vertical_Sweep_Span( RAS_ARGS Short y
,
2247 /* Drop-out control */
2249 e1
= TRUNC( CEILING( x1
) );
2251 if ( x2
- x1
- ras
.precision
<= ras
.precision_jitter
)
2254 e2
= TRUNC( FLOOR( x2
) );
2256 if ( e2
>= 0 && e1
< ras
.bWidth
)
2260 if ( e2
>= ras
.bWidth
)
2261 e2
= ras
.bWidth
- 1;
2263 c1
= (Short
)( e1
>> 3 );
2264 c2
= (Short
)( e2
>> 3 );
2266 f1
= (Byte
) ( 0xFF >> ( e1
& 7 ) );
2267 f2
= (Byte
) ~( 0x7F >> ( e2
& 7 ) );
2269 if ( ras
.gray_min_x
> c1
)
2270 ras
.gray_min_x
= (short)c1
;
2271 if ( ras
.gray_max_x
< c2
)
2272 ras
.gray_max_x
= (short)c2
;
2274 target
= ras
.bTarget
+ ras
.traceOfs
+ c1
;
2281 /* memset() is slower than the following code on many platforms. */
2282 /* This is due to the fact that, in the vast majority of cases, */
2283 /* the span length in bytes is relatively small. */
2293 *target
|= ( f1
& f2
);
2299 Vertical_Sweep_Drop( RAS_ARGS Short y
,
2309 /* Drop-out control */
2315 /* +-------------+---------------------+------------+ */
2319 /* pixel contour contour pixel */
2322 /* drop-out mode scan conversion rules (as defined in OpenType) */
2323 /* --------------------------------------------------------------- */
2327 /* 3 same as mode 2 */
2330 /* 6, 7 same as mode 2 */
2338 Int dropOutControl
= left
->flags
& 7;
2341 if ( e1
== e2
+ ras
.precision
)
2343 switch ( dropOutControl
)
2345 case 0: /* simple drop-outs including stubs */
2349 case 4: /* smart drop-outs including stubs */
2350 pxl
= FLOOR( ( x1
+ x2
- 1 ) / 2 + ras
.precision_half
);
2353 case 1: /* simple drop-outs excluding stubs */
2354 case 5: /* smart drop-outs excluding stubs */
2356 /* Drop-out Control Rules #4 and #6 */
2358 /* The specification neither provides an exact definition */
2359 /* of a `stub' nor gives exact rules to exclude them. */
2361 /* Here the constraints we use to recognize a stub. */
2365 /* - P_Left and P_Right are in the same contour */
2366 /* - P_Right is the successor of P_Left in that contour */
2367 /* - y is the top of P_Left and P_Right */
2371 /* - P_Left and P_Right are in the same contour */
2372 /* - P_Left is the successor of P_Right in that contour */
2373 /* - y is the bottom of P_Left */
2375 /* We draw a stub if the following constraints are met. */
2377 /* - for an upper or lower stub, there is top or bottom */
2378 /* overshoot, respectively */
2379 /* - the covered interval is greater or equal to a half */
2382 /* upper stub test */
2383 if ( left
->next
== right
&&
2384 left
->height
<= 0 &&
2385 !( left
->flags
& Overshoot_Top
&&
2386 x2
- x1
>= ras
.precision_half
) )
2389 /* lower stub test */
2390 if ( right
->next
== left
&&
2392 !( left
->flags
& Overshoot_Bottom
&&
2393 x2
- x1
>= ras
.precision_half
) )
2396 if ( dropOutControl
== 1 )
2399 pxl
= FLOOR( ( x1
+ x2
- 1 ) / 2 + ras
.precision_half
);
2402 default: /* modes 2, 3, 6, 7 */
2403 return; /* no drop-out control */
2406 /* check that the other pixel isn't set */
2407 e1
= pxl
== e1
? e2
: e1
;
2411 c1
= (Short
)( e1
>> 3 );
2412 f1
= (Short
)( e1
& 7 );
2414 if ( e1
>= 0 && e1
< ras
.bWidth
&&
2415 ras
.bTarget
[ras
.traceOfs
+ c1
] & ( 0x80 >> f1
) )
2424 if ( e1
>= 0 && e1
< ras
.bWidth
)
2426 c1
= (Short
)( e1
>> 3 );
2427 f1
= (Short
)( e1
& 7 );
2429 if ( ras
.gray_min_x
> c1
)
2430 ras
.gray_min_x
= c1
;
2431 if ( ras
.gray_max_x
< c1
)
2432 ras
.gray_max_x
= c1
;
2434 ras
.bTarget
[ras
.traceOfs
+ c1
] |= (char)( 0x80 >> f1
);
2440 Vertical_Sweep_Step( RAS_ARG
)
2442 ras
.traceOfs
+= ras
.traceIncr
;
2446 /***********************************************************************/
2448 /* Horizontal Sweep Procedure Set */
2450 /* These four routines are used during the horizontal black/white */
2451 /* sweep phase by the generic Draw_Sweep() function. */
2453 /***********************************************************************/
2456 Horizontal_Sweep_Init( RAS_ARGS Short
* min
,
2459 /* nothing, really */
2467 Horizontal_Sweep_Span( RAS_ARGS Short y
,
2481 if ( x2
- x1
< ras
.precision
)
2488 bits
= ras
.bTarget
+ ( y
>> 3 );
2489 f1
= (Byte
)( 0x80 >> ( y
& 7 ) );
2493 if ( e1
>= 0 && e1
< ras
.target
.rows
)
2498 p
= bits
- e1
* ras
.target
.pitch
;
2499 if ( ras
.target
.pitch
> 0 )
2500 p
+= ( ras
.target
.rows
- 1 ) * ras
.target
.pitch
;
2510 Horizontal_Sweep_Drop( RAS_ARGS Short y
,
2521 /* During the horizontal sweep, we only take care of drop-outs */
2523 /* e1 + <-- pixel center */
2525 /* x1 ---+--> <-- contour */
2528 /* x2 <--+--- <-- contour */
2531 /* e2 + <-- pixel center */
2539 Int dropOutControl
= left
->flags
& 7;
2542 if ( e1
== e2
+ ras
.precision
)
2544 switch ( dropOutControl
)
2546 case 0: /* simple drop-outs including stubs */
2550 case 4: /* smart drop-outs including stubs */
2551 pxl
= FLOOR( ( x1
+ x2
- 1 ) / 2 + ras
.precision_half
);
2554 case 1: /* simple drop-outs excluding stubs */
2555 case 5: /* smart drop-outs excluding stubs */
2556 /* see Vertical_Sweep_Drop for details */
2558 /* rightmost stub test */
2559 if ( left
->next
== right
&&
2560 left
->height
<= 0 &&
2561 !( left
->flags
& Overshoot_Top
&&
2562 x2
- x1
>= ras
.precision_half
) )
2565 /* leftmost stub test */
2566 if ( right
->next
== left
&&
2568 !( left
->flags
& Overshoot_Bottom
&&
2569 x2
- x1
>= ras
.precision_half
) )
2572 if ( dropOutControl
== 1 )
2575 pxl
= FLOOR( ( x1
+ x2
- 1 ) / 2 + ras
.precision_half
);
2578 default: /* modes 2, 3, 6, 7 */
2579 return; /* no drop-out control */
2582 /* check that the other pixel isn't set */
2583 e1
= pxl
== e1
? e2
: e1
;
2587 bits
= ras
.bTarget
+ ( y
>> 3 );
2588 f1
= (Byte
)( 0x80 >> ( y
& 7 ) );
2590 bits
-= e1
* ras
.target
.pitch
;
2591 if ( ras
.target
.pitch
> 0 )
2592 bits
+= ( ras
.target
.rows
- 1 ) * ras
.target
.pitch
;
2595 e1
< ras
.target
.rows
&&
2603 bits
= ras
.bTarget
+ ( y
>> 3 );
2604 f1
= (Byte
)( 0x80 >> ( y
& 7 ) );
2608 if ( e1
>= 0 && e1
< ras
.target
.rows
)
2610 bits
-= e1
* ras
.target
.pitch
;
2611 if ( ras
.target
.pitch
> 0 )
2612 bits
+= ( ras
.target
.rows
- 1 ) * ras
.target
.pitch
;
2620 Horizontal_Sweep_Step( RAS_ARG
)
2622 /* Nothing, really */
2627 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
2630 /*************************************************************************/
2632 /* Vertical Gray Sweep Procedure Set */
2634 /* These two routines are used during the vertical gray-levels sweep */
2635 /* phase by the generic Draw_Sweep() function. */
2639 /* - The target pixmap's width *must* be a multiple of 4. */
2641 /* - You have to use the function Vertical_Sweep_Span() for the gray */
2644 /*************************************************************************/
2647 Vertical_Gray_Sweep_Init( RAS_ARGS Short
* min
,
2650 Long pitch
, byte_len
;
2654 *max
= ( *max
+ 3 ) & -2;
2657 pitch
= ras
.target
.pitch
;
2659 ras
.traceIncr
= (Short
)byte_len
;
2660 ras
.traceG
= ( *min
/ 2 ) * byte_len
;
2664 ras
.traceG
+= ( ras
.target
.rows
- 1 ) * pitch
;
2665 byte_len
= -byte_len
;
2668 ras
.gray_min_x
= (Short
)byte_len
;
2669 ras
.gray_max_x
= -(Short
)byte_len
;
2674 Vertical_Gray_Sweep_Step( RAS_ARG
)
2677 PByte pix
, bit
, bit2
;
2678 short* count
= (short*)count_table
;
2682 ras
.traceOfs
+= ras
.gray_width
;
2684 if ( ras
.traceOfs
> ras
.gray_width
)
2686 pix
= ras
.gTarget
+ ras
.traceG
+ ras
.gray_min_x
* 4;
2689 if ( ras
.gray_max_x
>= 0 )
2691 Long last_pixel
= ras
.target
.width
- 1;
2692 Int last_cell
= last_pixel
>> 2;
2693 Int last_bit
= last_pixel
& 3;
2697 if ( ras
.gray_max_x
>= last_cell
&& last_bit
!= 3 )
2699 ras
.gray_max_x
= last_cell
- 1;
2703 if ( ras
.gray_min_x
< 0 )
2706 bit
= ras
.bTarget
+ ras
.gray_min_x
;
2707 bit2
= bit
+ ras
.gray_width
;
2709 c1
= ras
.gray_max_x
- ras
.gray_min_x
;
2713 c2
= count
[*bit
] + count
[*bit2
];
2717 pix
[0] = grays
[(c2
>> 12) & 0x000F];
2718 pix
[1] = grays
[(c2
>> 8 ) & 0x000F];
2719 pix
[2] = grays
[(c2
>> 4 ) & 0x000F];
2720 pix
[3] = grays
[ c2
& 0x000F];
2734 c2
= count
[*bit
] + count
[*bit2
];
2740 pix
[2] = grays
[(c2
>> 4 ) & 0x000F];
2742 pix
[1] = grays
[(c2
>> 8 ) & 0x000F];
2744 pix
[0] = grays
[(c2
>> 12) & 0x000F];
2754 ras
.traceG
+= ras
.traceIncr
;
2756 ras
.gray_min_x
= 32000;
2757 ras
.gray_max_x
= -32000;
2763 Horizontal_Gray_Sweep_Span( RAS_ARGS Short y
,
2769 /* nothing, really */
2780 Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y
,
2791 /* During the horizontal sweep, we only take care of drop-outs */
2798 Int dropOutControl
= left
->flags
& 7;
2801 if ( e1
== e2
+ ras
.precision
)
2803 switch ( dropOutControl
)
2805 case 0: /* simple drop-outs including stubs */
2809 case 4: /* smart drop-outs including stubs */
2810 e1
= FLOOR( ( x1
+ x2
- 1 ) / 2 + ras
.precision_half
);
2813 case 1: /* simple drop-outs excluding stubs */
2814 case 5: /* smart drop-outs excluding stubs */
2815 /* see Vertical_Sweep_Drop for details */
2817 /* rightmost stub test */
2818 if ( left
->next
== right
&& left
->height
<= 0 )
2821 /* leftmost stub test */
2822 if ( right
->next
== left
&& left
->start
== y
)
2825 if ( dropOutControl
== 1 )
2828 e1
= FLOOR( ( x1
+ x2
- 1 ) / 2 + ras
.precision_half
);
2832 default: /* modes 2, 3, 6, 7 */
2833 return; /* no drop-out control */
2842 if ( x2
- x1
>= ras
.precision_half
)
2843 color
= ras
.grays
[2];
2845 color
= ras
.grays
[1];
2847 e1
= TRUNC( e1
) / 2;
2848 if ( e1
< ras
.target
.rows
)
2850 pixel
= ras
.gTarget
- e1
* ras
.target
.pitch
+ y
/ 2;
2851 if ( ras
.target
.pitch
> 0 )
2852 pixel
+= ( ras
.target
.rows
- 1 ) * ras
.target
.pitch
;
2854 if ( pixel
[0] == ras
.grays
[0] )
2861 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
2864 /*************************************************************************/
2866 /* Generic Sweep Drawing routine */
2868 /*************************************************************************/
2871 Draw_Sweep( RAS_ARG
)
2873 Short y
, y_change
, y_height
;
2875 PProfile P
, Q
, P_Left
, P_Right
;
2877 Short min_Y
, max_Y
, top
, bottom
, dropouts
;
2879 Long x1
, x2
, xs
, e1
, e2
;
2881 TProfileList waiting
;
2882 TProfileList draw_left
, draw_right
;
2885 /* initialize empty linked lists */
2887 Init_Linked( &waiting
);
2889 Init_Linked( &draw_left
);
2890 Init_Linked( &draw_right
);
2892 /* first, compute min and max Y */
2895 max_Y
= (Short
)TRUNC( ras
.minY
);
2896 min_Y
= (Short
)TRUNC( ras
.maxY
);
2902 bottom
= (Short
)P
->start
;
2903 top
= (Short
)( P
->start
+ P
->height
- 1 );
2905 if ( min_Y
> bottom
)
2911 InsNew( &waiting
, P
);
2916 /* check the Y-turns */
2917 if ( ras
.numTurns
== 0 )
2919 ras
.error
= Raster_Err_Invalid
;
2923 /* now initialize the sweep */
2925 ras
.Proc_Sweep_Init( RAS_VARS
&min_Y
, &max_Y
);
2927 /* then compute the distance of each profile from min_Y */
2933 P
->countL
= (UShort
)( P
->start
- min_Y
);
2942 if ( ras
.numTurns
> 0 &&
2943 ras
.sizeBuff
[-ras
.numTurns
] == min_Y
)
2946 while ( ras
.numTurns
> 0 )
2948 /* check waiting list for new activations */
2955 P
->countL
-= y_height
;
2956 if ( P
->countL
== 0 )
2958 DelOld( &waiting
, P
);
2960 if ( P
->flags
& Flow_Up
)
2961 InsNew( &draw_left
, P
);
2963 InsNew( &draw_right
, P
);
2969 /* sort the drawing lists */
2972 Sort( &draw_right
);
2974 y_change
= (Short
)ras
.sizeBuff
[-ras
.numTurns
--];
2975 y_height
= (Short
)( y_change
- y
);
2977 while ( y
< y_change
)
2984 P_Right
= draw_right
;
3001 if ( x2
- x1
<= ras
.precision
&&
3002 e1
!= x1
&& e2
!= x2
)
3004 if ( e1
> e2
|| e2
== e1
+ ras
.precision
)
3006 Int dropOutControl
= P_Left
->flags
& 7;
3009 if ( dropOutControl
!= 2 )
3011 /* a drop-out was detected */
3016 /* mark profile for drop-out processing */
3025 ras
.Proc_Sweep_Span( RAS_VARS y
, x1
, x2
, P_Left
, P_Right
);
3029 P_Left
= P_Left
->link
;
3030 P_Right
= P_Right
->link
;
3033 /* handle drop-outs _after_ the span drawing -- */
3034 /* drop-out processing has been moved out of the loop */
3035 /* for performance tuning */
3041 ras
.Proc_Sweep_Step( RAS_VAR
);
3048 Sort( &draw_right
);
3052 /* now finalize the profiles that need it */
3058 if ( P
->height
== 0 )
3059 DelOld( &draw_left
, P
);
3067 if ( P
->height
== 0 )
3068 DelOld( &draw_right
, P
);
3073 /* for gray-scaling, flush the bitmap scanline cache */
3074 while ( y
<= max_Y
)
3076 ras
.Proc_Sweep_Step( RAS_VAR
);
3085 P_Right
= draw_right
;
3089 if ( P_Left
->countL
)
3093 dropouts
--; /* -- this is useful when debugging only */
3095 ras
.Proc_Sweep_Drop( RAS_VARS y
,
3102 P_Left
= P_Left
->link
;
3103 P_Right
= P_Right
->link
;
3110 /*************************************************************************/
3113 /* Render_Single_Pass */
3116 /* Perform one sweep with sub-banding. */
3119 /* flipped :: If set, flip the direction of the outline. */
3122 /* Renderer error code. */
3125 Render_Single_Pass( RAS_ARGS Bool flipped
)
3130 while ( ras
.band_top
>= 0 )
3132 ras
.maxY
= (Long
)ras
.band_stack
[ras
.band_top
].y_max
* ras
.precision
;
3133 ras
.minY
= (Long
)ras
.band_stack
[ras
.band_top
].y_min
* ras
.precision
;
3137 ras
.error
= Raster_Err_None
;
3139 if ( Convert_Glyph( RAS_VARS flipped
) )
3141 if ( ras
.error
!= Raster_Err_Overflow
)
3144 ras
.error
= Raster_Err_None
;
3149 ClearBand( RAS_VARS
TRUNC( ras
.minY
), TRUNC( ras
.maxY
) );
3152 i
= ras
.band_stack
[ras
.band_top
].y_min
;
3153 j
= ras
.band_stack
[ras
.band_top
].y_max
;
3155 k
= (Short
)( ( i
+ j
) / 2 );
3157 if ( ras
.band_top
>= 7 || k
< i
)
3160 ras
.error
= Raster_Err_Invalid
;
3165 ras
.band_stack
[ras
.band_top
+ 1].y_min
= k
;
3166 ras
.band_stack
[ras
.band_top
+ 1].y_max
= j
;
3168 ras
.band_stack
[ras
.band_top
].y_max
= (Short
)( k
- 1 );
3175 if ( Draw_Sweep( RAS_VAR
) )
3185 /*************************************************************************/
3191 /* Render a glyph in a bitmap. Sub-banding if needed. */
3194 /* FreeType error code. 0 means success. */
3196 FT_LOCAL_DEF( FT_Error
)
3197 Render_Glyph( RAS_ARG
)
3202 Set_High_Precision( RAS_VARS ras
.outline
.flags
&
3203 FT_OUTLINE_HIGH_PRECISION
);
3204 ras
.scale_shift
= ras
.precision_shift
;
3206 if ( ras
.outline
.flags
& FT_OUTLINE_IGNORE_DROPOUTS
)
3207 ras
.dropOutControl
= 2;
3210 if ( ras
.outline
.flags
& FT_OUTLINE_SMART_DROPOUTS
)
3211 ras
.dropOutControl
= 4;
3213 ras
.dropOutControl
= 0;
3215 if ( !( ras
.outline
.flags
& FT_OUTLINE_INCLUDE_STUBS
) )
3216 ras
.dropOutControl
+= 1;
3219 ras
.second_pass
= (FT_Byte
)( !( ras
.outline
.flags
&
3220 FT_OUTLINE_SINGLE_PASS
) );
3222 /* Vertical Sweep */
3223 ras
.Proc_Sweep_Init
= Vertical_Sweep_Init
;
3224 ras
.Proc_Sweep_Span
= Vertical_Sweep_Span
;
3225 ras
.Proc_Sweep_Drop
= Vertical_Sweep_Drop
;
3226 ras
.Proc_Sweep_Step
= Vertical_Sweep_Step
;
3229 ras
.band_stack
[0].y_min
= 0;
3230 ras
.band_stack
[0].y_max
= (short)( ras
.target
.rows
- 1 );
3232 ras
.bWidth
= (unsigned short)ras
.target
.width
;
3233 ras
.bTarget
= (Byte
*)ras
.target
.buffer
;
3235 if ( ( error
= Render_Single_Pass( RAS_VARS
0 ) ) != 0 )
3238 /* Horizontal Sweep */
3239 if ( ras
.second_pass
&& ras
.dropOutControl
!= 2 )
3241 ras
.Proc_Sweep_Init
= Horizontal_Sweep_Init
;
3242 ras
.Proc_Sweep_Span
= Horizontal_Sweep_Span
;
3243 ras
.Proc_Sweep_Drop
= Horizontal_Sweep_Drop
;
3244 ras
.Proc_Sweep_Step
= Horizontal_Sweep_Step
;
3247 ras
.band_stack
[0].y_min
= 0;
3248 ras
.band_stack
[0].y_max
= (short)( ras
.target
.width
- 1 );
3250 if ( ( error
= Render_Single_Pass( RAS_VARS
1 ) ) != 0 )
3254 return Raster_Err_None
;
3258 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3260 /*************************************************************************/
3263 /* Render_Gray_Glyph */
3266 /* Render a glyph with grayscaling. Sub-banding if needed. */
3269 /* FreeType error code. 0 means success. */
3271 FT_LOCAL_DEF( FT_Error
)
3272 Render_Gray_Glyph( RAS_ARG
)
3278 Set_High_Precision( RAS_VARS ras
.outline
.flags
&
3279 FT_OUTLINE_HIGH_PRECISION
);
3280 ras
.scale_shift
= ras
.precision_shift
+ 1;
3282 if ( ras
.outline
.flags
& FT_OUTLINE_IGNORE_DROPOUTS
)
3283 ras
.dropOutControl
= 2;
3286 if ( ras
.outline
.flags
& FT_OUTLINE_SMART_DROPOUTS
)
3287 ras
.dropOutControl
= 4;
3289 ras
.dropOutControl
= 0;
3291 if ( !( ras
.outline
.flags
& FT_OUTLINE_INCLUDE_STUBS
) )
3292 ras
.dropOutControl
+= 1;
3295 ras
.second_pass
= !( ras
.outline
.flags
& FT_OUTLINE_SINGLE_PASS
);
3297 /* Vertical Sweep */
3300 ras
.band_stack
[0].y_min
= 0;
3301 ras
.band_stack
[0].y_max
= 2 * ras
.target
.rows
- 1;
3303 ras
.bWidth
= ras
.gray_width
;
3304 pixel_width
= 2 * ( ( ras
.target
.width
+ 3 ) >> 2 );
3306 if ( ras
.bWidth
> pixel_width
)
3307 ras
.bWidth
= pixel_width
;
3309 ras
.bWidth
= ras
.bWidth
* 8;
3310 ras
.bTarget
= (Byte
*)ras
.gray_lines
;
3311 ras
.gTarget
= (Byte
*)ras
.target
.buffer
;
3313 ras
.Proc_Sweep_Init
= Vertical_Gray_Sweep_Init
;
3314 ras
.Proc_Sweep_Span
= Vertical_Sweep_Span
;
3315 ras
.Proc_Sweep_Drop
= Vertical_Sweep_Drop
;
3316 ras
.Proc_Sweep_Step
= Vertical_Gray_Sweep_Step
;
3318 error
= Render_Single_Pass( RAS_VARS
0 );
3322 /* Horizontal Sweep */
3323 if ( ras
.second_pass
&& ras
.dropOutControl
!= 2 )
3325 ras
.Proc_Sweep_Init
= Horizontal_Sweep_Init
;
3326 ras
.Proc_Sweep_Span
= Horizontal_Gray_Sweep_Span
;
3327 ras
.Proc_Sweep_Drop
= Horizontal_Gray_Sweep_Drop
;
3328 ras
.Proc_Sweep_Step
= Horizontal_Sweep_Step
;
3331 ras
.band_stack
[0].y_min
= 0;
3332 ras
.band_stack
[0].y_max
= ras
.target
.width
* 2 - 1;
3334 error
= Render_Single_Pass( RAS_VARS
1 );
3339 return Raster_Err_None
;
3342 #else /* !FT_RASTER_OPTION_ANTI_ALIASING */
3344 FT_LOCAL_DEF( FT_Error
)
3345 Render_Gray_Glyph( RAS_ARG
)
3349 return Raster_Err_Unsupported
;
3352 #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
3356 ft_black_init( PRaster raster
)
3358 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3362 /* set default 5-levels gray palette */
3363 for ( n
= 0; n
< 5; n
++ )
3364 raster
->grays
[n
] = n
* 255 / 4;
3366 raster
->gray_width
= RASTER_GRAY_LINES
/ 2;
3368 FT_UNUSED( raster
);
3373 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
3374 /**** a static object. *****/
3381 ft_black_new( void* memory
,
3382 FT_Raster
*araster
)
3384 static TRaster the_raster
;
3385 FT_UNUSED( memory
);
3388 *araster
= (FT_Raster
)&the_raster
;
3389 FT_MEM_ZERO( &the_raster
, sizeof ( the_raster
) );
3390 ft_black_init( &the_raster
);
3397 ft_black_done( FT_Raster raster
)
3400 FT_UNUSED( raster
);
3404 #else /* !_STANDALONE_ */
3408 ft_black_new( FT_Memory memory
,
3412 PRaster raster
= NULL
;
3416 if ( !FT_NEW( raster
) )
3418 raster
->memory
= memory
;
3419 ft_black_init( raster
);
3429 ft_black_done( PRaster raster
)
3431 FT_Memory memory
= (FT_Memory
)raster
->memory
;
3436 #endif /* !_STANDALONE_ */
3440 ft_black_reset( PRaster raster
,
3446 if ( pool_base
&& pool_size
>= (long)sizeof(TWorker
) + 2048 )
3448 PWorker worker
= (PWorker
)pool_base
;
3451 raster
->buffer
= pool_base
+ ( ( sizeof ( *worker
) + 7 ) & ~7 );
3452 raster
->buffer_size
= pool_base
+ pool_size
- (char*)raster
->buffer
;
3453 raster
->worker
= worker
;
3457 raster
->buffer
= NULL
;
3458 raster
->buffer_size
= 0;
3459 raster
->worker
= NULL
;
3466 ft_black_set_mode( PRaster raster
,
3468 const char* palette
)
3470 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3472 if ( mode
== FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
3474 /* set 5-levels gray palette */
3475 raster
->grays
[0] = palette
[0];
3476 raster
->grays
[1] = palette
[1];
3477 raster
->grays
[2] = palette
[2];
3478 raster
->grays
[3] = palette
[3];
3479 raster
->grays
[4] = palette
[4];
3484 FT_UNUSED( raster
);
3486 FT_UNUSED( palette
);
3493 ft_black_render( PRaster raster
,
3494 const FT_Raster_Params
* params
)
3496 const FT_Outline
* outline
= (const FT_Outline
*)params
->source
;
3497 const FT_Bitmap
* target_map
= params
->target
;
3501 if ( !raster
|| !raster
->buffer
|| !raster
->buffer_size
)
3502 return Raster_Err_Not_Ini
;
3505 return Raster_Err_Invalid
;
3507 /* return immediately if the outline is empty */
3508 if ( outline
->n_points
== 0 || outline
->n_contours
<= 0 )
3509 return Raster_Err_None
;
3511 if ( !outline
->contours
|| !outline
->points
)
3512 return Raster_Err_Invalid
;
3514 if ( outline
->n_points
!=
3515 outline
->contours
[outline
->n_contours
- 1] + 1 )
3516 return Raster_Err_Invalid
;
3518 worker
= raster
->worker
;
3520 /* this version of the raster does not support direct rendering, sorry */
3521 if ( params
->flags
& FT_RASTER_FLAG_DIRECT
)
3522 return Raster_Err_Unsupported
;
3525 return Raster_Err_Invalid
;
3528 if ( !target_map
->width
|| !target_map
->rows
)
3529 return Raster_Err_None
;
3531 if ( !target_map
->buffer
)
3532 return Raster_Err_Invalid
;
3534 ras
.outline
= *outline
;
3535 ras
.target
= *target_map
;
3537 worker
->buff
= (PLong
) raster
->buffer
;
3538 worker
->sizeBuff
= worker
->buff
+
3539 raster
->buffer_size
/ sizeof ( Long
);
3540 #ifdef FT_RASTER_OPTION_ANTI_ALIASING
3541 worker
->grays
= raster
->grays
;
3542 worker
->gray_width
= raster
->gray_width
;
3544 FT_MEM_ZERO( worker
->gray_lines
, worker
->gray_width
* 2 );
3547 return ( params
->flags
& FT_RASTER_FLAG_AA
)
3548 ? Render_Gray_Glyph( RAS_VAR
)
3549 : Render_Glyph( RAS_VAR
);
3553 FT_DEFINE_RASTER_FUNCS( ft_standard_raster
,
3554 FT_GLYPH_FORMAT_OUTLINE
,
3555 (FT_Raster_New_Func
) ft_black_new
,
3556 (FT_Raster_Reset_Func
) ft_black_reset
,
3557 (FT_Raster_Set_Mode_Func
)ft_black_set_mode
,
3558 (FT_Raster_Render_Func
) ft_black_render
,
3559 (FT_Raster_Done_Func
) ft_black_done