/src/freetype/src/raster/ftraster.c
C | 3612 lines | 2079 code | 732 blank | 801 comment | 336 complexity | 7039c09154560704ab85e1459afc4098 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/***************************************************************************/ 2/* */ 3/* ftraster.c */ 4/* */ 5/* The FreeType glyph rasterizer (body). */ 6/* */ 7/* Copyright 1996-2003, 2005, 2007-2012 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 <ft2build.h> 62#include "ftraster.h" 63#include FT_INTERNAL_CALC_H /* for FT_MulDiv only */ 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 183 /* This macro is used to indicate that a function parameter is unused. */ 184 /* Its purpose is simply to reduce compiler warnings. Note also that */ 185 /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 186 /* ANSI compilers (e.g. LCC). */ 187#define FT_UNUSED( x ) (x) = (x) 188 189 /* Disable the tracing mechanism for simplicity -- developers can */ 190 /* activate it easily by redefining these two macros. */ 191#ifndef FT_ERROR 192#define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ 193#endif 194 195#ifndef FT_TRACE 196#define FT_TRACE( x ) do { } while ( 0 ) /* nothing */ 197#define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */ 198#define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */ 199#endif 200 201#define Raster_Err_None 0 202#define Raster_Err_Not_Ini -1 203#define Raster_Err_Overflow -2 204#define Raster_Err_Neg_Height -3 205#define Raster_Err_Invalid -4 206#define Raster_Err_Unsupported -5 207 208#define ft_memset memset 209 210#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \ 211 raster_reset_, raster_set_mode_, \ 212 raster_render_, raster_done_ ) \ 213 const FT_Raster_Funcs class_ = \ 214 { \ 215 glyph_format_, \ 216 raster_new_, \ 217 raster_reset_, \ 218 raster_set_mode_, \ 219 raster_render_, \ 220 raster_done_ \ 221 }; 222 223#else /* !_STANDALONE_ */ 224 225 226#include FT_INTERNAL_OBJECTS_H 227#include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */ 228 229#include "rasterrs.h" 230 231#define Raster_Err_None Raster_Err_Ok 232#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized 233#define Raster_Err_Overflow Raster_Err_Raster_Overflow 234#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height 235#define Raster_Err_Invalid Raster_Err_Invalid_Outline 236#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph 237 238 239#endif /* !_STANDALONE_ */ 240 241 242#ifndef FT_MEM_SET 243#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) 244#endif 245 246#ifndef FT_MEM_ZERO 247#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) 248#endif 249 250 /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ 251 /* typically a small value and the result of a*b is known to fit into */ 252 /* 32 bits. */ 253#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) 254 255 /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ 256 /* for clipping computations. It simply uses the FT_MulDiv() function */ 257 /* defined in `ftcalc.h'. */ 258#define SMulDiv FT_MulDiv 259 260 /* The rasterizer is a very general purpose component; please leave */ 261 /* the following redefinitions there (you never know your target */ 262 /* environment). */ 263 264#ifndef TRUE 265#define TRUE 1 266#endif 267 268#ifndef FALSE 269#define FALSE 0 270#endif 271 272#ifndef NULL 273#define NULL (void*)0 274#endif 275 276#ifndef SUCCESS 277#define SUCCESS 0 278#endif 279 280#ifndef FAILURE 281#define FAILURE 1 282#endif 283 284 285#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ 286 /* Setting this constant to more than 32 is a */ 287 /* pure waste of space. */ 288 289#define Pixel_Bits 6 /* fractional bits of *input* coordinates */ 290 291 292 /*************************************************************************/ 293 /*************************************************************************/ 294 /** **/ 295 /** SIMPLE TYPE DECLARATIONS **/ 296 /** **/ 297 /*************************************************************************/ 298 /*************************************************************************/ 299 300 typedef int Int; 301 typedef unsigned int UInt; 302 typedef short Short; 303 typedef unsigned short UShort, *PUShort; 304 typedef long Long, *PLong; 305 306 typedef unsigned char Byte, *PByte; 307 typedef char Bool; 308 309 310 typedef union Alignment_ 311 { 312 long l; 313 void* p; 314 void (*f)(void); 315 316 } Alignment, *PAlignment; 317 318 319 typedef struct TPoint_ 320 { 321 Long x; 322 Long y; 323 324 } TPoint; 325 326 327 /* values for the `flags' bit field */ 328#define Flow_Up 0x8 329#define Overshoot_Top 0x10 330#define Overshoot_Bottom 0x20 331 332 333 /* States of each line, arc, and profile */ 334 typedef enum TStates_ 335 { 336 Unknown_State, 337 Ascending_State, 338 Descending_State, 339 Flat_State 340 341 } TStates; 342 343 344 typedef struct TProfile_ TProfile; 345 typedef TProfile* PProfile; 346 347 struct TProfile_ 348 { 349 FT_F26Dot6 X; /* current coordinate during sweep */ 350 PProfile link; /* link to next profile (various purposes) */ 351 PLong offset; /* start of profile's data in render pool */ 352 unsigned flags; /* Bit 0-2: drop-out mode */ 353 /* Bit 3: profile orientation (up/down) */ 354 /* Bit 4: is top profile? */ 355 /* Bit 5: is bottom profile? */ 356 long height; /* profile's height in scanlines */ 357 long start; /* profile's starting scanline */ 358 359 unsigned countL; /* number of lines to step before this */ 360 /* profile becomes drawable */ 361 362 PProfile next; /* next profile in same contour, used */ 363 /* during drop-out control */ 364 }; 365 366 typedef PProfile TProfileList; 367 typedef PProfile* PProfileList; 368 369 370 /* Simple record used to implement a stack of bands, required */ 371 /* by the sub-banding mechanism */ 372 typedef struct black_TBand_ 373 { 374 Short y_min; /* band's minimum */ 375 Short y_max; /* band's maximum */ 376 377 } black_TBand; 378 379 380#define AlignProfileSize \ 381 ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) ) 382 383 384#undef RAS_ARG 385#undef RAS_ARGS 386#undef RAS_VAR 387#undef RAS_VARS 388 389#ifdef FT_STATIC_RASTER 390 391 392#define RAS_ARGS /* void */ 393#define RAS_ARG /* void */ 394 395#define RAS_VARS /* void */ 396#define RAS_VAR /* void */ 397 398#define FT_UNUSED_RASTER do { } while ( 0 ) 399 400 401#else /* !FT_STATIC_RASTER */ 402 403 404#define RAS_ARGS black_PWorker worker, 405#define RAS_ARG black_PWorker worker 406 407#define RAS_VARS worker, 408#define RAS_VAR worker 409 410#define FT_UNUSED_RASTER FT_UNUSED( worker ) 411 412 413#endif /* !FT_STATIC_RASTER */ 414 415 416 typedef struct black_TWorker_ black_TWorker, *black_PWorker; 417 418 419 /* prototypes used for sweep function dispatch */ 420 typedef void 421 Function_Sweep_Init( RAS_ARGS Short* min, 422 Short* max ); 423 424 typedef void 425 Function_Sweep_Span( RAS_ARGS Short y, 426 FT_F26Dot6 x1, 427 FT_F26Dot6 x2, 428 PProfile left, 429 PProfile right ); 430 431 typedef void 432 Function_Sweep_Step( RAS_ARG ); 433 434 435 /* NOTE: These operations are only valid on 2's complement processors */ 436#undef FLOOR 437#undef CEILING 438#undef TRUNC 439#undef SCALED 440 441#define FLOOR( x ) ( (x) & -ras.precision ) 442#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) 443#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) 444#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) 445#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) 446 447#define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half ) 448#define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half ) 449 450 /* The most used variables are positioned at the top of the structure. */ 451 /* Thus, their offset can be coded with less opcodes, resulting in a */ 452 /* smaller executable. */ 453 454 struct black_TWorker_ 455 { 456 Int precision_bits; /* precision related variables */ 457 Int precision; 458 Int precision_half; 459 Int precision_shift; 460 Int precision_step; 461 Int precision_jitter; 462 463 Int scale_shift; /* == precision_shift for bitmaps */ 464 /* == precision_shift+1 for pixmaps */ 465 466 PLong buff; /* The profiles buffer */ 467 PLong sizeBuff; /* Render pool size */ 468 PLong maxBuff; /* Profiles buffer size */ 469 PLong top; /* Current cursor in buffer */ 470 471 FT_Error error; 472 473 Int numTurns; /* number of Y-turns in outline */ 474 475 TPoint* arc; /* current Bezier arc pointer */ 476 477 UShort bWidth; /* target bitmap width */ 478 PByte bTarget; /* target bitmap buffer */ 479 PByte gTarget; /* target pixmap buffer */ 480 481 Long lastX, lastY; 482 Long minY, maxY; 483 484 UShort num_Profs; /* current number of profiles */ 485 486 Bool fresh; /* signals a fresh new profile which */ 487 /* `start' field must be completed */ 488 Bool joint; /* signals that the last arc ended */ 489 /* exactly on a scanline. Allows */ 490 /* removal of doublets */ 491 PProfile cProfile; /* current profile */ 492 PProfile fProfile; /* head of linked list of profiles */ 493 PProfile gProfile; /* contour's first profile in case */ 494 /* of impact */ 495 496 TStates state; /* rendering state */ 497 498 FT_Bitmap target; /* description of target bit/pixmap */ 499 FT_Outline outline; 500 501 Long traceOfs; /* current offset in target bitmap */ 502 Long traceG; /* current offset in target pixmap */ 503 504 Short traceIncr; /* sweep's increment in target bitmap */ 505 506 Short gray_min_x; /* current min x during gray rendering */ 507 Short gray_max_x; /* current max x during gray rendering */ 508 509 /* dispatch variables */ 510 511 Function_Sweep_Init* Proc_Sweep_Init; 512 Function_Sweep_Span* Proc_Sweep_Span; 513 Function_Sweep_Span* Proc_Sweep_Drop; 514 Function_Sweep_Step* Proc_Sweep_Step; 515 516 Byte dropOutControl; /* current drop_out control method */ 517 518 Bool second_pass; /* indicates whether a horizontal pass */ 519 /* should be performed to control */ 520 /* drop-out accurately when calling */ 521 /* Render_Glyph. Note that there is */ 522 /* no horizontal pass during gray */ 523 /* rendering. */ 524 525 TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ 526 527 black_TBand band_stack[16]; /* band stack used for sub-banding */ 528 Int band_top; /* band stack top */ 529 530#ifdef FT_RASTER_OPTION_ANTI_ALIASING 531 532 Byte* grays; 533 534 Byte gray_lines[RASTER_GRAY_LINES]; 535 /* Intermediate table used to render the */ 536 /* graylevels pixmaps. */ 537 /* gray_lines is a buffer holding two */ 538 /* monochrome scanlines */ 539 540 Short gray_width; /* width in bytes of one monochrome */ 541 /* intermediate scanline of gray_lines. */ 542 /* Each gray pixel takes 2 bits long there */ 543 544 /* The gray_lines must hold 2 lines, thus with size */ 545 /* in bytes of at least `gray_width*2'. */ 546 547#endif /* FT_RASTER_ANTI_ALIASING */ 548 549 }; 550 551 552 typedef struct black_TRaster_ 553 { 554 char* buffer; 555 long buffer_size; 556 void* memory; 557 black_PWorker worker; 558 Byte grays[5]; 559 Short gray_width; 560 561 } black_TRaster, *black_PRaster; 562 563#ifdef FT_STATIC_RASTER 564 565 static black_TWorker cur_ras; 566#define ras cur_ras 567 568#else /* !FT_STATIC_RASTER */ 569 570#define ras (*worker) 571 572#endif /* !FT_STATIC_RASTER */ 573 574 575#ifdef FT_RASTER_OPTION_ANTI_ALIASING 576 577 /* A lookup table used to quickly count set bits in four gray 2x2 */ 578 /* cells. The values of the table have been produced with the */ 579 /* following code: */ 580 /* */ 581 /* for ( i = 0; i < 256; i++ ) */ 582 /* { */ 583 /* l = 0; */ 584 /* j = i; */ 585 /* */ 586 /* for ( c = 0; c < 4; c++ ) */ 587 /* { */ 588 /* l <<= 4; */ 589 /* */ 590 /* if ( j & 0x80 ) l++; */ 591 /* if ( j & 0x40 ) l++; */ 592 /* */ 593 /* j = ( j << 2 ) & 0xFF; */ 594 /* } */ 595 /* printf( "0x%04X", l ); */ 596 /* } */ 597 /* */ 598 599 static const short count_table[256] = 600 { 601 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012, 602 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022, 603 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112, 604 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122, 605 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112, 606 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122, 607 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212, 608 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222, 609 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012, 610 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022, 611 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 612 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 613 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 614 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 615 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212, 616 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222, 617 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012, 618 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022, 619 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 620 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 621 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 622 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 623 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212, 624 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222, 625 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012, 626 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022, 627 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112, 628 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122, 629 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112, 630 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122, 631 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212, 632 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222 633 }; 634 635#endif /* FT_RASTER_OPTION_ANTI_ALIASING */ 636 637 638 639 /*************************************************************************/ 640 /*************************************************************************/ 641 /** **/ 642 /** PROFILES COMPUTATION **/ 643 /** **/ 644 /*************************************************************************/ 645 /*************************************************************************/ 646 647 648 /*************************************************************************/ 649 /* */ 650 /* <Function> */ 651 /* Set_High_Precision */ 652 /* */ 653 /* <Description> */ 654 /* Set precision variables according to param flag. */ 655 /* */ 656 /* <Input> */ 657 /* High :: Set to True for high precision (typically for ppem < 18), */ 658 /* false otherwise. */ 659 /* */ 660 static void 661 Set_High_Precision( RAS_ARGS Int High ) 662 { 663 /* 664 * `precision_step' is used in `Bezier_Up' to decide when to split a 665 * given y-monotonous Bezier arc that crosses a scanline before 666 * approximating it as a straight segment. The default value of 32 (for 667 * low accuracy) corresponds to 668 * 669 * 32 / 64 == 0.5 pixels , 670 * 671 * while for the high accuracy case we have 672 * 673 * 256/ (1 << 12) = 0.0625 pixels . 674 * 675 * `precision_jitter' is an epsilon threshold used in 676 * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier 677 * decomposition (after all, we are working with approximations only); 678 * it avoids switching on additional pixels which would cause artifacts 679 * otherwise. 680 * 681 * The value of `precision_jitter' has been determined heuristically. 682 * 683 */ 684 685 if ( High ) 686 { 687 ras.precision_bits = 12; 688 ras.precision_step = 256; 689 ras.precision_jitter = 30; 690 } 691 else 692 { 693 ras.precision_bits = 6; 694 ras.precision_step = 32; 695 ras.precision_jitter = 2; 696 } 697 698 FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); 699 700 ras.precision = 1 << ras.precision_bits; 701 ras.precision_half = ras.precision / 2; 702 ras.precision_shift = ras.precision_bits - Pixel_Bits; 703 } 704 705 706 /*************************************************************************/ 707 /* */ 708 /* <Function> */ 709 /* New_Profile */ 710 /* */ 711 /* <Description> */ 712 /* Create a new profile in the render pool. */ 713 /* */ 714 /* <Input> */ 715 /* aState :: The state/orientation of the new profile. */ 716 /* */ 717 /* overshoot :: Whether the profile's unrounded start position */ 718 /* differs by at least a half pixel. */ 719 /* */ 720 /* <Return> */ 721 /* SUCCESS on success. FAILURE in case of overflow or of incoherent */ 722 /* profile. */ 723 /* */ 724 static Bool 725 New_Profile( RAS_ARGS TStates aState, 726 Bool overshoot ) 727 { 728 if ( !ras.fProfile ) 729 { 730 ras.cProfile = (PProfile)ras.top; 731 ras.fProfile = ras.cProfile; 732 ras.top += AlignProfileSize; 733 } 734 735 if ( ras.top >= ras.maxBuff ) 736 { 737 ras.error = Raster_Err_Overflow; 738 return FAILURE; 739 } 740 741 ras.cProfile->flags = 0; 742 ras.cProfile->start = 0; 743 ras.cProfile->height = 0; 744 ras.cProfile->offset = ras.top; 745 ras.cProfile->link = (PProfile)0; 746 ras.cProfile->next = (PProfile)0; 747 ras.cProfile->flags = ras.dropOutControl; 748 749 switch ( aState ) 750 { 751 case Ascending_State: 752 ras.cProfile->flags |= Flow_Up; 753 if ( overshoot ) 754 ras.cProfile->flags |= Overshoot_Bottom; 755 756 FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile )); 757 break; 758 759 case Descending_State: 760 if ( overshoot ) 761 ras.cProfile->flags |= Overshoot_Top; 762 FT_TRACE6(( "New descending profile = %p\n", ras.cProfile )); 763 break; 764 765 default: 766 FT_ERROR(( "New_Profile: invalid profile direction\n" )); 767 ras.error = Raster_Err_Invalid; 768 return FAILURE; 769 } 770 771 if ( !ras.gProfile ) 772 ras.gProfile = ras.cProfile; 773 774 ras.state = aState; 775 ras.fresh = TRUE; 776 ras.joint = FALSE; 777 778 return SUCCESS; 779 } 780 781 782 /*************************************************************************/ 783 /* */ 784 /* <Function> */ 785 /* End_Profile */ 786 /* */ 787 /* <Description> */ 788 /* Finalize the current profile. */ 789 /* */ 790 /* <Input> */ 791 /* overshoot :: Whether the profile's unrounded end position differs */ 792 /* by at least a half pixel. */ 793 /* */ 794 /* <Return> */ 795 /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ 796 /* */ 797 static Bool 798 End_Profile( RAS_ARGS Bool overshoot ) 799 { 800 Long h; 801 PProfile oldProfile; 802 803 804 h = (Long)( ras.top - ras.cProfile->offset ); 805 806 if ( h < 0 ) 807 { 808 FT_ERROR(( "End_Profile: negative height encountered\n" )); 809 ras.error = Raster_Err_Neg_Height; 810 return FAILURE; 811 } 812 813 if ( h > 0 ) 814 { 815 FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n", 816 ras.cProfile, ras.cProfile->start, h )); 817 818 ras.cProfile->height = h; 819 if ( overshoot ) 820 { 821 if ( ras.cProfile->flags & Flow_Up ) 822 ras.cProfile->flags |= Overshoot_Top; 823 else 824 ras.cProfile->flags |= Overshoot_Bottom; 825 } 826 827 oldProfile = ras.cProfile; 828 ras.cProfile = (PProfile)ras.top; 829 830 ras.top += AlignProfileSize; 831 832 ras.cProfile->height = 0; 833 ras.cProfile->offset = ras.top; 834 835 oldProfile->next = ras.cProfile; 836 ras.num_Profs++; 837 } 838 839 if ( ras.top >= ras.maxBuff ) 840 { 841 FT_TRACE1(( "overflow in End_Profile\n" )); 842 ras.error = Raster_Err_Overflow; 843 return FAILURE; 844 } 845 846 ras.joint = FALSE; 847 848 return SUCCESS; 849 } 850 851 852 /*************************************************************************/ 853 /* */ 854 /* <Function> */ 855 /* Insert_Y_Turn */ 856 /* */ 857 /* <Description> */ 858 /* Insert a salient into the sorted list placed on top of the render */ 859 /* pool. */ 860 /* */ 861 /* <Input> */ 862 /* New y scanline position. */ 863 /* */ 864 /* <Return> */ 865 /* SUCCESS on success. FAILURE in case of overflow. */ 866 /* */ 867 static Bool 868 Insert_Y_Turn( RAS_ARGS Int y ) 869 { 870 PLong y_turns; 871 Int y2, n; 872 873 874 n = ras.numTurns - 1; 875 y_turns = ras.sizeBuff - ras.numTurns; 876 877 /* look for first y value that is <= */ 878 while ( n >= 0 && y < y_turns[n] ) 879 n--; 880 881 /* if it is <, simply insert it, ignore if == */ 882 if ( n >= 0 && y > y_turns[n] ) 883 while ( n >= 0 ) 884 { 885 y2 = (Int)y_turns[n]; 886 y_turns[n] = y; 887 y = y2; 888 n--; 889 } 890 891 if ( n < 0 ) 892 { 893 ras.maxBuff--; 894 if ( ras.maxBuff <= ras.top ) 895 { 896 ras.error = Raster_Err_Overflow; 897 return FAILURE; 898 } 899 ras.numTurns++; 900 ras.sizeBuff[-ras.numTurns] = y; 901 } 902 903 return SUCCESS; 904 } 905 906 907 /*************************************************************************/ 908 /* */ 909 /* <Function> */ 910 /* Finalize_Profile_Table */ 911 /* */ 912 /* <Description> */ 913 /* Adjust all links in the profiles list. */ 914 /* */ 915 /* <Return> */ 916 /* SUCCESS on success. FAILURE in case of overflow. */ 917 /* */ 918 static Bool 919 Finalize_Profile_Table( RAS_ARG ) 920 { 921 Int bottom, top; 922 UShort n; 923 PProfile p; 924 925 926 n = ras.num_Profs; 927 p = ras.fProfile; 928 929 if ( n > 1 && p ) 930 { 931 while ( n > 0 ) 932 { 933 if ( n > 1 ) 934 p->link = (PProfile)( p->offset + p->height ); 935 else 936 p->link = NULL; 937 938 if ( p->flags & Flow_Up ) 939 { 940 bottom = (Int)p->start; 941 top = (Int)( p->start + p->height - 1 ); 942 } 943 else 944 { 945 bottom = (Int)( p->start - p->height + 1 ); 946 top = (Int)p->start; 947 p->start = bottom; 948 p->offset += p->height - 1; 949 } 950 951 if ( Insert_Y_Turn( RAS_VARS bottom ) || 952 Insert_Y_Turn( RAS_VARS top + 1 ) ) 953 return FAILURE; 954 955 p = p->link; 956 n--; 957 } 958 } 959 else 960 ras.fProfile = NULL; 961 962 return SUCCESS; 963 } 964 965 966 /*************************************************************************/ 967 /* */ 968 /* <Function> */ 969 /* Split_Conic */ 970 /* */ 971 /* <Description> */ 972 /* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */ 973 /* stack. */ 974 /* */ 975 /* <Input> */ 976 /* None (subdivided Bezier is taken from the top of the stack). */ 977 /* */ 978 /* <Note> */ 979 /* This routine is the `beef' of this component. It is _the_ inner */ 980 /* loop that should be optimized to hell to get the best performance. */ 981 /* */ 982 static void 983 Split_Conic( TPoint* base ) 984 { 985 Long a, b; 986 987 988 base[4].x = base[2].x; 989 b = base[1].x; 990 a = base[3].x = ( base[2].x + b ) / 2; 991 b = base[1].x = ( base[0].x + b ) / 2; 992 base[2].x = ( a + b ) / 2; 993 994 base[4].y = base[2].y; 995 b = base[1].y; 996 a = base[3].y = ( base[2].y + b ) / 2; 997 b = base[1].y = ( base[0].y + b ) / 2; 998 base[2].y = ( a + b ) / 2; 999 1000 /* hand optimized. gcc doesn't seem to be too good at common */ 1001 /* expression substitution and instruction scheduling ;-) */ 1002 } 1003 1004 1005 /*************************************************************************/ 1006 /* */ 1007 /* <Function> */ 1008 /* Split_Cubic */ 1009 /* */ 1010 /* <Description> */ 1011 /* Subdivide a third-order Bezier arc into two joint sub-arcs in the */ 1012 /* Bezier stack. */ 1013 /* */ 1014 /* <Note> */ 1015 /* This routine is the `beef' of the component. It is one of _the_ */ 1016 /* inner loops that should be optimized like hell to get the best */ 1017 /* performance. */ 1018 /* */ 1019 static void 1020 Split_Cubic( TPoint* base ) 1021 { 1022 Long a, b, c, d; 1023 1024 1025 base[6].x = base[3].x; 1026 c = base[1].x; 1027 d = base[2].x; 1028 base[1].x = a = ( base[0].x + c + 1 ) >> 1; 1029 base[5].x = b = ( base[3].x + d + 1 ) >> 1; 1030 c = ( c + d + 1 ) >> 1; 1031 base[2].x = a = ( a + c + 1 ) >> 1; 1032 base[4].x = b = ( b + c + 1 ) >> 1; 1033 base[3].x = ( a + b + 1 ) >> 1; 1034 1035 base[6].y = base[3].y; 1036 c = base[1].y; 1037 d = base[2].y; 1038 base[1].y = a = ( base[0].y + c + 1 ) >> 1; 1039 base[5].y = b = ( base[3].y + d + 1 ) >> 1; 1040 c = ( c + d + 1 ) >> 1; 1041 base[2].y = a = ( a + c + 1 ) >> 1; 1042 base[4].y = b = ( b + c + 1 ) >> 1; 1043 base[3].y = ( a + b + 1 ) >> 1; 1044 } 1045 1046 1047 /*************************************************************************/ 1048 /* */ 1049 /* <Function> */ 1050 /* Line_Up */ 1051 /* */ 1052 /* <Description> */ 1053 /* Compute the x-coordinates of an ascending line segment and store */ 1054 /* them in the render pool. */ 1055 /* */ 1056 /* <Input> */ 1057 /* x1 :: The x-coordinate of the segment's start point. */ 1058 /* */ 1059 /* y1 :: The y-coordinate of the segment's start point. */ 1060 /* */ 1061 /* x2 :: The x-coordinate of the segment's end point. */ 1062 /* */ 1063 /* y2 :: The y-coordinate of the segment's end point. */ 1064 /* */ 1065 /* miny :: A lower vertical clipping bound value. */ 1066 /* */ 1067 /* maxy :: An upper vertical clipping bound value. */ 1068 /* */ 1069 /* <Return> */ 1070 /* SUCCESS on success, FAILURE on render pool overflow. */ 1071 /* */ 1072 static Bool 1073 Line_Up( RAS_ARGS Long x1, 1074 Long y1, 1075 Long x2, 1076 Long y2, 1077 Long miny, 1078 Long maxy ) 1079 { 1080 Long Dx, Dy; 1081 Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ 1082 Long Ix, Rx, Ax; 1083 1084 PLong top; 1085 1086 1087 Dx = x2 - x1; 1088 Dy = y2 - y1; 1089 1090 if ( Dy <= 0 || y2 < miny || y1 > maxy ) 1091 return SUCCESS; 1092 1093 if ( y1 < miny ) 1094 { 1095 /* Take care: miny-y1 can be a very large value; we use */ 1096 /* a slow MulDiv function to avoid clipping bugs */ 1097 x1 += SMulDiv( Dx, miny - y1, Dy ); 1098 e1 = (Int)TRUNC( miny ); 1099 f1 = 0; 1100 } 1101 else 1102 { 1103 e1 = (Int)TRUNC( y1 ); 1104 f1 = (Int)FRAC( y1 ); 1105 } 1106 1107 if ( y2 > maxy ) 1108 { 1109 /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ 1110 e2 = (Int)TRUNC( maxy ); 1111 f2 = 0; 1112 } 1113 else 1114 { 1115 e2 = (Int)TRUNC( y2 ); 1116 f2 = (Int)FRAC( y2 ); 1117 } 1118 1119 if ( f1 > 0 ) 1120 { 1121 if ( e1 == e2 ) 1122 return SUCCESS; 1123 else 1124 { 1125 x1 += SMulDiv( Dx, ras.precision - f1, Dy ); 1126 e1 += 1; 1127 } 1128 } 1129 else 1130 if ( ras.joint ) 1131 { 1132 ras.top--; 1133 ras.joint = FALSE; 1134 } 1135 1136 ras.joint = (char)( f2 == 0 ); 1137 1138 if ( ras.fresh ) 1139 { 1140 ras.cProfile->start = e1; 1141 ras.fresh = FALSE; 1142 } 1143 1144 size = e2 - e1 + 1; 1145 if ( ras.top + size >= ras.maxBuff ) 1146 { 1147 ras.error = Raster_Err_Overflow; 1148 return FAILURE; 1149 } 1150 1151 if ( Dx > 0 ) 1152 { 1153 Ix = SMulDiv( ras.precision, Dx, Dy); 1154 Rx = ( ras.precision * Dx ) % Dy; 1155 Dx = 1; 1156 } 1157 else 1158 { 1159 Ix = SMulDiv( ras.precision, -Dx, Dy) * -1; 1160 Rx = ( ras.precision * -Dx ) % Dy; 1161 Dx = -1; 1162 } 1163 1164 Ax = -Dy; 1165 top = ras.top; 1166 1167 while ( size > 0 ) 1168 { 1169 *top++ = x1; 1170 1171 x1 += Ix; 1172 Ax += Rx; 1173 if ( Ax >= 0 ) 1174 { 1175 Ax -= Dy; 1176 x1 += Dx; 1177 } 1178 size--; 1179 } 1180 1181 ras.top = top; 1182 return SUCCESS; 1183 } 1184 1185 1186 /*************************************************************************/ 1187 /* */ 1188 /* <Function> */ 1189 /* Line_Down */ 1190 /* */ 1191 /* <Description> */ 1192 /* Compute the x-coordinates of an descending line segment and store */ 1193 /* them in the render pool. */ 1194 /* */ 1195 /* <Input> */ 1196 /* x1 :: The x-coordinate of the segment's start point. */ 1197 /* */ 1198 /* y1 :: The y-coordinate of the segment's start point. */ 1199 /* */ 1200 /* x2 :: The x-coordinate of the segment's end point. */ 1201 /* */ 1202 /* y2 :: The y-coordinate of the segment's end point. */ 1203 /* */ 1204 /* miny :: A lower vertical clipping bound value. */ 1205 /* */ 1206 /* maxy :: An upper vertical clipping bound value. */ 1207 /* */ 1208 /* <Return> */ 1209 /* SUCCESS on success, FAILURE on render pool overflow. */ 1210 /* */ 1211 static Bool 1212 Line_Down( RAS_ARGS Long x1, 1213 Long y1, 1214 Long x2, 1215 Long y2, 1216 Long miny, 1217 Long maxy ) 1218 { 1219 Bool result, fresh; 1220 1221 1222 fresh = ras.fresh; 1223 1224 result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny …
Large files files are truncated, but you can click here to view the full file