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