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