ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ftgrays.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.