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