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