Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Side by Side Diff: core/src/fxge/fx_freetype/fxft2.5.01/src/raster/ftraster.c

Issue 815103002: Update freetype to 2.5.4. (Closed) Base URL: https://pdfium.googlesource.com/pdfium.git@master
Patch Set: Adjust GYP and GN Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 = &current->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 = &current->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 = &current->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 */
OLDNEW
« no previous file with comments | « core/src/fxge/fx_freetype/fxft2.5.01/src/raster/ftraster.h ('k') | core/src/fxge/fx_freetype/fxft2.5.01/src/raster/ftrend1.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698