Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftgrays.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ftgrays.c */ 00004 /* */ 00005 /* A new `perfect' anti-aliasing renderer (body). */ 00006 /* */ 00007 /* Copyright 2000-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009, 2010 by */ 00008 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 /*************************************************************************/ 00019 /* */ 00020 /* This file can be compiled without the rest of the FreeType engine, by */ 00021 /* defining the _STANDALONE_ macro when compiling it. You also need to */ 00022 /* put the files `ftgrays.h' and `ftimage.h' into the current */ 00023 /* compilation directory. Typically, you could do something like */ 00024 /* */ 00025 /* - copy `src/smooth/ftgrays.c' (this file) to your current directory */ 00026 /* */ 00027 /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */ 00028 /* same directory */ 00029 /* */ 00030 /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ 00031 /* */ 00032 /* cc -c -D_STANDALONE_ ftgrays.c */ 00033 /* */ 00034 /* The renderer can be initialized with a call to */ 00035 /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */ 00036 /* with a call to `ft_gray_raster.raster_render'. */ 00037 /* */ 00038 /* See the comments and documentation in the file `ftimage.h' for more */ 00039 /* details on how the raster works. */ 00040 /* */ 00041 /*************************************************************************/ 00042 00043 /*************************************************************************/ 00044 /* */ 00045 /* This is a new anti-aliasing scan-converter for FreeType 2. The */ 00046 /* algorithm used here is _very_ different from the one in the standard */ 00047 /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ 00048 /* coverage of the outline on each pixel cell. */ 00049 /* */ 00050 /* It is based on ideas that I initially found in Raph Levien's */ 00051 /* excellent LibArt graphics library (see http://www.levien.com/libart */ 00052 /* for more information, though the web pages do not tell anything */ 00053 /* about the renderer; you'll have to dive into the source code to */ 00054 /* understand how it works). */ 00055 /* */ 00056 /* Note, however, that this is a _very_ different implementation */ 00057 /* compared to Raph's. Coverage information is stored in a very */ 00058 /* different way, and I don't use sorted vector paths. Also, it doesn't */ 00059 /* use floating point values. */ 00060 /* */ 00061 /* This renderer has the following advantages: */ 00062 /* */ 00063 /* - It doesn't need an intermediate bitmap. Instead, one can supply a */ 00064 /* callback function that will be called by the renderer to draw gray */ 00065 /* spans on any target surface. You can thus do direct composition on */ 00066 /* any kind of bitmap, provided that you give the renderer the right */ 00067 /* callback. */ 00068 /* */ 00069 /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ 00070 /* each pixel cell. */ 00071 /* */ 00072 /* - It performs a single pass on the outline (the `standard' FT2 */ 00073 /* renderer makes two passes). */ 00074 /* */ 00075 /* - It can easily be modified to render to _any_ number of gray levels */ 00076 /* cheaply. */ 00077 /* */ 00078 /* - For small (< 20) pixel sizes, it is faster than the standard */ 00079 /* renderer. */ 00080 /* */ 00081 /*************************************************************************/ 00082 00083 00084 /*************************************************************************/ 00085 /* */ 00086 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00087 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00088 /* messages during execution. */ 00089 /* */ 00090 #undef FT_COMPONENT 00091 #define FT_COMPONENT trace_smooth 00092 00093 00094 #ifdef _STANDALONE_ 00095 00096 00097 /* define this to dump debugging information */ 00098 /* #define FT_DEBUG_LEVEL_TRACE */ 00099 00100 00101 #ifdef FT_DEBUG_LEVEL_TRACE 00102 #include <stdio.h> 00103 #include <stdarg.h> 00104 #endif 00105 00106 #include <stddef.h> 00107 #include <string.h> 00108 #include <setjmp.h> 00109 #include <limits.h> 00110 #define FT_UINT_MAX UINT_MAX 00111 #define FT_INT_MAX INT_MAX 00112 00113 #define ft_memset memset 00114 00115 #define ft_setjmp setjmp 00116 #define ft_longjmp longjmp 00117 #define ft_jmp_buf jmp_buf 00118 00119 typedef ptrdiff_t FT_PtrDist; 00120 00121 00122 #define ErrRaster_Invalid_Mode -2 00123 #define ErrRaster_Invalid_Outline -1 00124 #define ErrRaster_Invalid_Argument -3 00125 #define ErrRaster_Memory_Overflow -4 00126 00127 #define FT_BEGIN_HEADER 00128 #define FT_END_HEADER 00129 00130 #include "ftimage.h" 00131 #include "ftgrays.h" 00132 00133 00134 /* This macro is used to indicate that a function parameter is unused. */ 00135 /* Its purpose is simply to reduce compiler warnings. Note also that */ 00136 /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 00137 /* ANSI compilers (e.g. LCC). */ 00138 #define FT_UNUSED( x ) (x) = (x) 00139 00140 00141 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */ 00142 00143 #ifdef FT_DEBUG_LEVEL_TRACE 00144 00145 void 00146 FT_Message( const char* fmt, 00147 ... ) 00148 { 00149 va_list ap; 00150 00151 00152 va_start( ap, fmt ); 00153 vfprintf( stderr, fmt, ap ); 00154 va_end( ap ); 00155 } 00156 00157 /* we don't handle tracing levels in stand-alone mode; */ 00158 #ifndef FT_TRACE5 00159 #define FT_TRACE5( varformat ) FT_Message varformat 00160 #endif 00161 #ifndef FT_TRACE7 00162 #define FT_TRACE7( varformat ) FT_Message varformat 00163 #endif 00164 #ifndef FT_ERROR 00165 #define FT_ERROR( varformat ) FT_Message varformat 00166 #endif 00167 00168 #else /* !FT_DEBUG_LEVEL_TRACE */ 00169 00170 #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ 00171 #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ 00172 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ 00173 00174 #endif /* !FT_DEBUG_LEVEL_TRACE */ 00175 00176 00177 #define FT_DEFINE_OUTLINE_FUNCS( class_, \ 00178 move_to_, line_to_, \ 00179 conic_to_, cubic_to_, \ 00180 shift_, delta_ ) \ 00181 static const FT_Outline_Funcs class_ = \ 00182 { \ 00183 move_to_, \ 00184 line_to_, \ 00185 conic_to_, \ 00186 cubic_to_, \ 00187 shift_, \ 00188 delta_ \ 00189 }; 00190 00191 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \ 00192 raster_new_, raster_reset_, \ 00193 raster_set_mode_, raster_render_, \ 00194 raster_done_ ) \ 00195 const FT_Raster_Funcs class_ = \ 00196 { \ 00197 glyph_format_, \ 00198 raster_new_, \ 00199 raster_reset_, \ 00200 raster_set_mode_, \ 00201 raster_render_, \ 00202 raster_done_ \ 00203 }; 00204 00205 #else /* !_STANDALONE_ */ 00206 00207 00208 #include <ft2build.h> 00209 #include "ftgrays.h" 00210 #include FT_INTERNAL_OBJECTS_H 00211 #include FT_INTERNAL_DEBUG_H 00212 #include FT_OUTLINE_H 00213 00214 #include "ftsmerrs.h" 00215 00216 #include "ftspic.h" 00217 00218 #define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph 00219 #define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline 00220 #define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory 00221 #define ErrRaster_Invalid_Argument Smooth_Err_Invalid_Argument 00222 00223 #endif /* !_STANDALONE_ */ 00224 00225 #ifndef FT_MEM_SET 00226 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) 00227 #endif 00228 00229 #ifndef FT_MEM_ZERO 00230 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) 00231 #endif 00232 00233 /* as usual, for the speed hungry :-) */ 00234 00235 #ifndef FT_STATIC_RASTER 00236 00237 #define RAS_ARG PWorker worker 00238 #define RAS_ARG_ PWorker worker, 00239 00240 #define RAS_VAR worker 00241 #define RAS_VAR_ worker, 00242 00243 #else /* FT_STATIC_RASTER */ 00244 00245 #define RAS_ARG /* empty */ 00246 #define RAS_ARG_ /* empty */ 00247 #define RAS_VAR /* empty */ 00248 #define RAS_VAR_ /* empty */ 00249 00250 #endif /* FT_STATIC_RASTER */ 00251 00252 00253 /* must be at least 6 bits! */ 00254 #define PIXEL_BITS 8 00255 00256 #define ONE_PIXEL ( 1L << PIXEL_BITS ) 00257 #define PIXEL_MASK ( -1L << PIXEL_BITS ) 00258 #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) 00259 #define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) 00260 #define FLOOR( x ) ( (x) & -ONE_PIXEL ) 00261 #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) 00262 #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) 00263 00264 #if PIXEL_BITS >= 6 00265 #define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) 00266 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) 00267 #else 00268 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) 00269 #define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) 00270 #endif 00271 00272 00273 /*************************************************************************/ 00274 /* */ 00275 /* TYPE DEFINITIONS */ 00276 /* */ 00277 00278 /* don't change the following types to FT_Int or FT_Pos, since we might */ 00279 /* need to define them to "float" or "double" when experimenting with */ 00280 /* new algorithms */ 00281 00282 typedef long TCoord; /* integer scanline/pixel coordinate */ 00283 typedef long TPos; /* sub-pixel coordinate */ 00284 00285 /* determine the type used to store cell areas. This normally takes at */ 00286 /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */ 00287 /* `long' instead of `int', otherwise bad things happen */ 00288 00289 #if PIXEL_BITS <= 7 00290 00291 typedef int TArea; 00292 00293 #else /* PIXEL_BITS >= 8 */ 00294 00295 /* approximately determine the size of integers using an ANSI-C header */ 00296 #if FT_UINT_MAX == 0xFFFFU 00297 typedef long TArea; 00298 #else 00299 typedef int TArea; 00300 #endif 00301 00302 #endif /* PIXEL_BITS >= 8 */ 00303 00304 00305 /* maximal number of gray spans in a call to the span callback */ 00306 #define FT_MAX_GRAY_SPANS 32 00307 00308 00309 typedef struct TCell_* PCell; 00310 00311 typedef struct TCell_ 00312 { 00313 TPos x; /* same with TWorker.ex */ 00314 TCoord cover; /* same with TWorker.cover */ 00315 TArea area; 00316 PCell next; 00317 00318 } TCell; 00319 00320 00321 typedef struct TWorker_ 00322 { 00323 TCoord ex, ey; 00324 TPos min_ex, max_ex; 00325 TPos min_ey, max_ey; 00326 TPos count_ex, count_ey; 00327 00328 TArea area; 00329 TCoord cover; 00330 int invalid; 00331 00332 PCell cells; 00333 FT_PtrDist max_cells; 00334 FT_PtrDist num_cells; 00335 00336 TCoord cx, cy; 00337 TPos x, y; 00338 00339 TPos last_ey; 00340 00341 FT_Vector bez_stack[32 * 3 + 1]; 00342 int lev_stack[32]; 00343 00344 FT_Outline outline; 00345 FT_Bitmap target; 00346 FT_BBox clip_box; 00347 00348 FT_Span gray_spans[FT_MAX_GRAY_SPANS]; 00349 int num_gray_spans; 00350 00351 FT_Raster_Span_Func render_span; 00352 void* render_span_data; 00353 int span_y; 00354 00355 int band_size; 00356 int band_shoot; 00357 00358 ft_jmp_buf jump_buffer; 00359 00360 void* buffer; 00361 long buffer_size; 00362 00363 PCell* ycells; 00364 TPos ycount; 00365 00366 } TWorker, *PWorker; 00367 00368 00369 #ifndef FT_STATIC_RASTER 00370 #define ras (*worker) 00371 #else 00372 static TWorker ras; 00373 #endif 00374 00375 00376 typedef struct TRaster_ 00377 { 00378 void* buffer; 00379 long buffer_size; 00380 int band_size; 00381 void* memory; 00382 PWorker worker; 00383 00384 } TRaster, *PRaster; 00385 00386 00387 00388 /*************************************************************************/ 00389 /* */ 00390 /* Initialize the cells table. */ 00391 /* */ 00392 static void 00393 gray_init_cells( RAS_ARG_ void* buffer, 00394 long byte_size ) 00395 { 00396 ras.buffer = buffer; 00397 ras.buffer_size = byte_size; 00398 00399 ras.ycells = (PCell*) buffer; 00400 ras.cells = NULL; 00401 ras.max_cells = 0; 00402 ras.num_cells = 0; 00403 ras.area = 0; 00404 ras.cover = 0; 00405 ras.invalid = 1; 00406 } 00407 00408 00409 /*************************************************************************/ 00410 /* */ 00411 /* Compute the outline bounding box. */ 00412 /* */ 00413 static void 00414 gray_compute_cbox( RAS_ARG ) 00415 { 00416 FT_Outline* outline = &ras.outline; 00417 FT_Vector* vec = outline->points; 00418 FT_Vector* limit = vec + outline->n_points; 00419 00420 00421 if ( outline->n_points <= 0 ) 00422 { 00423 ras.min_ex = ras.max_ex = 0; 00424 ras.min_ey = ras.max_ey = 0; 00425 return; 00426 } 00427 00428 ras.min_ex = ras.max_ex = vec->x; 00429 ras.min_ey = ras.max_ey = vec->y; 00430 00431 vec++; 00432 00433 for ( ; vec < limit; vec++ ) 00434 { 00435 TPos x = vec->x; 00436 TPos y = vec->y; 00437 00438 00439 if ( x < ras.min_ex ) ras.min_ex = x; 00440 if ( x > ras.max_ex ) ras.max_ex = x; 00441 if ( y < ras.min_ey ) ras.min_ey = y; 00442 if ( y > ras.max_ey ) ras.max_ey = y; 00443 } 00444 00445 /* truncate the bounding box to integer pixels */ 00446 ras.min_ex = ras.min_ex >> 6; 00447 ras.min_ey = ras.min_ey >> 6; 00448 ras.max_ex = ( ras.max_ex + 63 ) >> 6; 00449 ras.max_ey = ( ras.max_ey + 63 ) >> 6; 00450 } 00451 00452 00453 /*************************************************************************/ 00454 /* */ 00455 /* Record the current cell in the table. */ 00456 /* */ 00457 static PCell 00458 gray_find_cell( RAS_ARG ) 00459 { 00460 PCell *pcell, cell; 00461 TPos x = ras.ex; 00462 00463 00464 if ( x > ras.count_ex ) 00465 x = ras.count_ex; 00466 00467 pcell = &ras.ycells[ras.ey]; 00468 for (;;) 00469 { 00470 cell = *pcell; 00471 if ( cell == NULL || cell->x > x ) 00472 break; 00473 00474 if ( cell->x == x ) 00475 goto Exit; 00476 00477 pcell = &cell->next; 00478 } 00479 00480 if ( ras.num_cells >= ras.max_cells ) 00481 ft_longjmp( ras.jump_buffer, 1 ); 00482 00483 cell = ras.cells + ras.num_cells++; 00484 cell->x = x; 00485 cell->area = 0; 00486 cell->cover = 0; 00487 00488 cell->next = *pcell; 00489 *pcell = cell; 00490 00491 Exit: 00492 return cell; 00493 } 00494 00495 00496 static void 00497 gray_record_cell( RAS_ARG ) 00498 { 00499 if ( !ras.invalid && ( ras.area | ras.cover ) ) 00500 { 00501 PCell cell = gray_find_cell( RAS_VAR ); 00502 00503 00504 cell->area += ras.area; 00505 cell->cover += ras.cover; 00506 } 00507 } 00508 00509 00510 /*************************************************************************/ 00511 /* */ 00512 /* Set the current cell to a new position. */ 00513 /* */ 00514 static void 00515 gray_set_cell( RAS_ARG_ TCoord ex, 00516 TCoord ey ) 00517 { 00518 /* Move the cell pointer to a new position. We set the `invalid' */ 00519 /* flag to indicate that the cell isn't part of those we're interested */ 00520 /* in during the render phase. This means that: */ 00521 /* */ 00522 /* . the new vertical position must be within min_ey..max_ey-1. */ 00523 /* . the new horizontal position must be strictly less than max_ex */ 00524 /* */ 00525 /* Note that if a cell is to the left of the clipping region, it is */ 00526 /* actually set to the (min_ex-1) horizontal position. */ 00527 00528 /* All cells that are on the left of the clipping region go to the */ 00529 /* min_ex - 1 horizontal position. */ 00530 ey -= ras.min_ey; 00531 00532 if ( ex > ras.max_ex ) 00533 ex = ras.max_ex; 00534 00535 ex -= ras.min_ex; 00536 if ( ex < 0 ) 00537 ex = -1; 00538 00539 /* are we moving to a different cell ? */ 00540 if ( ex != ras.ex || ey != ras.ey ) 00541 { 00542 /* record the current one if it is valid */ 00543 if ( !ras.invalid ) 00544 gray_record_cell( RAS_VAR ); 00545 00546 ras.area = 0; 00547 ras.cover = 0; 00548 } 00549 00550 ras.ex = ex; 00551 ras.ey = ey; 00552 ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey || 00553 ex >= ras.count_ex ); 00554 } 00555 00556 00557 /*************************************************************************/ 00558 /* */ 00559 /* Start a new contour at a given cell. */ 00560 /* */ 00561 static void 00562 gray_start_cell( RAS_ARG_ TCoord ex, 00563 TCoord ey ) 00564 { 00565 if ( ex > ras.max_ex ) 00566 ex = (TCoord)( ras.max_ex ); 00567 00568 if ( ex < ras.min_ex ) 00569 ex = (TCoord)( ras.min_ex - 1 ); 00570 00571 ras.area = 0; 00572 ras.cover = 0; 00573 ras.ex = ex - ras.min_ex; 00574 ras.ey = ey - ras.min_ey; 00575 ras.last_ey = SUBPIXELS( ey ); 00576 ras.invalid = 0; 00577 00578 gray_set_cell( RAS_VAR_ ex, ey ); 00579 } 00580 00581 00582 /*************************************************************************/ 00583 /* */ 00584 /* Render a scanline as one or more cells. */ 00585 /* */ 00586 static void 00587 gray_render_scanline( RAS_ARG_ TCoord ey, 00588 TPos x1, 00589 TCoord y1, 00590 TPos x2, 00591 TCoord y2 ) 00592 { 00593 TCoord ex1, ex2, fx1, fx2, delta, mod, lift, rem; 00594 long p, first, dx; 00595 int incr; 00596 00597 00598 dx = x2 - x1; 00599 00600 ex1 = TRUNC( x1 ); 00601 ex2 = TRUNC( x2 ); 00602 fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); 00603 fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); 00604 00605 /* trivial case. Happens often */ 00606 if ( y1 == y2 ) 00607 { 00608 gray_set_cell( RAS_VAR_ ex2, ey ); 00609 return; 00610 } 00611 00612 /* everything is located in a single cell. That is easy! */ 00613 /* */ 00614 if ( ex1 == ex2 ) 00615 { 00616 delta = y2 - y1; 00617 ras.area += (TArea)(( fx1 + fx2 ) * delta); 00618 ras.cover += delta; 00619 return; 00620 } 00621 00622 /* ok, we'll have to render a run of adjacent cells on the same */ 00623 /* scanline... */ 00624 /* */ 00625 p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); 00626 first = ONE_PIXEL; 00627 incr = 1; 00628 00629 if ( dx < 0 ) 00630 { 00631 p = fx1 * ( y2 - y1 ); 00632 first = 0; 00633 incr = -1; 00634 dx = -dx; 00635 } 00636 00637 delta = (TCoord)( p / dx ); 00638 mod = (TCoord)( p % dx ); 00639 if ( mod < 0 ) 00640 { 00641 delta--; 00642 mod += (TCoord)dx; 00643 } 00644 00645 ras.area += (TArea)(( fx1 + first ) * delta); 00646 ras.cover += delta; 00647 00648 ex1 += incr; 00649 gray_set_cell( RAS_VAR_ ex1, ey ); 00650 y1 += delta; 00651 00652 if ( ex1 != ex2 ) 00653 { 00654 p = ONE_PIXEL * ( y2 - y1 + delta ); 00655 lift = (TCoord)( p / dx ); 00656 rem = (TCoord)( p % dx ); 00657 if ( rem < 0 ) 00658 { 00659 lift--; 00660 rem += (TCoord)dx; 00661 } 00662 00663 mod -= (int)dx; 00664 00665 while ( ex1 != ex2 ) 00666 { 00667 delta = lift; 00668 mod += rem; 00669 if ( mod >= 0 ) 00670 { 00671 mod -= (TCoord)dx; 00672 delta++; 00673 } 00674 00675 ras.area += (TArea)(ONE_PIXEL * delta); 00676 ras.cover += delta; 00677 y1 += delta; 00678 ex1 += incr; 00679 gray_set_cell( RAS_VAR_ ex1, ey ); 00680 } 00681 } 00682 00683 delta = y2 - y1; 00684 ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta); 00685 ras.cover += delta; 00686 } 00687 00688 00689 /*************************************************************************/ 00690 /* */ 00691 /* Render a given line as a series of scanlines. */ 00692 /* */ 00693 static void 00694 gray_render_line( RAS_ARG_ TPos to_x, 00695 TPos to_y ) 00696 { 00697 TCoord ey1, ey2, fy1, fy2, mod; 00698 TPos dx, dy, x, x2; 00699 long p, first; 00700 int delta, rem, lift, incr; 00701 00702 00703 ey1 = TRUNC( ras.last_ey ); 00704 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ 00705 fy1 = (TCoord)( ras.y - ras.last_ey ); 00706 fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); 00707 00708 dx = to_x - ras.x; 00709 dy = to_y - ras.y; 00710 00711 /* XXX: we should do something about the trivial case where dx == 0, */ 00712 /* as it happens very often! */ 00713 00714 /* perform vertical clipping */ 00715 { 00716 TCoord min, max; 00717 00718 00719 min = ey1; 00720 max = ey2; 00721 if ( ey1 > ey2 ) 00722 { 00723 min = ey2; 00724 max = ey1; 00725 } 00726 if ( min >= ras.max_ey || max < ras.min_ey ) 00727 goto End; 00728 } 00729 00730 /* everything is on a single scanline */ 00731 if ( ey1 == ey2 ) 00732 { 00733 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); 00734 goto End; 00735 } 00736 00737 /* vertical line - avoid calling gray_render_scanline */ 00738 incr = 1; 00739 00740 if ( dx == 0 ) 00741 { 00742 TCoord ex = TRUNC( ras.x ); 00743 TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); 00744 TArea area; 00745 00746 00747 first = ONE_PIXEL; 00748 if ( dy < 0 ) 00749 { 00750 first = 0; 00751 incr = -1; 00752 } 00753 00754 delta = (int)( first - fy1 ); 00755 ras.area += (TArea)two_fx * delta; 00756 ras.cover += delta; 00757 ey1 += incr; 00758 00759 gray_set_cell( RAS_VAR_ ex, ey1 ); 00760 00761 delta = (int)( first + first - ONE_PIXEL ); 00762 area = (TArea)two_fx * delta; 00763 while ( ey1 != ey2 ) 00764 { 00765 ras.area += area; 00766 ras.cover += delta; 00767 ey1 += incr; 00768 00769 gray_set_cell( RAS_VAR_ ex, ey1 ); 00770 } 00771 00772 delta = (int)( fy2 - ONE_PIXEL + first ); 00773 ras.area += (TArea)two_fx * delta; 00774 ras.cover += delta; 00775 00776 goto End; 00777 } 00778 00779 /* ok, we have to render several scanlines */ 00780 p = ( ONE_PIXEL - fy1 ) * dx; 00781 first = ONE_PIXEL; 00782 incr = 1; 00783 00784 if ( dy < 0 ) 00785 { 00786 p = fy1 * dx; 00787 first = 0; 00788 incr = -1; 00789 dy = -dy; 00790 } 00791 00792 delta = (int)( p / dy ); 00793 mod = (int)( p % dy ); 00794 if ( mod < 0 ) 00795 { 00796 delta--; 00797 mod += (TCoord)dy; 00798 } 00799 00800 x = ras.x + delta; 00801 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); 00802 00803 ey1 += incr; 00804 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 00805 00806 if ( ey1 != ey2 ) 00807 { 00808 p = ONE_PIXEL * dx; 00809 lift = (int)( p / dy ); 00810 rem = (int)( p % dy ); 00811 if ( rem < 0 ) 00812 { 00813 lift--; 00814 rem += (int)dy; 00815 } 00816 mod -= (int)dy; 00817 00818 while ( ey1 != ey2 ) 00819 { 00820 delta = lift; 00821 mod += rem; 00822 if ( mod >= 0 ) 00823 { 00824 mod -= (int)dy; 00825 delta++; 00826 } 00827 00828 x2 = x + delta; 00829 gray_render_scanline( RAS_VAR_ ey1, x, 00830 (TCoord)( ONE_PIXEL - first ), x2, 00831 (TCoord)first ); 00832 x = x2; 00833 00834 ey1 += incr; 00835 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); 00836 } 00837 } 00838 00839 gray_render_scanline( RAS_VAR_ ey1, x, 00840 (TCoord)( ONE_PIXEL - first ), to_x, 00841 fy2 ); 00842 00843 End: 00844 ras.x = to_x; 00845 ras.y = to_y; 00846 ras.last_ey = SUBPIXELS( ey2 ); 00847 } 00848 00849 00850 static void 00851 gray_split_conic( FT_Vector* base ) 00852 { 00853 TPos a, b; 00854 00855 00856 base[4].x = base[2].x; 00857 b = base[1].x; 00858 a = base[3].x = ( base[2].x + b ) / 2; 00859 b = base[1].x = ( base[0].x + b ) / 2; 00860 base[2].x = ( a + b ) / 2; 00861 00862 base[4].y = base[2].y; 00863 b = base[1].y; 00864 a = base[3].y = ( base[2].y + b ) / 2; 00865 b = base[1].y = ( base[0].y + b ) / 2; 00866 base[2].y = ( a + b ) / 2; 00867 } 00868 00869 00870 static void 00871 gray_render_conic( RAS_ARG_ const FT_Vector* control, 00872 const FT_Vector* to ) 00873 { 00874 TPos dx, dy; 00875 int top, level; 00876 int* levels; 00877 FT_Vector* arc; 00878 00879 00880 arc = ras.bez_stack; 00881 arc[0].x = UPSCALE( to->x ); 00882 arc[0].y = UPSCALE( to->y ); 00883 arc[1].x = UPSCALE( control->x ); 00884 arc[1].y = UPSCALE( control->y ); 00885 arc[2].x = ras.x; 00886 arc[2].y = ras.y; 00887 00888 dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); 00889 dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); 00890 if ( dx < dy ) 00891 dx = dy; 00892 00893 if ( dx <= ONE_PIXEL / 4 ) 00894 { 00895 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 00896 return; 00897 } 00898 00899 level = 0; 00900 while ( dx > ONE_PIXEL / 4 ) 00901 { 00902 dx >>= 2; 00903 level++; 00904 } 00905 00906 levels = ras.lev_stack; 00907 levels[0] = level; 00908 top = 0; 00909 00910 while ( top >= 0 ) 00911 { 00912 level = levels[top]; 00913 if ( level > 1 ) 00914 { 00915 /* check that the arc crosses the current band */ 00916 TPos min, max, y; 00917 00918 00919 min = max = arc[0].y; 00920 00921 y = arc[1].y; 00922 if ( y < min ) min = y; 00923 if ( y > max ) max = y; 00924 00925 y = arc[2].y; 00926 if ( y < min ) min = y; 00927 if ( y > max ) max = y; 00928 00929 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) 00930 goto Draw; 00931 00932 gray_split_conic( arc ); 00933 arc += 2; 00934 top++; 00935 levels[top] = levels[top - 1] = level - 1; 00936 continue; 00937 } 00938 00939 Draw: 00940 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 00941 top--; 00942 arc -= 2; 00943 } 00944 00945 return; 00946 } 00947 00948 00949 static void 00950 gray_split_cubic( FT_Vector* base ) 00951 { 00952 TPos a, b, c, d; 00953 00954 00955 base[6].x = base[3].x; 00956 c = base[1].x; 00957 d = base[2].x; 00958 base[1].x = a = ( base[0].x + c ) / 2; 00959 base[5].x = b = ( base[3].x + d ) / 2; 00960 c = ( c + d ) / 2; 00961 base[2].x = a = ( a + c ) / 2; 00962 base[4].x = b = ( b + c ) / 2; 00963 base[3].x = ( a + b ) / 2; 00964 00965 base[6].y = base[3].y; 00966 c = base[1].y; 00967 d = base[2].y; 00968 base[1].y = a = ( base[0].y + c ) / 2; 00969 base[5].y = b = ( base[3].y + d ) / 2; 00970 c = ( c + d ) / 2; 00971 base[2].y = a = ( a + c ) / 2; 00972 base[4].y = b = ( b + c ) / 2; 00973 base[3].y = ( a + b ) / 2; 00974 } 00975 00976 00977 static void 00978 gray_render_cubic( RAS_ARG_ const FT_Vector* control1, 00979 const FT_Vector* control2, 00980 const FT_Vector* to ) 00981 { 00982 FT_Vector* arc; 00983 00984 00985 arc = ras.bez_stack; 00986 arc[0].x = UPSCALE( to->x ); 00987 arc[0].y = UPSCALE( to->y ); 00988 arc[1].x = UPSCALE( control2->x ); 00989 arc[1].y = UPSCALE( control2->y ); 00990 arc[2].x = UPSCALE( control1->x ); 00991 arc[2].y = UPSCALE( control1->y ); 00992 arc[3].x = ras.x; 00993 arc[3].y = ras.y; 00994 00995 for (;;) 00996 { 00997 /* Check that the arc crosses the current band. */ 00998 TPos min, max, y; 00999 01000 01001 min = max = arc[0].y; 01002 01003 y = arc[1].y; 01004 if ( y < min ) 01005 min = y; 01006 if ( y > max ) 01007 max = y; 01008 01009 y = arc[2].y; 01010 if ( y < min ) 01011 min = y; 01012 if ( y > max ) 01013 max = y; 01014 01015 y = arc[3].y; 01016 if ( y < min ) 01017 min = y; 01018 if ( y > max ) 01019 max = y; 01020 01021 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) 01022 goto Draw; 01023 01024 /* Decide whether to split or draw. See `Rapid Termination */ 01025 /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */ 01026 /* F. Hain, at */ 01027 /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */ 01028 01029 { 01030 TPos dx, dy, dx_, dy_; 01031 TPos dx1, dy1, dx2, dy2; 01032 TPos L, s, s_limit; 01033 01034 01035 /* dx and dy are x and y components of the P0-P3 chord vector. */ 01036 dx = arc[3].x - arc[0].x; 01037 dy = arc[3].y - arc[0].y; 01038 01039 /* L is an (under)estimate of the Euclidean distance P0-P3. */ 01040 /* */ 01041 /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated */ 01042 /* with least maximum error by */ 01043 /* */ 01044 /* r_upperbound = dx + (sqrt(2) - 1) * dy , */ 01045 /* */ 01046 /* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */ 01047 /* error of no more than 8.4%. */ 01048 /* */ 01049 /* Similarly, some elementary calculus shows that r can be */ 01050 /* underestimated with least maximum error by */ 01051 /* */ 01052 /* r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx */ 01053 /* + sqrt(2 - sqrt(2)) / 2 * dy . */ 01054 /* */ 01055 /* 236/256 and 97/256 are (under)estimates of the two algebraic */ 01056 /* numbers, giving an error of no more than 8.1%. */ 01057 01058 dx_ = FT_ABS( dx ); 01059 dy_ = FT_ABS( dy ); 01060 01061 /* This is the same as */ 01062 /* */ 01063 /* L = ( 236 * FT_MAX( dx_, dy_ ) */ 01064 /* + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */ 01065 L = ( dx_ > dy_ ? 236 * dx_ + 97 * dy_ 01066 : 97 * dx_ + 236 * dy_ ) >> 8; 01067 01068 /* Avoid possible arithmetic overflow below by splitting. */ 01069 if ( L > 32767 ) 01070 goto Split; 01071 01072 /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */ 01073 s_limit = L * (TPos)( ONE_PIXEL / 6 ); 01074 01075 /* s is L * the perpendicular distance from P1 to the line P0-P3. */ 01076 dx1 = arc[1].x - arc[0].x; 01077 dy1 = arc[1].y - arc[0].y; 01078 s = FT_ABS( dy * dx1 - dx * dy1 ); 01079 01080 if ( s > s_limit ) 01081 goto Split; 01082 01083 /* s is L * the perpendicular distance from P2 to the line P0-P3. */ 01084 dx2 = arc[2].x - arc[0].x; 01085 dy2 = arc[2].y - arc[0].y; 01086 s = FT_ABS( dy * dx2 - dx * dy2 ); 01087 01088 if ( s > s_limit ) 01089 goto Split; 01090 01091 /* If P1 or P2 is outside P0-P3, split the curve. */ 01092 if ( dy * dy1 + dx * dx1 < 0 || 01093 dy * dy2 + dx * dx2 < 0 || 01094 dy * (arc[3].y - arc[1].y) + dx * (arc[3].x - arc[1].x) < 0 || 01095 dy * (arc[3].y - arc[2].y) + dx * (arc[3].x - arc[2].x) < 0 ) 01096 goto Split; 01097 01098 /* No reason to split. */ 01099 goto Draw; 01100 } 01101 01102 Split: 01103 gray_split_cubic( arc ); 01104 arc += 3; 01105 continue; 01106 01107 Draw: 01108 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); 01109 01110 if ( arc == ras.bez_stack ) 01111 return; 01112 01113 arc -= 3; 01114 } 01115 } 01116 01117 01118 static int 01119 gray_move_to( const FT_Vector* to, 01120 PWorker worker ) 01121 { 01122 TPos x, y; 01123 01124 01125 /* record current cell, if any */ 01126 gray_record_cell( RAS_VAR ); 01127 01128 /* start to a new position */ 01129 x = UPSCALE( to->x ); 01130 y = UPSCALE( to->y ); 01131 01132 gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); 01133 01134 worker->x = x; 01135 worker->y = y; 01136 return 0; 01137 } 01138 01139 01140 static int 01141 gray_line_to( const FT_Vector* to, 01142 PWorker worker ) 01143 { 01144 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); 01145 return 0; 01146 } 01147 01148 01149 static int 01150 gray_conic_to( const FT_Vector* control, 01151 const FT_Vector* to, 01152 PWorker worker ) 01153 { 01154 gray_render_conic( RAS_VAR_ control, to ); 01155 return 0; 01156 } 01157 01158 01159 static int 01160 gray_cubic_to( const FT_Vector* control1, 01161 const FT_Vector* control2, 01162 const FT_Vector* to, 01163 PWorker worker ) 01164 { 01165 gray_render_cubic( RAS_VAR_ control1, control2, to ); 01166 return 0; 01167 } 01168 01169 01170 static void 01171 gray_render_span( int y, 01172 int count, 01173 const FT_Span* spans, 01174 PWorker worker ) 01175 { 01176 unsigned char* p; 01177 FT_Bitmap* map = &worker->target; 01178 01179 01180 /* first of all, compute the scanline offset */ 01181 p = (unsigned char*)map->buffer - y * map->pitch; 01182 if ( map->pitch >= 0 ) 01183 p += (unsigned)( ( map->rows - 1 ) * map->pitch ); 01184 01185 for ( ; count > 0; count--, spans++ ) 01186 { 01187 unsigned char coverage = spans->coverage; 01188 01189 01190 if ( coverage ) 01191 { 01192 /* For small-spans it is faster to do it by ourselves than 01193 * calling `memset'. This is mainly due to the cost of the 01194 * function call. 01195 */ 01196 if ( spans->len >= 8 ) 01197 FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len ); 01198 else 01199 { 01200 unsigned char* q = p + spans->x; 01201 01202 01203 switch ( spans->len ) 01204 { 01205 case 7: *q++ = (unsigned char)coverage; 01206 case 6: *q++ = (unsigned char)coverage; 01207 case 5: *q++ = (unsigned char)coverage; 01208 case 4: *q++ = (unsigned char)coverage; 01209 case 3: *q++ = (unsigned char)coverage; 01210 case 2: *q++ = (unsigned char)coverage; 01211 case 1: *q = (unsigned char)coverage; 01212 default: 01213 ; 01214 } 01215 } 01216 } 01217 } 01218 } 01219 01220 01221 static void 01222 gray_hline( RAS_ARG_ TCoord x, 01223 TCoord y, 01224 TPos area, 01225 TCoord acount ) 01226 { 01227 FT_Span* span; 01228 int count; 01229 int coverage; 01230 01231 01232 /* compute the coverage line's coverage, depending on the */ 01233 /* outline fill rule */ 01234 /* */ 01235 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ 01236 /* */ 01237 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); 01238 /* use range 0..256 */ 01239 if ( coverage < 0 ) 01240 coverage = -coverage; 01241 01242 if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) 01243 { 01244 coverage &= 511; 01245 01246 if ( coverage > 256 ) 01247 coverage = 512 - coverage; 01248 else if ( coverage == 256 ) 01249 coverage = 255; 01250 } 01251 else 01252 { 01253 /* normal non-zero winding rule */ 01254 if ( coverage >= 256 ) 01255 coverage = 255; 01256 } 01257 01258 y += (TCoord)ras.min_ey; 01259 x += (TCoord)ras.min_ex; 01260 01261 /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ 01262 if ( x >= 32767 ) 01263 x = 32767; 01264 01265 /* FT_Span.y is an integer, so limit our coordinates appropriately */ 01266 if ( y >= FT_INT_MAX ) 01267 y = FT_INT_MAX; 01268 01269 if ( coverage ) 01270 { 01271 /* see whether we can add this span to the current list */ 01272 count = ras.num_gray_spans; 01273 span = ras.gray_spans + count - 1; 01274 if ( count > 0 && 01275 ras.span_y == y && 01276 (int)span->x + span->len == (int)x && 01277 span->coverage == coverage ) 01278 { 01279 span->len = (unsigned short)( span->len + acount ); 01280 return; 01281 } 01282 01283 if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) 01284 { 01285 if ( ras.render_span && count > 0 ) 01286 ras.render_span( ras.span_y, count, ras.gray_spans, 01287 ras.render_span_data ); 01288 01289 #ifdef FT_DEBUG_LEVEL_TRACE 01290 01291 if ( count > 0 ) 01292 { 01293 int n; 01294 01295 01296 FT_TRACE7(( "y = %3d ", ras.span_y )); 01297 span = ras.gray_spans; 01298 for ( n = 0; n < count; n++, span++ ) 01299 FT_TRACE7(( "[%d..%d]:%02x ", 01300 span->x, span->x + span->len - 1, span->coverage )); 01301 FT_TRACE7(( "\n" )); 01302 } 01303 01304 #endif /* FT_DEBUG_LEVEL_TRACE */ 01305 01306 ras.num_gray_spans = 0; 01307 ras.span_y = (int)y; 01308 01309 count = 0; 01310 span = ras.gray_spans; 01311 } 01312 else 01313 span++; 01314 01315 /* add a gray span to the current list */ 01316 span->x = (short)x; 01317 span->len = (unsigned short)acount; 01318 span->coverage = (unsigned char)coverage; 01319 01320 ras.num_gray_spans++; 01321 } 01322 } 01323 01324 01325 #ifdef FT_DEBUG_LEVEL_TRACE 01326 01327 /* to be called while in the debugger -- */ 01328 /* this function causes a compiler warning since it is unused otherwise */ 01329 static void 01330 gray_dump_cells( RAS_ARG ) 01331 { 01332 int yindex; 01333 01334 01335 for ( yindex = 0; yindex < ras.ycount; yindex++ ) 01336 { 01337 PCell cell; 01338 01339 01340 printf( "%3d:", yindex ); 01341 01342 for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next ) 01343 printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area ); 01344 printf( "\n" ); 01345 } 01346 } 01347 01348 #endif /* FT_DEBUG_LEVEL_TRACE */ 01349 01350 01351 static void 01352 gray_sweep( RAS_ARG_ const FT_Bitmap* target ) 01353 { 01354 int yindex; 01355 01356 FT_UNUSED( target ); 01357 01358 01359 if ( ras.num_cells == 0 ) 01360 return; 01361 01362 ras.num_gray_spans = 0; 01363 01364 FT_TRACE7(( "gray_sweep: start\n" )); 01365 01366 for ( yindex = 0; yindex < ras.ycount; yindex++ ) 01367 { 01368 PCell cell = ras.ycells[yindex]; 01369 TCoord cover = 0; 01370 TCoord x = 0; 01371 01372 01373 for ( ; cell != NULL; cell = cell->next ) 01374 { 01375 TPos area; 01376 01377 01378 if ( cell->x > x && cover != 0 ) 01379 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), 01380 cell->x - x ); 01381 01382 cover += cell->cover; 01383 area = cover * ( ONE_PIXEL * 2 ) - cell->area; 01384 01385 if ( area != 0 && cell->x >= 0 ) 01386 gray_hline( RAS_VAR_ cell->x, yindex, area, 1 ); 01387 01388 x = cell->x + 1; 01389 } 01390 01391 if ( cover != 0 ) 01392 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), 01393 ras.count_ex - x ); 01394 } 01395 01396 if ( ras.render_span && ras.num_gray_spans > 0 ) 01397 ras.render_span( ras.span_y, ras.num_gray_spans, 01398 ras.gray_spans, ras.render_span_data ); 01399 01400 FT_TRACE7(( "gray_sweep: end\n" )); 01401 } 01402 01403 01404 #ifdef _STANDALONE_ 01405 01406 /*************************************************************************/ 01407 /* */ 01408 /* The following function should only compile in stand-alone mode, */ 01409 /* i.e., when building this component without the rest of FreeType. */ 01410 /* */ 01411 /*************************************************************************/ 01412 01413 /*************************************************************************/ 01414 /* */ 01415 /* <Function> */ 01416 /* FT_Outline_Decompose */ 01417 /* */ 01418 /* <Description> */ 01419 /* Walk over an outline's structure to decompose it into individual */ 01420 /* segments and Bézier arcs. This function is also able to emit */ 01421 /* `move to' and `close to' operations to indicate the start and end */ 01422 /* of new contours in the outline. */ 01423 /* */ 01424 /* <Input> */ 01425 /* outline :: A pointer to the source target. */ 01426 /* */ 01427 /* func_interface :: A table of `emitters', i.e., function pointers */ 01428 /* called during decomposition to indicate path */ 01429 /* operations. */ 01430 /* */ 01431 /* <InOut> */ 01432 /* user :: A typeless pointer which is passed to each */ 01433 /* emitter during the decomposition. It can be */ 01434 /* used to store the state during the */ 01435 /* decomposition. */ 01436 /* */ 01437 /* <Return> */ 01438 /* Error code. 0 means success. */ 01439 /* */ 01440 static int 01441 FT_Outline_Decompose( const FT_Outline* outline, 01442 const FT_Outline_Funcs* func_interface, 01443 void* user ) 01444 { 01445 #undef SCALED 01446 #define SCALED( x ) ( ( (x) << shift ) - delta ) 01447 01448 FT_Vector v_last; 01449 FT_Vector v_control; 01450 FT_Vector v_start; 01451 01452 FT_Vector* point; 01453 FT_Vector* limit; 01454 char* tags; 01455 01456 int error; 01457 01458 int n; /* index of contour in outline */ 01459 int first; /* index of first point in contour */ 01460 char tag; /* current point's state */ 01461 01462 int shift; 01463 TPos delta; 01464 01465 01466 if ( !outline || !func_interface ) 01467 return ErrRaster_Invalid_Argument; 01468 01469 shift = func_interface->shift; 01470 delta = func_interface->delta; 01471 first = 0; 01472 01473 for ( n = 0; n < outline->n_contours; n++ ) 01474 { 01475 int last; /* index of last point in contour */ 01476 01477 01478 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); 01479 01480 last = outline->contours[n]; 01481 if ( last < 0 ) 01482 goto Invalid_Outline; 01483 limit = outline->points + last; 01484 01485 v_start = outline->points[first]; 01486 v_start.x = SCALED( v_start.x ); 01487 v_start.y = SCALED( v_start.y ); 01488 01489 v_last = outline->points[last]; 01490 v_last.x = SCALED( v_last.x ); 01491 v_last.y = SCALED( v_last.y ); 01492 01493 v_control = v_start; 01494 01495 point = outline->points + first; 01496 tags = outline->tags + first; 01497 tag = FT_CURVE_TAG( tags[0] ); 01498 01499 /* A contour cannot start with a cubic control point! */ 01500 if ( tag == FT_CURVE_TAG_CUBIC ) 01501 goto Invalid_Outline; 01502 01503 /* check first point to determine origin */ 01504 if ( tag == FT_CURVE_TAG_CONIC ) 01505 { 01506 /* first point is conic control. Yes, this happens. */ 01507 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 01508 { 01509 /* start at last point if it is on the curve */ 01510 v_start = v_last; 01511 limit--; 01512 } 01513 else 01514 { 01515 /* if both first and last points are conic, */ 01516 /* start at their middle and record its position */ 01517 /* for closure */ 01518 v_start.x = ( v_start.x + v_last.x ) / 2; 01519 v_start.y = ( v_start.y + v_last.y ) / 2; 01520 01521 v_last = v_start; 01522 } 01523 point--; 01524 tags--; 01525 } 01526 01527 FT_TRACE5(( " move to (%.2f, %.2f)\n", 01528 v_start.x / 64.0, v_start.y / 64.0 )); 01529 error = func_interface->move_to( &v_start, user ); 01530 if ( error ) 01531 goto Exit; 01532 01533 while ( point < limit ) 01534 { 01535 point++; 01536 tags++; 01537 01538 tag = FT_CURVE_TAG( tags[0] ); 01539 switch ( tag ) 01540 { 01541 case FT_CURVE_TAG_ON: /* emit a single line_to */ 01542 { 01543 FT_Vector vec; 01544 01545 01546 vec.x = SCALED( point->x ); 01547 vec.y = SCALED( point->y ); 01548 01549 FT_TRACE5(( " line to (%.2f, %.2f)\n", 01550 vec.x / 64.0, vec.y / 64.0 )); 01551 error = func_interface->line_to( &vec, user ); 01552 if ( error ) 01553 goto Exit; 01554 continue; 01555 } 01556 01557 case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 01558 v_control.x = SCALED( point->x ); 01559 v_control.y = SCALED( point->y ); 01560 01561 Do_Conic: 01562 if ( point < limit ) 01563 { 01564 FT_Vector vec; 01565 FT_Vector v_middle; 01566 01567 01568 point++; 01569 tags++; 01570 tag = FT_CURVE_TAG( tags[0] ); 01571 01572 vec.x = SCALED( point->x ); 01573 vec.y = SCALED( point->y ); 01574 01575 if ( tag == FT_CURVE_TAG_ON ) 01576 { 01577 FT_TRACE5(( " conic to (%.2f, %.2f)" 01578 " with control (%.2f, %.2f)\n", 01579 vec.x / 64.0, vec.y / 64.0, 01580 v_control.x / 64.0, v_control.y / 64.0 )); 01581 error = func_interface->conic_to( &v_control, &vec, user ); 01582 if ( error ) 01583 goto Exit; 01584 continue; 01585 } 01586 01587 if ( tag != FT_CURVE_TAG_CONIC ) 01588 goto Invalid_Outline; 01589 01590 v_middle.x = ( v_control.x + vec.x ) / 2; 01591 v_middle.y = ( v_control.y + vec.y ) / 2; 01592 01593 FT_TRACE5(( " conic to (%.2f, %.2f)" 01594 " with control (%.2f, %.2f)\n", 01595 v_middle.x / 64.0, v_middle.y / 64.0, 01596 v_control.x / 64.0, v_control.y / 64.0 )); 01597 error = func_interface->conic_to( &v_control, &v_middle, user ); 01598 if ( error ) 01599 goto Exit; 01600 01601 v_control = vec; 01602 goto Do_Conic; 01603 } 01604 01605 FT_TRACE5(( " conic to (%.2f, %.2f)" 01606 " with control (%.2f, %.2f)\n", 01607 v_start.x / 64.0, v_start.y / 64.0, 01608 v_control.x / 64.0, v_control.y / 64.0 )); 01609 error = func_interface->conic_to( &v_control, &v_start, user ); 01610 goto Close; 01611 01612 default: /* FT_CURVE_TAG_CUBIC */ 01613 { 01614 FT_Vector vec1, vec2; 01615 01616 01617 if ( point + 1 > limit || 01618 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 01619 goto Invalid_Outline; 01620 01621 point += 2; 01622 tags += 2; 01623 01624 vec1.x = SCALED( point[-2].x ); 01625 vec1.y = SCALED( point[-2].y ); 01626 01627 vec2.x = SCALED( point[-1].x ); 01628 vec2.y = SCALED( point[-1].y ); 01629 01630 if ( point <= limit ) 01631 { 01632 FT_Vector vec; 01633 01634 01635 vec.x = SCALED( point->x ); 01636 vec.y = SCALED( point->y ); 01637 01638 FT_TRACE5(( " cubic to (%.2f, %.2f)" 01639 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 01640 vec.x / 64.0, vec.y / 64.0, 01641 vec1.x / 64.0, vec1.y / 64.0, 01642 vec2.x / 64.0, vec2.y / 64.0 )); 01643 error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); 01644 if ( error ) 01645 goto Exit; 01646 continue; 01647 } 01648 01649 FT_TRACE5(( " cubic to (%.2f, %.2f)" 01650 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", 01651 v_start.x / 64.0, v_start.y / 64.0, 01652 vec1.x / 64.0, vec1.y / 64.0, 01653 vec2.x / 64.0, vec2.y / 64.0 )); 01654 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); 01655 goto Close; 01656 } 01657 } 01658 } 01659 01660 /* close the contour with a line segment */ 01661 FT_TRACE5(( " line to (%.2f, %.2f)\n", 01662 v_start.x / 64.0, v_start.y / 64.0 )); 01663 error = func_interface->line_to( &v_start, user ); 01664 01665 Close: 01666 if ( error ) 01667 goto Exit; 01668 01669 first = last + 1; 01670 } 01671 01672 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); 01673 return 0; 01674 01675 Exit: 01676 FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error )); 01677 return error; 01678 01679 Invalid_Outline: 01680 return ErrRaster_Invalid_Outline; 01681 } 01682 01683 #endif /* _STANDALONE_ */ 01684 01685 01686 typedef struct TBand_ 01687 { 01688 TPos min, max; 01689 01690 } TBand; 01691 01692 FT_DEFINE_OUTLINE_FUNCS(func_interface, 01693 (FT_Outline_MoveTo_Func) gray_move_to, 01694 (FT_Outline_LineTo_Func) gray_line_to, 01695 (FT_Outline_ConicTo_Func)gray_conic_to, 01696 (FT_Outline_CubicTo_Func)gray_cubic_to, 01697 0, 01698 0 01699 ) 01700 01701 static int 01702 gray_convert_glyph_inner( RAS_ARG ) 01703 { 01704 01705 volatile int error = 0; 01706 01707 #ifdef FT_CONFIG_OPTION_PIC 01708 FT_Outline_Funcs func_interface; 01709 Init_Class_func_interface(&func_interface); 01710 #endif 01711 01712 if ( ft_setjmp( ras.jump_buffer ) == 0 ) 01713 { 01714 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); 01715 gray_record_cell( RAS_VAR ); 01716 } 01717 else 01718 error = ErrRaster_Memory_Overflow; 01719 01720 return error; 01721 } 01722 01723 01724 static int 01725 gray_convert_glyph( RAS_ARG ) 01726 { 01727 TBand bands[40]; 01728 TBand* volatile band; 01729 int volatile n, num_bands; 01730 TPos volatile min, max, max_y; 01731 FT_BBox* clip; 01732 01733 01734 /* Set up state in the raster object */ 01735 gray_compute_cbox( RAS_VAR ); 01736 01737 /* clip to target bitmap, exit if nothing to do */ 01738 clip = &ras.clip_box; 01739 01740 if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || 01741 ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) 01742 return 0; 01743 01744 if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; 01745 if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; 01746 01747 if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; 01748 if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; 01749 01750 ras.count_ex = ras.max_ex - ras.min_ex; 01751 ras.count_ey = ras.max_ey - ras.min_ey; 01752 01753 /* set up vertical bands */ 01754 num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); 01755 if ( num_bands == 0 ) 01756 num_bands = 1; 01757 if ( num_bands >= 39 ) 01758 num_bands = 39; 01759 01760 ras.band_shoot = 0; 01761 01762 min = ras.min_ey; 01763 max_y = ras.max_ey; 01764 01765 for ( n = 0; n < num_bands; n++, min = max ) 01766 { 01767 max = min + ras.band_size; 01768 if ( n == num_bands - 1 || max > max_y ) 01769 max = max_y; 01770 01771 bands[0].min = min; 01772 bands[0].max = max; 01773 band = bands; 01774 01775 while ( band >= bands ) 01776 { 01777 TPos bottom, top, middle; 01778 int error; 01779 01780 { 01781 PCell cells_max; 01782 int yindex; 01783 long cell_start, cell_end, cell_mod; 01784 01785 01786 ras.ycells = (PCell*)ras.buffer; 01787 ras.ycount = band->max - band->min; 01788 01789 cell_start = sizeof ( PCell ) * ras.ycount; 01790 cell_mod = cell_start % sizeof ( TCell ); 01791 if ( cell_mod > 0 ) 01792 cell_start += sizeof ( TCell ) - cell_mod; 01793 01794 cell_end = ras.buffer_size; 01795 cell_end -= cell_end % sizeof( TCell ); 01796 01797 cells_max = (PCell)( (char*)ras.buffer + cell_end ); 01798 ras.cells = (PCell)( (char*)ras.buffer + cell_start ); 01799 if ( ras.cells >= cells_max ) 01800 goto ReduceBands; 01801 01802 ras.max_cells = cells_max - ras.cells; 01803 if ( ras.max_cells < 2 ) 01804 goto ReduceBands; 01805 01806 for ( yindex = 0; yindex < ras.ycount; yindex++ ) 01807 ras.ycells[yindex] = NULL; 01808 } 01809 01810 ras.num_cells = 0; 01811 ras.invalid = 1; 01812 ras.min_ey = band->min; 01813 ras.max_ey = band->max; 01814 ras.count_ey = band->max - band->min; 01815 01816 error = gray_convert_glyph_inner( RAS_VAR ); 01817 01818 if ( !error ) 01819 { 01820 gray_sweep( RAS_VAR_ &ras.target ); 01821 band--; 01822 continue; 01823 } 01824 else if ( error != ErrRaster_Memory_Overflow ) 01825 return 1; 01826 01827 ReduceBands: 01828 /* render pool overflow; we will reduce the render band by half */ 01829 bottom = band->min; 01830 top = band->max; 01831 middle = bottom + ( ( top - bottom ) >> 1 ); 01832 01833 /* This is too complex for a single scanline; there must */ 01834 /* be some problems. */ 01835 if ( middle == bottom ) 01836 { 01837 #ifdef FT_DEBUG_LEVEL_TRACE 01838 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); 01839 #endif 01840 return 1; 01841 } 01842 01843 if ( bottom-top >= ras.band_size ) 01844 ras.band_shoot++; 01845 01846 band[1].min = bottom; 01847 band[1].max = middle; 01848 band[0].min = middle; 01849 band[0].max = top; 01850 band++; 01851 } 01852 } 01853 01854 if ( ras.band_shoot > 8 && ras.band_size > 16 ) 01855 ras.band_size = ras.band_size / 2; 01856 01857 return 0; 01858 } 01859 01860 01861 static int 01862 gray_raster_render( PRaster raster, 01863 const FT_Raster_Params* params ) 01864 { 01865 const FT_Outline* outline = (const FT_Outline*)params->source; 01866 const FT_Bitmap* target_map = params->target; 01867 PWorker worker; 01868 01869 01870 if ( !raster || !raster->buffer || !raster->buffer_size ) 01871 return ErrRaster_Invalid_Argument; 01872 01873 if ( !outline ) 01874 return ErrRaster_Invalid_Outline; 01875 01876 /* return immediately if the outline is empty */ 01877 if ( outline->n_points == 0 || outline->n_contours <= 0 ) 01878 return 0; 01879 01880 if ( !outline->contours || !outline->points ) 01881 return ErrRaster_Invalid_Outline; 01882 01883 if ( outline->n_points != 01884 outline->contours[outline->n_contours - 1] + 1 ) 01885 return ErrRaster_Invalid_Outline; 01886 01887 worker = raster->worker; 01888 01889 /* if direct mode is not set, we must have a target bitmap */ 01890 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) ) 01891 { 01892 if ( !target_map ) 01893 return ErrRaster_Invalid_Argument; 01894 01895 /* nothing to do */ 01896 if ( !target_map->width || !target_map->rows ) 01897 return 0; 01898 01899 if ( !target_map->buffer ) 01900 return ErrRaster_Invalid_Argument; 01901 } 01902 01903 /* this version does not support monochrome rendering */ 01904 if ( !( params->flags & FT_RASTER_FLAG_AA ) ) 01905 return ErrRaster_Invalid_Mode; 01906 01907 /* compute clipping box */ 01908 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) ) 01909 { 01910 /* compute clip box from target pixmap */ 01911 ras.clip_box.xMin = 0; 01912 ras.clip_box.yMin = 0; 01913 ras.clip_box.xMax = target_map->width; 01914 ras.clip_box.yMax = target_map->rows; 01915 } 01916 else if ( params->flags & FT_RASTER_FLAG_CLIP ) 01917 ras.clip_box = params->clip_box; 01918 else 01919 { 01920 ras.clip_box.xMin = -32768L; 01921 ras.clip_box.yMin = -32768L; 01922 ras.clip_box.xMax = 32767L; 01923 ras.clip_box.yMax = 32767L; 01924 } 01925 01926 gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size ); 01927 01928 ras.outline = *outline; 01929 ras.num_cells = 0; 01930 ras.invalid = 1; 01931 ras.band_size = raster->band_size; 01932 ras.num_gray_spans = 0; 01933 01934 if ( params->flags & FT_RASTER_FLAG_DIRECT ) 01935 { 01936 ras.render_span = (FT_Raster_Span_Func)params->gray_spans; 01937 ras.render_span_data = params->user; 01938 } 01939 else 01940 { 01941 ras.target = *target_map; 01942 ras.render_span = (FT_Raster_Span_Func)gray_render_span; 01943 ras.render_span_data = &ras; 01944 } 01945 01946 return gray_convert_glyph( RAS_VAR ); 01947 } 01948 01949 01950 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ 01951 /**** a static object. *****/ 01952 01953 #ifdef _STANDALONE_ 01954 01955 static int 01956 gray_raster_new( void* memory, 01957 FT_Raster* araster ) 01958 { 01959 static TRaster the_raster; 01960 01961 FT_UNUSED( memory ); 01962 01963 01964 *araster = (FT_Raster)&the_raster; 01965 FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); 01966 01967 return 0; 01968 } 01969 01970 01971 static void 01972 gray_raster_done( FT_Raster raster ) 01973 { 01974 /* nothing */ 01975 FT_UNUSED( raster ); 01976 } 01977 01978 #else /* !_STANDALONE_ */ 01979 01980 static int 01981 gray_raster_new( FT_Memory memory, 01982 FT_Raster* araster ) 01983 { 01984 FT_Error error; 01985 PRaster raster = NULL; 01986 01987 01988 *araster = 0; 01989 if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) ) 01990 { 01991 raster->memory = memory; 01992 *araster = (FT_Raster)raster; 01993 } 01994 01995 return error; 01996 } 01997 01998 01999 static void 02000 gray_raster_done( FT_Raster raster ) 02001 { 02002 FT_Memory memory = (FT_Memory)((PRaster)raster)->memory; 02003 02004 02005 FT_FREE( raster ); 02006 } 02007 02008 #endif /* !_STANDALONE_ */ 02009 02010 02011 static void 02012 gray_raster_reset( FT_Raster raster, 02013 char* pool_base, 02014 long pool_size ) 02015 { 02016 PRaster rast = (PRaster)raster; 02017 02018 02019 if ( raster ) 02020 { 02021 if ( pool_base && pool_size >= (long)sizeof ( TWorker ) + 2048 ) 02022 { 02023 PWorker worker = (PWorker)pool_base; 02024 02025 02026 rast->worker = worker; 02027 rast->buffer = pool_base + 02028 ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) & 02029 ~( sizeof ( TCell ) - 1 ) ); 02030 rast->buffer_size = (long)( ( pool_base + pool_size ) - 02031 (char*)rast->buffer ) & 02032 ~( sizeof ( TCell ) - 1 ); 02033 rast->band_size = (int)( rast->buffer_size / 02034 ( sizeof ( TCell ) * 8 ) ); 02035 } 02036 else 02037 { 02038 rast->buffer = NULL; 02039 rast->buffer_size = 0; 02040 rast->worker = NULL; 02041 } 02042 } 02043 } 02044 02045 02046 FT_DEFINE_RASTER_FUNCS(ft_grays_raster, 02047 FT_GLYPH_FORMAT_OUTLINE, 02048 02049 (FT_Raster_New_Func) gray_raster_new, 02050 (FT_Raster_Reset_Func) gray_raster_reset, 02051 (FT_Raster_Set_Mode_Func)0, 02052 (FT_Raster_Render_Func) gray_raster_render, 02053 (FT_Raster_Done_Func) gray_raster_done 02054 ) 02055 02056 02057 /* END */ 02058 02059 02060 /* Local Variables: */ 02061 /* coding: utf-8 */ 02062 /* End: */ Generated on Sun May 27 2012 04:34:02 for ReactOS by
1.7.6.1
|