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