1 /**************************************************************************** 2 * 3 * ftgrays.c 4 * 5 * A new `perfect' anti-aliasing renderer (body). 6 * 7 * Copyright (C) 2000-2023 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 `ftgrays.h' and `ftimage.h' into the current 23 * compilation directory. Typically, you could do something like 24 * 25 * - copy `src/smooth/ftgrays.c' (this file) to your current directory 26 * 27 * - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the 28 * same directory 29 * 30 * - compile `ftgrays' with the STANDALONE_ macro defined, as in 31 * 32 * cc -c -DSTANDALONE_ ftgrays.c 33 * 34 * The renderer can be initialized with a call to 35 * `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated 36 * with a call to `ft_gray_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 * This is a new anti-aliasing scan-converter for FreeType 2. The 46 * algorithm used here is _very_ different from the one in the standard 47 * `ftraster' module. Actually, `ftgrays' computes the _exact_ 48 * coverage of the outline on each pixel cell by straight segments. 49 * 50 * It is based on ideas that I initially found in Raph Levien's 51 * excellent LibArt graphics library (see https://www.levien.com/libart 52 * for more information, though the web pages do not tell anything 53 * about the renderer; you'll have to dive into the source code to 54 * understand how it works). 55 * 56 * Note, however, that this is a _very_ different implementation 57 * compared to Raph's. Coverage information is stored in a very 58 * different way, and I don't use sorted vector paths. Also, it doesn't 59 * use floating point values. 60 * 61 * Bézier segments are flattened by splitting them until their deviation 62 * from straight line becomes much smaller than a pixel. Therefore, the 63 * pixel coverage by a Bézier curve is calculated approximately. To 64 * estimate the deviation, we use the distance from the control point 65 * to the conic chord centre or the cubic chord trisection. These 66 * distances vanish fast after each split. In the conic case, they vanish 67 * predictably and the number of necessary splits can be calculated. 68 * 69 * This renderer has the following advantages: 70 * 71 * - It doesn't need an intermediate bitmap. Instead, one can supply a 72 * callback function that will be called by the renderer to draw gray 73 * spans on any target surface. You can thus do direct composition on 74 * any kind of bitmap, provided that you give the renderer the right 75 * callback. 76 * 77 * - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on 78 * each pixel cell by straight segments. 79 * 80 * - It performs a single pass on the outline (the `standard' FT2 81 * renderer makes two passes). 82 * 83 * - It can easily be modified to render to _any_ number of gray levels 84 * cheaply. 85 * 86 * - For small (< 80) pixel sizes, it is faster than the standard 87 * renderer. 88 * 89 */ 90 91 92 /************************************************************************** 93 * 94 * The macro FT_COMPONENT is used in trace mode. It is an implicit 95 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 96 * messages during execution. 97 */ 98 #undef FT_COMPONENT 99 #define FT_COMPONENT smooth 100 101 102 #ifdef STANDALONE_ 103 104 105 /* The size in bytes of the render pool used by the scan-line converter */ 106 /* to do all of its work. */ 107 #define FT_RENDER_POOL_SIZE 16384L 108 109 110 /* Auxiliary macros for token concatenation. */ 111 #define FT_ERR_XCAT( x, y ) x ## y 112 #define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) 113 114 #define FT_BEGIN_STMNT do { 115 #define FT_END_STMNT } while ( 0 ) 116 117 #define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) 118 #define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) 119 #define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) 120 121 122 /* 123 * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' 124 * algorithm. We use alpha = 1, beta = 3/8, giving us results with a 125 * largest error less than 7% compared to the exact value. 126 */ 127 #define FT_HYPOT( x, y ) \ 128 ( x = FT_ABS( x ), \ 129 y = FT_ABS( y ), \ 130 x > y ? x + ( 3 * y >> 3 ) \ 131 : y + ( 3 * x >> 3 ) ) 132 133 134 /* define this to dump debugging information */ 135 /* #define FT_DEBUG_LEVEL_TRACE */ 136 137 138 #ifdef FT_DEBUG_LEVEL_TRACE 139 #include <stdio.h> 140 #include <stdarg.h> 141 #endif 142 143 #include <stddef.h> 144 #include <string.h> 145 #include <setjmp.h> 146 #include <limits.h> 147 #define FT_CHAR_BIT CHAR_BIT 148 #define FT_UINT_MAX UINT_MAX 149 #define FT_INT_MAX INT_MAX 150 #define FT_ULONG_MAX ULONG_MAX 151 152 #define ADD_INT( a, b ) \ 153 (int)( (unsigned int)(a) + (unsigned int)(b) ) 154 155 #define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) 156 157 158 #define ft_memset memset 159 160 #define ft_setjmp setjmp 161 #define ft_longjmp longjmp 162 #define ft_jmp_buf jmp_buf 163 164 typedef ptrdiff_t FT_PtrDist; 165 166 167 #define Smooth_Err_Ok 0 168 #define Smooth_Err_Invalid_Outline -1 169 #define Smooth_Err_Cannot_Render_Glyph -2 170 #define Smooth_Err_Invalid_Argument -3 171 #define Smooth_Err_Raster_Overflow -4 172 173 #define FT_BEGIN_HEADER 174 #define FT_END_HEADER 175 176 #include "ftimage.h" 177 #include "ftgrays.h" 178 179 180 /* This macro is used to indicate that a function parameter is unused. */ 181 /* Its purpose is simply to reduce compiler warnings. Note also that */ 182 /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 183 /* ANSI compilers (e.g. LCC). */ 184 #define FT_UNUSED( x ) (x) = (x) 185 186 187 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */ 188 189 #ifdef FT_DEBUG_LEVEL_TRACE 190 191 void FT_Message(const char * fmt,...)192 FT_Message( const char* fmt, 193 ... ) 194 { 195 va_list ap; 196 197 198 va_start( ap, fmt ); 199 vfprintf( stderr, fmt, ap ); 200 va_end( ap ); 201 } 202 203 204 /* empty function useful for setting a breakpoint to catch errors */ 205 int FT_Throw(int error,int line,const char * file)206 FT_Throw( int error, 207 int line, 208 const char* file ) 209 { 210 FT_UNUSED( error ); 211 FT_UNUSED( line ); 212 FT_UNUSED( file ); 213 214 return 0; 215 } 216 217 218 /* we don't handle tracing levels in stand-alone mode; */ 219 #ifndef FT_TRACE5 220 #define FT_TRACE5( varformat ) FT_Message varformat 221 #endif 222 #ifndef FT_TRACE7 223 #define FT_TRACE7( varformat ) FT_Message varformat 224 #endif 225 #ifndef FT_ERROR 226 #define FT_ERROR( varformat ) FT_Message varformat 227 #endif 228 229 #define FT_THROW( e ) \ 230 ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \ 231 __LINE__, \ 232 __FILE__ ) | \ 233 FT_ERR_CAT( Smooth_Err_, e ) ) 234 235 #else /* !FT_DEBUG_LEVEL_TRACE */ 236 237 #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ 238 #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ 239 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ 240 #define FT_THROW( e ) FT_ERR_CAT( Smooth_Err_, e ) 241 242 #endif /* !FT_DEBUG_LEVEL_TRACE */ 243 244 245 #define FT_Trace_Enable() do { } while ( 0 ) /* nothing */ 246 #define FT_Trace_Disable() do { } while ( 0 ) /* nothing */ 247 248 249 #define FT_DEFINE_OUTLINE_FUNCS( class_, \ 250 move_to_, line_to_, \ 251 conic_to_, cubic_to_, \ 252 shift_, delta_ ) \ 253 static const FT_Outline_Funcs class_ = \ 254 { \ 255 move_to_, \ 256 line_to_, \ 257 conic_to_, \ 258 cubic_to_, \ 259 shift_, \ 260 delta_ \ 261 }; 262 263 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \ 264 raster_new_, raster_reset_, \ 265 raster_set_mode_, raster_render_, \ 266 raster_done_ ) \ 267 const FT_Raster_Funcs class_ = \ 268 { \ 269 glyph_format_, \ 270 raster_new_, \ 271 raster_reset_, \ 272 raster_set_mode_, \ 273 raster_render_, \ 274 raster_done_ \ 275 }; 276 277 278 #else /* !STANDALONE_ */ 279 280 281 #include <ft2build.h> 282 #include FT_CONFIG_CONFIG_H 283 #include "ftgrays.h" 284 #include <freetype/internal/ftobjs.h> 285 #include <freetype/internal/ftdebug.h> 286 #include <freetype/internal/ftcalc.h> 287 #include <freetype/ftoutln.h> 288 289 #include "ftsmerrs.h" 290 291 292 #endif /* !STANDALONE_ */ 293 294 295 #ifndef FT_MEM_SET 296 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) 297 #endif 298 299 #ifndef FT_MEM_ZERO 300 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) 301 #endif 302 303 #ifndef FT_ZERO 304 #define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) 305 #endif 306 307 /* as usual, for the speed hungry :-) */ 308 309 #undef RAS_ARG 310 #undef RAS_ARG_ 311 #undef RAS_VAR 312 #undef RAS_VAR_ 313 314 #ifndef FT_STATIC_RASTER 315 316 #define RAS_ARG gray_PWorker worker 317 #define RAS_ARG_ gray_PWorker worker, 318 319 #define RAS_VAR worker 320 #define RAS_VAR_ worker, 321 322 #else /* FT_STATIC_RASTER */ 323 324 #define RAS_ARG void 325 #define RAS_ARG_ /* empty */ 326 #define RAS_VAR /* empty */ 327 #define RAS_VAR_ /* empty */ 328 329 #endif /* FT_STATIC_RASTER */ 330 331 332 /* must be at least 6 bits! */ 333 #define PIXEL_BITS 8 334 335 #define ONE_PIXEL ( 1 << PIXEL_BITS ) 336 #undef TRUNC 337 #define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) 338 #undef FRACT 339 #define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) 340 341 #if PIXEL_BITS >= 6 342 #define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) ) 343 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) 344 #else 345 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) 346 #define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) ) 347 #endif 348 349 350 /* Compute `dividend / divisor' and return both its quotient and */ 351 /* remainder, cast to a specific type. This macro also ensures that */ 352 /* the remainder is always positive. We use the remainder to keep */ 353 /* track of accumulating errors and compensate for them. */ 354 #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ 355 FT_BEGIN_STMNT \ 356 (quotient) = (type)( (dividend) / (divisor) ); \ 357 (remainder) = (type)( (dividend) % (divisor) ); \ 358 if ( (remainder) < 0 ) \ 359 { \ 360 (quotient)--; \ 361 (remainder) += (type)(divisor); \ 362 } \ 363 FT_END_STMNT 364 365 #if defined( __GNUC__ ) && __GNUC__ < 7 && defined( __arm__ ) 366 /* Work around a bug specific to GCC which make the compiler fail to */ 367 /* optimize a division and modulo operation on the same parameters */ 368 /* into a single call to `__aeabi_idivmod'. See */ 369 /* */ 370 /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */ 371 #undef FT_DIV_MOD 372 #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ 373 FT_BEGIN_STMNT \ 374 (quotient) = (type)( (dividend) / (divisor) ); \ 375 (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \ 376 if ( (remainder) < 0 ) \ 377 { \ 378 (quotient)--; \ 379 (remainder) += (type)(divisor); \ 380 } \ 381 FT_END_STMNT 382 #endif /* __arm__ */ 383 384 385 /* Calculating coverages for a slanted line requires a division each */ 386 /* time the line crosses from cell to cell. These macros speed up */ 387 /* the repetitive divisions by replacing them with multiplications */ 388 /* and right shifts so that at most two divisions are performed for */ 389 /* each slanted line. Nevertheless, these divisions are noticeable */ 390 /* in the overall performance because flattened curves produce a */ 391 /* very large number of slanted lines. */ 392 /* */ 393 /* The division results here are always within ONE_PIXEL. Therefore */ 394 /* the shift magnitude should be at least PIXEL_BITS wider than the */ 395 /* divisors to provide sufficient accuracy of the multiply-shift. */ 396 /* It should not exceed (64 - PIXEL_BITS) to prevent overflowing and */ 397 /* leave enough room for 64-bit unsigned multiplication however. */ 398 #define FT_UDIVPREP( c, b ) \ 399 FT_Int64 b ## _r = c ? (FT_Int64)0xFFFFFFFF / ( b ) : 0 400 #define FT_UDIV( a, b ) \ 401 (TCoord)( ( (FT_UInt64)( a ) * (FT_UInt64)( b ## _r ) ) >> 32 ) 402 403 404 /* Scale area and apply fill rule to calculate the coverage byte. */ 405 /* The top fill bit is used for the non-zero rule. The eighth */ 406 /* fill bit is used for the even-odd rule. The higher coverage */ 407 /* bytes are either clamped for the non-zero-rule or discarded */ 408 /* later for the even-odd rule. */ 409 #define FT_FILL_RULE( coverage, area, fill ) \ 410 FT_BEGIN_STMNT \ 411 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \ 412 if ( coverage & fill ) \ 413 coverage = ~coverage; \ 414 if ( coverage > 255 && fill & INT_MIN ) \ 415 coverage = 255; \ 416 FT_END_STMNT 417 418 419 /* It is faster to write small spans byte-by-byte than calling */ 420 /* `memset'. This is mainly due to the cost of the function call. */ 421 #define FT_GRAY_SET( d, s, count ) \ 422 FT_BEGIN_STMNT \ 423 unsigned char* q = d; \ 424 switch ( count ) \ 425 { \ 426 case 7: *q++ = (unsigned char)s; FALL_THROUGH; \ 427 case 6: *q++ = (unsigned char)s; FALL_THROUGH; \ 428 case 5: *q++ = (unsigned char)s; FALL_THROUGH; \ 429 case 4: *q++ = (unsigned char)s; FALL_THROUGH; \ 430 case 3: *q++ = (unsigned char)s; FALL_THROUGH; \ 431 case 2: *q++ = (unsigned char)s; FALL_THROUGH; \ 432 case 1: *q = (unsigned char)s; FALL_THROUGH; \ 433 case 0: break; \ 434 default: FT_MEM_SET( d, s, count ); \ 435 } \ 436 FT_END_STMNT 437 438 439 /************************************************************************** 440 * 441 * TYPE DEFINITIONS 442 */ 443 444 /* don't change the following types to FT_Int or FT_Pos, since we might */ 445 /* need to define them to "float" or "double" when experimenting with */ 446 /* new algorithms */ 447 448 typedef long TPos; /* subpixel coordinate */ 449 typedef int TCoord; /* integer scanline/pixel coordinate */ 450 typedef int TArea; /* cell areas, coordinate products */ 451 452 453 typedef struct TCell_* PCell; 454 455 typedef struct TCell_ 456 { 457 TCoord x; /* same with gray_TWorker.ex */ 458 TCoord cover; /* same with gray_TWorker.cover */ 459 TArea area; 460 PCell next; 461 462 } TCell; 463 464 typedef struct TPixmap_ 465 { 466 unsigned char* origin; /* pixmap origin at the bottom-left */ 467 int pitch; /* pitch to go down one row */ 468 469 } TPixmap; 470 471 /* maximum number of gray cells in the buffer */ 472 #if FT_RENDER_POOL_SIZE > 2048 473 #define FT_MAX_GRAY_POOL ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) ) 474 #else 475 #define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) ) 476 #endif 477 478 /* FT_Span buffer size for direct rendering only */ 479 #define FT_MAX_GRAY_SPANS 16 480 481 482 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ 483 /* We disable the warning `structure was padded due to */ 484 /* __declspec(align())' in order to compile cleanly with */ 485 /* the maximum level of warnings. */ 486 #pragma warning( push ) 487 #pragma warning( disable : 4324 ) 488 #endif /* _MSC_VER */ 489 490 typedef struct gray_TWorker_ 491 { 492 ft_jmp_buf jump_buffer; 493 494 TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ 495 TCoord min_ey, max_ey; 496 TCoord count_ey; /* same as (max_ey - min_ey) */ 497 498 PCell cell; /* current cell */ 499 PCell cell_free; /* call allocation next free slot */ 500 PCell cell_null; /* last cell, used as dumpster and limit */ 501 502 PCell* ycells; /* array of cell linked-lists; one per */ 503 /* vertical coordinate in the current band */ 504 505 TPos x, y; /* last point position */ 506 507 FT_Outline outline; /* input outline */ 508 TPixmap target; /* target pixmap */ 509 510 FT_Raster_Span_Func render_span; 511 void* render_span_data; 512 513 } gray_TWorker, *gray_PWorker; 514 515 #if defined( _MSC_VER ) 516 #pragma warning( pop ) 517 #endif 518 519 #ifndef FT_STATIC_RASTER 520 #define ras (*worker) 521 #else 522 static gray_TWorker ras; 523 #endif 524 525 /* The |x| value of the null cell. Must be the largest possible */ 526 /* integer value stored in a `TCell.x` field. */ 527 #define CELL_MAX_X_VALUE INT_MAX 528 529 530 #define FT_INTEGRATE( ras, a, b ) \ 531 ras.cell->cover = ADD_INT( ras.cell->cover, a ), \ 532 ras.cell->area = ADD_INT( ras.cell->area, (a) * (TArea)(b) ) 533 534 535 typedef struct gray_TRaster_ 536 { 537 void* memory; 538 539 } gray_TRaster, *gray_PRaster; 540 541 542 #ifdef FT_DEBUG_LEVEL_TRACE 543 544 /* to be called while in the debugger -- */ 545 /* this function causes a compiler warning since it is unused otherwise */ 546 static void gray_dump_cells(RAS_ARG)547 gray_dump_cells( RAS_ARG ) 548 { 549 int y; 550 551 552 for ( y = ras.min_ey; y < ras.max_ey; y++ ) 553 { 554 PCell cell = ras.ycells[y - ras.min_ey]; 555 556 557 printf( "%3d:", y ); 558 559 for ( ; cell != ras.cell_null; cell = cell->next ) 560 printf( " (%3d, c:%4d, a:%6d)", 561 cell->x, cell->cover, cell->area ); 562 printf( "\n" ); 563 } 564 } 565 566 #endif /* FT_DEBUG_LEVEL_TRACE */ 567 568 569 /************************************************************************** 570 * 571 * Set the current cell to a new position. 572 */ 573 static void gray_set_cell(RAS_ARG_ TCoord ex,TCoord ey)574 gray_set_cell( RAS_ARG_ TCoord ex, 575 TCoord ey ) 576 { 577 /* Move the cell pointer to a new position in the linked list. We use */ 578 /* a dumpster null cell for everything outside of the clipping region */ 579 /* during the render phase. This means that: */ 580 /* */ 581 /* . the new vertical position must be within min_ey..max_ey-1. */ 582 /* . the new horizontal position must be strictly less than max_ex */ 583 /* */ 584 /* Note that if a cell is to the left of the clipping region, it is */ 585 /* actually set to the (min_ex-1) horizontal position. */ 586 587 TCoord ey_index = ey - ras.min_ey; 588 589 590 if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex ) 591 ras.cell = ras.cell_null; 592 else 593 { 594 PCell* pcell = ras.ycells + ey_index; 595 PCell cell; 596 597 598 ex = FT_MAX( ex, ras.min_ex - 1 ); 599 600 while ( 1 ) 601 { 602 cell = *pcell; 603 604 if ( cell->x > ex ) 605 break; 606 607 if ( cell->x == ex ) 608 goto Found; 609 610 pcell = &cell->next; 611 } 612 613 /* insert new cell */ 614 cell = ras.cell_free++; 615 if ( cell >= ras.cell_null ) 616 ft_longjmp( ras.jump_buffer, 1 ); 617 618 cell->x = ex; 619 cell->area = 0; 620 cell->cover = 0; 621 622 cell->next = *pcell; 623 *pcell = cell; 624 625 Found: 626 ras.cell = cell; 627 } 628 } 629 630 631 #ifndef FT_INT64 632 633 /************************************************************************** 634 * 635 * Render a scanline as one or more cells. 636 */ 637 static void gray_render_scanline(RAS_ARG_ TCoord ey,TPos x1,TCoord y1,TPos x2,TCoord y2)638 gray_render_scanline( RAS_ARG_ TCoord ey, 639 TPos x1, 640 TCoord y1, 641 TPos x2, 642 TCoord y2 ) 643 { 644 TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod; 645 TPos p, dx; 646 int incr; 647 648 649 ex1 = TRUNC( x1 ); 650 ex2 = TRUNC( x2 ); 651 652 /* trivial case. Happens often */ 653 if ( y1 == y2 ) 654 { 655 gray_set_cell( RAS_VAR_ ex2, ey ); 656 return; 657 } 658 659 fx1 = FRACT( x1 ); 660 fx2 = FRACT( x2 ); 661 662 /* everything is located in a single cell. That is easy! */ 663 /* */ 664 if ( ex1 == ex2 ) 665 goto End; 666 667 /* ok, we'll have to render a run of adjacent cells on the same */ 668 /* scanline... */ 669 /* */ 670 dx = x2 - x1; 671 dy = y2 - y1; 672 673 if ( dx > 0 ) 674 { 675 p = ( ONE_PIXEL - fx1 ) * dy; 676 first = ONE_PIXEL; 677 incr = 1; 678 } 679 else 680 { 681 p = fx1 * dy; 682 first = 0; 683 incr = -1; 684 dx = -dx; 685 } 686 687 /* the fractional part of y-delta is mod/dx. It is essential to */ 688 /* keep track of its accumulation for accurate rendering. */ 689 /* XXX: y-delta and x-delta below should be related. */ 690 FT_DIV_MOD( TCoord, p, dx, delta, mod ); 691 692 FT_INTEGRATE( ras, delta, fx1 + first ); 693 y1 += delta; 694 ex1 += incr; 695 gray_set_cell( RAS_VAR_ ex1, ey ); 696 697 if ( ex1 != ex2 ) 698 { 699 TCoord lift, rem; 700 701 702 p = ONE_PIXEL * dy; 703 FT_DIV_MOD( TCoord, p, dx, lift, rem ); 704 705 do 706 { 707 delta = lift; 708 mod += rem; 709 if ( mod >= (TCoord)dx ) 710 { 711 mod -= (TCoord)dx; 712 delta++; 713 } 714 715 FT_INTEGRATE( ras, delta, ONE_PIXEL ); 716 y1 += delta; 717 ex1 += incr; 718 gray_set_cell( RAS_VAR_ ex1, ey ); 719 } while ( ex1 != ex2 ); 720 } 721 722 fx1 = ONE_PIXEL - first; 723 724 End: 725 FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 ); 726 } 727 728 729 /************************************************************************** 730 * 731 * Render a given line as a series of scanlines. 732 */ 733 static void gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)734 gray_render_line( RAS_ARG_ TPos to_x, 735 TPos to_y ) 736 { 737 TCoord ey1, ey2, fy1, fy2, first, delta, mod; 738 TPos p, dx, dy, x, x2; 739 int incr; 740 741 742 ey1 = TRUNC( ras.y ); 743 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ 744 745 /* perform vertical clipping */ 746 if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || 747 ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) 748 goto End; 749 750 fy1 = FRACT( ras.y ); 751 fy2 = FRACT( to_y ); 752 753 /* everything is on a single scanline */ 754 if ( ey1 == ey2 ) 755 { 756 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); 757 goto End; 758 } 759 760 dx = to_x - ras.x; 761 dy = to_y - ras.y; 762 763 /* vertical line - avoid calling gray_render_scanline */ 764 if ( dx == 0 ) 765 { 766 TCoord ex = TRUNC( ras.x ); 767 TCoord two_fx = FRACT( ras.x ) << 1; 768 769 770 if ( dy > 0) 771 { 772 first = ONE_PIXEL; 773 incr = 1; 774 } 775 else 776 { 777 first = 0; 778 incr = -1; 779 } 780 781 delta = first - fy1; 782 FT_INTEGRATE( ras, delta, two_fx); 783 ey1 += incr; 784 785 gray_set_cell( RAS_VAR_ ex, ey1 ); 786 787 delta = first + first - ONE_PIXEL; 788 while ( ey1 != ey2 ) 789 { 790 FT_INTEGRATE( ras, delta, two_fx); 791 ey1 += incr; 792 793 gray_set_cell( RAS_VAR_ ex, ey1 ); 794 } 795 796 delta = fy2 - ONE_PIXEL + first; 797 FT_INTEGRATE( ras, delta, two_fx); 798 799 goto End; 800 } 801 802 /* ok, we have to render several scanlines */ 803 if ( dy > 0) 804 { 805 p = ( ONE_PIXEL - fy1 ) * dx; 806 first = ONE_PIXEL; 807 incr = 1; 808 } 809 else 810 { 811 p = fy1 * dx; 812 first = 0; 813 incr = -1; 814 dy = -dy; 815 } 816 817 /* the fractional part of x-delta is mod/dy. It is essential to */ 818 /* keep track of its accumulation for accurate rendering. */ 819 FT_DIV_MOD( TCoord, p, dy, delta, mod ); 820 821 x = ras.x + delta; 822 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ); 823 824 ey1 += incr; 825 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 826 827 if ( ey1 != ey2 ) 828 { 829 TCoord lift, rem; 830 831 832 p = ONE_PIXEL * dx; 833 FT_DIV_MOD( TCoord, p, dy, lift, rem ); 834 835 do 836 { 837 delta = lift; 838 mod += rem; 839 if ( mod >= (TCoord)dy ) 840 { 841 mod -= (TCoord)dy; 842 delta++; 843 } 844 845 x2 = x + delta; 846 gray_render_scanline( RAS_VAR_ ey1, 847 x, ONE_PIXEL - first, 848 x2, first ); 849 x = x2; 850 851 ey1 += incr; 852 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 853 } while ( ey1 != ey2 ); 854 } 855 856 gray_render_scanline( RAS_VAR_ ey1, 857 x, ONE_PIXEL - first, 858 to_x, fy2 ); 859 860 End: 861 ras.x = to_x; 862 ras.y = to_y; 863 } 864 865 #else 866 867 /************************************************************************** 868 * 869 * Render a straight line across multiple cells in any direction. 870 */ 871 static void gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)872 gray_render_line( RAS_ARG_ TPos to_x, 873 TPos to_y ) 874 { 875 TPos dx, dy; 876 TCoord fx1, fy1, fx2, fy2; 877 TCoord ex1, ey1, ex2, ey2; 878 879 880 ey1 = TRUNC( ras.y ); 881 ey2 = TRUNC( to_y ); 882 883 /* perform vertical clipping */ 884 if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || 885 ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) 886 goto End; 887 888 ex1 = TRUNC( ras.x ); 889 ex2 = TRUNC( to_x ); 890 891 fx1 = FRACT( ras.x ); 892 fy1 = FRACT( ras.y ); 893 894 dx = to_x - ras.x; 895 dy = to_y - ras.y; 896 897 if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ 898 ; 899 else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ 900 { 901 gray_set_cell( RAS_VAR_ ex2, ey2 ); 902 goto End; 903 } 904 else if ( dx == 0 ) 905 { 906 if ( dy > 0 ) /* vertical line up */ 907 do 908 { 909 fy2 = ONE_PIXEL; 910 FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); 911 fy1 = 0; 912 ey1++; 913 gray_set_cell( RAS_VAR_ ex1, ey1 ); 914 } while ( ey1 != ey2 ); 915 else /* vertical line down */ 916 do 917 { 918 fy2 = 0; 919 FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); 920 fy1 = ONE_PIXEL; 921 ey1--; 922 gray_set_cell( RAS_VAR_ ex1, ey1 ); 923 } while ( ey1 != ey2 ); 924 } 925 else /* any other line */ 926 { 927 FT_Int64 prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1; 928 FT_UDIVPREP( ex1 != ex2, dx ); 929 FT_UDIVPREP( ey1 != ey2, dy ); 930 931 932 /* The fundamental value `prod' determines which side and the */ 933 /* exact coordinate where the line exits current cell. It is */ 934 /* also easily updated when moving from one cell to the next. */ 935 do 936 { 937 if ( prod - dx * ONE_PIXEL > 0 && 938 prod <= 0 ) /* left */ 939 { 940 fx2 = 0; 941 fy2 = FT_UDIV( -prod, -dx ); 942 prod -= dy * ONE_PIXEL; 943 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); 944 fx1 = ONE_PIXEL; 945 fy1 = fy2; 946 ex1--; 947 } 948 else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 && 949 prod - dx * ONE_PIXEL <= 0 ) /* up */ 950 { 951 prod -= dx * ONE_PIXEL; 952 fx2 = FT_UDIV( -prod, dy ); 953 fy2 = ONE_PIXEL; 954 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); 955 fx1 = fx2; 956 fy1 = 0; 957 ey1++; 958 } 959 else if ( prod + dy * ONE_PIXEL >= 0 && 960 prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */ 961 { 962 prod += dy * ONE_PIXEL; 963 fx2 = ONE_PIXEL; 964 fy2 = FT_UDIV( prod, dx ); 965 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); 966 fx1 = 0; 967 fy1 = fy2; 968 ex1++; 969 } 970 else /* ( prod > 0 && 971 prod + dy * ONE_PIXEL < 0 ) down */ 972 { 973 fx2 = FT_UDIV( prod, -dy ); 974 fy2 = 0; 975 prod += dx * ONE_PIXEL; 976 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); 977 fx1 = fx2; 978 fy1 = ONE_PIXEL; 979 ey1--; 980 } 981 982 gray_set_cell( RAS_VAR_ ex1, ey1 ); 983 984 } while ( ex1 != ex2 || ey1 != ey2 ); 985 } 986 987 fx2 = FRACT( to_x ); 988 fy2 = FRACT( to_y ); 989 990 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); 991 992 End: 993 ras.x = to_x; 994 ras.y = to_y; 995 } 996 997 #endif 998 999 /* 1000 * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs 1001 * is slightly faster in the following cases: 1002 * 1003 * - When the host CPU is 64-bit. 1004 * - When SSE2 SIMD registers and instructions are available (even on 1005 * x86). 1006 * 1007 * For other cases, using binary splits is actually slightly faster. 1008 */ 1009 #if ( defined( __SSE2__ ) || \ 1010 defined( __x86_64__ ) || \ 1011 defined( _M_AMD64 ) || \ 1012 ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) ) && \ 1013 !defined( __VMS ) 1014 # define FT_SSE2 1 1015 #else 1016 # define FT_SSE2 0 1017 #endif 1018 1019 #if FT_SSE2 || \ 1020 defined( __aarch64__ ) || \ 1021 defined( _M_ARM64 ) 1022 # define BEZIER_USE_DDA 1 1023 #else 1024 # define BEZIER_USE_DDA 0 1025 #endif 1026 1027 /* 1028 * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64` 1029 * to be defined. If `FT_INT64` is not defined, meaning there is no 1030 * 64-bit type available, disable it to avoid compilation errors. See for 1031 * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. 1032 */ 1033 #if !defined( FT_INT64 ) 1034 # undef BEZIER_USE_DDA 1035 # define BEZIER_USE_DDA 0 1036 #endif 1037 1038 #if BEZIER_USE_DDA 1039 1040 #if FT_SSE2 1041 # include <emmintrin.h> 1042 #endif 1043 1044 #define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) 1045 1046 1047 static void gray_render_conic(RAS_ARG_ const FT_Vector * control,const FT_Vector * to)1048 gray_render_conic( RAS_ARG_ const FT_Vector* control, 1049 const FT_Vector* to ) 1050 { 1051 FT_Vector p0, p1, p2; 1052 TPos ax, ay, bx, by, dx, dy; 1053 int shift; 1054 1055 FT_Int64 rx, ry; 1056 FT_Int64 qx, qy; 1057 FT_Int64 px, py; 1058 1059 FT_UInt count; 1060 1061 1062 p0.x = ras.x; 1063 p0.y = ras.y; 1064 p1.x = UPSCALE( control->x ); 1065 p1.y = UPSCALE( control->y ); 1066 p2.x = UPSCALE( to->x ); 1067 p2.y = UPSCALE( to->y ); 1068 1069 /* short-cut the arc that crosses the current band */ 1070 if ( ( TRUNC( p0.y ) >= ras.max_ey && 1071 TRUNC( p1.y ) >= ras.max_ey && 1072 TRUNC( p2.y ) >= ras.max_ey ) || 1073 ( TRUNC( p0.y ) < ras.min_ey && 1074 TRUNC( p1.y ) < ras.min_ey && 1075 TRUNC( p2.y ) < ras.min_ey ) ) 1076 { 1077 ras.x = p2.x; 1078 ras.y = p2.y; 1079 return; 1080 } 1081 1082 bx = p1.x - p0.x; 1083 by = p1.y - p0.y; 1084 ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */ 1085 ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */ 1086 1087 dx = FT_ABS( ax ); 1088 dy = FT_ABS( ay ); 1089 if ( dx < dy ) 1090 dx = dy; 1091 1092 if ( dx <= ONE_PIXEL / 4 ) 1093 { 1094 gray_render_line( RAS_VAR_ p2.x, p2.y ); 1095 return; 1096 } 1097 1098 /* We can calculate the number of necessary bisections because */ 1099 /* each bisection predictably reduces deviation exactly 4-fold. */ 1100 /* Even 32-bit deviation would vanish after 16 bisections. */ 1101 shift = 0; 1102 do 1103 { 1104 dx >>= 2; 1105 shift += 1; 1106 1107 } while ( dx > ONE_PIXEL / 4 ); 1108 1109 /* 1110 * The (P0,P1,P2) arc equation, for t in [0,1] range: 1111 * 1112 * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2 1113 * 1114 * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2 1115 * = P0 + 2*B*t + A*t^2 1116 * 1117 * for A = P0 + P2 - 2*P1 1118 * and B = P1 - P0 1119 * 1120 * Let's consider the difference when advancing by a small 1121 * parameter h: 1122 * 1123 * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t 1124 * 1125 * And then its own difference: 1126 * 1127 * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant) 1128 * 1129 * Since R is always a constant, it is possible to compute 1130 * successive positions with: 1131 * 1132 * P = P0 1133 * Q = Q(h,0) = 2*B*h + A*h*h 1134 * R = 2*A*h*h 1135 * 1136 * loop: 1137 * P += Q 1138 * Q += R 1139 * EMIT(P) 1140 * 1141 * To ensure accurate results, perform computations on 64-bit 1142 * values, after scaling them by 2^32. 1143 * 1144 * h = 1 / 2^N 1145 * 1146 * R << 32 = 2 * A << (32 - N - N) 1147 * = A << (33 - 2*N) 1148 * 1149 * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N)) 1150 * = (B << (33 - N)) + (A << (32 - 2*N)) 1151 */ 1152 1153 #if FT_SSE2 1154 /* Experience shows that for small shift values, */ 1155 /* SSE2 is actually slower. */ 1156 if ( shift > 2 ) 1157 { 1158 union 1159 { 1160 struct { FT_Int64 ax, ay, bx, by; } i; 1161 struct { __m128i a, b; } vec; 1162 1163 } u; 1164 1165 union 1166 { 1167 struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i; 1168 __m128i vec; 1169 1170 } v; 1171 1172 __m128i a, b; 1173 __m128i r, q, q2; 1174 __m128i p; 1175 1176 1177 u.i.ax = ax; 1178 u.i.ay = ay; 1179 u.i.bx = bx; 1180 u.i.by = by; 1181 1182 a = _mm_load_si128( &u.vec.a ); 1183 b = _mm_load_si128( &u.vec.b ); 1184 1185 r = _mm_slli_epi64( a, 33 - 2 * shift ); 1186 q = _mm_slli_epi64( b, 33 - shift ); 1187 q2 = _mm_slli_epi64( a, 32 - 2 * shift ); 1188 1189 q = _mm_add_epi64( q2, q ); 1190 1191 v.i.px_lo = 0; 1192 v.i.px_hi = p0.x; 1193 v.i.py_lo = 0; 1194 v.i.py_hi = p0.y; 1195 1196 p = _mm_load_si128( &v.vec ); 1197 1198 for ( count = 1U << shift; count > 0; count-- ) 1199 { 1200 p = _mm_add_epi64( p, q ); 1201 q = _mm_add_epi64( q, r ); 1202 1203 _mm_store_si128( &v.vec, p ); 1204 1205 gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi ); 1206 } 1207 1208 return; 1209 } 1210 #endif /* FT_SSE2 */ 1211 1212 rx = LEFT_SHIFT( ax, 33 - 2 * shift ); 1213 ry = LEFT_SHIFT( ay, 33 - 2 * shift ); 1214 1215 qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift ); 1216 qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift ); 1217 1218 px = LEFT_SHIFT( p0.x, 32 ); 1219 py = LEFT_SHIFT( p0.y, 32 ); 1220 1221 for ( count = 1U << shift; count > 0; count-- ) 1222 { 1223 px += qx; 1224 py += qy; 1225 qx += rx; 1226 qy += ry; 1227 1228 gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), 1229 (FT_Pos)( py >> 32 ) ); 1230 } 1231 } 1232 1233 #else /* !BEZIER_USE_DDA */ 1234 1235 /* 1236 * Note that multiple attempts to speed up the function below 1237 * with SSE2 intrinsics, using various data layouts, have turned 1238 * out to be slower than the non-SIMD code below. 1239 */ 1240 static void gray_split_conic(FT_Vector * base)1241 gray_split_conic( FT_Vector* base ) 1242 { 1243 TPos a, b; 1244 1245 1246 base[4].x = base[2].x; 1247 a = base[0].x + base[1].x; 1248 b = base[1].x + base[2].x; 1249 base[3].x = b >> 1; 1250 base[2].x = ( a + b ) >> 2; 1251 base[1].x = a >> 1; 1252 1253 base[4].y = base[2].y; 1254 a = base[0].y + base[1].y; 1255 b = base[1].y + base[2].y; 1256 base[3].y = b >> 1; 1257 base[2].y = ( a + b ) >> 2; 1258 base[1].y = a >> 1; 1259 } 1260 1261 1262 static void gray_render_conic(RAS_ARG_ const FT_Vector * control,const FT_Vector * to)1263 gray_render_conic( RAS_ARG_ const FT_Vector* control, 1264 const FT_Vector* to ) 1265 { 1266 FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ 1267 FT_Vector* arc = bez_stack; 1268 TPos dx, dy; 1269 int draw; 1270 1271 1272 arc[0].x = UPSCALE( to->x ); 1273 arc[0].y = UPSCALE( to->y ); 1274 arc[1].x = UPSCALE( control->x ); 1275 arc[1].y = UPSCALE( control->y ); 1276 arc[2].x = ras.x; 1277 arc[2].y = ras.y; 1278 1279 /* short-cut the arc that crosses the current band */ 1280 if ( ( TRUNC( arc[0].y ) >= ras.max_ey && 1281 TRUNC( arc[1].y ) >= ras.max_ey && 1282 TRUNC( arc[2].y ) >= ras.max_ey ) || 1283 ( TRUNC( arc[0].y ) < ras.min_ey && 1284 TRUNC( arc[1].y ) < ras.min_ey && 1285 TRUNC( arc[2].y ) < ras.min_ey ) ) 1286 { 1287 ras.x = arc[0].x; 1288 ras.y = arc[0].y; 1289 return; 1290 } 1291 1292 dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); 1293 dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); 1294 if ( dx < dy ) 1295 dx = dy; 1296 1297 /* We can calculate the number of necessary bisections because */ 1298 /* each bisection predictably reduces deviation exactly 4-fold. */ 1299 /* Even 32-bit deviation would vanish after 16 bisections. */ 1300 draw = 1; 1301 while ( dx > ONE_PIXEL / 4 ) 1302 { 1303 dx >>= 2; 1304 draw <<= 1; 1305 } 1306 1307 /* We use decrement counter to count the total number of segments */ 1308 /* to draw starting from 2^level. Before each draw we split as */ 1309 /* many times as there are trailing zeros in the counter. */ 1310 do 1311 { 1312 int split = draw & ( -draw ); /* isolate the rightmost 1-bit */ 1313 1314 1315 while ( ( split >>= 1 ) ) 1316 { 1317 gray_split_conic( arc ); 1318 arc += 2; 1319 } 1320 1321 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 1322 arc -= 2; 1323 1324 } while ( --draw ); 1325 } 1326 1327 #endif /* !BEZIER_USE_DDA */ 1328 1329 1330 /* 1331 * For cubic Bézier, binary splits are still faster than DDA 1332 * because the splits are adaptive to how quickly each sub-arc 1333 * approaches their chord trisection points. 1334 * 1335 * It might be useful to experiment with SSE2 to speed up 1336 * `gray_split_cubic`, though. 1337 */ 1338 static void gray_split_cubic(FT_Vector * base)1339 gray_split_cubic( FT_Vector* base ) 1340 { 1341 TPos a, b, c; 1342 1343 1344 base[6].x = base[3].x; 1345 a = base[0].x + base[1].x; 1346 b = base[1].x + base[2].x; 1347 c = base[2].x + base[3].x; 1348 base[5].x = c >> 1; 1349 c += b; 1350 base[4].x = c >> 2; 1351 base[1].x = a >> 1; 1352 a += b; 1353 base[2].x = a >> 2; 1354 base[3].x = ( a + c ) >> 3; 1355 1356 base[6].y = base[3].y; 1357 a = base[0].y + base[1].y; 1358 b = base[1].y + base[2].y; 1359 c = base[2].y + base[3].y; 1360 base[5].y = c >> 1; 1361 c += b; 1362 base[4].y = c >> 2; 1363 base[1].y = a >> 1; 1364 a += b; 1365 base[2].y = a >> 2; 1366 base[3].y = ( a + c ) >> 3; 1367 } 1368 1369 1370 static void gray_render_cubic(RAS_ARG_ const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to)1371 gray_render_cubic( RAS_ARG_ const FT_Vector* control1, 1372 const FT_Vector* control2, 1373 const FT_Vector* to ) 1374 { 1375 FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ 1376 FT_Vector* arc = bez_stack; 1377 1378 1379 arc[0].x = UPSCALE( to->x ); 1380 arc[0].y = UPSCALE( to->y ); 1381 arc[1].x = UPSCALE( control2->x ); 1382 arc[1].y = UPSCALE( control2->y ); 1383 arc[2].x = UPSCALE( control1->x ); 1384 arc[2].y = UPSCALE( control1->y ); 1385 arc[3].x = ras.x; 1386 arc[3].y = ras.y; 1387 1388 /* short-cut the arc that crosses the current band */ 1389 if ( ( TRUNC( arc[0].y ) >= ras.max_ey && 1390 TRUNC( arc[1].y ) >= ras.max_ey && 1391 TRUNC( arc[2].y ) >= ras.max_ey && 1392 TRUNC( arc[3].y ) >= ras.max_ey ) || 1393 ( TRUNC( arc[0].y ) < ras.min_ey && 1394 TRUNC( arc[1].y ) < ras.min_ey && 1395 TRUNC( arc[2].y ) < ras.min_ey && 1396 TRUNC( arc[3].y ) < ras.min_ey ) ) 1397 { 1398 ras.x = arc[0].x; 1399 ras.y = arc[0].y; 1400 return; 1401 } 1402 1403 for (;;) 1404 { 1405 /* with each split, control points quickly converge towards */ 1406 /* chord trisection points and the vanishing distances below */ 1407 /* indicate when the segment is flat enough to draw */ 1408 if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || 1409 FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || 1410 FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || 1411 FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) 1412 goto Split; 1413 1414 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 1415 1416 if ( arc == bez_stack ) 1417 return; 1418 1419 arc -= 3; 1420 continue; 1421 1422 Split: 1423 gray_split_cubic( arc ); 1424 arc += 3; 1425 } 1426 } 1427 1428 1429 static int gray_move_to(const FT_Vector * to,void * worker_)1430 gray_move_to( const FT_Vector* to, 1431 void* worker_ ) /* gray_PWorker */ 1432 { 1433 gray_PWorker worker = (gray_PWorker)worker_; 1434 1435 TPos x, y; 1436 1437 1438 /* start to a new position */ 1439 x = UPSCALE( to->x ); 1440 y = UPSCALE( to->y ); 1441 1442 gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); 1443 1444 ras.x = x; 1445 ras.y = y; 1446 return 0; 1447 } 1448 1449 1450 static int gray_line_to(const FT_Vector * to,void * worker_)1451 gray_line_to( const FT_Vector* to, 1452 void* worker_ ) /* gray_PWorker */ 1453 { 1454 gray_PWorker worker = (gray_PWorker)worker_; 1455 1456 1457 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); 1458 return 0; 1459 } 1460 1461 1462 static int gray_conic_to(const FT_Vector * control,const FT_Vector * to,void * worker_)1463 gray_conic_to( const FT_Vector* control, 1464 const FT_Vector* to, 1465 void* worker_ ) /* gray_PWorker */ 1466 { 1467 gray_PWorker worker = (gray_PWorker)worker_; 1468 1469 1470 gray_render_conic( RAS_VAR_ control, to ); 1471 return 0; 1472 } 1473 1474 1475 static int gray_cubic_to(const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to,void * worker_)1476 gray_cubic_to( const FT_Vector* control1, 1477 const FT_Vector* control2, 1478 const FT_Vector* to, 1479 void* worker_ ) /* gray_PWorker */ 1480 { 1481 gray_PWorker worker = (gray_PWorker)worker_; 1482 1483 1484 gray_render_cubic( RAS_VAR_ control1, control2, to ); 1485 return 0; 1486 } 1487 1488 1489 static void gray_sweep(RAS_ARG)1490 gray_sweep( RAS_ARG ) 1491 { 1492 int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 1493 : INT_MIN; 1494 int coverage; 1495 int y; 1496 1497 1498 for ( y = ras.min_ey; y < ras.max_ey; y++ ) 1499 { 1500 PCell cell = ras.ycells[y - ras.min_ey]; 1501 TCoord x = ras.min_ex; 1502 TArea cover = 0; 1503 1504 unsigned char* line = ras.target.origin - ras.target.pitch * y; 1505 1506 1507 for ( ; cell != ras.cell_null; cell = cell->next ) 1508 { 1509 TArea area; 1510 1511 1512 if ( cover != 0 && cell->x > x ) 1513 { 1514 FT_FILL_RULE( coverage, cover, fill ); 1515 FT_GRAY_SET( line + x, coverage, cell->x - x ); 1516 } 1517 1518 cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); 1519 area = cover - cell->area; 1520 1521 if ( area != 0 && cell->x >= ras.min_ex ) 1522 { 1523 FT_FILL_RULE( coverage, area, fill ); 1524 line[cell->x] = (unsigned char)coverage; 1525 } 1526 1527 x = cell->x + 1; 1528 } 1529 1530 if ( cover != 0 ) /* only if cropped */ 1531 { 1532 FT_FILL_RULE( coverage, cover, fill ); 1533 FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); 1534 } 1535 } 1536 } 1537 1538 1539 static void gray_sweep_direct(RAS_ARG)1540 gray_sweep_direct( RAS_ARG ) 1541 { 1542 int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 1543 : INT_MIN; 1544 int coverage; 1545 int y; 1546 1547 FT_Span span[FT_MAX_GRAY_SPANS]; 1548 int n = 0; 1549 1550 1551 for ( y = ras.min_ey; y < ras.max_ey; y++ ) 1552 { 1553 PCell cell = ras.ycells[y - ras.min_ey]; 1554 TCoord x = ras.min_ex; 1555 TArea cover = 0; 1556 1557 1558 for ( ; cell != ras.cell_null; cell = cell->next ) 1559 { 1560 TArea area; 1561 1562 1563 if ( cover != 0 && cell->x > x ) 1564 { 1565 FT_FILL_RULE( coverage, cover, fill ); 1566 1567 span[n].coverage = (unsigned char)coverage; 1568 span[n].x = (short)x; 1569 span[n].len = (unsigned short)( cell->x - x ); 1570 1571 if ( ++n == FT_MAX_GRAY_SPANS ) 1572 { 1573 /* flush the span buffer and reset the count */ 1574 ras.render_span( y, n, span, ras.render_span_data ); 1575 n = 0; 1576 } 1577 } 1578 1579 cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); 1580 area = cover - cell->area; 1581 1582 if ( area != 0 && cell->x >= ras.min_ex ) 1583 { 1584 FT_FILL_RULE( coverage, area, fill ); 1585 1586 span[n].coverage = (unsigned char)coverage; 1587 span[n].x = (short)cell->x; 1588 span[n].len = 1; 1589 1590 if ( ++n == FT_MAX_GRAY_SPANS ) 1591 { 1592 /* flush the span buffer and reset the count */ 1593 ras.render_span( y, n, span, ras.render_span_data ); 1594 n = 0; 1595 } 1596 } 1597 1598 x = cell->x + 1; 1599 } 1600 1601 if ( cover != 0 ) /* only if cropped */ 1602 { 1603 FT_FILL_RULE( coverage, cover, fill ); 1604 1605 span[n].coverage = (unsigned char)coverage; 1606 span[n].x = (short)x; 1607 span[n].len = (unsigned short)( ras.max_ex - x ); 1608 1609 ++n; 1610 } 1611 1612 if ( n ) 1613 { 1614 /* flush the span buffer and reset the count */ 1615 ras.render_span( y, n, span, ras.render_span_data ); 1616 n = 0; 1617 } 1618 } 1619 } 1620 1621 1622 #ifdef STANDALONE_ 1623 1624 /************************************************************************** 1625 * 1626 * The following functions should only compile in stand-alone mode, 1627 * i.e., when building this component without the rest of FreeType. 1628 * 1629 */ 1630 1631 /************************************************************************** 1632 * 1633 * @Function: 1634 * FT_Outline_Decompose 1635 * 1636 * @Description: 1637 * Walk over an outline's structure to decompose it into individual 1638 * segments and Bézier arcs. This function is also able to emit 1639 * `move to' and `close to' operations to indicate the start and end 1640 * of new contours in the outline. 1641 * 1642 * @Input: 1643 * outline :: 1644 * A pointer to the source target. 1645 * 1646 * func_interface :: 1647 * A table of `emitters', i.e., function pointers 1648 * called during decomposition to indicate path 1649 * operations. 1650 * 1651 * @InOut: 1652 * user :: 1653 * A typeless pointer which is passed to each 1654 * emitter during the decomposition. It can be 1655 * used to store the state during the 1656 * decomposition. 1657 * 1658 * @Return: 1659 * Error code. 0 means success. 1660 */ 1661 static int FT_Outline_Decompose(const FT_Outline * outline,const FT_Outline_Funcs * func_interface,void * user)1662 FT_Outline_Decompose( const FT_Outline* outline, 1663 const FT_Outline_Funcs* func_interface, 1664 void* user ) 1665 { 1666 #undef SCALED 1667 #define SCALED( x ) ( (x) * ( 1L << shift ) - delta ) 1668 1669 FT_Vector v_last; 1670 FT_Vector v_control; 1671 FT_Vector v_start; 1672 1673 FT_Vector* point; 1674 FT_Vector* limit; 1675 char* tags; 1676 1677 int error; 1678 1679 int n; /* index of contour in outline */ 1680 int first; /* index of first point in contour */ 1681 int last; /* index of last point in contour */ 1682 1683 char tag; /* current point's state */ 1684 1685 int shift; 1686 TPos delta; 1687 1688 1689 if ( !outline ) 1690 return FT_THROW( Invalid_Outline ); 1691 1692 if ( !func_interface ) 1693 return FT_THROW( Invalid_Argument ); 1694 1695 shift = func_interface->shift; 1696 delta = func_interface->delta; 1697 1698 last = -1; 1699 for ( n = 0; n < outline->n_contours; n++ ) 1700 { 1701 FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); 1702 1703 first = last + 1; 1704 last = outline->contours[n]; 1705 if ( last < first ) 1706 goto Invalid_Outline; 1707 1708 limit = outline->points + last; 1709 1710 v_start = outline->points[first]; 1711 v_start.x = SCALED( v_start.x ); 1712 v_start.y = SCALED( v_start.y ); 1713 1714 v_last = outline->points[last]; 1715 v_last.x = SCALED( v_last.x ); 1716 v_last.y = SCALED( v_last.y ); 1717 1718 v_control = v_start; 1719 1720 point = outline->points + first; 1721 tags = outline->tags + first; 1722 tag = FT_CURVE_TAG( tags[0] ); 1723 1724 /* A contour cannot start with a cubic control point! */ 1725 if ( tag == FT_CURVE_TAG_CUBIC ) 1726 goto Invalid_Outline; 1727 1728 /* check first point to determine origin */ 1729 if ( tag == FT_CURVE_TAG_CONIC ) 1730 { 1731 /* first point is conic control. Yes, this happens. */ 1732 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 1733 { 1734 /* start at last point if it is on the curve */ 1735 v_start = v_last; 1736 limit--; 1737 } 1738 else 1739 { 1740 /* if both first and last points are conic, */ 1741 /* start at their middle and record its position */ 1742 /* for closure */ 1743 v_start.x = ( v_start.x + v_last.x ) / 2; 1744 v_start.y = ( v_start.y + v_last.y ) / 2; 1745 1746 v_last = v_start; 1747 } 1748 point--; 1749 tags--; 1750 } 1751 1752 FT_TRACE5(( " move to (%.2f, %.2f)\n", 1753 v_start.x / 64.0, v_start.y / 64.0 )); 1754 error = func_interface->move_to( &v_start, user ); 1755 if ( error ) 1756 goto Exit; 1757 1758 while ( point < limit ) 1759 { 1760 point++; 1761 tags++; 1762 1763 tag = FT_CURVE_TAG( tags[0] ); 1764 switch ( tag ) 1765 { 1766 case FT_CURVE_TAG_ON: /* emit a single line_to */ 1767 { 1768 FT_Vector vec; 1769 1770 1771 vec.x = SCALED( point->x ); 1772 vec.y = SCALED( point->y ); 1773 1774 FT_TRACE5(( " line to (%.2f, %.2f)\n", 1775 vec.x / 64.0, vec.y / 64.0 )); 1776 error = func_interface->line_to( &vec, user ); 1777 if ( error ) 1778 goto Exit; 1779 continue; 1780 } 1781 1782 case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 1783 v_control.x = SCALED( point->x ); 1784 v_control.y = SCALED( point->y ); 1785 1786 Do_Conic: 1787 if ( point < limit ) 1788 { 1789 FT_Vector vec; 1790 FT_Vector v_middle; 1791 1792 1793 point++; 1794 tags++; 1795 tag = FT_CURVE_TAG( tags[0] ); 1796 1797 vec.x = SCALED( point->x ); 1798 vec.y = SCALED( point->y ); 1799 1800 if ( tag == FT_CURVE_TAG_ON ) 1801 { 1802 FT_TRACE5(( " conic to (%.2f, %.2f)" 1803 " with control (%.2f, %.2f)\n", 1804 vec.x / 64.0, vec.y / 64.0, 1805 v_control.x / 64.0, v_control.y / 64.0 )); 1806 error = func_interface->conic_to( &v_control, &vec, user ); 1807 if ( error ) 1808 goto Exit; 1809 continue; 1810 } 1811 1812 if ( tag != FT_CURVE_TAG_CONIC ) 1813 goto Invalid_Outline; 1814 1815 v_middle.x = ( v_control.x + vec.x ) / 2; 1816 v_middle.y = ( v_control.y + vec.y ) / 2; 1817 1818 FT_TRACE5(( " conic to (%.2f, %.2f)" 1819 " with control (%.2f, %.2f)\n", 1820 v_middle.x / 64.0, v_middle.y / 64.0, 1821 v_control.x / 64.0, v_control.y / 64.0 )); 1822 error = func_interface->conic_to( &v_control, &v_middle, user ); 1823 if ( error ) 1824 goto Exit; 1825 1826 v_control = vec; 1827 goto Do_Conic; 1828 } 1829 1830 FT_TRACE5(( " conic to (%.2f, %.2f)" 1831 " with control (%.2f, %.2f)\n", 1832 v_start.x / 64.0, v_start.y / 64.0, 1833 v_control.x / 64.0, v_control.y / 64.0 )); 1834 error = func_interface->conic_to( &v_control, &v_start, user ); 1835 goto Close; 1836 1837 default: /* FT_CURVE_TAG_CUBIC */ 1838 { 1839 FT_Vector vec1, vec2; 1840 1841 1842 if ( point + 1 > limit || 1843 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 1844 goto Invalid_Outline; 1845 1846 point += 2; 1847 tags += 2; 1848 1849 vec1.x = SCALED( point[-2].x ); 1850 vec1.y = SCALED( point[-2].y ); 1851 1852 vec2.x = SCALED( point[-1].x ); 1853 vec2.y = SCALED( point[-1].y ); 1854 1855 if ( point <= limit ) 1856 { 1857 FT_Vector vec; 1858 1859 1860 vec.x = SCALED( point->x ); 1861 vec.y = SCALED( point->y ); 1862 1863 FT_TRACE5(( " cubic to (%.2f, %.2f)" 1864 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 1865 vec.x / 64.0, vec.y / 64.0, 1866 vec1.x / 64.0, vec1.y / 64.0, 1867 vec2.x / 64.0, vec2.y / 64.0 )); 1868 error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); 1869 if ( error ) 1870 goto Exit; 1871 continue; 1872 } 1873 1874 FT_TRACE5(( " cubic to (%.2f, %.2f)" 1875 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 1876 v_start.x / 64.0, v_start.y / 64.0, 1877 vec1.x / 64.0, vec1.y / 64.0, 1878 vec2.x / 64.0, vec2.y / 64.0 )); 1879 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); 1880 goto Close; 1881 } 1882 } 1883 } 1884 1885 /* close the contour with a line segment */ 1886 FT_TRACE5(( " line to (%.2f, %.2f)\n", 1887 v_start.x / 64.0, v_start.y / 64.0 )); 1888 error = func_interface->line_to( &v_start, user ); 1889 1890 Close: 1891 if ( error ) 1892 goto Exit; 1893 } 1894 1895 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); 1896 return Smooth_Err_Ok; 1897 1898 Exit: 1899 FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); 1900 return error; 1901 1902 Invalid_Outline: 1903 return FT_THROW( Invalid_Outline ); 1904 } 1905 1906 #endif /* STANDALONE_ */ 1907 1908 1909 FT_DEFINE_OUTLINE_FUNCS( 1910 func_interface, 1911 1912 (FT_Outline_MoveTo_Func) gray_move_to, /* move_to */ 1913 (FT_Outline_LineTo_Func) gray_line_to, /* line_to */ 1914 (FT_Outline_ConicTo_Func)gray_conic_to, /* conic_to */ 1915 (FT_Outline_CubicTo_Func)gray_cubic_to, /* cubic_to */ 1916 1917 0, /* shift */ 1918 0 /* delta */ 1919 ) 1920 1921 1922 static int gray_convert_glyph_inner(RAS_ARG_ int continued)1923 gray_convert_glyph_inner( RAS_ARG_ 1924 int continued ) 1925 { 1926 volatile int error; 1927 1928 1929 if ( ft_setjmp( ras.jump_buffer ) == 0 ) 1930 { 1931 if ( continued ) 1932 FT_Trace_Disable(); 1933 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); 1934 if ( continued ) 1935 FT_Trace_Enable(); 1936 1937 FT_TRACE7(( "band [%d..%d]: %td cell%s remaining/\n", 1938 ras.min_ey, 1939 ras.max_ey, 1940 ras.cell_null - ras.cell_free, 1941 ras.cell_null - ras.cell_free == 1 ? "" : "s" )); 1942 } 1943 else 1944 { 1945 error = FT_THROW( Raster_Overflow ); 1946 1947 FT_TRACE7(( "band [%d..%d]: to be bisected\n", 1948 ras.min_ey, ras.max_ey )); 1949 } 1950 1951 return error; 1952 } 1953 1954 1955 static int gray_convert_glyph(RAS_ARG)1956 gray_convert_glyph( RAS_ARG ) 1957 { 1958 const TCoord yMin = ras.min_ey; 1959 const TCoord yMax = ras.max_ey; 1960 1961 TCell buffer[FT_MAX_GRAY_POOL]; 1962 size_t height = (size_t)( yMax - yMin ); 1963 size_t n = FT_MAX_GRAY_POOL / 8; 1964 TCoord y; 1965 TCoord bands[32]; /* enough to accommodate bisections */ 1966 TCoord* band; 1967 1968 int continued = 0; 1969 1970 1971 /* Initialize the null cell at the end of the poll. */ 1972 ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; 1973 ras.cell_null->x = CELL_MAX_X_VALUE; 1974 ras.cell_null->area = 0; 1975 ras.cell_null->cover = 0; 1976 ras.cell_null->next = NULL; 1977 1978 /* set up vertical bands */ 1979 ras.ycells = (PCell*)buffer; 1980 1981 if ( height > n ) 1982 { 1983 /* two divisions rounded up */ 1984 n = ( height + n - 1 ) / n; 1985 height = ( height + n - 1 ) / n; 1986 } 1987 1988 for ( y = yMin; y < yMax; ) 1989 { 1990 ras.min_ey = y; 1991 y += height; 1992 ras.max_ey = FT_MIN( y, yMax ); 1993 1994 band = bands; 1995 band[1] = ras.min_ey; 1996 band[0] = ras.max_ey; 1997 1998 do 1999 { 2000 TCoord width = band[0] - band[1]; 2001 TCoord w; 2002 int error; 2003 2004 2005 for ( w = 0; w < width; ++w ) 2006 ras.ycells[w] = ras.cell_null; 2007 2008 /* memory management: skip ycells */ 2009 n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / 2010 sizeof ( TCell ); 2011 2012 ras.cell_free = buffer + n; 2013 ras.cell = ras.cell_null; 2014 ras.min_ey = band[1]; 2015 ras.max_ey = band[0]; 2016 ras.count_ey = width; 2017 2018 error = gray_convert_glyph_inner( RAS_VAR_ continued ); 2019 continued = 1; 2020 2021 if ( !error ) 2022 { 2023 if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ 2024 gray_sweep_direct( RAS_VAR ); 2025 else 2026 gray_sweep( RAS_VAR ); 2027 band--; 2028 continue; 2029 } 2030 else if ( error != Smooth_Err_Raster_Overflow ) 2031 return error; 2032 2033 /* render pool overflow; we will reduce the render band by half */ 2034 width >>= 1; 2035 2036 /* this should never happen even with tiny rendering pool */ 2037 if ( width == 0 ) 2038 { 2039 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); 2040 return FT_THROW( Raster_Overflow ); 2041 } 2042 2043 band++; 2044 band[1] = band[0]; 2045 band[0] += width; 2046 } while ( band >= bands ); 2047 } 2048 2049 return Smooth_Err_Ok; 2050 } 2051 2052 2053 static int gray_raster_render(FT_Raster raster,const FT_Raster_Params * params)2054 gray_raster_render( FT_Raster raster, 2055 const FT_Raster_Params* params ) 2056 { 2057 const FT_Outline* outline = (const FT_Outline*)params->source; 2058 const FT_Bitmap* target_map = params->target; 2059 2060 #ifndef FT_STATIC_RASTER 2061 gray_TWorker worker[1]; 2062 #endif 2063 2064 2065 if ( !raster ) 2066 return FT_THROW( Invalid_Argument ); 2067 2068 /* this version does not support monochrome rendering */ 2069 if ( !( params->flags & FT_RASTER_FLAG_AA ) ) 2070 return FT_THROW( Cannot_Render_Glyph ); 2071 2072 if ( !outline ) 2073 return FT_THROW( Invalid_Outline ); 2074 2075 /* return immediately if the outline is empty */ 2076 if ( outline->n_points == 0 || outline->n_contours <= 0 ) 2077 return Smooth_Err_Ok; 2078 2079 if ( !outline->contours || !outline->points ) 2080 return FT_THROW( Invalid_Outline ); 2081 2082 if ( outline->n_points != 2083 outline->contours[outline->n_contours - 1] + 1 ) 2084 return FT_THROW( Invalid_Outline ); 2085 2086 ras.outline = *outline; 2087 2088 if ( params->flags & FT_RASTER_FLAG_DIRECT ) 2089 { 2090 if ( !params->gray_spans ) 2091 return Smooth_Err_Ok; 2092 2093 ras.render_span = (FT_Raster_Span_Func)params->gray_spans; 2094 ras.render_span_data = params->user; 2095 2096 ras.min_ex = params->clip_box.xMin; 2097 ras.min_ey = params->clip_box.yMin; 2098 ras.max_ex = params->clip_box.xMax; 2099 ras.max_ey = params->clip_box.yMax; 2100 } 2101 else 2102 { 2103 /* if direct mode is not set, we must have a target bitmap */ 2104 if ( !target_map ) 2105 return FT_THROW( Invalid_Argument ); 2106 2107 /* nothing to do */ 2108 if ( !target_map->width || !target_map->rows ) 2109 return Smooth_Err_Ok; 2110 2111 if ( !target_map->buffer ) 2112 return FT_THROW( Invalid_Argument ); 2113 2114 if ( target_map->pitch < 0 ) 2115 ras.target.origin = target_map->buffer; 2116 else 2117 ras.target.origin = target_map->buffer 2118 + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch; 2119 2120 ras.target.pitch = target_map->pitch; 2121 2122 ras.render_span = (FT_Raster_Span_Func)NULL; 2123 ras.render_span_data = NULL; 2124 2125 ras.min_ex = 0; 2126 ras.min_ey = 0; 2127 ras.max_ex = (FT_Pos)target_map->width; 2128 ras.max_ey = (FT_Pos)target_map->rows; 2129 } 2130 2131 /* exit if nothing to do */ 2132 if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey ) 2133 return Smooth_Err_Ok; 2134 2135 return gray_convert_glyph( RAS_VAR ); 2136 } 2137 2138 2139 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ 2140 /**** a static object. *****/ 2141 2142 #ifdef STANDALONE_ 2143 2144 static int gray_raster_new(void * memory,FT_Raster * araster)2145 gray_raster_new( void* memory, 2146 FT_Raster* araster ) 2147 { 2148 static gray_TRaster the_raster; 2149 2150 FT_UNUSED( memory ); 2151 2152 2153 *araster = (FT_Raster)&the_raster; 2154 FT_ZERO( &the_raster ); 2155 2156 return 0; 2157 } 2158 2159 2160 static void gray_raster_done(FT_Raster raster)2161 gray_raster_done( FT_Raster raster ) 2162 { 2163 /* nothing */ 2164 FT_UNUSED( raster ); 2165 } 2166 2167 #else /* !STANDALONE_ */ 2168 2169 static int gray_raster_new(void * memory_,FT_Raster * araster_)2170 gray_raster_new( void* memory_, 2171 FT_Raster* araster_ ) 2172 { 2173 FT_Memory memory = (FT_Memory)memory_; 2174 gray_PRaster* araster = (gray_PRaster*)araster_; 2175 2176 FT_Error error; 2177 gray_PRaster raster = NULL; 2178 2179 2180 if ( !FT_NEW( raster ) ) 2181 raster->memory = memory; 2182 2183 *araster = raster; 2184 2185 return error; 2186 } 2187 2188 2189 static void gray_raster_done(FT_Raster raster)2190 gray_raster_done( FT_Raster raster ) 2191 { 2192 FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; 2193 2194 2195 FT_FREE( raster ); 2196 } 2197 2198 #endif /* !STANDALONE_ */ 2199 2200 2201 static void gray_raster_reset(FT_Raster raster,unsigned char * pool_base,unsigned long pool_size)2202 gray_raster_reset( FT_Raster raster, 2203 unsigned char* pool_base, 2204 unsigned long pool_size ) 2205 { 2206 FT_UNUSED( raster ); 2207 FT_UNUSED( pool_base ); 2208 FT_UNUSED( pool_size ); 2209 } 2210 2211 2212 static int gray_raster_set_mode(FT_Raster raster,unsigned long mode,void * args)2213 gray_raster_set_mode( FT_Raster raster, 2214 unsigned long mode, 2215 void* args ) 2216 { 2217 FT_UNUSED( raster ); 2218 FT_UNUSED( mode ); 2219 FT_UNUSED( args ); 2220 2221 2222 return 0; /* nothing to do */ 2223 } 2224 2225 2226 FT_DEFINE_RASTER_FUNCS( 2227 ft_grays_raster, 2228 2229 FT_GLYPH_FORMAT_OUTLINE, 2230 2231 (FT_Raster_New_Func) gray_raster_new, /* raster_new */ 2232 (FT_Raster_Reset_Func) gray_raster_reset, /* raster_reset */ 2233 (FT_Raster_Set_Mode_Func)gray_raster_set_mode, /* raster_set_mode */ 2234 (FT_Raster_Render_Func) gray_raster_render, /* raster_render */ 2235 (FT_Raster_Done_Func) gray_raster_done /* raster_done */ 2236 ) 2237 2238 2239 /* END */ 2240 2241 2242 /* Local Variables: */ 2243 /* coding: utf-8 */ 2244 /* End: */ 2245