Advertisement
honey_the_codewitch

plutovg-rasterize

Oct 22nd, 2024
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 49.01 KB | None | 0 0
  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  ftgrays.c                                                              */
  4. /*                                                                         */
  5. /*    A new `perfect' anti-aliasing renderer (body).                       */
  6. /*                                                                         */
  7. /*  Copyright 2000-2003, 2005-2014 by                                      */
  8. /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
  9. /*                                                                         */
  10. /*  This file is part of the FreeType project, and may only be used,       */
  11. /*  modified, and distributed under the terms of the FreeType project      */
  12. /*  license, FTL.txt.  By continuing to use, modify, or distribute     */
  13. /*  this file you indicate that you have read the license and              */
  14. /*  understand and accept it fully.                                        */
  15. /*                                                                         */
  16. /***************************************************************************/
  17.  
  18. /*************************************************************************/
  19. /*                                                                       */
  20. /* This is a new anti-aliasing scan-converter for FreeType 2.  The       */
  21. /* algorithm used here is _very_ different from the one in the standard  */
  22. /* `ftraster' module.  Actually, `ftgrays' computes the _exact_          */
  23. /* coverage of the outline on each pixel cell.                           */
  24. /*                                                                       */
  25. /* It is based on ideas that I initially found in Raph Levien's          */
  26. /* excellent LibArt graphics library (see http://www.levien.com/libart   */
  27. /* for more information, though the web pages do not tell anything       */
  28. /* about the renderer; you'll have to dive into the source code to       */
  29. /* understand how it works).                                             */
  30. /*                                                                       */
  31. /* Note, however, that this is a _very_ different implementation         */
  32. /* compared to Raph's.  Coverage information is stored in a very         */
  33. /* different way, and I don't use sorted vector paths.  Also, it doesn't */
  34. /* use floating point values.                                            */
  35. /*                                                                       */
  36. /* This renderer has the following advantages:                           */
  37. /*                                                                       */
  38. /* - It doesn't need an intermediate bitmap.  Instead, one can supply a  */
  39. /*   callback function that will be called by the renderer to draw gray  */
  40. /*   spans on any target surface.  You can thus do direct composition on */
  41. /*   any kind of bitmap, provided that you give the renderer the right   */
  42. /*   callback.                                                           */
  43. /*                                                                       */
  44. /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on   */
  45. /*   each pixel cell.                                                    */
  46. /*                                                                       */
  47. /* - It performs a single pass on the outline (the `standard' FT2        */
  48. /*   renderer makes two passes).                                         */
  49. /*                                                                       */
  50. /* - It can easily be modified to render to _any_ number of gray levels  */
  51. /*   cheaply.                                                            */
  52. /*                                                                       */
  53. /* - For small (< 20) pixel sizes, it is faster than the standard        */
  54. /*   renderer.                                                           */
  55. /*                                                                       */
  56. /*************************************************************************/
  57.  
  58. #include "plutovg-ft-raster.h"
  59. #include "plutovg-ft-math.h"
  60.  
  61. #define PVG_FT_BEGIN_STMNT  do {
  62. #define PVG_FT_END_STMNT    } while ( 0 )
  63.  
  64. #include <setjmp.h>
  65.  
  66. #define pvg_ft_setjmp   setjmp
  67. #define pvg_ft_longjmp  longjmp
  68. #define pvg_ft_jmp_buf  jmp_buf
  69.  
  70. #include <stddef.h>
  71.  
  72. typedef ptrdiff_t  PVG_FT_PtrDist;
  73.  
  74. #define ErrRaster_Invalid_Mode      -2
  75. #define ErrRaster_Invalid_Outline   -1
  76. #define ErrRaster_Invalid_Argument  -3
  77. #define ErrRaster_Memory_Overflow   -4
  78. #define ErrRaster_OutOfMemory       -6
  79.  
  80. #include <stdlib.h>
  81. #include <limits.h>
  82.  
  83. #define PVG_FT_MINIMUM_POOL_SIZE 8192
  84.  
  85. #define RAS_ARG   PWorker  worker
  86. #define RAS_ARG_  PWorker  worker,
  87.  
  88. #define RAS_VAR   worker
  89. #define RAS_VAR_  worker,
  90.  
  91. #define ras       (*worker)
  92.  
  93.   /* must be at least 6 bits! */
  94. #define PIXEL_BITS  8
  95.  
  96. #define ONE_PIXEL       ( 1L << PIXEL_BITS )
  97. #define TRUNC( x )      (TCoord)( (x) >> PIXEL_BITS )
  98. #define FRACT( x )      (TCoord)( (x) & ( ONE_PIXEL - 1 ) )
  99.  
  100. #if PIXEL_BITS >= 6
  101. #define UPSCALE( x )    ( (x) * ( ONE_PIXEL >> 6 ) )
  102. #define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
  103. #else
  104. #define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
  105. #define DOWNSCALE( x )  ( (x) * ( 64 >> PIXEL_BITS ) )
  106. #endif
  107.  
  108. /* Compute `dividend / divisor' and return both its quotient and     */
  109. /* remainder, cast to a specific type.  This macro also ensures that */
  110. /* the remainder is always positive.                                 */
  111. #define PVG_FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
  112. PVG_FT_BEGIN_STMNT                                                   \
  113.   (quotient)  = (type)( (dividend) / (divisor) );                \
  114.   (remainder) = (type)( (dividend) % (divisor) );                \
  115.   if ( (remainder) < 0 )                                         \
  116.   {                                                              \
  117.     (quotient)--;                                                \
  118.     (remainder) += (type)(divisor);                              \
  119.   }                                                              \
  120. PVG_FT_END_STMNT
  121.  
  122.   /* These macros speed up repetitive divisions by replacing them */
  123.   /* with multiplications and right shifts.                       */
  124. #define PVG_FT_UDIVPREP( b )                                       \
  125.   long  b ## _r = (long)( ULONG_MAX >> PIXEL_BITS ) / ( b )
  126. #define PVG_FT_UDIV( a, b )                                        \
  127.   ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >>   \
  128.     ( sizeof( long ) * CHAR_BIT - PIXEL_BITS ) )
  129.  
  130.  
  131.   /*************************************************************************/
  132.   /*                                                                       */
  133.   /*   TYPE DEFINITIONS                                                    */
  134.   /*                                                                       */
  135.  
  136.   /* don't change the following types to PVG_FT_Int or PVG_FT_Pos, since we might */
  137.   /* need to define them to "float" or "double" when experimenting with   */
  138.   /* new algorithms                                                       */
  139.  
  140.   typedef long   TCoord;   /* integer scanline/pixel coordinate */
  141.   typedef long   TPos;     /* sub-pixel coordinate              */
  142.   typedef long   TArea ;   /* cell areas, coordinate products   */
  143.  
  144.   /* maximal number of gray spans in a call to the span callback */
  145. #define PVG_FT_MAX_GRAY_SPANS  256
  146.  
  147.  
  148.   typedef struct TCell_*  PCell;
  149.  
  150.   typedef struct  TCell_
  151.   {
  152.     int    x;
  153.     int    cover;
  154.     TArea  area;
  155.     PCell  next;
  156.  
  157.   } TCell;
  158.  
  159.  
  160.   typedef struct  TWorker_
  161.   {
  162.     TCoord  ex, ey;
  163.     TPos    min_ex, max_ex;
  164.     TPos    min_ey, max_ey;
  165.     TPos    count_ex, count_ey;
  166.  
  167.     TArea   area;
  168.     int     cover;
  169.     int     invalid;
  170.  
  171.     PCell   cells;
  172.     PVG_FT_PtrDist     max_cells;
  173.     PVG_FT_PtrDist     num_cells;
  174.  
  175.     TPos    x,  y;
  176.  
  177.     PVG_FT_Outline  outline;
  178.     PVG_FT_BBox     clip_box;
  179.  
  180.     PVG_FT_Span     gray_spans[PVG_FT_MAX_GRAY_SPANS];
  181.     int         num_gray_spans;
  182.     int         skip_spans;
  183.  
  184.     PVG_FT_Raster_Span_Func  render_span;
  185.     void*                render_span_data;
  186.  
  187.     int  band_size;
  188.     int  band_shoot;
  189.     pvg_ft_jmp_buf  jump_buffer;
  190.     void*       buffer;
  191.     long        buffer_size;
  192.  
  193.     PCell*     ycells;
  194.     TPos       ycount;
  195.   } TWorker, *PWorker;
  196.  
  197.  
  198.   /*************************************************************************/
  199.   /*                                                                       */
  200.   /* Initialize the cells table.                                           */
  201.   /*                                                                       */
  202.   static void
  203.   gray_init_cells( RAS_ARG_ void*  buffer,
  204.                             long   byte_size )
  205.   {
  206.     ras.buffer      = buffer;
  207.     ras.buffer_size = byte_size;
  208.  
  209.     ras.ycells      = (PCell*) buffer;
  210.     ras.cells       = NULL;
  211.     ras.max_cells   = 0;
  212.     ras.num_cells   = 0;
  213.     ras.area        = 0;
  214.     ras.cover       = 0;
  215.     ras.invalid     = 1;
  216.   }
  217.  
  218.  
  219.   /*************************************************************************/
  220.   /*                                                                       */
  221.   /* Compute the outline bounding box.                                     */
  222.   /*                                                                       */
  223.   static void
  224.   gray_compute_cbox( RAS_ARG )
  225.   {
  226.     PVG_FT_Outline*  outline = &ras.outline;
  227.     vector_t*   vec     = outline->points;
  228.     vector_t*   limit   = vec + outline->n_points;
  229.  
  230.  
  231.     if ( outline->n_points <= 0 )
  232.     {
  233.       ras.min_ex = ras.max_ex = 0;
  234.       ras.min_ey = ras.max_ey = 0;
  235.       return;
  236.     }
  237.  
  238.     ras.min_ex = ras.max_ex = vec->x;
  239.     ras.min_ey = ras.max_ey = vec->y;
  240.  
  241.     vec++;
  242.  
  243.     for ( ; vec < limit; vec++ )
  244.     {
  245.       TPos  x = vec->x;
  246.       TPos  y = vec->y;
  247.  
  248.  
  249.       if ( x < ras.min_ex ) ras.min_ex = x;
  250.       if ( x > ras.max_ex ) ras.max_ex = x;
  251.       if ( y < ras.min_ey ) ras.min_ey = y;
  252.       if ( y > ras.max_ey ) ras.max_ey = y;
  253.     }
  254.  
  255.     /* truncate the bounding box to integer pixels */
  256.     ras.min_ex = ras.min_ex >> 6;
  257.     ras.min_ey = ras.min_ey >> 6;
  258.     ras.max_ex = ( ras.max_ex + 63 ) >> 6;
  259.     ras.max_ey = ( ras.max_ey + 63 ) >> 6;
  260.   }
  261.  
  262.  
  263.   /*************************************************************************/
  264.   /*                                                                       */
  265.   /* Record the current cell in the table.                                 */
  266.   /*                                                                       */
  267.   static PCell
  268.   gray_find_cell( RAS_ARG )
  269.   {
  270.     PCell  *pcell, cell;
  271.     TPos    x = ras.ex;
  272.  
  273.  
  274.     if ( x > ras.count_ex )
  275.       x = ras.count_ex;
  276.  
  277.     pcell = &ras.ycells[ras.ey];
  278.     for (;;)
  279.     {
  280.       cell = *pcell;
  281.       if ( cell == NULL || cell->x > x )
  282.         break;
  283.  
  284.       if ( cell->x == x )
  285.         goto Exit;
  286.  
  287.       pcell = &cell->next;
  288.     }
  289.  
  290.     if ( ras.num_cells >= ras.max_cells ) {
  291.         pvg_ft_longjmp( ras.jump_buffer, 1 );
  292.     }
  293.  
  294.     cell        = ras.cells + ras.num_cells++;
  295.     cell->x     = x;
  296.     cell->area  = 0;
  297.     cell->cover = 0;
  298.  
  299.     cell->next  = *pcell;
  300.     *pcell      = cell;
  301.  
  302.   Exit:
  303.     return cell;
  304.   }
  305.  
  306.  
  307.   static void
  308.   gray_record_cell( RAS_ARG )
  309.   {
  310.     if ( ras.area | ras.cover )
  311.     {
  312.       PCell  cell = gray_find_cell( RAS_VAR );
  313.       if(cell==NULL) {
  314.         return;
  315.       }
  316.  
  317.       cell->area  += ras.area;
  318.       cell->cover += ras.cover;
  319.     }
  320.   }
  321.  
  322.  
  323.   /*************************************************************************/
  324.   /*                                                                       */
  325.   /* Set the current cell to a new position.                               */
  326.   /*                                                                       */
  327.   static void
  328.   gray_set_cell( RAS_ARG_ TCoord  ex,
  329.                           TCoord  ey )
  330.   {
  331.     /* Move the cell pointer to a new position.  We set the `invalid'      */
  332.     /* flag to indicate that the cell isn't part of those we're interested */
  333.     /* in during the render phase.  This means that:                       */
  334.     /*                                                                     */
  335.     /* . the new vertical position must be within min_ey..max_ey-1.        */
  336.     /* . the new horizontal position must be strictly less than max_ex     */
  337.     /*                                                                     */
  338.     /* Note that if a cell is to the left of the clipping region, it is    */
  339.     /* actually set to the (min_ex-1) horizontal position.                 */
  340.  
  341.     /* All cells that are on the left of the clipping region go to the */
  342.     /* min_ex - 1 horizontal position.                                 */
  343.     ey -= ras.min_ey;
  344.  
  345.     if ( ex > ras.max_ex )
  346.       ex = ras.max_ex;
  347.  
  348.     ex -= ras.min_ex;
  349.     if ( ex < 0 )
  350.       ex = -1;
  351.  
  352.     /* are we moving to a different cell ? */
  353.     if ( ex != ras.ex || ey != ras.ey )
  354.     {
  355.       /* record the current one if it is valid */
  356.       if ( !ras.invalid )
  357.         gray_record_cell( RAS_VAR );
  358.  
  359.       ras.area  = 0;
  360.       ras.cover = 0;
  361.       ras.ex    = ex;
  362.       ras.ey    = ey;
  363.     }
  364.  
  365.     ras.invalid = ( (unsigned int)ey >= (unsigned int)ras.count_ey ||
  366.                                   ex >= ras.count_ex           );
  367.   }
  368.  
  369.  
  370.   /*************************************************************************/
  371.   /*                                                                       */
  372.   /* Start a new contour at a given cell.                                  */
  373.   /*                                                                       */
  374.   static void
  375.   gray_start_cell( RAS_ARG_ TCoord  ex,
  376.                             TCoord  ey )
  377.   {
  378.     if ( ex > ras.max_ex )
  379.       ex = (TCoord)( ras.max_ex );
  380.  
  381.     if ( ex < ras.min_ex )
  382.       ex = (TCoord)( ras.min_ex - 1 );
  383.  
  384.     ras.area    = 0;
  385.     ras.cover   = 0;
  386.     ras.ex      = ex - ras.min_ex;
  387.     ras.ey      = ey - ras.min_ey;
  388.     ras.invalid = 0;
  389.  
  390.     gray_set_cell( RAS_VAR_ ex, ey );
  391.   }
  392.  
  393. // The new render-line implementation is not yet used
  394. #if 1
  395.  
  396.   /*************************************************************************/
  397.   /*                                                                       */
  398.   /* Render a scanline as one or more cells.                               */
  399.   /*                                                                       */
  400.   static void
  401.   gray_render_scanline( RAS_ARG_ TCoord  ey,
  402.                                  TPos    x1,
  403.                                  TCoord  y1,
  404.                                  TPos    x2,
  405.                                  TCoord  y2 )
  406.   {
  407.     TCoord  ex1, ex2, fx1, fx2, first, dy, delta, mod;
  408.     TPos    p, dx;
  409.     int     incr;
  410.  
  411.  
  412.     ex1 = TRUNC( x1 );
  413.     ex2 = TRUNC( x2 );
  414.  
  415.     /* trivial case.  Happens often */
  416.     if ( y1 == y2 )
  417.     {
  418.       gray_set_cell( RAS_VAR_ ex2, ey );
  419.       return;
  420.     }
  421.  
  422.     fx1   = FRACT( x1 );
  423.     fx2   = FRACT( x2 );
  424.  
  425.     /* everything is located in a single cell.  That is easy! */
  426.     /*                                                        */
  427.     if ( ex1 == ex2 )
  428.       goto End;
  429.  
  430.     /* ok, we'll have to render a run of adjacent cells on the same */
  431.     /* scanline...                                                  */
  432.     /*                                                              */
  433.     dx = x2 - x1;
  434.     dy = y2 - y1;
  435.  
  436.     if ( dx > 0 )
  437.     {
  438.       p     = ( ONE_PIXEL - fx1 ) * dy;
  439.       first = ONE_PIXEL;
  440.       incr  = 1;
  441.     } else {
  442.       p     = fx1 * dy;
  443.       first = 0;
  444.       incr  = -1;
  445.       dx    = -dx;
  446.     }
  447.  
  448.     PVG_FT_DIV_MOD( TCoord, p, dx, delta, mod );
  449.  
  450.     ras.area  += (TArea)( fx1 + first ) * delta;
  451.     ras.cover += delta;
  452.     y1        += delta;
  453.     ex1       += incr;
  454.     gray_set_cell( RAS_VAR_ ex1, ey );
  455.  
  456.     if ( ex1 != ex2 )
  457.     {
  458.       TCoord  lift, rem;
  459.  
  460.  
  461.       p = ONE_PIXEL * dy;
  462.       PVG_FT_DIV_MOD( TCoord, p, dx, lift, rem );
  463.  
  464.       do
  465.       {
  466.         delta = lift;
  467.         mod  += rem;
  468.         if ( mod >= (TCoord)dx )
  469.         {
  470.           mod -= (TCoord)dx;
  471.           delta++;
  472.         }
  473.  
  474.         ras.area  += (TArea)( ONE_PIXEL * delta );
  475.         ras.cover += delta;
  476.         y1        += delta;
  477.         ex1       += incr;
  478.         gray_set_cell( RAS_VAR_ ex1, ey );
  479.       } while ( ex1 != ex2 );
  480.     }
  481.     fx1 = ONE_PIXEL - first;
  482.  
  483.   End:
  484.     dy = y2 - y1;
  485.  
  486.     ras.area  += (TArea)( ( fx1 + fx2 ) * dy );
  487.     ras.cover += dy;
  488.   }
  489.  
  490.  
  491.   /*************************************************************************/
  492.   /*                                                                       */
  493.   /* Render a given line as a series of scanlines.                         */
  494.   /*                                                                       */
  495.   static void
  496.   gray_render_line( RAS_ARG_ TPos  to_x,
  497.                              TPos  to_y )
  498.   {
  499.     TCoord  ey1, ey2, fy1, fy2, first, delta, mod;
  500.     TPos    p, dx, dy, x, x2;
  501.     int     incr;
  502.  
  503.     ey1 = TRUNC( ras.y );
  504.     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
  505.  
  506.     /* perform vertical clipping */
  507.     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
  508.          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
  509.       goto End;
  510.  
  511.     fy1 = FRACT( ras.y );
  512.     fy2 = FRACT( to_y );
  513.  
  514.     /* everything is on a single scanline */
  515.     if ( ey1 == ey2 )
  516.     {
  517.       gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
  518.       goto End;
  519.     }
  520.  
  521.     dx = to_x - ras.x;
  522.     dy = to_y - ras.y;
  523.  
  524.     /* vertical line - avoid calling gray_render_scanline */
  525.     if ( dx == 0 )
  526.     {
  527.       TCoord  ex     = TRUNC( ras.x );
  528.       TCoord  two_fx = FRACT( ras.x ) << 1;
  529.       TPos    area, max_ey1;
  530.  
  531.  
  532.       if ( dy > 0)
  533.       {
  534.         first = ONE_PIXEL;
  535.       }
  536.       else
  537.       {
  538.         first = 0;
  539.       }
  540.  
  541.       delta      = first - fy1;
  542.       ras.area  += (TArea)two_fx * delta;
  543.       ras.cover += delta;
  544.  
  545.       delta = first + first - ONE_PIXEL;
  546.       area  = (TArea)two_fx * delta;
  547.       max_ey1 = ras.count_ey + ras.min_ey;
  548.       if (dy < 0) {
  549.         if (ey1 > max_ey1) {
  550.           ey1 = (max_ey1 > ey2) ? max_ey1 : ey2;
  551.           gray_set_cell( &ras, ex, ey1 );
  552.         } else {
  553.           ey1--;
  554.           gray_set_cell( &ras, ex, ey1 );
  555.         }
  556.         while ( ey1 > ey2 && ey1 >= ras.min_ey)
  557.         {
  558.           ras.area  += area;
  559.           ras.cover += delta;
  560.           ey1--;
  561.  
  562.           gray_set_cell( &ras, ex, ey1 );
  563.         }
  564.         if (ey1 != ey2) {
  565.           ey1 = ey2;
  566.           gray_set_cell( &ras, ex, ey1 );
  567.         }
  568.       } else {
  569.         if (ey1 < ras.min_ey) {
  570.           ey1 = (ras.min_ey < ey2) ? ras.min_ey : ey2;
  571.           gray_set_cell( &ras, ex, ey1 );
  572.         } else {
  573.           ey1++;
  574.           gray_set_cell( &ras, ex, ey1 );
  575.         }
  576.         while ( ey1 < ey2 && ey1 < max_ey1)
  577.         {
  578.           ras.area  += area;
  579.           ras.cover += delta;
  580.           ey1++;
  581.  
  582.           gray_set_cell( &ras, ex, ey1 );
  583.         }
  584.         if (ey1 != ey2) {
  585.           ey1 = ey2;
  586.           gray_set_cell( &ras, ex, ey1 );
  587.         }
  588.       }
  589.  
  590.       delta      = (int)( fy2 - ONE_PIXEL + first );
  591.       ras.area  += (TArea)two_fx * delta;
  592.       ras.cover += delta;
  593.  
  594.       goto End;
  595.     }
  596.  
  597.     /* ok, we have to render several scanlines */
  598.     if ( dy > 0)
  599.     {
  600.       p     = ( ONE_PIXEL - fy1 ) * dx;
  601.       first = ONE_PIXEL;
  602.       incr  = 1;
  603.     }
  604.     else
  605.     {
  606.       p     = fy1 * dx;
  607.       first = 0;
  608.       incr  = -1;
  609.       dy    = -dy;
  610.     }
  611.  
  612.     /* the fractional part of x-delta is mod/dy. It is essential to */
  613.     /* keep track of its accumulation for accurate rendering.       */
  614.     PVG_FT_DIV_MOD( TCoord, p, dy, delta, mod );
  615.  
  616.     x = ras.x + delta;
  617.     gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
  618.  
  619.     ey1 += incr;
  620.     gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
  621.  
  622.     if ( ey1 != ey2 )
  623.     {
  624.       TCoord  lift, rem;
  625.  
  626.  
  627.       p    = ONE_PIXEL * dx;
  628.       PVG_FT_DIV_MOD( TCoord, p, dy, lift, rem );
  629.  
  630.       do
  631.       {
  632.         delta = lift;
  633.         mod  += rem;
  634.         if ( mod >= (TCoord)dy )
  635.         {
  636.           mod -= (TCoord)dy;
  637.           delta++;
  638.         }
  639.  
  640.         x2 = x + delta;
  641.         gray_render_scanline( RAS_VAR_ ey1,
  642.                                        x, ONE_PIXEL - first,
  643.                                        x2, first );
  644.         x = x2;
  645.  
  646.         ey1 += incr;
  647.         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
  648.       } while ( ey1 != ey2 );
  649.     }
  650.  
  651.     gray_render_scanline( RAS_VAR_ ey1,
  652.                                    x, ONE_PIXEL - first,
  653.                                    to_x, fy2 );
  654.  
  655.   End:
  656.     ras.x       = to_x;
  657.     ras.y       = to_y;
  658.   }
  659.  
  660.  
  661. #else
  662.  
  663.   /*************************************************************************/
  664.   /*                                                                       */
  665.   /* Render a straight line across multiple cells in any direction.        */
  666.   /*                                                                       */
  667.   static void
  668.   gray_render_line( RAS_ARG_ TPos  to_x,
  669.                              TPos  to_y )
  670.   {
  671.     TPos    dx, dy, fx1, fy1, fx2, fy2;
  672.     TCoord  ex1, ex2, ey1, ey2;
  673.  
  674.  
  675.     ex1 = TRUNC( ras.x );
  676.     ex2 = TRUNC( to_x );
  677.     ey1 = TRUNC( ras.y );
  678.     ey2 = TRUNC( to_y );
  679.  
  680.     /* perform vertical clipping */
  681.     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
  682.          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
  683.       goto End;
  684.  
  685.     dx = to_x - ras.x;
  686.     dy = to_y - ras.y;
  687.  
  688.     fx1 = FRACT( ras.x );
  689.     fy1 = FRACT( ras.y );
  690.  
  691.     if ( ex1 == ex2 && ey1 == ey2 )       /* inside one cell */
  692.       ;
  693.     else if ( dy == 0 ) /* ex1 != ex2 */  /* any horizontal line */
  694.     {
  695.       ex1 = ex2;
  696.       gray_set_cell( RAS_VAR_ ex1, ey1 );
  697.     }
  698.     else if ( dx == 0 )
  699.     {
  700.       if ( dy > 0 )                       /* vertical line up */
  701.         do
  702.         {
  703.           fy2 = ONE_PIXEL;
  704.           ras.cover += ( fy2 - fy1 );
  705.           ras.area  += ( fy2 - fy1 ) * fx1 * 2;
  706.           fy1 = 0;
  707.           ey1++;
  708.           gray_set_cell( RAS_VAR_ ex1, ey1 );
  709.         } while ( ey1 != ey2 );
  710.       else                                /* vertical line down */
  711.         do
  712.         {
  713.           fy2 = 0;
  714.           ras.cover += ( fy2 - fy1 );
  715.           ras.area  += ( fy2 - fy1 ) * fx1 * 2;
  716.           fy1 = ONE_PIXEL;
  717.           ey1--;
  718.           gray_set_cell( RAS_VAR_ ex1, ey1 );
  719.         } while ( ey1 != ey2 );
  720.     }
  721.     else                                  /* any other line */
  722.     {
  723.       TArea  prod = dx * fy1 - dy * fx1;
  724.       PVG_FT_UDIVPREP( dx );
  725.       PVG_FT_UDIVPREP( dy );
  726.  
  727.  
  728.       /* The fundamental value `prod' determines which side and the  */
  729.       /* exact coordinate where the line exits current cell.  It is  */
  730.       /* also easily updated when moving from one cell to the next.  */
  731.       do
  732.       {
  733.         if      ( prod                                   <= 0 &&
  734.                   prod - dx * ONE_PIXEL                  >  0 ) /* left */
  735.         {
  736.           fx2 = 0;
  737.           fy2 = (TPos)PVG_FT_UDIV( -prod, -dx );
  738.           prod -= dy * ONE_PIXEL;
  739.           ras.cover += ( fy2 - fy1 );
  740.           ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
  741.           fx1 = ONE_PIXEL;
  742.           fy1 = fy2;
  743.           ex1--;
  744.         }
  745.         else if ( prod - dx * ONE_PIXEL                  <= 0 &&
  746.                   prod - dx * ONE_PIXEL + dy * ONE_PIXEL >  0 ) /* up */
  747.         {
  748.           prod -= dx * ONE_PIXEL;
  749.           fx2 = (TPos)PVG_FT_UDIV( -prod, dy );
  750.           fy2 = ONE_PIXEL;
  751.           ras.cover += ( fy2 - fy1 );
  752.           ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
  753.           fx1 = fx2;
  754.           fy1 = 0;
  755.           ey1++;
  756.         }
  757.         else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
  758.                   prod                  + dy * ONE_PIXEL >= 0 ) /* right */
  759.         {
  760.           prod += dy * ONE_PIXEL;
  761.           fx2 = ONE_PIXEL;
  762.           fy2 = (TPos)PVG_FT_UDIV( prod, dx );
  763.           ras.cover += ( fy2 - fy1 );
  764.           ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
  765.           fx1 = 0;
  766.           fy1 = fy2;
  767.           ex1++;
  768.         }
  769.         else /* ( prod                  + dy * ONE_PIXEL <  0 &&
  770.                   prod                                   >  0 )    down */
  771.         {
  772.           fx2 = (TPos)PVG_FT_UDIV( prod, -dy );
  773.           fy2 = 0;
  774.           prod += dx * ONE_PIXEL;
  775.           ras.cover += ( fy2 - fy1 );
  776.           ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
  777.           fx1 = fx2;
  778.           fy1 = ONE_PIXEL;
  779.           ey1--;
  780.         }
  781.  
  782.         gray_set_cell( RAS_VAR_ ex1, ey1 );
  783.       } while ( ex1 != ex2 || ey1 != ey2 );
  784.     }
  785.  
  786.     fx2 = FRACT( to_x );
  787.     fy2 = FRACT( to_y );
  788.  
  789.     ras.cover += ( fy2 - fy1 );
  790.     ras.area  += ( fy2 - fy1 ) * ( fx1 + fx2 );
  791.  
  792.   End:
  793.     ras.x       = to_x;
  794.     ras.y       = to_y;
  795.   }
  796.  
  797. #endif
  798.  
  799.   static void
  800.   gray_split_conic( vector_t*  base )
  801.   {
  802.     TPos  a, b;
  803.  
  804.  
  805.     base[4].x = base[2].x;
  806.     b = base[1].x;
  807.     a = base[3].x = ( base[2].x + b ) / 2;
  808.     b = base[1].x = ( base[0].x + b ) / 2;
  809.     base[2].x = ( a + b ) / 2;
  810.  
  811.     base[4].y = base[2].y;
  812.     b = base[1].y;
  813.     a = base[3].y = ( base[2].y + b ) / 2;
  814.     b = base[1].y = ( base[0].y + b ) / 2;
  815.     base[2].y = ( a + b ) / 2;
  816.   }
  817.  
  818.  
  819.   static void
  820.   gray_render_conic( RAS_ARG_ const vector_t*  control,
  821.                               const vector_t*  to )
  822.   {
  823.     vector_t   bez_stack[16 * 2 + 1];  /* enough to accommodate bisections */
  824.     vector_t*  arc = bez_stack;
  825.     TPos        dx, dy;
  826.     int         draw, split;
  827.  
  828.  
  829.     arc[0].x = UPSCALE( to->x );
  830.     arc[0].y = UPSCALE( to->y );
  831.     arc[1].x = UPSCALE( control->x );
  832.     arc[1].y = UPSCALE( control->y );
  833.     arc[2].x = ras.x;
  834.     arc[2].y = ras.y;
  835.  
  836.     /* short-cut the arc that crosses the current band */
  837.     if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
  838.            TRUNC( arc[1].y ) >= ras.max_ey &&
  839.            TRUNC( arc[2].y ) >= ras.max_ey ) ||
  840.          ( TRUNC( arc[0].y ) <  ras.min_ey &&
  841.            TRUNC( arc[1].y ) <  ras.min_ey &&
  842.            TRUNC( arc[2].y ) <  ras.min_ey ) )
  843.     {
  844.       ras.x = arc[0].x;
  845.       ras.y = arc[0].y;
  846.       return;
  847.     }
  848.  
  849.     dx = PVG_FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
  850.     dy = PVG_FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
  851.     if ( dx < dy )
  852.       dx = dy;
  853.  
  854.     /* We can calculate the number of necessary bisections because  */
  855.     /* each bisection predictably reduces deviation exactly 4-fold. */
  856.     /* Even 32-bit deviation would vanish after 16 bisections.      */
  857.     draw = 1;
  858.     while ( dx > ONE_PIXEL / 4 )
  859.     {
  860.       dx >>= 2;
  861.       draw <<= 1;
  862.     }
  863.  
  864.     /* We use decrement counter to count the total number of segments */
  865.     /* to draw starting from 2^level. Before each draw we split as    */
  866.     /* many times as there are trailing zeros in the counter.         */
  867.     do
  868.     {
  869.       split = 1;
  870.       while ( ( draw & split ) == 0 )
  871.       {
  872.         gray_split_conic( arc );
  873.         arc += 2;
  874.         split <<= 1;
  875.       }
  876.  
  877.       gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
  878.       arc -= 2;
  879.  
  880.     } while ( --draw );
  881.   }
  882.  
  883.  
  884.   static void
  885.   gray_split_cubic( vector_t*  base )
  886.   {
  887.     TPos  a, b, c, d;
  888.  
  889.  
  890.     base[6].x = base[3].x;
  891.     c = base[1].x;
  892.     d = base[2].x;
  893.     base[1].x = a = ( base[0].x + c ) / 2;
  894.     base[5].x = b = ( base[3].x + d ) / 2;
  895.     c = ( c + d ) / 2;
  896.     base[2].x = a = ( a + c ) / 2;
  897.     base[4].x = b = ( b + c ) / 2;
  898.     base[3].x = ( a + b ) / 2;
  899.  
  900.     base[6].y = base[3].y;
  901.     c = base[1].y;
  902.     d = base[2].y;
  903.     base[1].y = a = ( base[0].y + c ) / 2;
  904.     base[5].y = b = ( base[3].y + d ) / 2;
  905.     c = ( c + d ) / 2;
  906.     base[2].y = a = ( a + c ) / 2;
  907.     base[4].y = b = ( b + c ) / 2;
  908.     base[3].y = ( a + b ) / 2;
  909.   }
  910.  
  911.  
  912.   static void
  913.   gray_render_cubic( RAS_ARG_ const vector_t*  control1,
  914.                               const vector_t*  control2,
  915.                               const vector_t*  to )
  916.   {
  917.     vector_t   bez_stack[16 * 3 + 1];  /* enough to accommodate bisections */
  918.     vector_t*  arc = bez_stack;
  919.     vector_t*  limit = bez_stack + 45;
  920.     TPos        dx, dy, dx_, dy_;
  921.     TPos        dx1, dy1, dx2, dy2;
  922.     TPos        L, s, s_limit;
  923.  
  924.  
  925.     arc[0].x = UPSCALE( to->x );
  926.     arc[0].y = UPSCALE( to->y );
  927.     arc[1].x = UPSCALE( control2->x );
  928.     arc[1].y = UPSCALE( control2->y );
  929.     arc[2].x = UPSCALE( control1->x );
  930.     arc[2].y = UPSCALE( control1->y );
  931.     arc[3].x = ras.x;
  932.     arc[3].y = ras.y;
  933.  
  934.     /* short-cut the arc that crosses the current band */
  935.     if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
  936.            TRUNC( arc[1].y ) >= ras.max_ey &&
  937.            TRUNC( arc[2].y ) >= ras.max_ey &&
  938.            TRUNC( arc[3].y ) >= ras.max_ey ) ||
  939.          ( TRUNC( arc[0].y ) <  ras.min_ey &&
  940.            TRUNC( arc[1].y ) <  ras.min_ey &&
  941.            TRUNC( arc[2].y ) <  ras.min_ey &&
  942.            TRUNC( arc[3].y ) <  ras.min_ey ) )
  943.     {
  944.       ras.x = arc[0].x;
  945.       ras.y = arc[0].y;
  946.       return;
  947.     }
  948.  
  949.     for (;;)
  950.     {
  951.       /* Decide whether to split or draw. See `Rapid Termination          */
  952.       /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
  953.       /* F. Hain, at                                                      */
  954.       /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
  955.  
  956.  
  957.       /* dx and dy are x and y components of the P0-P3 chord vector. */
  958.       dx = dx_ = arc[3].x - arc[0].x;
  959.       dy = dy_ = arc[3].y - arc[0].y;
  960.  
  961.       L = PVG_FT_HYPOT( dx_, dy_ );
  962.  
  963.       /* Avoid possible arithmetic overflow below by splitting. */
  964.       if ( L >= (1 << 23) )
  965.         goto Split;
  966.  
  967.       /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
  968.       s_limit = L * (TPos)( ONE_PIXEL / 6 );
  969.  
  970.       /* s is L * the perpendicular distance from P1 to the line P0-P3. */
  971.       dx1 = arc[1].x - arc[0].x;
  972.       dy1 = arc[1].y - arc[0].y;
  973.       s = PVG_FT_ABS( dy * dx1 - dx * dy1 );
  974.  
  975.       if ( s > s_limit )
  976.         goto Split;
  977.  
  978.       /* s is L * the perpendicular distance from P2 to the line P0-P3. */
  979.       dx2 = arc[2].x - arc[0].x;
  980.       dy2 = arc[2].y - arc[0].y;
  981.       s = PVG_FT_ABS( dy * dx2 - dx * dy2 );
  982.  
  983.       if ( s > s_limit )
  984.         goto Split;
  985.  
  986.       /* Split super curvy segments where the off points are so far
  987.          from the chord that the angles P0-P1-P3 or P0-P2-P3 become
  988.          acute as detected by appropriate dot products. */
  989.       if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 ||
  990.            dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 )
  991.         goto Split;
  992.  
  993.       gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
  994.  
  995.       if ( arc == bez_stack )
  996.         return;
  997.  
  998.       arc -= 3;
  999.       continue;
  1000.  
  1001.     Split:
  1002.       if( arc == limit )
  1003.         return;
  1004.       gray_split_cubic( arc );
  1005.       arc += 3;
  1006.     }
  1007.   }
  1008.  
  1009.  
  1010.  
  1011.   static int
  1012.   gray_move_to( const vector_t*  to,
  1013.                 PWorker           worker )
  1014.   {
  1015.     TPos  x, y;
  1016.  
  1017.  
  1018.     /* record current cell, if any */
  1019.     if ( !ras.invalid )
  1020.       gray_record_cell( worker );
  1021.  
  1022.     /* start to a new position */
  1023.     x = UPSCALE( to->x );
  1024.     y = UPSCALE( to->y );
  1025.  
  1026.     gray_start_cell( worker, TRUNC( x ), TRUNC( y ) );
  1027.  
  1028.     ras.x = x;
  1029.     ras.y = y;
  1030.     return 0;
  1031.   }
  1032.  
  1033.  
  1034.   static void
  1035.   gray_hline( RAS_ARG_ TCoord  x,
  1036.                        TCoord  y,
  1037.                        TPos    area,
  1038.                        int     acount )
  1039.   {
  1040.     int coverage;
  1041.  
  1042.  
  1043.     /* compute the coverage line's coverage, depending on the    */
  1044.     /* outline fill rule                                         */
  1045.     /*                                                           */
  1046.     /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
  1047.     /*                                                           */
  1048.     coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
  1049.                                                     /* use range 0..256 */
  1050.     if ( coverage < 0 )
  1051.       coverage = -coverage;
  1052.  
  1053.     if ( ras.outline.flags & PVG_FT_OUTLINE_EVEN_ODD_FILL )
  1054.     {
  1055.       coverage &= 511;
  1056.  
  1057.       if ( coverage > 256 )
  1058.         coverage = 512 - coverage;
  1059.       else if ( coverage == 256 )
  1060.         coverage = 255;
  1061.     }
  1062.     else
  1063.     {
  1064.       /* normal non-zero winding rule */
  1065.       if ( coverage >= 256 )
  1066.         coverage = 255;
  1067.     }
  1068.  
  1069.     y += (TCoord)ras.min_ey;
  1070.     x += (TCoord)ras.min_ex;
  1071.  
  1072.     /* PVG_FT_Span.x is an int, so limit our coordinates appropriately */
  1073.     if ( x >= (1 << 23) )
  1074.       x = (1 << 23) - 1;
  1075.  
  1076.     /* PVG_FT_Span.y is an int, so limit our coordinates appropriately */
  1077.     if ( y >= (1 << 23) )
  1078.       y = (1 << 23) - 1;
  1079.  
  1080.     if ( coverage )
  1081.     {
  1082.       PVG_FT_Span*  span;
  1083.       int       count;
  1084.       int       skip;
  1085.  
  1086.       /* see whether we can add this span to the current list */
  1087.       count = ras.num_gray_spans;
  1088.       span  = ras.gray_spans + count - 1;
  1089.       if ( count > 0                          &&
  1090.            span->y == y                       &&
  1091.            span->x + span->len == x           &&
  1092.            span->coverage == coverage         )
  1093.       {
  1094.         span->len = span->len + acount;
  1095.         return;
  1096.       }
  1097.  
  1098.       if ( count >= PVG_FT_MAX_GRAY_SPANS )
  1099.       {
  1100.         if ( ras.render_span && count > ras.skip_spans )
  1101.         {
  1102.           skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
  1103.           ras.render_span( ras.num_gray_spans - skip,
  1104.                            ras.gray_spans + skip,
  1105.                            ras.render_span_data );
  1106.         }
  1107.  
  1108.         ras.skip_spans -= ras.num_gray_spans;
  1109.         /* ras.render_span( span->y, ras.gray_spans, count ); */
  1110.         ras.num_gray_spans = 0;
  1111.  
  1112.         span  = ras.gray_spans;
  1113.       }
  1114.       else
  1115.         span++;
  1116.  
  1117.       /* add a gray span to the current list */
  1118.       span->x        = x;
  1119.       span->len      = acount;
  1120.       span->y        = y;
  1121.       span->coverage = (unsigned char)coverage;
  1122.  
  1123.       ras.num_gray_spans++;
  1124.     }
  1125.   }
  1126.  
  1127.  
  1128.  
  1129.   static void
  1130.   gray_sweep( RAS_ARG)
  1131.   {
  1132.     int  yindex;
  1133.  
  1134.     if ( ras.num_cells == 0 )
  1135.       return;
  1136.  
  1137.     for ( yindex = 0; yindex < ras.ycount; yindex++ )
  1138.     {
  1139.       PCell   cell  = ras.ycells[yindex];
  1140.       TCoord  cover = 0;
  1141.       TCoord  x     = 0;
  1142.  
  1143.  
  1144.       for ( ; cell != NULL; cell = cell->next )
  1145.       {
  1146.         TArea  area;
  1147.  
  1148.  
  1149.         if ( cell->x > x && cover != 0 )
  1150.           gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
  1151.                       cell->x - x );
  1152.  
  1153.         cover += cell->cover;
  1154.         area   = cover * ( ONE_PIXEL * 2 ) - cell->area;
  1155.  
  1156.         if ( area != 0 && cell->x >= 0 )
  1157.           gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
  1158.  
  1159.         x = cell->x + 1;
  1160.       }
  1161.  
  1162.       if ( ras.count_ex > x && cover != 0 )
  1163.         gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
  1164.                     ras.count_ex - x );
  1165.     }
  1166.   }
  1167.  
  1168.   /*************************************************************************/
  1169.   /*                                                                       */
  1170.   /*  The following function should only compile in stand_alone mode,      */
  1171.   /*  i.e., when building this component without the rest of FreeType.     */
  1172.   /*                                                                       */
  1173.   /*************************************************************************/
  1174.  
  1175.   /*************************************************************************/
  1176.   /*                                                                       */
  1177.   /* <Function>                                                            */
  1178.   /*    PVG_FT_Outline_Decompose                                               */
  1179.   /*                                                                       */
  1180.   /* <Description>                                                         */
  1181.   /*    Walks over an outline's structure to decompose it into individual  */
  1182.   /*    segments and Bezier arcs.  This function is also able to emit      */
  1183.   /*    `move to' and `close to' operations to indicate the start and end  */
  1184.   /*    of new contours in the outline.                                    */
  1185.   /*                                                                       */
  1186.   /* <Input>                                                               */
  1187.   /*    outline        :: A pointer to the source target.                  */
  1188.   /*                                                                       */
  1189.   /*    user           :: A typeless pointer which is passed to each       */
  1190.   /*                      emitter during the decomposition.  It can be     */
  1191.   /*                      used to store the state during the               */
  1192.   /*                      decomposition.                                   */
  1193.   /*                                                                       */
  1194.   /* <Return>                                                              */
  1195.   /*    Error code.  0 means success.                                      */
  1196.   /*                                                                       */
  1197.   static
  1198.   int  PVG_FT_Outline_Decompose( const PVG_FT_Outline*        outline,
  1199.                                 void*                       user )
  1200.   {
  1201. #undef SCALED
  1202. #define SCALED( x )  (x)
  1203.  
  1204.     vector_t   v_last;
  1205.     vector_t   v_control;
  1206.     vector_t   v_start;
  1207.  
  1208.     vector_t*  point;
  1209.     vector_t*  limit;
  1210.     char*       tags;
  1211.  
  1212.     int   n;         /* index of contour in outline     */
  1213.     int   first;     /* index of first point in contour */
  1214.     int   error;
  1215.     char  tag;       /* current point's state           */
  1216.  
  1217.     if ( !outline )
  1218.       return ErrRaster_Invalid_Outline;
  1219.  
  1220.     first = 0;
  1221.  
  1222.     for ( n = 0; n < outline->n_contours; n++ )
  1223.     {
  1224.       int  last;  /* index of last point in contour */
  1225.  
  1226.  
  1227.       last  = outline->contours[n];
  1228.       if ( last < 0 )
  1229.         goto Invalid_Outline;
  1230.       limit = outline->points + last;
  1231.  
  1232.       v_start   = outline->points[first];
  1233.       v_start.x = SCALED( v_start.x );
  1234.       v_start.y = SCALED( v_start.y );
  1235.  
  1236.       v_last   = outline->points[last];
  1237.       v_last.x = SCALED( v_last.x );
  1238.       v_last.y = SCALED( v_last.y );
  1239.  
  1240.       v_control = v_start;
  1241.  
  1242.       point = outline->points + first;
  1243.       tags  = outline->tags  + first;
  1244.       tag   = PVG_FT_CURVE_TAG( tags[0] );
  1245.  
  1246.       /* A contour cannot start with a cubic control point! */
  1247.       if ( tag == PVG_FT_CURVE_TAG_CUBIC )
  1248.         goto Invalid_Outline;
  1249.  
  1250.       /* check first point to determine origin */
  1251.       if ( tag == PVG_FT_CURVE_TAG_CONIC )
  1252.       {
  1253.         /* first point is conic control.  Yes, this happens. */
  1254.         if ( PVG_FT_CURVE_TAG( outline->tags[last] ) == PVG_FT_CURVE_TAG_ON )
  1255.         {
  1256.           /* start at last point if it is on the curve */
  1257.           v_start = v_last;
  1258.           limit--;
  1259.         }
  1260.         else
  1261.         {
  1262.           /* if both first and last points are conic,         */
  1263.           /* start at their middle and record its position    */
  1264.           /* for closure                                      */
  1265.           v_start.x = ( v_start.x + v_last.x ) / 2;
  1266.           v_start.y = ( v_start.y + v_last.y ) / 2;
  1267.  
  1268.           v_last = v_start;
  1269.         }
  1270.         point--;
  1271.         tags--;
  1272.       }
  1273.  
  1274.       error = gray_move_to( &v_start,(PWorker) user );
  1275.       if ( error )
  1276.         goto Exit;
  1277.  
  1278.       while ( point < limit )
  1279.       {
  1280.         point++;
  1281.         tags++;
  1282.  
  1283.         tag = PVG_FT_CURVE_TAG( tags[0] );
  1284.         switch ( tag )
  1285.         {
  1286.         case PVG_FT_CURVE_TAG_ON:  /* emit a single line_to */
  1287.           {
  1288.             vector_t  vec;
  1289.  
  1290.  
  1291.             vec.x = SCALED( point->x );
  1292.             vec.y = SCALED( point->y );
  1293.  
  1294.             gray_render_line((PWorker)user, UPSCALE(vec.x), UPSCALE(vec.y));
  1295.             continue;
  1296.           }
  1297.  
  1298.         case PVG_FT_CURVE_TAG_CONIC:  /* consume conic arcs */
  1299.           {
  1300.             v_control.x = SCALED( point->x );
  1301.             v_control.y = SCALED( point->y );
  1302.  
  1303.           Do_Conic:
  1304.             if ( point < limit )
  1305.             {
  1306.               vector_t  vec;
  1307.               vector_t  v_middle;
  1308.  
  1309.  
  1310.               point++;
  1311.               tags++;
  1312.               tag = PVG_FT_CURVE_TAG( tags[0] );
  1313.  
  1314.               vec.x = SCALED( point->x );
  1315.               vec.y = SCALED( point->y );
  1316.  
  1317.               if ( tag == PVG_FT_CURVE_TAG_ON )
  1318.               {
  1319.                 gray_render_conic((PWorker) user, &v_control, &vec);
  1320.                 continue;
  1321.               }
  1322.  
  1323.               if ( tag != PVG_FT_CURVE_TAG_CONIC )
  1324.                 goto Invalid_Outline;
  1325.  
  1326.               v_middle.x = ( v_control.x + vec.x ) / 2;
  1327.               v_middle.y = ( v_control.y + vec.y ) / 2;
  1328.  
  1329.               gray_render_conic((PWorker)user, &v_control, &v_middle);
  1330.  
  1331.               v_control = vec;
  1332.               goto Do_Conic;
  1333.             }
  1334.  
  1335.             gray_render_conic((PWorker)user, &v_control, &v_start);
  1336.             goto Close;
  1337.           }
  1338.  
  1339.         default:  /* PVG_FT_CURVE_TAG_CUBIC */
  1340.           {
  1341.             vector_t  vec1, vec2;
  1342.  
  1343.  
  1344.             if ( point + 1 > limit                             ||
  1345.                  PVG_FT_CURVE_TAG( tags[1] ) != PVG_FT_CURVE_TAG_CUBIC )
  1346.               goto Invalid_Outline;
  1347.  
  1348.             point += 2;
  1349.             tags  += 2;
  1350.  
  1351.             vec1.x = SCALED( point[-2].x );
  1352.             vec1.y = SCALED( point[-2].y );
  1353.  
  1354.             vec2.x = SCALED( point[-1].x );
  1355.             vec2.y = SCALED( point[-1].y );
  1356.  
  1357.             if ( point <= limit )
  1358.             {
  1359.               vector_t  vec;
  1360.  
  1361.  
  1362.               vec.x = SCALED( point->x );
  1363.               vec.y = SCALED( point->y );
  1364.  
  1365.               gray_render_cubic((PWorker)user, &vec1, &vec2, &vec);
  1366.               continue;
  1367.             }
  1368.  
  1369.             gray_render_cubic((PWorker)user, &vec1, &vec2, &v_start);
  1370.             goto Close;
  1371.           }
  1372.         }
  1373.       }
  1374.  
  1375.       /* close the contour with a line segment */
  1376.       gray_render_line((PWorker)user, UPSCALE(v_start.x), UPSCALE(v_start.y));
  1377.  
  1378.    Close:
  1379.       first = last + 1;
  1380.     }
  1381.  
  1382.     return 0;
  1383.  
  1384.   Exit:
  1385.     return error;
  1386.  
  1387.   Invalid_Outline:
  1388.     return ErrRaster_Invalid_Outline;
  1389.   }
  1390.  
  1391.   typedef struct  TBand_
  1392.   {
  1393.     TPos  min, max;
  1394.  
  1395.   } TBand;
  1396.  
  1397.   static int
  1398.   gray_convert_glyph_inner( RAS_ARG )
  1399.   {
  1400.     volatile int  error = 0;
  1401.     if ( pvg_ft_setjmp( ras.jump_buffer ) == 0 )
  1402.     {
  1403.       error = PVG_FT_Outline_Decompose( &ras.outline, &ras );
  1404.       if ( !ras.invalid )
  1405.         gray_record_cell( RAS_VAR );
  1406.     }
  1407.     else
  1408.     {
  1409.       error = ErrRaster_Memory_Overflow;
  1410.     }
  1411.     return error;
  1412.   }
  1413.  
  1414.  
  1415.   static int
  1416.   gray_convert_glyph( RAS_ARG )
  1417.   {
  1418.     TBand            bands[40];
  1419.     TBand* volatile  band;
  1420.     int volatile     n, num_bands;
  1421.     TPos volatile    min, max, max_y;
  1422.     PVG_FT_BBox*      clip;
  1423.     int              skip;
  1424.  
  1425.     ras.num_gray_spans = 0;
  1426.  
  1427.     /* Set up state in the raster object */
  1428.     gray_compute_cbox( RAS_VAR );
  1429.  
  1430.     /* clip to target bitmap, exit if nothing to do */
  1431.     clip = &ras.clip_box;
  1432.  
  1433.     if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
  1434.          ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
  1435.       return 0;
  1436.  
  1437.     if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
  1438.     if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
  1439.  
  1440.     if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
  1441.     if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
  1442.  
  1443.     ras.count_ex = ras.max_ex - ras.min_ex;
  1444.     ras.count_ey = ras.max_ey - ras.min_ey;
  1445.  
  1446.     /* set up vertical bands */
  1447.     num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
  1448.     if ( num_bands == 0 )
  1449.       num_bands = 1;
  1450.     if ( num_bands >= 39 )
  1451.       num_bands = 39;
  1452.  
  1453.     ras.band_shoot = 0;
  1454.  
  1455.     min   = ras.min_ey;
  1456.     max_y = ras.max_ey;
  1457.  
  1458.     for ( n = 0; n < num_bands; n++, min = max )
  1459.     {
  1460.       max = min + ras.band_size;
  1461.       if ( n == num_bands - 1 || max > max_y )
  1462.         max = max_y;
  1463.  
  1464.       bands[0].min = min;
  1465.       bands[0].max = max;
  1466.       band         = bands;
  1467.  
  1468.       while ( band >= bands )
  1469.       {
  1470.         TPos  bottom, top, middle;
  1471.         int   error;
  1472.  
  1473.         {
  1474.           PCell  cells_max;
  1475.           int    yindex;
  1476.           int    cell_start, cell_end, cell_mod;
  1477.  
  1478.  
  1479.           ras.ycells = (PCell*)ras.buffer;
  1480.           ras.ycount = band->max - band->min;
  1481.  
  1482.           cell_start = sizeof ( PCell ) * ras.ycount;
  1483.           cell_mod   = cell_start % sizeof ( TCell );
  1484.           if ( cell_mod > 0 )
  1485.             cell_start += sizeof ( TCell ) - cell_mod;
  1486.  
  1487.           cell_end  = ras.buffer_size;
  1488.           cell_end -= cell_end % sizeof( TCell );
  1489.  
  1490.           cells_max = (PCell)( (char*)ras.buffer + cell_end );
  1491.           ras.cells = (PCell)( (char*)ras.buffer + cell_start );
  1492.           if ( ras.cells >= cells_max )
  1493.             goto ReduceBands;
  1494.  
  1495.           ras.max_cells = (int)(cells_max - ras.cells);
  1496.           if ( ras.max_cells < 2 )
  1497.             goto ReduceBands;
  1498.  
  1499.           for ( yindex = 0; yindex < ras.ycount; yindex++ )
  1500.             ras.ycells[yindex] = NULL;
  1501.         }
  1502.  
  1503.         ras.num_cells = 0;
  1504.         ras.invalid   = 1;
  1505.         ras.min_ey    = band->min;
  1506.         ras.max_ey    = band->max;
  1507.         ras.count_ey  = band->max - band->min;
  1508.         error = gray_convert_glyph_inner( RAS_VAR );
  1509.         if ( !error )
  1510.         {
  1511.           gray_sweep( RAS_VAR);
  1512.           band--;
  1513.           continue;
  1514.         }
  1515.         else if ( error != ErrRaster_Memory_Overflow )
  1516.           return 1;
  1517.  
  1518.       ReduceBands:
  1519.         /* render pool overflow; we will reduce the render band by half */
  1520.         bottom = band->min;
  1521.         top    = band->max;
  1522.         middle = bottom + ( ( top - bottom ) >> 1 );
  1523.  
  1524.         /* This is too complex for a single scanline; there must */
  1525.         /* be some problems.                                     */
  1526.         if ( middle == bottom )
  1527.         {
  1528.           return ErrRaster_OutOfMemory;
  1529.         }
  1530.  
  1531.         if ( bottom-top >= ras.band_size )
  1532.           ras.band_shoot++;
  1533.  
  1534.         band[1].min = bottom;
  1535.         band[1].max = middle;
  1536.         band[0].min = middle;
  1537.         band[0].max = top;
  1538.         band++;
  1539.       }
  1540.     }
  1541.  
  1542.     if ( ras.render_span && ras.num_gray_spans > ras.skip_spans )
  1543.     {
  1544.         skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
  1545.         ras.render_span( ras.num_gray_spans - skip,
  1546.                          ras.gray_spans + skip,
  1547.                          ras.render_span_data );
  1548.     }
  1549.  
  1550.     ras.skip_spans -= ras.num_gray_spans;
  1551.  
  1552.     if ( ras.band_shoot > 8 && ras.band_size > 16 )
  1553.       ras.band_size = ras.band_size / 2;
  1554.  
  1555.     return 0;
  1556.   }
  1557.  
  1558.  
  1559.   static int
  1560.   gray_raster_render( RAS_ARG_ void* buffer, long buffer_size,
  1561.                       const PVG_FT_Raster_Params*  params )
  1562.   {
  1563.     const PVG_FT_Outline*  outline    = (const PVG_FT_Outline*)params->source;
  1564.     if ( outline == NULL )
  1565.       return ErrRaster_Invalid_Outline;
  1566.  
  1567.     /* return immediately if the outline is empty */
  1568.     if ( outline->n_points == 0 || outline->n_contours <= 0 )
  1569.       return 0;
  1570.  
  1571.     if ( !outline->contours || !outline->points )
  1572.       return ErrRaster_Invalid_Outline;
  1573.  
  1574.     if ( outline->n_points !=
  1575.            outline->contours[outline->n_contours - 1] + 1 )
  1576.       return ErrRaster_Invalid_Outline;
  1577.  
  1578.     /* this version does not support monochrome rendering */
  1579.     if ( !( params->flags & PVG_FT_RASTER_FLAG_AA ) )
  1580.       return ErrRaster_Invalid_Mode;
  1581.  
  1582.     if ( !( params->flags & PVG_FT_RASTER_FLAG_DIRECT ) )
  1583.       return ErrRaster_Invalid_Mode;
  1584.  
  1585.     /* compute clipping box */
  1586.     if ( params->flags & PVG_FT_RASTER_FLAG_CLIP )
  1587.     {
  1588.       ras.clip_box = params->clip_box;
  1589.     }
  1590.     else
  1591.     {
  1592.       ras.clip_box.xMin = -(1 << 23);
  1593.       ras.clip_box.yMin = -(1 << 23);
  1594.       ras.clip_box.xMax =  (1 << 23) - 1;
  1595.       ras.clip_box.yMax =  (1 << 23) - 1;
  1596.     }
  1597.  
  1598.     gray_init_cells( RAS_VAR_ buffer, buffer_size );
  1599.  
  1600.     ras.outline   = *outline;
  1601.     ras.num_cells = 0;
  1602.     ras.invalid   = 1;
  1603.     ras.band_size = (int)(buffer_size / (long)(sizeof(TCell) * 8));
  1604.  
  1605.     ras.render_span      = (PVG_FT_Raster_Span_Func)params->gray_spans;
  1606.     ras.render_span_data = params->user;
  1607.  
  1608.     return gray_convert_glyph( RAS_VAR );
  1609.   }
  1610.  
  1611.   bool
  1612.   PVG_FT_Raster_Render(const PVG_FT_Raster_Params *params)
  1613.   {
  1614.       void* memory = malloc(PVG_FT_MINIMUM_POOL_SIZE);
  1615.       if(memory==nullptr) {
  1616.         return false;
  1617.       }
  1618.       size_t length = PVG_FT_MINIMUM_POOL_SIZE;
  1619.  
  1620.       TWorker worker;
  1621.       worker.skip_spans = 0;
  1622.       int rendered_spans = 0;
  1623.       int error = gray_raster_render(&worker, memory, length, params);
  1624.       while(error == ErrRaster_OutOfMemory) {
  1625.           if(worker.skip_spans < 0)
  1626.               rendered_spans += -worker.skip_spans;
  1627.           worker.skip_spans = rendered_spans;
  1628.           length *= 2;
  1629.           memory = realloc(memory, length);
  1630.           if(memory==nullptr) {
  1631.             return false;
  1632.           }
  1633.           error = gray_raster_render(&worker, memory, length, params);
  1634.       }
  1635.  
  1636.       free(memory);
  1637.       return true;
  1638.   }
  1639.  
  1640. /* END */
  1641.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement