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