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