1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2015 The Qt Company Ltd. 4 ** Contact: http://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtGui module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see http://www.qt.io/terms-conditions. For further 15 ** information use the contact form at http://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 2.1 or version 3 as published by the Free 20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22 ** following information to ensure the GNU Lesser General Public License 23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25 ** 26 ** As a special exception, The Qt Company gives you certain additional 27 ** rights. These rights are described in The Qt Company LGPL Exception 28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29 ** 30 ** GNU General Public License Usage 31 ** Alternatively, this file may be used under the terms of the GNU 32 ** General Public License version 3.0 as published by the Free Software 33 ** Foundation and appearing in the file LICENSE.GPL included in the 34 ** packaging of this file. Please review the following information to 35 ** ensure the GNU General Public License version 3.0 requirements will be 36 ** met: http://www.gnu.org/copyleft/gpl.html. 37 ** 38 ** $QT_END_LICENSE$ 39 ** 40 ****************************************************************************/ 41 42 /***************************************************************************/ 43 /* */ 44 /* qgrayraster.c, derived from ftgrays.c */ 45 /* */ 46 /* A new `perfect' anti-aliasing renderer (body). */ 47 /* */ 48 /* Copyright 2000-2001, 2002, 2003 by */ 49 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 50 /* */ 51 /* This file is part of the FreeType project, and may only be used, */ 52 /* modified, and distributed under the terms of the FreeType project */ 53 /* license, ../../3rdparty/freetype/docs/FTL.TXT. By continuing to use, */ 54 /* modify, or distribute this file you indicate that you have read */ 55 /* the license and understand and accept it fully. */ 56 /* */ 57 /***************************************************************************/ 58 59 /*************************************************************************/ 60 /* */ 61 /* This file can be compiled without the rest of the FreeType engine, by */ 62 /* defining the _STANDALONE_ macro when compiling it. You also need to */ 63 /* put the files `ftgrays.h' and `ftimage.h' into the current */ 64 /* compilation directory. Typically, you could do something like */ 65 /* */ 66 /* - copy `src/smooth/ftgrays.c' (this file) to your current directory */ 67 /* */ 68 /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */ 69 /* same directory */ 70 /* */ 71 /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ 72 /* */ 73 /* cc -c -D_STANDALONE_ ftgrays.c */ 74 /* */ 75 /* The renderer can be initialized with a call to */ 76 /* `qt_ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */ 77 /* with a call to `qt_ft_gray_raster.raster_render'. */ 78 /* */ 79 /* See the comments and documentation in the file `ftimage.h' for more */ 80 /* details on how the raster works. */ 81 /* */ 82 /*************************************************************************/ 83 84 /*************************************************************************/ 85 /* */ 86 /* This is a new anti-aliasing scan-converter for FreeType 2. The */ 87 /* algorithm used here is _very_ different from the one in the standard */ 88 /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ 89 /* coverage of the outline on each pixel cell. */ 90 /* */ 91 /* It is based on ideas that I initially found in Raph Levien's */ 92 /* excellent LibArt graphics library (see http://www.levien.com/libart */ 93 /* for more information, though the web pages do not tell anything */ 94 /* about the renderer; you'll have to dive into the source code to */ 95 /* understand how it works). */ 96 /* */ 97 /* Note, however, that this is a _very_ different implementation */ 98 /* compared to Raph's. Coverage information is stored in a very */ 99 /* different way, and I don't use sorted vector paths. Also, it doesn't */ 100 /* use floating point values. */ 101 /* */ 102 /* This renderer has the following advantages: */ 103 /* */ 104 /* - It doesn't need an intermediate bitmap. Instead, one can supply a */ 105 /* callback function that will be called by the renderer to draw gray */ 106 /* spans on any target surface. You can thus do direct composition on */ 107 /* any kind of bitmap, provided that you give the renderer the right */ 108 /* callback. */ 109 /* */ 110 /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ 111 /* each pixel cell. */ 112 /* */ 113 /* - It performs a single pass on the outline (the `standard' FT2 */ 114 /* renderer makes two passes). */ 115 /* */ 116 /* - It can easily be modified to render to _any_ number of gray levels */ 117 /* cheaply. */ 118 /* */ 119 /* - For small (< 20) pixel sizes, it is faster than the standard */ 120 /* renderer. */ 121 /* */ 122 /*************************************************************************/ 123 124 /* experimental support for gamma correction within the rasterizer */ 125 #define xxxGRAYS_USE_GAMMA 126 127 128 /*************************************************************************/ 129 /* */ 130 /* The macro QT_FT_COMPONENT is used in trace mode. It is an implicit */ 131 /* parameter of the QT_FT_TRACE() and QT_FT_ERROR() macros, used to print/log */ 132 /* messages during execution. */ 133 /* */ 134 #undef QT_FT_COMPONENT 135 #define QT_FT_COMPONENT trace_smooth 136 137 138 #define ErrRaster_MemoryOverflow -4 139 140 #if defined(VXWORKS) 141 # include <vxWorksCommon.h> /* needed for setjmp.h */ 142 #endif 143 #include <string.h> /* for qt_ft_memcpy() */ 144 #include <setjmp.h> 145 #include <limits.h> 146 147 #define QT_FT_UINT_MAX UINT_MAX 148 149 #define qt_ft_memset memset 150 151 #define qt_ft_setjmp setjmp 152 #define qt_ft_longjmp longjmp 153 #define qt_ft_jmp_buf jmp_buf 154 155 #define ErrRaster_Invalid_Mode -2 156 #define ErrRaster_Invalid_Outline -1 157 #define ErrRaster_Invalid_Argument -3 158 #define ErrRaster_Memory_Overflow -4 159 #define ErrRaster_OutOfMemory -6 160 161 #define QT_FT_BEGIN_HEADER 162 #define QT_FT_END_HEADER 163 164 #include <private/qrasterdefs_p.h> 165 #include <private/qgrayraster_p.h> 166 167 #include <stdlib.h> 168 #include <stdio.h> 169 170 /* This macro is used to indicate that a function parameter is unused. */ 171 /* Its purpose is simply to reduce compiler warnings. Note also that */ 172 /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 173 /* ANSI compilers (e.g. LCC). */ 174 #define QT_FT_UNUSED( x ) (x) = (x) 175 176 /* Disable the tracing mechanism for simplicity -- developers can */ 177 /* activate it easily by redefining these two macros. */ 178 #ifndef QT_FT_ERROR 179 #define QT_FT_ERROR( x ) do ; while ( 0 ) /* nothing */ 180 #endif 181 182 #ifndef QT_FT_TRACE 183 #define QT_FT_TRACE( x ) do ; while ( 0 ) /* nothing */ 184 #endif 185 186 #ifndef QT_FT_MEM_SET 187 #define QT_FT_MEM_SET( d, s, c ) qt_ft_memset( d, s, c ) 188 #endif 189 190 #ifndef QT_FT_MEM_ZERO 191 #define QT_FT_MEM_ZERO( dest, count ) QT_FT_MEM_SET( dest, 0, count ) 192 #endif 193 194 /* define this to dump debugging information */ 195 #define xxxDEBUG_GRAYS 196 197 198 #define RAS_ARG PWorker worker 199 #define RAS_ARG_ PWorker worker, 200 201 #define RAS_VAR worker 202 #define RAS_VAR_ worker, 203 204 #define ras (*worker) 205 206 207 /* must be at least 6 bits! */ 208 #define PIXEL_BITS 8 209 210 #define ONE_PIXEL ( 1L << PIXEL_BITS ) 211 #define PIXEL_MASK ( -1L << PIXEL_BITS ) 212 #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) 213 #define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) 214 #define FLOOR( x ) ( (x) & -ONE_PIXEL ) 215 #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) 216 #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) 217 218 #if PIXEL_BITS >= 6 219 #define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) 220 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) 221 #else 222 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) 223 #define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) 224 #endif 225 226 /*************************************************************************/ 227 /* */ 228 /* TYPE DEFINITIONS */ 229 /* */ 230 231 /* don't change the following types to QT_FT_Int or QT_FT_Pos, since we might */ 232 /* need to define them to "float" or "double" when experimenting with */ 233 /* new algorithms */ 234 235 typedef int TCoord; /* integer scanline/pixel coordinate */ 236 typedef int TPos; /* sub-pixel coordinate */ 237 238 /* determine the type used to store cell areas. This normally takes at */ 239 /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */ 240 /* `long' instead of `int', otherwise bad things happen */ 241 242 #if PIXEL_BITS <= 7 243 244 typedef int TArea; 245 246 #else /* PIXEL_BITS >= 8 */ 247 248 /* approximately determine the size of integers using an ANSI-C header */ 249 #if QT_FT_UINT_MAX == 0xFFFFU 250 typedef long TArea; 251 #else 252 typedef int TArea; 253 #endif 254 255 #endif /* PIXEL_BITS >= 8 */ 256 257 258 /* maximal number of gray spans in a call to the span callback */ 259 #define QT_FT_MAX_GRAY_SPANS 256 260 261 262 typedef struct TCell_* PCell; 263 264 typedef struct TCell_ 265 { 266 int x; 267 int cover; 268 TArea area; 269 PCell next; 270 271 } TCell; 272 273 274 typedef struct TWorker_ 275 { 276 TCoord ex, ey; 277 TPos min_ex, max_ex; 278 TPos min_ey, max_ey; 279 TPos count_ex, count_ey; 280 281 TArea area; 282 int cover; 283 int invalid; 284 285 PCell cells; 286 int max_cells; 287 int num_cells; 288 289 TCoord cx, cy; 290 TPos x, y; 291 292 TPos last_ey; 293 294 QT_FT_Vector bez_stack[32 * 3 + 1]; 295 int lev_stack[32]; 296 297 QT_FT_Outline outline; 298 QT_FT_Bitmap target; 299 QT_FT_BBox clip_box; 300 301 QT_FT_Span gray_spans[QT_FT_MAX_GRAY_SPANS]; 302 int num_gray_spans; 303 304 QT_FT_Raster_Span_Func render_span; 305 void* render_span_data; 306 307 int band_size; 308 int band_shoot; 309 int conic_level; 310 int cubic_level; 311 312 qt_ft_jmp_buf jump_buffer; 313 314 void* buffer; 315 long buffer_size; 316 317 PCell* ycells; 318 int ycount; 319 320 int skip_spans; 321 } TWorker, *PWorker; 322 323 324 typedef struct TRaster_ 325 { 326 void* buffer; 327 long buffer_size; 328 long buffer_allocated_size; 329 int band_size; 330 void* memory; 331 PWorker worker; 332 333 } TRaster, *PRaster; 334 q_gray_rendered_spans(TRaster * raster)335 int q_gray_rendered_spans(TRaster *raster) 336 { 337 if ( raster && raster->worker ) 338 return raster->worker->skip_spans > 0 ? 0 : -raster->worker->skip_spans; 339 return 0; 340 } 341 342 /*************************************************************************/ 343 /* */ 344 /* Initialize the cells table. */ 345 /* */ 346 static void gray_init_cells(RAS_ARG_ void * buffer,long byte_size)347 gray_init_cells( RAS_ARG_ void* buffer, 348 long byte_size ) 349 { 350 ras.buffer = buffer; 351 ras.buffer_size = byte_size; 352 353 ras.ycells = (PCell*) buffer; 354 ras.cells = NULL; 355 ras.max_cells = 0; 356 ras.num_cells = 0; 357 ras.area = 0; 358 ras.cover = 0; 359 ras.invalid = 1; 360 } 361 362 363 /*************************************************************************/ 364 /* */ 365 /* Compute the outline bounding box. */ 366 /* */ 367 static void gray_compute_cbox(RAS_ARG)368 gray_compute_cbox( RAS_ARG ) 369 { 370 QT_FT_Outline* outline = &ras.outline; 371 QT_FT_Vector* vec = outline->points; 372 QT_FT_Vector* limit = vec + outline->n_points; 373 374 375 if ( outline->n_points <= 0 ) 376 { 377 ras.min_ex = ras.max_ex = 0; 378 ras.min_ey = ras.max_ey = 0; 379 return; 380 } 381 382 ras.min_ex = ras.max_ex = vec->x; 383 ras.min_ey = ras.max_ey = vec->y; 384 385 vec++; 386 387 for ( ; vec < limit; vec++ ) 388 { 389 TPos x = vec->x; 390 TPos y = vec->y; 391 392 393 if ( x < ras.min_ex ) ras.min_ex = x; 394 if ( x > ras.max_ex ) ras.max_ex = x; 395 if ( y < ras.min_ey ) ras.min_ey = y; 396 if ( y > ras.max_ey ) ras.max_ey = y; 397 } 398 399 /* truncate the bounding box to integer pixels */ 400 ras.min_ex = ras.min_ex >> 6; 401 ras.min_ey = ras.min_ey >> 6; 402 ras.max_ex = ( ras.max_ex + 63 ) >> 6; 403 ras.max_ey = ( ras.max_ey + 63 ) >> 6; 404 } 405 406 407 /*************************************************************************/ 408 /* */ 409 /* Record the current cell in the table. */ 410 /* */ 411 static void gray_record_cell(RAS_ARG)412 gray_record_cell( RAS_ARG ) 413 { 414 PCell *pcell, cell; 415 int x = ras.ex; 416 417 if ( ras.invalid || !( ras.area | ras.cover ) ) 418 return; 419 420 if ( x > ras.max_ex ) 421 x = ras.max_ex; 422 423 pcell = &ras.ycells[ras.ey]; 424 425 for (;;) 426 { 427 cell = *pcell; 428 if ( cell == NULL || cell->x > x ) 429 break; 430 431 if ( cell->x == x ) { 432 cell->area += ras.area; 433 cell->cover += ras.cover; 434 return; 435 } 436 437 pcell = &cell->next; 438 } 439 440 if ( ras.num_cells >= ras.max_cells ) 441 qt_ft_longjmp( ras.jump_buffer, 1 ); 442 443 cell = ras.cells + ras.num_cells++; 444 cell->x = x; 445 cell->area = ras.area; 446 cell->cover = ras.cover; 447 448 cell->next = *pcell; 449 *pcell = cell; 450 } 451 452 453 /*************************************************************************/ 454 /* */ 455 /* Set the current cell to a new position. */ 456 /* */ 457 static void gray_set_cell(RAS_ARG_ TCoord ex,TCoord ey)458 gray_set_cell( RAS_ARG_ TCoord ex, 459 TCoord ey ) 460 { 461 /* Move the cell pointer to a new position. We set the `invalid' */ 462 /* flag to indicate that the cell isn't part of those we're interested */ 463 /* in during the render phase. This means that: */ 464 /* */ 465 /* . the new vertical position must be within min_ey..max_ey-1. */ 466 /* . the new horizontal position must be strictly less than max_ex */ 467 /* */ 468 /* Note that if a cell is to the left of the clipping region, it is */ 469 /* actually set to the (min_ex-1) horizontal position. */ 470 471 /* All cells that are on the left of the clipping region go to the */ 472 /* min_ex - 1 horizontal position. */ 473 ey -= ras.min_ey; 474 475 if ( ex > ras.max_ex ) 476 ex = ras.max_ex; 477 478 ex -= ras.min_ex; 479 if ( ex < 0 ) 480 ex = -1; 481 482 /* are we moving to a different cell ? */ 483 if ( ex != ras.ex || ey != ras.ey ) 484 { 485 /* record the current one if it is valid */ 486 if ( !ras.invalid ) 487 gray_record_cell( RAS_VAR ); 488 489 ras.area = 0; 490 ras.cover = 0; 491 } 492 493 ras.ex = ex; 494 ras.ey = ey; 495 ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey || 496 ex >= ras.count_ex ); 497 } 498 499 500 /*************************************************************************/ 501 /* */ 502 /* Start a new contour at a given cell. */ 503 /* */ 504 static void gray_start_cell(RAS_ARG_ TCoord ex,TCoord ey)505 gray_start_cell( RAS_ARG_ TCoord ex, 506 TCoord ey ) 507 { 508 if ( ex > ras.max_ex ) 509 ex = (TCoord)( ras.max_ex ); 510 511 if ( ex < ras.min_ex ) 512 ex = (TCoord)( ras.min_ex - 1 ); 513 514 ras.area = 0; 515 ras.cover = 0; 516 ras.ex = ex - ras.min_ex; 517 ras.ey = ey - ras.min_ey; 518 ras.last_ey = SUBPIXELS( ey ); 519 ras.invalid = 0; 520 521 gray_set_cell( RAS_VAR_ ex, ey ); 522 } 523 524 525 /*************************************************************************/ 526 /* */ 527 /* Render a scanline as one or more cells. */ 528 /* */ 529 static void gray_render_scanline(RAS_ARG_ TCoord ey,TPos x1,TCoord y1,TPos x2,TCoord y2)530 gray_render_scanline( RAS_ARG_ TCoord ey, 531 TPos x1, 532 TCoord y1, 533 TPos x2, 534 TCoord y2 ) 535 { 536 TCoord ex1, ex2, fx1, fx2, delta; 537 int p, first, dx; 538 int incr, lift, mod, rem; 539 540 541 dx = x2 - x1; 542 543 ex1 = TRUNC( x1 ); 544 ex2 = TRUNC( x2 ); 545 fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); 546 fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); 547 548 /* trivial case. Happens often */ 549 if ( y1 == y2 ) 550 { 551 gray_set_cell( RAS_VAR_ ex2, ey ); 552 return; 553 } 554 555 /* everything is located in a single cell. That is easy! */ 556 /* */ 557 if ( ex1 == ex2 ) 558 { 559 delta = y2 - y1; 560 ras.area += (TArea)( fx1 + fx2 ) * delta; 561 ras.cover += delta; 562 return; 563 } 564 565 /* ok, we'll have to render a run of adjacent cells on the same */ 566 /* scanline... */ 567 /* */ 568 p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); 569 first = ONE_PIXEL; 570 incr = 1; 571 572 if ( dx < 0 ) 573 { 574 p = fx1 * ( y2 - y1 ); 575 first = 0; 576 incr = -1; 577 dx = -dx; 578 } 579 580 delta = (TCoord)( p / dx ); 581 mod = (TCoord)( p % dx ); 582 if ( mod < 0 ) 583 { 584 delta--; 585 mod += (TCoord)dx; 586 } 587 588 ras.area += (TArea)( fx1 + first ) * delta; 589 ras.cover += delta; 590 591 ex1 += incr; 592 gray_set_cell( RAS_VAR_ ex1, ey ); 593 y1 += delta; 594 595 if ( ex1 != ex2 ) 596 { 597 p = ONE_PIXEL * ( y2 - y1 + delta ); 598 lift = (TCoord)( p / dx ); 599 rem = (TCoord)( p % dx ); 600 if ( rem < 0 ) 601 { 602 lift--; 603 rem += (TCoord)dx; 604 } 605 606 mod -= (int)dx; 607 608 while ( ex1 != ex2 ) 609 { 610 delta = lift; 611 mod += rem; 612 if ( mod >= 0 ) 613 { 614 mod -= (TCoord)dx; 615 delta++; 616 } 617 618 ras.area += (TArea)ONE_PIXEL * delta; 619 ras.cover += delta; 620 y1 += delta; 621 ex1 += incr; 622 gray_set_cell( RAS_VAR_ ex1, ey ); 623 } 624 } 625 626 delta = y2 - y1; 627 ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta; 628 ras.cover += delta; 629 } 630 631 632 /*************************************************************************/ 633 /* */ 634 /* Render a given line as a series of scanlines. */ 635 /* */ 636 static void gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)637 gray_render_line( RAS_ARG_ TPos to_x, 638 TPos to_y ) 639 { 640 TCoord ey1, ey2, fy1, fy2; 641 TPos dx, dy, x, x2; 642 int p, first; 643 int delta, rem, mod, lift, incr; 644 645 646 ey1 = TRUNC( ras.last_ey ); 647 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ 648 fy1 = (TCoord)( ras.y - ras.last_ey ); 649 fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); 650 651 dx = to_x - ras.x; 652 dy = to_y - ras.y; 653 654 /* XXX: we should do something about the trivial case where dx == 0, */ 655 /* as it happens very often! */ 656 657 /* perform vertical clipping */ 658 { 659 TCoord min, max; 660 661 662 min = ey1; 663 max = ey2; 664 if ( ey1 > ey2 ) 665 { 666 min = ey2; 667 max = ey1; 668 } 669 if ( min >= ras.max_ey || max < ras.min_ey ) 670 goto End; 671 } 672 673 /* everything is on a single scanline */ 674 if ( ey1 == ey2 ) 675 { 676 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); 677 goto End; 678 } 679 680 /* vertical line - avoid calling gray_render_scanline */ 681 incr = 1; 682 683 if ( dx == 0 ) 684 { 685 TCoord ex = TRUNC( ras.x ); 686 TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); 687 TPos area; 688 689 690 first = ONE_PIXEL; 691 if ( dy < 0 ) 692 { 693 first = 0; 694 incr = -1; 695 } 696 697 delta = (int)( first - fy1 ); 698 ras.area += (TArea)two_fx * delta; 699 ras.cover += delta; 700 ey1 += incr; 701 702 gray_set_cell( &ras, ex, ey1 ); 703 704 delta = (int)( first + first - ONE_PIXEL ); 705 area = (TArea)two_fx * delta; 706 while ( ey1 != ey2 ) 707 { 708 ras.area += area; 709 ras.cover += delta; 710 ey1 += incr; 711 712 gray_set_cell( &ras, ex, ey1 ); 713 } 714 715 delta = (int)( fy2 - ONE_PIXEL + first ); 716 ras.area += (TArea)two_fx * delta; 717 ras.cover += delta; 718 719 goto End; 720 } 721 722 /* ok, we have to render several scanlines */ 723 p = ( ONE_PIXEL - fy1 ) * dx; 724 first = ONE_PIXEL; 725 incr = 1; 726 727 if ( dy < 0 ) 728 { 729 p = fy1 * dx; 730 first = 0; 731 incr = -1; 732 dy = -dy; 733 } 734 735 delta = (int)( p / dy ); 736 mod = (int)( p % dy ); 737 if ( mod < 0 ) 738 { 739 delta--; 740 mod += (TCoord)dy; 741 } 742 743 x = ras.x + delta; 744 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); 745 746 ey1 += incr; 747 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 748 749 if ( ey1 != ey2 ) 750 { 751 p = ONE_PIXEL * dx; 752 lift = (int)( p / dy ); 753 rem = (int)( p % dy ); 754 if ( rem < 0 ) 755 { 756 lift--; 757 rem += (int)dy; 758 } 759 mod -= (int)dy; 760 761 while ( ey1 != ey2 ) 762 { 763 delta = lift; 764 mod += rem; 765 if ( mod >= 0 ) 766 { 767 mod -= (int)dy; 768 delta++; 769 } 770 771 x2 = x + delta; 772 gray_render_scanline( RAS_VAR_ ey1, x, 773 (TCoord)( ONE_PIXEL - first ), x2, 774 (TCoord)first ); 775 x = x2; 776 777 ey1 += incr; 778 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 779 } 780 } 781 782 gray_render_scanline( RAS_VAR_ ey1, x, 783 (TCoord)( ONE_PIXEL - first ), to_x, 784 fy2 ); 785 786 End: 787 ras.x = to_x; 788 ras.y = to_y; 789 ras.last_ey = SUBPIXELS( ey2 ); 790 } 791 792 793 static void gray_split_conic(QT_FT_Vector * base)794 gray_split_conic( QT_FT_Vector* base ) 795 { 796 TPos a, b; 797 798 799 base[4].x = base[2].x; 800 b = base[1].x; 801 a = base[3].x = ( base[2].x + b ) / 2; 802 b = base[1].x = ( base[0].x + b ) / 2; 803 base[2].x = ( a + b ) / 2; 804 805 base[4].y = base[2].y; 806 b = base[1].y; 807 a = base[3].y = ( base[2].y + b ) / 2; 808 b = base[1].y = ( base[0].y + b ) / 2; 809 base[2].y = ( a + b ) / 2; 810 } 811 812 813 static void gray_render_conic(RAS_ARG_ const QT_FT_Vector * control,const QT_FT_Vector * to)814 gray_render_conic( RAS_ARG_ const QT_FT_Vector* control, 815 const QT_FT_Vector* to ) 816 { 817 TPos dx, dy; 818 int top, level; 819 int* levels; 820 QT_FT_Vector* arc; 821 822 823 dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 ); 824 if ( dx < 0 ) 825 dx = -dx; 826 dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 ); 827 if ( dy < 0 ) 828 dy = -dy; 829 if ( dx < dy ) 830 dx = dy; 831 832 level = 1; 833 dx = dx / ras.conic_level; 834 while ( dx > 0 ) 835 { 836 dx >>= 2; 837 level++; 838 } 839 840 /* a shortcut to speed things up */ 841 if ( level <= 1 ) 842 { 843 /* we compute the mid-point directly in order to avoid */ 844 /* calling gray_split_conic() */ 845 TPos to_x, to_y, mid_x, mid_y; 846 847 848 to_x = UPSCALE( to->x ); 849 to_y = UPSCALE( to->y ); 850 mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4; 851 mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4; 852 853 gray_render_line( RAS_VAR_ mid_x, mid_y ); 854 gray_render_line( RAS_VAR_ to_x, to_y ); 855 856 return; 857 } 858 859 arc = ras.bez_stack; 860 levels = ras.lev_stack; 861 top = 0; 862 levels[0] = level; 863 864 arc[0].x = UPSCALE( to->x ); 865 arc[0].y = UPSCALE( to->y ); 866 arc[1].x = UPSCALE( control->x ); 867 arc[1].y = UPSCALE( control->y ); 868 arc[2].x = ras.x; 869 arc[2].y = ras.y; 870 871 while ( top >= 0 ) 872 { 873 level = levels[top]; 874 if ( level > 1 ) 875 { 876 /* check that the arc crosses the current band */ 877 TPos min, max, y; 878 879 880 min = max = arc[0].y; 881 882 y = arc[1].y; 883 if ( y < min ) min = y; 884 if ( y > max ) max = y; 885 886 y = arc[2].y; 887 if ( y < min ) min = y; 888 if ( y > max ) max = y; 889 890 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) 891 goto Draw; 892 893 gray_split_conic( arc ); 894 arc += 2; 895 top++; 896 levels[top] = levels[top - 1] = level - 1; 897 continue; 898 } 899 900 Draw: 901 { 902 TPos to_x, to_y, mid_x, mid_y; 903 904 905 to_x = arc[0].x; 906 to_y = arc[0].y; 907 mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4; 908 mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4; 909 910 gray_render_line( RAS_VAR_ mid_x, mid_y ); 911 gray_render_line( RAS_VAR_ to_x, to_y ); 912 913 top--; 914 arc -= 2; 915 } 916 } 917 918 return; 919 } 920 921 922 static void gray_split_cubic(QT_FT_Vector * base)923 gray_split_cubic( QT_FT_Vector* base ) 924 { 925 TPos a, b, c, d; 926 927 928 base[6].x = base[3].x; 929 c = base[1].x; 930 d = base[2].x; 931 base[1].x = a = ( base[0].x + c ) / 2; 932 base[5].x = b = ( base[3].x + d ) / 2; 933 c = ( c + d ) / 2; 934 base[2].x = a = ( a + c ) / 2; 935 base[4].x = b = ( b + c ) / 2; 936 base[3].x = ( a + b ) / 2; 937 938 base[6].y = base[3].y; 939 c = base[1].y; 940 d = base[2].y; 941 base[1].y = a = ( base[0].y + c ) / 2; 942 base[5].y = b = ( base[3].y + d ) / 2; 943 c = ( c + d ) / 2; 944 base[2].y = a = ( a + c ) / 2; 945 base[4].y = b = ( b + c ) / 2; 946 base[3].y = ( a + b ) / 2; 947 } 948 949 950 static void gray_render_cubic(RAS_ARG_ const QT_FT_Vector * control1,const QT_FT_Vector * control2,const QT_FT_Vector * to)951 gray_render_cubic( RAS_ARG_ const QT_FT_Vector* control1, 952 const QT_FT_Vector* control2, 953 const QT_FT_Vector* to ) 954 { 955 TPos dx, dy, da, db; 956 int top, level; 957 int* levels; 958 QT_FT_Vector* arc; 959 960 961 dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 ); 962 if ( dx < 0 ) 963 dx = -dx; 964 dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 ); 965 if ( dy < 0 ) 966 dy = -dy; 967 if ( dx < dy ) 968 dx = dy; 969 da = dx; 970 971 dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x ); 972 if ( dx < 0 ) 973 dx = -dx; 974 dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->y + control2->y ); 975 if ( dy < 0 ) 976 dy = -dy; 977 if ( dx < dy ) 978 dx = dy; 979 db = dx; 980 981 level = 1; 982 da = da / ras.cubic_level; 983 db = db / ras.conic_level; 984 while ( da > 0 || db > 0 ) 985 { 986 da >>= 2; 987 db >>= 3; 988 level++; 989 } 990 991 if ( level <= 1 ) 992 { 993 TPos to_x, to_y, mid_x, mid_y; 994 995 996 to_x = UPSCALE( to->x ); 997 to_y = UPSCALE( to->y ); 998 mid_x = ( ras.x + to_x + 999 3 * UPSCALE( control1->x + control2->x ) ) / 8; 1000 mid_y = ( ras.y + to_y + 1001 3 * UPSCALE( control1->y + control2->y ) ) / 8; 1002 1003 gray_render_line( RAS_VAR_ mid_x, mid_y ); 1004 gray_render_line( RAS_VAR_ to_x, to_y ); 1005 return; 1006 } 1007 1008 arc = ras.bez_stack; 1009 arc[0].x = UPSCALE( to->x ); 1010 arc[0].y = UPSCALE( to->y ); 1011 arc[1].x = UPSCALE( control2->x ); 1012 arc[1].y = UPSCALE( control2->y ); 1013 arc[2].x = UPSCALE( control1->x ); 1014 arc[2].y = UPSCALE( control1->y ); 1015 arc[3].x = ras.x; 1016 arc[3].y = ras.y; 1017 1018 levels = ras.lev_stack; 1019 top = 0; 1020 levels[0] = level; 1021 1022 while ( top >= 0 ) 1023 { 1024 level = levels[top]; 1025 if ( level > 1 ) 1026 { 1027 /* check that the arc crosses the current band */ 1028 TPos min, max, y; 1029 1030 1031 min = max = arc[0].y; 1032 y = arc[1].y; 1033 if ( y < min ) min = y; 1034 if ( y > max ) max = y; 1035 y = arc[2].y; 1036 if ( y < min ) min = y; 1037 if ( y > max ) max = y; 1038 y = arc[3].y; 1039 if ( y < min ) min = y; 1040 if ( y > max ) max = y; 1041 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) 1042 goto Draw; 1043 gray_split_cubic( arc ); 1044 arc += 3; 1045 top ++; 1046 levels[top] = levels[top - 1] = level - 1; 1047 continue; 1048 } 1049 1050 Draw: 1051 { 1052 TPos to_x, to_y, mid_x, mid_y; 1053 1054 1055 to_x = arc[0].x; 1056 to_y = arc[0].y; 1057 mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8; 1058 mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8; 1059 1060 gray_render_line( RAS_VAR_ mid_x, mid_y ); 1061 gray_render_line( RAS_VAR_ to_x, to_y ); 1062 top --; 1063 arc -= 3; 1064 } 1065 } 1066 1067 return; 1068 } 1069 1070 1071 1072 static int gray_move_to(const QT_FT_Vector * to,PWorker worker)1073 gray_move_to( const QT_FT_Vector* to, 1074 PWorker worker ) 1075 { 1076 TPos x, y; 1077 1078 1079 /* record current cell, if any */ 1080 gray_record_cell( worker ); 1081 1082 /* start to a new position */ 1083 x = UPSCALE( to->x ); 1084 y = UPSCALE( to->y ); 1085 1086 gray_start_cell( worker, TRUNC( x ), TRUNC( y ) ); 1087 1088 worker->x = x; 1089 worker->y = y; 1090 return 0; 1091 } 1092 1093 1094 static int gray_line_to(const QT_FT_Vector * to,PWorker worker)1095 gray_line_to( const QT_FT_Vector* to, 1096 PWorker worker ) 1097 { 1098 gray_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) ); 1099 return 0; 1100 } 1101 1102 1103 static int gray_conic_to(const QT_FT_Vector * control,const QT_FT_Vector * to,PWorker worker)1104 gray_conic_to( const QT_FT_Vector* control, 1105 const QT_FT_Vector* to, 1106 PWorker worker ) 1107 { 1108 gray_render_conic( worker, control, to ); 1109 return 0; 1110 } 1111 1112 1113 static int gray_cubic_to(const QT_FT_Vector * control1,const QT_FT_Vector * control2,const QT_FT_Vector * to,PWorker worker)1114 gray_cubic_to( const QT_FT_Vector* control1, 1115 const QT_FT_Vector* control2, 1116 const QT_FT_Vector* to, 1117 PWorker worker ) 1118 { 1119 gray_render_cubic( worker, control1, control2, to ); 1120 return 0; 1121 } 1122 1123 1124 static void gray_render_span(int count,const QT_FT_Span * spans,PWorker worker)1125 gray_render_span( int count, 1126 const QT_FT_Span* spans, 1127 PWorker worker ) 1128 { 1129 unsigned char* p; 1130 QT_FT_Bitmap* map = &worker->target; 1131 1132 for ( ; count > 0; count--, spans++ ) 1133 { 1134 unsigned char coverage = spans->coverage; 1135 1136 /* first of all, compute the scanline offset */ 1137 p = (unsigned char*)map->buffer - spans->y * map->pitch; 1138 if ( map->pitch >= 0 ) 1139 p += ( map->rows - 1 ) * map->pitch; 1140 1141 1142 if ( coverage ) 1143 { 1144 /* For small-spans it is faster to do it by ourselves than 1145 * calling `memset'. This is mainly due to the cost of the 1146 * function call. 1147 */ 1148 if ( spans->len >= 8 ) 1149 QT_FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len ); 1150 else 1151 { 1152 unsigned char* q = p + spans->x; 1153 1154 1155 switch ( spans->len ) 1156 { 1157 case 7: *q++ = (unsigned char)coverage; 1158 case 6: *q++ = (unsigned char)coverage; 1159 case 5: *q++ = (unsigned char)coverage; 1160 case 4: *q++ = (unsigned char)coverage; 1161 case 3: *q++ = (unsigned char)coverage; 1162 case 2: *q++ = (unsigned char)coverage; 1163 case 1: *q = (unsigned char)coverage; 1164 default: 1165 ; 1166 } 1167 } 1168 } 1169 } 1170 } 1171 1172 1173 static void gray_hline(RAS_ARG_ TCoord x,TCoord y,TPos area,int acount)1174 gray_hline( RAS_ARG_ TCoord x, 1175 TCoord y, 1176 TPos area, 1177 int acount ) 1178 { 1179 QT_FT_Span* span; 1180 int coverage; 1181 int skip; 1182 1183 1184 /* compute the coverage line's coverage, depending on the */ 1185 /* outline fill rule */ 1186 /* */ 1187 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ 1188 /* */ 1189 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); 1190 /* use range 0..256 */ 1191 if ( coverage < 0 ) 1192 coverage = -coverage; 1193 1194 if ( ras.outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL ) 1195 { 1196 coverage &= 511; 1197 1198 if ( coverage > 256 ) 1199 coverage = 512 - coverage; 1200 else if ( coverage == 256 ) 1201 coverage = 255; 1202 } 1203 else 1204 { 1205 /* normal non-zero winding rule */ 1206 if ( coverage >= 256 ) 1207 coverage = 255; 1208 } 1209 1210 y += (TCoord)ras.min_ey; 1211 x += (TCoord)ras.min_ex; 1212 1213 /* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ 1214 if ( x >= 32768 ) 1215 x = 32767; 1216 1217 if ( coverage ) 1218 { 1219 /* see whether we can add this span to the current list */ 1220 span = ras.gray_spans + ras.num_gray_spans - 1; 1221 if ( ras.num_gray_spans > 0 && 1222 span->y == y && 1223 (int)span->x + span->len == (int)x && 1224 span->coverage == coverage ) 1225 { 1226 span->len = (unsigned short)( span->len + acount ); 1227 return; 1228 } 1229 1230 if ( ras.num_gray_spans >= QT_FT_MAX_GRAY_SPANS ) 1231 { 1232 if ( ras.render_span && ras.num_gray_spans > ras.skip_spans ) 1233 { 1234 skip = ras.skip_spans > 0 ? ras.skip_spans : 0; 1235 ras.render_span( ras.num_gray_spans - skip, 1236 ras.gray_spans + skip, 1237 ras.render_span_data ); 1238 } 1239 1240 ras.skip_spans -= ras.num_gray_spans; 1241 1242 /* ras.render_span( span->y, ras.gray_spans, count ); */ 1243 1244 #ifdef DEBUG_GRAYS 1245 1246 if ( 1 ) 1247 { 1248 int n; 1249 1250 1251 fprintf( stderr, "y=%3d ", y ); 1252 span = ras.gray_spans; 1253 for ( n = 0; n < count; n++, span++ ) 1254 fprintf( stderr, "[%d..%d]:%02x ", 1255 span->x, span->x + span->len - 1, span->coverage ); 1256 fprintf( stderr, "\n" ); 1257 } 1258 1259 #endif /* DEBUG_GRAYS */ 1260 1261 ras.num_gray_spans = 0; 1262 1263 span = ras.gray_spans; 1264 } 1265 else 1266 span++; 1267 1268 /* add a gray span to the current list */ 1269 span->x = (short)x; 1270 span->len = (unsigned short)acount; 1271 span->y = (short)y; 1272 span->coverage = (unsigned char)coverage; 1273 1274 ras.num_gray_spans++; 1275 } 1276 } 1277 1278 1279 #ifdef DEBUG_GRAYS 1280 1281 /* to be called while in the debugger */ gray_dump_cells(RAS_ARG)1282 gray_dump_cells( RAS_ARG ) 1283 { 1284 int yindex; 1285 1286 1287 for ( yindex = 0; yindex < ras.ycount; yindex++ ) 1288 { 1289 PCell cell; 1290 1291 1292 printf( "%3d:", yindex ); 1293 1294 for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next ) 1295 printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area ); 1296 printf( "\n" ); 1297 } 1298 } 1299 1300 #endif /* DEBUG_GRAYS */ 1301 1302 1303 static void gray_sweep(RAS_ARG_ const QT_FT_Bitmap * target)1304 gray_sweep( RAS_ARG_ const QT_FT_Bitmap* target ) 1305 { 1306 int yindex; 1307 1308 QT_FT_UNUSED( target ); 1309 1310 1311 if ( ras.num_cells == 0 ) 1312 return; 1313 1314 for ( yindex = 0; yindex < ras.ycount; yindex++ ) 1315 { 1316 PCell cell = ras.ycells[yindex]; 1317 TCoord cover = 0; 1318 TCoord x = 0; 1319 1320 1321 for ( ; cell != NULL; cell = cell->next ) 1322 { 1323 TArea area; 1324 1325 1326 if ( cell->x > x && cover != 0 ) 1327 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), 1328 cell->x - x ); 1329 1330 cover += cell->cover; 1331 area = cover * ( ONE_PIXEL * 2 ) - cell->area; 1332 1333 if ( area != 0 && cell->x >= 0 ) 1334 gray_hline( RAS_VAR_ cell->x, yindex, area, 1 ); 1335 1336 x = cell->x + 1; 1337 } 1338 1339 if ( ras.count_ex > x && cover != 0 ) 1340 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), 1341 ras.count_ex - x ); 1342 } 1343 } 1344 1345 /*************************************************************************/ 1346 /* */ 1347 /* The following function should only compile in stand_alone mode, */ 1348 /* i.e., when building this component without the rest of FreeType. */ 1349 /* */ 1350 /*************************************************************************/ 1351 1352 /*************************************************************************/ 1353 /* */ 1354 /* <Function> */ 1355 /* QT_FT_Outline_Decompose */ 1356 /* */ 1357 /* <Description> */ 1358 /* Walks over an outline's structure to decompose it into individual */ 1359 /* segments and Bezier arcs. This function is also able to emit */ 1360 /* `move to' and `close to' operations to indicate the start and end */ 1361 /* of new contours in the outline. */ 1362 /* */ 1363 /* <Input> */ 1364 /* outline :: A pointer to the source target. */ 1365 /* */ 1366 /* user :: A typeless pointer which is passed to each */ 1367 /* emitter during the decomposition. It can be */ 1368 /* used to store the state during the */ 1369 /* decomposition. */ 1370 /* */ 1371 /* <Return> */ 1372 /* Error code. 0 means success. */ 1373 /* */ 1374 static QT_FT_Outline_Decompose(const QT_FT_Outline * outline,void * user)1375 int QT_FT_Outline_Decompose( const QT_FT_Outline* outline, 1376 void* user ) 1377 { 1378 #undef SCALED 1379 #define SCALED( x ) (x) 1380 1381 QT_FT_Vector v_last; 1382 QT_FT_Vector v_control; 1383 QT_FT_Vector v_start; 1384 1385 QT_FT_Vector* point; 1386 QT_FT_Vector* limit; 1387 char* tags; 1388 1389 int n; /* index of contour in outline */ 1390 int first; /* index of first point in contour */ 1391 int error; 1392 char tag; /* current point's state */ 1393 1394 first = 0; 1395 1396 for ( n = 0; n < outline->n_contours; n++ ) 1397 { 1398 int last; /* index of last point in contour */ 1399 1400 1401 last = outline->contours[n]; 1402 limit = outline->points + last; 1403 1404 v_start = outline->points[first]; 1405 v_last = outline->points[last]; 1406 1407 v_start.x = SCALED( v_start.x ); 1408 v_start.y = SCALED( v_start.y ); 1409 1410 v_last.x = SCALED( v_last.x ); 1411 v_last.y = SCALED( v_last.y ); 1412 1413 v_control = v_start; 1414 1415 point = outline->points + first; 1416 tags = outline->tags + first; 1417 tag = QT_FT_CURVE_TAG( tags[0] ); 1418 1419 /* A contour cannot start with a cubic control point! */ 1420 if ( tag == QT_FT_CURVE_TAG_CUBIC ) 1421 goto Invalid_Outline; 1422 1423 /* check first point to determine origin */ 1424 if ( tag == QT_FT_CURVE_TAG_CONIC ) 1425 { 1426 /* first point is conic control. Yes, this happens. */ 1427 if ( QT_FT_CURVE_TAG( outline->tags[last] ) == QT_FT_CURVE_TAG_ON ) 1428 { 1429 /* start at last point if it is on the curve */ 1430 v_start = v_last; 1431 limit--; 1432 } 1433 else 1434 { 1435 /* if both first and last points are conic, */ 1436 /* start at their middle and record its position */ 1437 /* for closure */ 1438 v_start.x = ( v_start.x + v_last.x ) / 2; 1439 v_start.y = ( v_start.y + v_last.y ) / 2; 1440 1441 v_last = v_start; 1442 } 1443 point--; 1444 tags--; 1445 } 1446 1447 error = gray_move_to( &v_start, user ); 1448 if ( error ) 1449 goto Exit; 1450 1451 while ( point < limit ) 1452 { 1453 point++; 1454 tags++; 1455 1456 tag = QT_FT_CURVE_TAG( tags[0] ); 1457 switch ( tag ) 1458 { 1459 case QT_FT_CURVE_TAG_ON: /* emit a single line_to */ 1460 { 1461 QT_FT_Vector vec; 1462 1463 1464 vec.x = SCALED( point->x ); 1465 vec.y = SCALED( point->y ); 1466 1467 error = gray_line_to( &vec, user ); 1468 if ( error ) 1469 goto Exit; 1470 continue; 1471 } 1472 1473 case QT_FT_CURVE_TAG_CONIC: /* consume conic arcs */ 1474 { 1475 v_control.x = SCALED( point->x ); 1476 v_control.y = SCALED( point->y ); 1477 1478 Do_Conic: 1479 if ( point < limit ) 1480 { 1481 QT_FT_Vector vec; 1482 QT_FT_Vector v_middle; 1483 1484 1485 point++; 1486 tags++; 1487 tag = QT_FT_CURVE_TAG( tags[0] ); 1488 1489 vec.x = SCALED( point->x ); 1490 vec.y = SCALED( point->y ); 1491 1492 if ( tag == QT_FT_CURVE_TAG_ON ) 1493 { 1494 error = gray_conic_to( &v_control, &vec, 1495 user ); 1496 if ( error ) 1497 goto Exit; 1498 continue; 1499 } 1500 1501 if ( tag != QT_FT_CURVE_TAG_CONIC ) 1502 goto Invalid_Outline; 1503 1504 v_middle.x = ( v_control.x + vec.x ) / 2; 1505 v_middle.y = ( v_control.y + vec.y ) / 2; 1506 1507 error = gray_conic_to( &v_control, &v_middle, 1508 user ); 1509 if ( error ) 1510 goto Exit; 1511 1512 v_control = vec; 1513 goto Do_Conic; 1514 } 1515 1516 error = gray_conic_to( &v_control, &v_start, 1517 user ); 1518 goto Close; 1519 } 1520 1521 default: /* QT_FT_CURVE_TAG_CUBIC */ 1522 { 1523 QT_FT_Vector vec1, vec2; 1524 1525 1526 if ( point + 1 > limit || 1527 QT_FT_CURVE_TAG( tags[1] ) != QT_FT_CURVE_TAG_CUBIC ) 1528 goto Invalid_Outline; 1529 1530 point += 2; 1531 tags += 2; 1532 1533 vec1.x = SCALED( point[-2].x ); 1534 vec1.y = SCALED( point[-2].y ); 1535 1536 vec2.x = SCALED( point[-1].x ); 1537 vec2.y = SCALED( point[-1].y ); 1538 1539 if ( point <= limit ) 1540 { 1541 QT_FT_Vector vec; 1542 1543 1544 vec.x = SCALED( point->x ); 1545 vec.y = SCALED( point->y ); 1546 1547 error = gray_cubic_to( &vec1, &vec2, &vec, user ); 1548 if ( error ) 1549 goto Exit; 1550 continue; 1551 } 1552 1553 error = gray_cubic_to( &vec1, &vec2, &v_start, user ); 1554 goto Close; 1555 } 1556 } 1557 } 1558 1559 /* close the contour with a line segment */ 1560 error = gray_line_to( &v_start, user ); 1561 1562 Close: 1563 if ( error ) 1564 goto Exit; 1565 1566 first = last + 1; 1567 } 1568 1569 return 0; 1570 1571 Exit: 1572 return error; 1573 1574 Invalid_Outline: 1575 return ErrRaster_Invalid_Outline; 1576 } 1577 1578 typedef struct TBand_ 1579 { 1580 TPos min, max; 1581 1582 } TBand; 1583 1584 1585 static int gray_convert_glyph_inner(RAS_ARG)1586 gray_convert_glyph_inner( RAS_ARG ) 1587 { 1588 volatile int error = 0; 1589 1590 if ( qt_ft_setjmp( ras.jump_buffer ) == 0 ) 1591 { 1592 error = QT_FT_Outline_Decompose( &ras.outline, &ras ); 1593 gray_record_cell( RAS_VAR ); 1594 } 1595 else 1596 { 1597 error = ErrRaster_Memory_Overflow; 1598 } 1599 1600 return error; 1601 } 1602 1603 1604 static int gray_convert_glyph(RAS_ARG)1605 gray_convert_glyph( RAS_ARG ) 1606 { 1607 TBand bands[40]; 1608 TBand* volatile band; 1609 int volatile n, num_bands; 1610 TPos volatile min, max, max_y; 1611 QT_FT_BBox* clip; 1612 int skip; 1613 1614 ras.num_gray_spans = 0; 1615 1616 /* Set up state in the raster object */ 1617 gray_compute_cbox( RAS_VAR ); 1618 1619 /* clip to target bitmap, exit if nothing to do */ 1620 clip = &ras.clip_box; 1621 1622 if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || 1623 ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) 1624 return 0; 1625 1626 if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; 1627 if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; 1628 1629 if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; 1630 if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; 1631 1632 ras.count_ex = ras.max_ex - ras.min_ex; 1633 ras.count_ey = ras.max_ey - ras.min_ey; 1634 1635 /* simple heuristic used to speed-up the bezier decomposition -- see */ 1636 /* the code in gray_render_conic() and gray_render_cubic() for more */ 1637 /* details */ 1638 ras.conic_level = 32; 1639 ras.cubic_level = 16; 1640 1641 { 1642 int level = 0; 1643 1644 1645 if ( ras.count_ex > 24 || ras.count_ey > 24 ) 1646 level++; 1647 if ( ras.count_ex > 120 || ras.count_ey > 120 ) 1648 level++; 1649 1650 ras.conic_level <<= level; 1651 ras.cubic_level <<= level; 1652 } 1653 1654 /* setup vertical bands */ 1655 num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); 1656 if ( num_bands == 0 ) num_bands = 1; 1657 if ( num_bands >= 39 ) num_bands = 39; 1658 1659 ras.band_shoot = 0; 1660 1661 min = ras.min_ey; 1662 max_y = ras.max_ey; 1663 1664 for ( n = 0; n < num_bands; n++, min = max ) 1665 { 1666 max = min + ras.band_size; 1667 if ( n == num_bands - 1 || max > max_y ) 1668 max = max_y; 1669 1670 bands[0].min = min; 1671 bands[0].max = max; 1672 band = bands; 1673 1674 while ( band >= bands ) 1675 { 1676 TPos bottom, top, middle; 1677 int error; 1678 1679 { 1680 PCell cells_max; 1681 int yindex; 1682 int cell_start, cell_end, cell_mod; 1683 1684 1685 ras.ycells = (PCell*)ras.buffer; 1686 ras.ycount = band->max - band->min; 1687 1688 cell_start = sizeof ( PCell ) * ras.ycount; 1689 cell_mod = cell_start % sizeof ( TCell ); 1690 if ( cell_mod > 0 ) 1691 cell_start += sizeof ( TCell ) - cell_mod; 1692 1693 cell_end = ras.buffer_size; 1694 cell_end -= cell_end % sizeof( TCell ); 1695 1696 cells_max = (PCell)( (char*)ras.buffer + cell_end ); 1697 ras.cells = (PCell)( (char*)ras.buffer + cell_start ); 1698 if ( ras.cells >= cells_max ) 1699 goto ReduceBands; 1700 1701 ras.max_cells = (int)(cells_max - ras.cells); 1702 if ( ras.max_cells < 2 ) 1703 goto ReduceBands; 1704 1705 for ( yindex = 0; yindex < ras.ycount; yindex++ ) 1706 ras.ycells[yindex] = NULL; 1707 } 1708 1709 ras.num_cells = 0; 1710 ras.invalid = 1; 1711 ras.min_ey = band->min; 1712 ras.max_ey = band->max; 1713 ras.count_ey = band->max - band->min; 1714 1715 error = gray_convert_glyph_inner( RAS_VAR ); 1716 1717 if ( !error ) 1718 { 1719 gray_sweep( RAS_VAR_ &ras.target ); 1720 band--; 1721 continue; 1722 } 1723 else if ( error != ErrRaster_Memory_Overflow ) 1724 return 1; 1725 1726 ReduceBands: 1727 /* render pool overflow; we will reduce the render band by half */ 1728 bottom = band->min; 1729 top = band->max; 1730 middle = bottom + ( ( top - bottom ) >> 1 ); 1731 1732 /* This is too complex for a single scanline; there must */ 1733 /* be some problems. */ 1734 if ( middle == bottom ) 1735 { 1736 #ifdef DEBUG_GRAYS 1737 fprintf( stderr, "Rotten glyph!\n" ); 1738 #endif 1739 return ErrRaster_OutOfMemory; 1740 } 1741 1742 if ( bottom-top >= ras.band_size ) 1743 ras.band_shoot++; 1744 1745 band[1].min = bottom; 1746 band[1].max = middle; 1747 band[0].min = middle; 1748 band[0].max = top; 1749 band++; 1750 } 1751 } 1752 1753 if ( ras.render_span && ras.num_gray_spans > ras.skip_spans ) 1754 { 1755 skip = ras.skip_spans > 0 ? ras.skip_spans : 0; 1756 ras.render_span( ras.num_gray_spans - skip, 1757 ras.gray_spans + skip, 1758 ras.render_span_data ); 1759 } 1760 1761 ras.skip_spans -= ras.num_gray_spans; 1762 1763 if ( ras.band_shoot > 8 && ras.band_size > 16 ) 1764 ras.band_size = ras.band_size / 2; 1765 1766 return 0; 1767 } 1768 1769 1770 static int gray_raster_render(QT_FT_Raster raster,const QT_FT_Raster_Params * params)1771 gray_raster_render( QT_FT_Raster raster, 1772 const QT_FT_Raster_Params* params ) 1773 { 1774 const QT_FT_Outline* outline = (const QT_FT_Outline*)params->source; 1775 const QT_FT_Bitmap* target_map = params->target; 1776 PWorker worker; 1777 1778 1779 if ( !raster || !raster->buffer || !raster->buffer_size ) 1780 return ErrRaster_Invalid_Argument; 1781 1782 if ( raster->worker ) 1783 raster->worker->skip_spans = params->skip_spans; 1784 1785 /* If raster object and raster buffer are allocated, but */ 1786 /* raster size isn't of the minimum size, indicate out of */ 1787 /* memory. */ 1788 if (raster->buffer_allocated_size < MINIMUM_POOL_SIZE ) 1789 return ErrRaster_OutOfMemory; 1790 1791 /* return immediately if the outline is empty */ 1792 if ( outline->n_points == 0 || outline->n_contours <= 0 ) 1793 return 0; 1794 1795 if ( !outline || !outline->contours || !outline->points ) 1796 return ErrRaster_Invalid_Outline; 1797 1798 if ( outline->n_points != 1799 outline->contours[outline->n_contours - 1] + 1 ) 1800 return ErrRaster_Invalid_Outline; 1801 1802 worker = raster->worker; 1803 1804 /* if direct mode is not set, we must have a target bitmap */ 1805 if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 ) 1806 { 1807 if ( !target_map ) 1808 return ErrRaster_Invalid_Argument; 1809 1810 /* nothing to do */ 1811 if ( !target_map->width || !target_map->rows ) 1812 return 0; 1813 1814 if ( !target_map->buffer ) 1815 return ErrRaster_Invalid_Argument; 1816 } 1817 1818 /* this version does not support monochrome rendering */ 1819 if ( !( params->flags & QT_FT_RASTER_FLAG_AA ) ) 1820 return ErrRaster_Invalid_Mode; 1821 1822 /* compute clipping box */ 1823 if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 ) 1824 { 1825 /* compute clip box from target pixmap */ 1826 ras.clip_box.xMin = 0; 1827 ras.clip_box.yMin = 0; 1828 ras.clip_box.xMax = target_map->width; 1829 ras.clip_box.yMax = target_map->rows; 1830 } 1831 else if ( params->flags & QT_FT_RASTER_FLAG_CLIP ) 1832 { 1833 ras.clip_box = params->clip_box; 1834 } 1835 else 1836 { 1837 ras.clip_box.xMin = -32768L; 1838 ras.clip_box.yMin = -32768L; 1839 ras.clip_box.xMax = 32767L; 1840 ras.clip_box.yMax = 32767L; 1841 } 1842 1843 gray_init_cells( worker, raster->buffer, raster->buffer_size ); 1844 1845 ras.outline = *outline; 1846 ras.num_cells = 0; 1847 ras.invalid = 1; 1848 ras.band_size = raster->band_size; 1849 1850 if ( target_map ) 1851 ras.target = *target_map; 1852 1853 ras.render_span = (QT_FT_Raster_Span_Func)gray_render_span; 1854 ras.render_span_data = &ras; 1855 1856 if ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) 1857 { 1858 ras.render_span = (QT_FT_Raster_Span_Func)params->gray_spans; 1859 ras.render_span_data = params->user; 1860 } 1861 1862 return gray_convert_glyph( worker ); 1863 } 1864 1865 1866 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ 1867 /**** a static object. *****/ 1868 1869 static int gray_raster_new(QT_FT_Raster * araster)1870 gray_raster_new( QT_FT_Raster* araster ) 1871 { 1872 *araster = malloc(sizeof(TRaster)); 1873 if (!*araster) { 1874 *araster = 0; 1875 return ErrRaster_Memory_Overflow; 1876 } 1877 QT_FT_MEM_ZERO(*araster, sizeof(TRaster)); 1878 1879 return 0; 1880 } 1881 1882 1883 static void gray_raster_done(QT_FT_Raster raster)1884 gray_raster_done( QT_FT_Raster raster ) 1885 { 1886 free(raster); 1887 } 1888 1889 1890 static void gray_raster_reset(QT_FT_Raster raster,char * pool_base,long pool_size)1891 gray_raster_reset( QT_FT_Raster raster, 1892 char* pool_base, 1893 long pool_size ) 1894 { 1895 PRaster rast = (PRaster)raster; 1896 1897 if ( raster ) 1898 { 1899 if ( pool_base && ( pool_size >= MINIMUM_POOL_SIZE ) ) 1900 { 1901 PWorker worker = (PWorker)pool_base; 1902 1903 1904 rast->worker = worker; 1905 rast->buffer = pool_base + 1906 ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) & 1907 ~( sizeof ( TCell ) - 1 ) ); 1908 rast->buffer_size = (long)( ( pool_base + pool_size ) - 1909 (char*)rast->buffer ) & 1910 ~( sizeof ( TCell ) - 1 ); 1911 rast->band_size = (int)( rast->buffer_size / 1912 ( sizeof ( TCell ) * 8 ) ); 1913 } 1914 else if ( pool_base) 1915 { /* Case when there is a raster pool allocated, but it */ 1916 /* doesn't have the minimum size (and so memory will be reallocated) */ 1917 rast->buffer = pool_base; 1918 rast->worker = NULL; 1919 rast->buffer_size = pool_size; 1920 } 1921 else 1922 { 1923 rast->buffer = NULL; 1924 rast->buffer_size = 0; 1925 rast->worker = NULL; 1926 } 1927 rast->buffer_allocated_size = pool_size; 1928 } 1929 } 1930 1931 const QT_FT_Raster_Funcs qt_ft_grays_raster = 1932 { 1933 QT_FT_GLYPH_FORMAT_OUTLINE, 1934 1935 (QT_FT_Raster_New_Func) gray_raster_new, 1936 (QT_FT_Raster_Reset_Func) gray_raster_reset, 1937 (QT_FT_Raster_Set_Mode_Func)0, 1938 (QT_FT_Raster_Render_Func) gray_raster_render, 1939 (QT_FT_Raster_Done_Func) gray_raster_done 1940 }; 1941 1942 /* END */ 1943