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