| 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 |