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 # define FT_SSE2 1 1014 #else 1015 # define FT_SSE2 0 1016 #endif 1017 1018 #if FT_SSE2 || \ 1019 defined( __aarch64__ ) || \ 1020 defined( _M_ARM64 ) 1021 # define BEZIER_USE_DDA 1 1022 #else 1023 # define BEZIER_USE_DDA 0 1024 #endif 1025 1026 /* 1027 * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64` 1028 * to be defined. If `FT_INT64` is not defined, meaning there is no 1029 * 64-bit type available, disable it to avoid compilation errors. See for 1030 * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. 1031 */ 1032 #if !defined( FT_INT64 ) 1033 # undef BEZIER_USE_DDA 1034 # define BEZIER_USE_DDA 0 1035 #endif 1036 1037 #if BEZIER_USE_DDA 1038 1039 #if FT_SSE2 1040 # include <emmintrin.h> 1041 #endif 1042 1043 #define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) 1044 1045 1046 static void gray_render_conic(RAS_ARG_ const FT_Vector * control,const FT_Vector * to)1047 gray_render_conic( RAS_ARG_ const FT_Vector* control, 1048 const FT_Vector* to ) 1049 { 1050 FT_Vector p0, p1, p2; 1051 TPos ax, ay, bx, by, dx, dy; 1052 int shift; 1053 1054 FT_Int64 rx, ry; 1055 FT_Int64 qx, qy; 1056 FT_Int64 px, py; 1057 1058 FT_UInt count; 1059 1060 1061 p0.x = ras.x; 1062 p0.y = ras.y; 1063 p1.x = UPSCALE( control->x ); 1064 p1.y = UPSCALE( control->y ); 1065 p2.x = UPSCALE( to->x ); 1066 p2.y = UPSCALE( to->y ); 1067 1068 /* short-cut the arc that crosses the current band */ 1069 if ( ( TRUNC( p0.y ) >= ras.max_ey && 1070 TRUNC( p1.y ) >= ras.max_ey && 1071 TRUNC( p2.y ) >= ras.max_ey ) || 1072 ( TRUNC( p0.y ) < ras.min_ey && 1073 TRUNC( p1.y ) < ras.min_ey && 1074 TRUNC( p2.y ) < ras.min_ey ) ) 1075 { 1076 ras.x = p2.x; 1077 ras.y = p2.y; 1078 return; 1079 } 1080 1081 bx = p1.x - p0.x; 1082 by = p1.y - p0.y; 1083 ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */ 1084 ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */ 1085 1086 dx = FT_ABS( ax ); 1087 dy = FT_ABS( ay ); 1088 if ( dx < dy ) 1089 dx = dy; 1090 1091 if ( dx <= ONE_PIXEL / 4 ) 1092 { 1093 gray_render_line( RAS_VAR_ p2.x, p2.y ); 1094 return; 1095 } 1096 1097 /* We can calculate the number of necessary bisections because */ 1098 /* each bisection predictably reduces deviation exactly 4-fold. */ 1099 /* Even 32-bit deviation would vanish after 16 bisections. */ 1100 shift = 0; 1101 do 1102 { 1103 dx >>= 2; 1104 shift += 1; 1105 1106 } while ( dx > ONE_PIXEL / 4 ); 1107 1108 /* 1109 * The (P0,P1,P2) arc equation, for t in [0,1] range: 1110 * 1111 * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2 1112 * 1113 * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2 1114 * = P0 + 2*B*t + A*t^2 1115 * 1116 * for A = P0 + P2 - 2*P1 1117 * and B = P1 - P0 1118 * 1119 * Let's consider the difference when advancing by a small 1120 * parameter h: 1121 * 1122 * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t 1123 * 1124 * And then its own difference: 1125 * 1126 * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant) 1127 * 1128 * Since R is always a constant, it is possible to compute 1129 * successive positions with: 1130 * 1131 * P = P0 1132 * Q = Q(h,0) = 2*B*h + A*h*h 1133 * R = 2*A*h*h 1134 * 1135 * loop: 1136 * P += Q 1137 * Q += R 1138 * EMIT(P) 1139 * 1140 * To ensure accurate results, perform computations on 64-bit 1141 * values, after scaling them by 2^32. 1142 * 1143 * h = 1 / 2^N 1144 * 1145 * R << 32 = 2 * A << (32 - N - N) 1146 * = A << (33 - 2*N) 1147 * 1148 * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N)) 1149 * = (B << (33 - N)) + (A << (32 - 2*N)) 1150 */ 1151 1152 #if FT_SSE2 1153 /* Experience shows that for small shift values, */ 1154 /* SSE2 is actually slower. */ 1155 if ( shift > 2 ) 1156 { 1157 union 1158 { 1159 struct { FT_Int64 ax, ay, bx, by; } i; 1160 struct { __m128i a, b; } vec; 1161 1162 } u; 1163 1164 union 1165 { 1166 struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i; 1167 __m128i vec; 1168 1169 } v; 1170 1171 __m128i a, b; 1172 __m128i r, q, q2; 1173 __m128i p; 1174 1175 1176 u.i.ax = ax; 1177 u.i.ay = ay; 1178 u.i.bx = bx; 1179 u.i.by = by; 1180 1181 a = _mm_load_si128( &u.vec.a ); 1182 b = _mm_load_si128( &u.vec.b ); 1183 1184 r = _mm_slli_epi64( a, 33 - 2 * shift ); 1185 q = _mm_slli_epi64( b, 33 - shift ); 1186 q2 = _mm_slli_epi64( a, 32 - 2 * shift ); 1187 1188 q = _mm_add_epi64( q2, q ); 1189 1190 v.i.px_lo = 0; 1191 v.i.px_hi = p0.x; 1192 v.i.py_lo = 0; 1193 v.i.py_hi = p0.y; 1194 1195 p = _mm_load_si128( &v.vec ); 1196 1197 for ( count = 1U << shift; count > 0; count-- ) 1198 { 1199 p = _mm_add_epi64( p, q ); 1200 q = _mm_add_epi64( q, r ); 1201 1202 _mm_store_si128( &v.vec, p ); 1203 1204 gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi ); 1205 } 1206 1207 return; 1208 } 1209 #endif /* FT_SSE2 */ 1210 1211 rx = LEFT_SHIFT( ax, 33 - 2 * shift ); 1212 ry = LEFT_SHIFT( ay, 33 - 2 * shift ); 1213 1214 qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift ); 1215 qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift ); 1216 1217 px = LEFT_SHIFT( p0.x, 32 ); 1218 py = LEFT_SHIFT( p0.y, 32 ); 1219 1220 for ( count = 1U << shift; count > 0; count-- ) 1221 { 1222 px += qx; 1223 py += qy; 1224 qx += rx; 1225 qy += ry; 1226 1227 gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), 1228 (FT_Pos)( py >> 32 ) ); 1229 } 1230 } 1231 1232 #else /* !BEZIER_USE_DDA */ 1233 1234 /* 1235 * Note that multiple attempts to speed up the function below 1236 * with SSE2 intrinsics, using various data layouts, have turned 1237 * out to be slower than the non-SIMD code below. 1238 */ 1239 static void gray_split_conic(FT_Vector * base)1240 gray_split_conic( FT_Vector* base ) 1241 { 1242 TPos a, b; 1243 1244 1245 base[4].x = base[2].x; 1246 a = base[0].x + base[1].x; 1247 b = base[1].x + base[2].x; 1248 base[3].x = b >> 1; 1249 base[2].x = ( a + b ) >> 2; 1250 base[1].x = a >> 1; 1251 1252 base[4].y = base[2].y; 1253 a = base[0].y + base[1].y; 1254 b = base[1].y + base[2].y; 1255 base[3].y = b >> 1; 1256 base[2].y = ( a + b ) >> 2; 1257 base[1].y = a >> 1; 1258 } 1259 1260 1261 static void gray_render_conic(RAS_ARG_ const FT_Vector * control,const FT_Vector * to)1262 gray_render_conic( RAS_ARG_ const FT_Vector* control, 1263 const FT_Vector* to ) 1264 { 1265 FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ 1266 FT_Vector* arc = bez_stack; 1267 TPos dx, dy; 1268 int draw; 1269 1270 1271 arc[0].x = UPSCALE( to->x ); 1272 arc[0].y = UPSCALE( to->y ); 1273 arc[1].x = UPSCALE( control->x ); 1274 arc[1].y = UPSCALE( control->y ); 1275 arc[2].x = ras.x; 1276 arc[2].y = ras.y; 1277 1278 /* short-cut the arc that crosses the current band */ 1279 if ( ( TRUNC( arc[0].y ) >= ras.max_ey && 1280 TRUNC( arc[1].y ) >= ras.max_ey && 1281 TRUNC( arc[2].y ) >= ras.max_ey ) || 1282 ( TRUNC( arc[0].y ) < ras.min_ey && 1283 TRUNC( arc[1].y ) < ras.min_ey && 1284 TRUNC( arc[2].y ) < ras.min_ey ) ) 1285 { 1286 ras.x = arc[0].x; 1287 ras.y = arc[0].y; 1288 return; 1289 } 1290 1291 dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); 1292 dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); 1293 if ( dx < dy ) 1294 dx = dy; 1295 1296 /* We can calculate the number of necessary bisections because */ 1297 /* each bisection predictably reduces deviation exactly 4-fold. */ 1298 /* Even 32-bit deviation would vanish after 16 bisections. */ 1299 draw = 1; 1300 while ( dx > ONE_PIXEL / 4 ) 1301 { 1302 dx >>= 2; 1303 draw <<= 1; 1304 } 1305 1306 /* We use decrement counter to count the total number of segments */ 1307 /* to draw starting from 2^level. Before each draw we split as */ 1308 /* many times as there are trailing zeros in the counter. */ 1309 do 1310 { 1311 int split = draw & ( -draw ); /* isolate the rightmost 1-bit */ 1312 1313 1314 while ( ( split >>= 1 ) ) 1315 { 1316 gray_split_conic( arc ); 1317 arc += 2; 1318 } 1319 1320 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 1321 arc -= 2; 1322 1323 } while ( --draw ); 1324 } 1325 1326 #endif /* !BEZIER_USE_DDA */ 1327 1328 1329 /* 1330 * For cubic Bézier, binary splits are still faster than DDA 1331 * because the splits are adaptive to how quickly each sub-arc 1332 * approaches their chord trisection points. 1333 * 1334 * It might be useful to experiment with SSE2 to speed up 1335 * `gray_split_cubic`, though. 1336 */ 1337 static void gray_split_cubic(FT_Vector * base)1338 gray_split_cubic( FT_Vector* base ) 1339 { 1340 TPos a, b, c; 1341 1342 1343 base[6].x = base[3].x; 1344 a = base[0].x + base[1].x; 1345 b = base[1].x + base[2].x; 1346 c = base[2].x + base[3].x; 1347 base[5].x = c >> 1; 1348 c += b; 1349 base[4].x = c >> 2; 1350 base[1].x = a >> 1; 1351 a += b; 1352 base[2].x = a >> 2; 1353 base[3].x = ( a + c ) >> 3; 1354 1355 base[6].y = base[3].y; 1356 a = base[0].y + base[1].y; 1357 b = base[1].y + base[2].y; 1358 c = base[2].y + base[3].y; 1359 base[5].y = c >> 1; 1360 c += b; 1361 base[4].y = c >> 2; 1362 base[1].y = a >> 1; 1363 a += b; 1364 base[2].y = a >> 2; 1365 base[3].y = ( a + c ) >> 3; 1366 } 1367 1368 1369 static void gray_render_cubic(RAS_ARG_ const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to)1370 gray_render_cubic( RAS_ARG_ const FT_Vector* control1, 1371 const FT_Vector* control2, 1372 const FT_Vector* to ) 1373 { 1374 FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ 1375 FT_Vector* arc = bez_stack; 1376 1377 1378 arc[0].x = UPSCALE( to->x ); 1379 arc[0].y = UPSCALE( to->y ); 1380 arc[1].x = UPSCALE( control2->x ); 1381 arc[1].y = UPSCALE( control2->y ); 1382 arc[2].x = UPSCALE( control1->x ); 1383 arc[2].y = UPSCALE( control1->y ); 1384 arc[3].x = ras.x; 1385 arc[3].y = ras.y; 1386 1387 /* short-cut the arc that crosses the current band */ 1388 if ( ( TRUNC( arc[0].y ) >= ras.max_ey && 1389 TRUNC( arc[1].y ) >= ras.max_ey && 1390 TRUNC( arc[2].y ) >= ras.max_ey && 1391 TRUNC( arc[3].y ) >= ras.max_ey ) || 1392 ( TRUNC( arc[0].y ) < ras.min_ey && 1393 TRUNC( arc[1].y ) < ras.min_ey && 1394 TRUNC( arc[2].y ) < ras.min_ey && 1395 TRUNC( arc[3].y ) < ras.min_ey ) ) 1396 { 1397 ras.x = arc[0].x; 1398 ras.y = arc[0].y; 1399 return; 1400 } 1401 1402 for (;;) 1403 { 1404 /* with each split, control points quickly converge towards */ 1405 /* chord trisection points and the vanishing distances below */ 1406 /* indicate when the segment is flat enough to draw */ 1407 if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || 1408 FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || 1409 FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || 1410 FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) 1411 goto Split; 1412 1413 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 1414 1415 if ( arc == bez_stack ) 1416 return; 1417 1418 arc -= 3; 1419 continue; 1420 1421 Split: 1422 gray_split_cubic( arc ); 1423 arc += 3; 1424 } 1425 } 1426 1427 1428 static int gray_move_to(const FT_Vector * to,gray_PWorker worker)1429 gray_move_to( const FT_Vector* to, 1430 gray_PWorker worker ) 1431 { 1432 TPos x, y; 1433 1434 1435 /* start to a new position */ 1436 x = UPSCALE( to->x ); 1437 y = UPSCALE( to->y ); 1438 1439 gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); 1440 1441 ras.x = x; 1442 ras.y = y; 1443 return 0; 1444 } 1445 1446 1447 static int gray_line_to(const FT_Vector * to,gray_PWorker worker)1448 gray_line_to( const FT_Vector* to, 1449 gray_PWorker worker ) 1450 { 1451 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); 1452 return 0; 1453 } 1454 1455 1456 static int gray_conic_to(const FT_Vector * control,const FT_Vector * to,gray_PWorker worker)1457 gray_conic_to( const FT_Vector* control, 1458 const FT_Vector* to, 1459 gray_PWorker worker ) 1460 { 1461 gray_render_conic( RAS_VAR_ control, to ); 1462 return 0; 1463 } 1464 1465 1466 static int gray_cubic_to(const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to,gray_PWorker worker)1467 gray_cubic_to( const FT_Vector* control1, 1468 const FT_Vector* control2, 1469 const FT_Vector* to, 1470 gray_PWorker worker ) 1471 { 1472 gray_render_cubic( RAS_VAR_ control1, control2, to ); 1473 return 0; 1474 } 1475 1476 1477 static void gray_sweep(RAS_ARG)1478 gray_sweep( RAS_ARG ) 1479 { 1480 int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 1481 : INT_MIN; 1482 int coverage; 1483 int y; 1484 1485 1486 for ( y = ras.min_ey; y < ras.max_ey; y++ ) 1487 { 1488 PCell cell = ras.ycells[y - ras.min_ey]; 1489 TCoord x = ras.min_ex; 1490 TArea cover = 0; 1491 1492 unsigned char* line = ras.target.origin - ras.target.pitch * y; 1493 1494 1495 for ( ; cell != ras.cell_null; cell = cell->next ) 1496 { 1497 TArea area; 1498 1499 1500 if ( cover != 0 && cell->x > x ) 1501 { 1502 FT_FILL_RULE( coverage, cover, fill ); 1503 FT_GRAY_SET( line + x, coverage, cell->x - x ); 1504 } 1505 1506 cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); 1507 area = cover - cell->area; 1508 1509 if ( area != 0 && cell->x >= ras.min_ex ) 1510 { 1511 FT_FILL_RULE( coverage, area, fill ); 1512 line[cell->x] = (unsigned char)coverage; 1513 } 1514 1515 x = cell->x + 1; 1516 } 1517 1518 if ( cover != 0 ) /* only if cropped */ 1519 { 1520 FT_FILL_RULE( coverage, cover, fill ); 1521 FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); 1522 } 1523 } 1524 } 1525 1526 1527 static void gray_sweep_direct(RAS_ARG)1528 gray_sweep_direct( RAS_ARG ) 1529 { 1530 int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 1531 : INT_MIN; 1532 int coverage; 1533 int y; 1534 1535 FT_Span span[FT_MAX_GRAY_SPANS]; 1536 int n = 0; 1537 1538 1539 for ( y = ras.min_ey; y < ras.max_ey; y++ ) 1540 { 1541 PCell cell = ras.ycells[y - ras.min_ey]; 1542 TCoord x = ras.min_ex; 1543 TArea cover = 0; 1544 1545 1546 for ( ; cell != ras.cell_null; cell = cell->next ) 1547 { 1548 TArea area; 1549 1550 1551 if ( cover != 0 && cell->x > x ) 1552 { 1553 FT_FILL_RULE( coverage, cover, fill ); 1554 1555 span[n].coverage = (unsigned char)coverage; 1556 span[n].x = (short)x; 1557 span[n].len = (unsigned short)( cell->x - x ); 1558 1559 if ( ++n == FT_MAX_GRAY_SPANS ) 1560 { 1561 /* flush the span buffer and reset the count */ 1562 ras.render_span( y, n, span, ras.render_span_data ); 1563 n = 0; 1564 } 1565 } 1566 1567 cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); 1568 area = cover - cell->area; 1569 1570 if ( area != 0 && cell->x >= ras.min_ex ) 1571 { 1572 FT_FILL_RULE( coverage, area, fill ); 1573 1574 span[n].coverage = (unsigned char)coverage; 1575 span[n].x = (short)cell->x; 1576 span[n].len = 1; 1577 1578 if ( ++n == FT_MAX_GRAY_SPANS ) 1579 { 1580 /* flush the span buffer and reset the count */ 1581 ras.render_span( y, n, span, ras.render_span_data ); 1582 n = 0; 1583 } 1584 } 1585 1586 x = cell->x + 1; 1587 } 1588 1589 if ( cover != 0 ) /* only if cropped */ 1590 { 1591 FT_FILL_RULE( coverage, cover, fill ); 1592 1593 span[n].coverage = (unsigned char)coverage; 1594 span[n].x = (short)x; 1595 span[n].len = (unsigned short)( ras.max_ex - x ); 1596 1597 ++n; 1598 } 1599 1600 if ( n ) 1601 { 1602 /* flush the span buffer and reset the count */ 1603 ras.render_span( y, n, span, ras.render_span_data ); 1604 n = 0; 1605 } 1606 } 1607 } 1608 1609 1610 #ifdef STANDALONE_ 1611 1612 /************************************************************************** 1613 * 1614 * The following functions should only compile in stand-alone mode, 1615 * i.e., when building this component without the rest of FreeType. 1616 * 1617 */ 1618 1619 /************************************************************************** 1620 * 1621 * @Function: 1622 * FT_Outline_Decompose 1623 * 1624 * @Description: 1625 * Walk over an outline's structure to decompose it into individual 1626 * segments and Bézier arcs. This function is also able to emit 1627 * `move to' and `close to' operations to indicate the start and end 1628 * of new contours in the outline. 1629 * 1630 * @Input: 1631 * outline :: 1632 * A pointer to the source target. 1633 * 1634 * func_interface :: 1635 * A table of `emitters', i.e., function pointers 1636 * called during decomposition to indicate path 1637 * operations. 1638 * 1639 * @InOut: 1640 * user :: 1641 * A typeless pointer which is passed to each 1642 * emitter during the decomposition. It can be 1643 * used to store the state during the 1644 * decomposition. 1645 * 1646 * @Return: 1647 * Error code. 0 means success. 1648 */ 1649 static int FT_Outline_Decompose(const FT_Outline * outline,const FT_Outline_Funcs * func_interface,void * user)1650 FT_Outline_Decompose( const FT_Outline* outline, 1651 const FT_Outline_Funcs* func_interface, 1652 void* user ) 1653 { 1654 #undef SCALED 1655 #define SCALED( x ) ( (x) * ( 1L << shift ) - delta ) 1656 1657 FT_Vector v_last; 1658 FT_Vector v_control; 1659 FT_Vector v_start; 1660 1661 FT_Vector* point; 1662 FT_Vector* limit; 1663 char* tags; 1664 1665 int error; 1666 1667 int n; /* index of contour in outline */ 1668 int first; /* index of first point in contour */ 1669 char tag; /* current point's state */ 1670 1671 int shift; 1672 TPos delta; 1673 1674 1675 if ( !outline ) 1676 return FT_THROW( Invalid_Outline ); 1677 1678 if ( !func_interface ) 1679 return FT_THROW( Invalid_Argument ); 1680 1681 shift = func_interface->shift; 1682 delta = func_interface->delta; 1683 first = 0; 1684 1685 for ( n = 0; n < outline->n_contours; n++ ) 1686 { 1687 int last; /* index of last point in contour */ 1688 1689 1690 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); 1691 1692 last = outline->contours[n]; 1693 if ( last < 0 ) 1694 goto Invalid_Outline; 1695 limit = outline->points + last; 1696 1697 v_start = outline->points[first]; 1698 v_start.x = SCALED( v_start.x ); 1699 v_start.y = SCALED( v_start.y ); 1700 1701 v_last = outline->points[last]; 1702 v_last.x = SCALED( v_last.x ); 1703 v_last.y = SCALED( v_last.y ); 1704 1705 v_control = v_start; 1706 1707 point = outline->points + first; 1708 tags = outline->tags + first; 1709 tag = FT_CURVE_TAG( tags[0] ); 1710 1711 /* A contour cannot start with a cubic control point! */ 1712 if ( tag == FT_CURVE_TAG_CUBIC ) 1713 goto Invalid_Outline; 1714 1715 /* check first point to determine origin */ 1716 if ( tag == FT_CURVE_TAG_CONIC ) 1717 { 1718 /* first point is conic control. Yes, this happens. */ 1719 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 1720 { 1721 /* start at last point if it is on the curve */ 1722 v_start = v_last; 1723 limit--; 1724 } 1725 else 1726 { 1727 /* if both first and last points are conic, */ 1728 /* start at their middle and record its position */ 1729 /* for closure */ 1730 v_start.x = ( v_start.x + v_last.x ) / 2; 1731 v_start.y = ( v_start.y + v_last.y ) / 2; 1732 1733 v_last = v_start; 1734 } 1735 point--; 1736 tags--; 1737 } 1738 1739 FT_TRACE5(( " move to (%.2f, %.2f)\n", 1740 v_start.x / 64.0, v_start.y / 64.0 )); 1741 error = func_interface->move_to( &v_start, user ); 1742 if ( error ) 1743 goto Exit; 1744 1745 while ( point < limit ) 1746 { 1747 point++; 1748 tags++; 1749 1750 tag = FT_CURVE_TAG( tags[0] ); 1751 switch ( tag ) 1752 { 1753 case FT_CURVE_TAG_ON: /* emit a single line_to */ 1754 { 1755 FT_Vector vec; 1756 1757 1758 vec.x = SCALED( point->x ); 1759 vec.y = SCALED( point->y ); 1760 1761 FT_TRACE5(( " line to (%.2f, %.2f)\n", 1762 vec.x / 64.0, vec.y / 64.0 )); 1763 error = func_interface->line_to( &vec, user ); 1764 if ( error ) 1765 goto Exit; 1766 continue; 1767 } 1768 1769 case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 1770 v_control.x = SCALED( point->x ); 1771 v_control.y = SCALED( point->y ); 1772 1773 Do_Conic: 1774 if ( point < limit ) 1775 { 1776 FT_Vector vec; 1777 FT_Vector v_middle; 1778 1779 1780 point++; 1781 tags++; 1782 tag = FT_CURVE_TAG( tags[0] ); 1783 1784 vec.x = SCALED( point->x ); 1785 vec.y = SCALED( point->y ); 1786 1787 if ( tag == FT_CURVE_TAG_ON ) 1788 { 1789 FT_TRACE5(( " conic to (%.2f, %.2f)" 1790 " with control (%.2f, %.2f)\n", 1791 vec.x / 64.0, vec.y / 64.0, 1792 v_control.x / 64.0, v_control.y / 64.0 )); 1793 error = func_interface->conic_to( &v_control, &vec, user ); 1794 if ( error ) 1795 goto Exit; 1796 continue; 1797 } 1798 1799 if ( tag != FT_CURVE_TAG_CONIC ) 1800 goto Invalid_Outline; 1801 1802 v_middle.x = ( v_control.x + vec.x ) / 2; 1803 v_middle.y = ( v_control.y + vec.y ) / 2; 1804 1805 FT_TRACE5(( " conic to (%.2f, %.2f)" 1806 " with control (%.2f, %.2f)\n", 1807 v_middle.x / 64.0, v_middle.y / 64.0, 1808 v_control.x / 64.0, v_control.y / 64.0 )); 1809 error = func_interface->conic_to( &v_control, &v_middle, user ); 1810 if ( error ) 1811 goto Exit; 1812 1813 v_control = vec; 1814 goto Do_Conic; 1815 } 1816 1817 FT_TRACE5(( " conic to (%.2f, %.2f)" 1818 " with control (%.2f, %.2f)\n", 1819 v_start.x / 64.0, v_start.y / 64.0, 1820 v_control.x / 64.0, v_control.y / 64.0 )); 1821 error = func_interface->conic_to( &v_control, &v_start, user ); 1822 goto Close; 1823 1824 default: /* FT_CURVE_TAG_CUBIC */ 1825 { 1826 FT_Vector vec1, vec2; 1827 1828 1829 if ( point + 1 > limit || 1830 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 1831 goto Invalid_Outline; 1832 1833 point += 2; 1834 tags += 2; 1835 1836 vec1.x = SCALED( point[-2].x ); 1837 vec1.y = SCALED( point[-2].y ); 1838 1839 vec2.x = SCALED( point[-1].x ); 1840 vec2.y = SCALED( point[-1].y ); 1841 1842 if ( point <= limit ) 1843 { 1844 FT_Vector vec; 1845 1846 1847 vec.x = SCALED( point->x ); 1848 vec.y = SCALED( point->y ); 1849 1850 FT_TRACE5(( " cubic to (%.2f, %.2f)" 1851 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 1852 vec.x / 64.0, vec.y / 64.0, 1853 vec1.x / 64.0, vec1.y / 64.0, 1854 vec2.x / 64.0, vec2.y / 64.0 )); 1855 error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); 1856 if ( error ) 1857 goto Exit; 1858 continue; 1859 } 1860 1861 FT_TRACE5(( " cubic to (%.2f, %.2f)" 1862 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 1863 v_start.x / 64.0, v_start.y / 64.0, 1864 vec1.x / 64.0, vec1.y / 64.0, 1865 vec2.x / 64.0, vec2.y / 64.0 )); 1866 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); 1867 goto Close; 1868 } 1869 } 1870 } 1871 1872 /* close the contour with a line segment */ 1873 FT_TRACE5(( " line to (%.2f, %.2f)\n", 1874 v_start.x / 64.0, v_start.y / 64.0 )); 1875 error = func_interface->line_to( &v_start, user ); 1876 1877 Close: 1878 if ( error ) 1879 goto Exit; 1880 1881 first = last + 1; 1882 } 1883 1884 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); 1885 return Smooth_Err_Ok; 1886 1887 Exit: 1888 FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); 1889 return error; 1890 1891 Invalid_Outline: 1892 return FT_THROW( Invalid_Outline ); 1893 } 1894 1895 #endif /* STANDALONE_ */ 1896 1897 1898 FT_DEFINE_OUTLINE_FUNCS( 1899 func_interface, 1900 1901 (FT_Outline_MoveTo_Func) gray_move_to, /* move_to */ 1902 (FT_Outline_LineTo_Func) gray_line_to, /* line_to */ 1903 (FT_Outline_ConicTo_Func)gray_conic_to, /* conic_to */ 1904 (FT_Outline_CubicTo_Func)gray_cubic_to, /* cubic_to */ 1905 1906 0, /* shift */ 1907 0 /* delta */ 1908 ) 1909 1910 1911 static int gray_convert_glyph_inner(RAS_ARG_ int continued)1912 gray_convert_glyph_inner( RAS_ARG_ 1913 int continued ) 1914 { 1915 volatile int error; 1916 1917 1918 if ( ft_setjmp( ras.jump_buffer ) == 0 ) 1919 { 1920 if ( continued ) 1921 FT_Trace_Disable(); 1922 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); 1923 if ( continued ) 1924 FT_Trace_Enable(); 1925 1926 FT_TRACE7(( "band [%d..%d]: %ld cell%s remaining/\n", 1927 ras.min_ey, 1928 ras.max_ey, 1929 ras.cell_null - ras.cell_free, 1930 ras.cell_null - ras.cell_free == 1 ? "" : "s" )); 1931 } 1932 else 1933 { 1934 error = FT_THROW( Raster_Overflow ); 1935 1936 FT_TRACE7(( "band [%d..%d]: to be bisected\n", 1937 ras.min_ey, ras.max_ey )); 1938 } 1939 1940 return error; 1941 } 1942 1943 1944 static int gray_convert_glyph(RAS_ARG)1945 gray_convert_glyph( RAS_ARG ) 1946 { 1947 const TCoord yMin = ras.min_ey; 1948 const TCoord yMax = ras.max_ey; 1949 1950 TCell buffer[FT_MAX_GRAY_POOL]; 1951 size_t height = (size_t)( yMax - yMin ); 1952 size_t n = FT_MAX_GRAY_POOL / 8; 1953 TCoord y; 1954 TCoord bands[32]; /* enough to accommodate bisections */ 1955 TCoord* band; 1956 1957 int continued = 0; 1958 1959 1960 /* Initialize the null cell at the end of the poll. */ 1961 ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; 1962 ras.cell_null->x = CELL_MAX_X_VALUE; 1963 ras.cell_null->area = 0; 1964 ras.cell_null->cover = 0; 1965 ras.cell_null->next = NULL; 1966 1967 /* set up vertical bands */ 1968 ras.ycells = (PCell*)buffer; 1969 1970 if ( height > n ) 1971 { 1972 /* two divisions rounded up */ 1973 n = ( height + n - 1 ) / n; 1974 height = ( height + n - 1 ) / n; 1975 } 1976 1977 for ( y = yMin; y < yMax; ) 1978 { 1979 ras.min_ey = y; 1980 y += height; 1981 ras.max_ey = FT_MIN( y, yMax ); 1982 1983 band = bands; 1984 band[1] = ras.min_ey; 1985 band[0] = ras.max_ey; 1986 1987 do 1988 { 1989 TCoord width = band[0] - band[1]; 1990 TCoord w; 1991 int error; 1992 1993 1994 for ( w = 0; w < width; ++w ) 1995 ras.ycells[w] = ras.cell_null; 1996 1997 /* memory management: skip ycells */ 1998 n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / 1999 sizeof ( TCell ); 2000 2001 ras.cell_free = buffer + n; 2002 ras.cell = ras.cell_null; 2003 ras.min_ey = band[1]; 2004 ras.max_ey = band[0]; 2005 ras.count_ey = width; 2006 2007 error = gray_convert_glyph_inner( RAS_VAR_ continued ); 2008 continued = 1; 2009 2010 if ( !error ) 2011 { 2012 if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ 2013 gray_sweep_direct( RAS_VAR ); 2014 else 2015 gray_sweep( RAS_VAR ); 2016 band--; 2017 continue; 2018 } 2019 else if ( error != Smooth_Err_Raster_Overflow ) 2020 return error; 2021 2022 /* render pool overflow; we will reduce the render band by half */ 2023 width >>= 1; 2024 2025 /* this should never happen even with tiny rendering pool */ 2026 if ( width == 0 ) 2027 { 2028 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); 2029 return FT_THROW( Raster_Overflow ); 2030 } 2031 2032 band++; 2033 band[1] = band[0]; 2034 band[0] += width; 2035 } while ( band >= bands ); 2036 } 2037 2038 return Smooth_Err_Ok; 2039 } 2040 2041 2042 static int gray_raster_render(FT_Raster raster,const FT_Raster_Params * params)2043 gray_raster_render( FT_Raster raster, 2044 const FT_Raster_Params* params ) 2045 { 2046 const FT_Outline* outline = (const FT_Outline*)params->source; 2047 const FT_Bitmap* target_map = params->target; 2048 2049 #ifndef FT_STATIC_RASTER 2050 gray_TWorker worker[1]; 2051 #endif 2052 2053 2054 if ( !raster ) 2055 return FT_THROW( Invalid_Argument ); 2056 2057 /* this version does not support monochrome rendering */ 2058 if ( !( params->flags & FT_RASTER_FLAG_AA ) ) 2059 return FT_THROW( Cannot_Render_Glyph ); 2060 2061 if ( !outline ) 2062 return FT_THROW( Invalid_Outline ); 2063 2064 /* return immediately if the outline is empty */ 2065 if ( outline->n_points == 0 || outline->n_contours <= 0 ) 2066 return Smooth_Err_Ok; 2067 2068 if ( !outline->contours || !outline->points ) 2069 return FT_THROW( Invalid_Outline ); 2070 2071 if ( outline->n_points != 2072 outline->contours[outline->n_contours - 1] + 1 ) 2073 return FT_THROW( Invalid_Outline ); 2074 2075 ras.outline = *outline; 2076 2077 if ( params->flags & FT_RASTER_FLAG_DIRECT ) 2078 { 2079 if ( !params->gray_spans ) 2080 return Smooth_Err_Ok; 2081 2082 ras.render_span = (FT_Raster_Span_Func)params->gray_spans; 2083 ras.render_span_data = params->user; 2084 2085 ras.min_ex = params->clip_box.xMin; 2086 ras.min_ey = params->clip_box.yMin; 2087 ras.max_ex = params->clip_box.xMax; 2088 ras.max_ey = params->clip_box.yMax; 2089 } 2090 else 2091 { 2092 /* if direct mode is not set, we must have a target bitmap */ 2093 if ( !target_map ) 2094 return FT_THROW( Invalid_Argument ); 2095 2096 /* nothing to do */ 2097 if ( !target_map->width || !target_map->rows ) 2098 return Smooth_Err_Ok; 2099 2100 if ( !target_map->buffer ) 2101 return FT_THROW( Invalid_Argument ); 2102 2103 if ( target_map->pitch < 0 ) 2104 ras.target.origin = target_map->buffer; 2105 else 2106 ras.target.origin = target_map->buffer 2107 + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch; 2108 2109 ras.target.pitch = target_map->pitch; 2110 2111 ras.render_span = (FT_Raster_Span_Func)NULL; 2112 ras.render_span_data = NULL; 2113 2114 ras.min_ex = 0; 2115 ras.min_ey = 0; 2116 ras.max_ex = (FT_Pos)target_map->width; 2117 ras.max_ey = (FT_Pos)target_map->rows; 2118 } 2119 2120 /* exit if nothing to do */ 2121 if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey ) 2122 return Smooth_Err_Ok; 2123 2124 return gray_convert_glyph( RAS_VAR ); 2125 } 2126 2127 2128 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ 2129 /**** a static object. *****/ 2130 2131 #ifdef STANDALONE_ 2132 2133 static int gray_raster_new(void * memory,FT_Raster * araster)2134 gray_raster_new( void* memory, 2135 FT_Raster* araster ) 2136 { 2137 static gray_TRaster the_raster; 2138 2139 FT_UNUSED( memory ); 2140 2141 2142 *araster = (FT_Raster)&the_raster; 2143 FT_ZERO( &the_raster ); 2144 2145 return 0; 2146 } 2147 2148 2149 static void gray_raster_done(FT_Raster raster)2150 gray_raster_done( FT_Raster raster ) 2151 { 2152 /* nothing */ 2153 FT_UNUSED( raster ); 2154 } 2155 2156 #else /* !STANDALONE_ */ 2157 2158 static int gray_raster_new(FT_Memory memory,gray_PRaster * araster)2159 gray_raster_new( FT_Memory memory, 2160 gray_PRaster* araster ) 2161 { 2162 FT_Error error; 2163 gray_PRaster raster = NULL; 2164 2165 2166 if ( !FT_NEW( raster ) ) 2167 raster->memory = memory; 2168 2169 *araster = raster; 2170 2171 return error; 2172 } 2173 2174 2175 static void gray_raster_done(FT_Raster raster)2176 gray_raster_done( FT_Raster raster ) 2177 { 2178 FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; 2179 2180 2181 FT_FREE( raster ); 2182 } 2183 2184 #endif /* !STANDALONE_ */ 2185 2186 2187 static void gray_raster_reset(FT_Raster raster,unsigned char * pool_base,unsigned long pool_size)2188 gray_raster_reset( FT_Raster raster, 2189 unsigned char* pool_base, 2190 unsigned long pool_size ) 2191 { 2192 FT_UNUSED( raster ); 2193 FT_UNUSED( pool_base ); 2194 FT_UNUSED( pool_size ); 2195 } 2196 2197 2198 static int gray_raster_set_mode(FT_Raster raster,unsigned long mode,void * args)2199 gray_raster_set_mode( FT_Raster raster, 2200 unsigned long mode, 2201 void* args ) 2202 { 2203 FT_UNUSED( raster ); 2204 FT_UNUSED( mode ); 2205 FT_UNUSED( args ); 2206 2207 2208 return 0; /* nothing to do */ 2209 } 2210 2211 2212 FT_DEFINE_RASTER_FUNCS( 2213 ft_grays_raster, 2214 2215 FT_GLYPH_FORMAT_OUTLINE, 2216 2217 (FT_Raster_New_Func) gray_raster_new, /* raster_new */ 2218 (FT_Raster_Reset_Func) gray_raster_reset, /* raster_reset */ 2219 (FT_Raster_Set_Mode_Func)gray_raster_set_mode, /* raster_set_mode */ 2220 (FT_Raster_Render_Func) gray_raster_render, /* raster_render */ 2221 (FT_Raster_Done_Func) gray_raster_done /* raster_done */ 2222 ) 2223 2224 2225 /* END */ 2226 2227 2228 /* Local Variables: */ 2229 /* coding: utf-8 */ 2230 /* End: */ 2231