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