< prev index next >

src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c

Print this page


   1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  ftgrays.c                                                              */
   4 /*                                                                         */
   5 /*    A new `perfect' anti-aliasing renderer (body).                       */
   6 /*                                                                         */
   7 /*  Copyright 2000-2018 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, LICENSE.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 file can be compiled without the rest of the FreeType engine, by */
  21   /* defining the STANDALONE_ macro when compiling it.  You also need to   */
  22   /* put the files `ftgrays.h' and `ftimage.h' into the current            */
  23   /* compilation directory.  Typically, you could do something like        */
  24   /*                                                                       */
  25   /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
  26   /*                                                                       */
  27   /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
  28   /*   same directory                                                      */
  29   /*                                                                       */
  30   /* - compile `ftgrays' with the STANDALONE_ macro defined, as in         */
  31   /*                                                                       */
  32   /*     cc -c -DSTANDALONE_ ftgrays.c                                     */
  33   /*                                                                       */
  34   /* The renderer can be initialized with a call to                        */
  35   /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated  */
  36   /* with a call to `ft_gray_raster.raster_render'.                        */
  37   /*                                                                       */
  38   /* See the comments and documentation in the file `ftimage.h' for more   */
  39   /* details on how the raster works.                                      */
  40   /*                                                                       */
  41   /*************************************************************************/
  42 
  43   /*************************************************************************/
  44   /*                                                                       */
  45   /* This is a new anti-aliasing scan-converter for FreeType 2.  The       */
  46   /* algorithm used here is _very_ different from the one in the standard  */
  47   /* `ftraster' module.  Actually, `ftgrays' computes the _exact_          */
  48   /* coverage of the outline on each pixel cell.                           */
  49   /*                                                                       */
  50   /* It is based on ideas that I initially found in Raph Levien's          */
  51   /* excellent LibArt graphics library (see http://www.levien.com/libart   */
  52   /* for more information, though the web pages do not tell anything       */
  53   /* about the renderer; you'll have to dive into the source code to       */
  54   /* understand how it works).                                             */
  55   /*                                                                       */
  56   /* Note, however, that this is a _very_ different implementation         */
  57   /* compared to Raph's.  Coverage information is stored in a very         */
  58   /* different way, and I don't use sorted vector paths.  Also, it doesn't */
  59   /* use floating point values.                                            */
  60   /*                                                                       */
  61   /* This renderer has the following advantages:                           */
  62   /*                                                                       */
  63   /* - It doesn't need an intermediate bitmap.  Instead, one can supply a  */
  64   /*   callback function that will be called by the renderer to draw gray  */
  65   /*   spans on any target surface.  You can thus do direct composition on */
  66   /*   any kind of bitmap, provided that you give the renderer the right   */
  67   /*   callback.                                                           */
  68   /*                                                                       */
  69   /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on   */
  70   /*   each pixel cell.                                                    */
  71   /*                                                                       */
  72   /* - It performs a single pass on the outline (the `standard' FT2        */
  73   /*   renderer makes two passes).                                         */
  74   /*                                                                       */
  75   /* - It can easily be modified to render to _any_ number of gray levels  */
  76   /*   cheaply.                                                            */
  77   /*                                                                       */
  78   /* - For small (< 20) pixel sizes, it is faster than the standard        */
  79   /*   renderer.                                                           */
  80   /*                                                                       */
  81   /*************************************************************************/
  82 
  83 
  84   /*************************************************************************/
  85   /*                                                                       */
  86   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  87   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  88   /* messages during execution.                                            */
  89   /*                                                                       */
  90 #undef  FT_COMPONENT
  91 #define FT_COMPONENT  trace_smooth
  92 
  93 
  94 #ifdef STANDALONE_
  95 
  96 
  97   /* The size in bytes of the render pool used by the scan-line converter  */
  98   /* to do all of its work.                                                */
  99 #define FT_RENDER_POOL_SIZE  16384L
 100 
 101 
 102   /* Auxiliary macros for token concatenation. */
 103 #define FT_ERR_XCAT( x, y )  x ## y
 104 #define FT_ERR_CAT( x, y )   FT_ERR_XCAT( x, y )
 105 
 106 #define FT_BEGIN_STMNT  do {
 107 #define FT_END_STMNT    } while ( 0 )
 108 
 109 #define FT_MIN( a, b )  ( (a) < (b) ? (a) : (b) )
 110 #define FT_MAX( a, b )  ( (a) > (b) ? (a) : (b) )
 111 #define FT_ABS( a )     ( (a) < 0 ? -(a) : (a) )


 205     FT_UNUSED( error );
 206     FT_UNUSED( line );
 207     FT_UNUSED( file );
 208 
 209     return 0;
 210   }
 211 
 212 
 213   /* we don't handle tracing levels in stand-alone mode; */
 214 #ifndef FT_TRACE5
 215 #define FT_TRACE5( varformat )  FT_Message varformat
 216 #endif
 217 #ifndef FT_TRACE7
 218 #define FT_TRACE7( varformat )  FT_Message varformat
 219 #endif
 220 #ifndef FT_ERROR
 221 #define FT_ERROR( varformat )   FT_Message varformat
 222 #endif
 223 
 224 #define FT_THROW( e )                               \
 225           ( FT_Throw( FT_ERR_CAT( ErrRaster, e ),   \
 226                       __LINE__,                     \
 227                       __FILE__ )                  | \
 228             FT_ERR_CAT( ErrRaster, e )            )
 229 
 230 #else /* !FT_DEBUG_LEVEL_TRACE */
 231 
 232 #define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
 233 #define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
 234 #define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
 235 #define FT_THROW( e )   FT_ERR_CAT( ErrRaster_, e )
 236 
 237 
 238 #endif /* !FT_DEBUG_LEVEL_TRACE */
 239 
 240 
 241 #define FT_DEFINE_OUTLINE_FUNCS( class_,               \
 242                                  move_to_, line_to_,   \
 243                                  conic_to_, cubic_to_, \
 244                                  shift_, delta_ )      \
 245           static const FT_Outline_Funcs class_ =       \
 246           {                                            \
 247             move_to_,                                  \
 248             line_to_,                                  \


 262             raster_new_,                                          \
 263             raster_reset_,                                        \
 264             raster_set_mode_,                                     \
 265             raster_render_,                                       \
 266             raster_done_                                          \
 267          };
 268 
 269 
 270 #else /* !STANDALONE_ */
 271 
 272 
 273 #include <ft2build.h>
 274 #include "ftgrays.h"
 275 #include FT_INTERNAL_OBJECTS_H
 276 #include FT_INTERNAL_DEBUG_H
 277 #include FT_INTERNAL_CALC_H
 278 #include FT_OUTLINE_H
 279 
 280 #include "ftsmerrs.h"
 281 
 282 #include "ftspic.h"
 283 
 284 #define Smooth_Err_Invalid_Mode     Smooth_Err_Cannot_Render_Glyph
 285 #define Smooth_Err_Memory_Overflow  Smooth_Err_Out_Of_Memory
 286 #define ErrRaster_Memory_Overflow   Smooth_Err_Out_Of_Memory
 287 
 288 
 289 #endif /* !STANDALONE_ */
 290 
 291 
 292 #ifndef FT_MEM_SET
 293 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
 294 #endif
 295 
 296 #ifndef FT_MEM_ZERO
 297 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
 298 #endif
 299 
 300 #ifndef FT_ZERO
 301 #define FT_ZERO( p )  FT_MEM_ZERO( p, sizeof ( *(p) ) )
 302 #endif
 303 


 378     (remainder) = (type)( (dividend) - (quotient) * (divisor) );   \
 379     if ( (remainder) < 0 )                                         \
 380     {                                                              \
 381       (quotient)--;                                                \
 382       (remainder) += (type)(divisor);                              \
 383     }                                                              \
 384   FT_END_STMNT
 385 #endif /* __arm__ */
 386 
 387 
 388   /* These macros speed up repetitive divisions by replacing them */
 389   /* with multiplications and right shifts.                       */
 390 #define FT_UDIVPREP( c, b )                                        \
 391   long  b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \
 392                     : 0
 393 #define FT_UDIV( a, b )                                        \
 394   ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >>   \
 395     ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
 396 
 397 
 398   /*************************************************************************/
 399   /*                                                                       */
 400   /*   TYPE DEFINITIONS                                                    */
 401   /*                                                                       */
 402 
 403   /* don't change the following types to FT_Int or FT_Pos, since we might */
 404   /* need to define them to "float" or "double" when experimenting with   */
 405   /* new algorithms                                                       */
 406 
 407   typedef long  TPos;     /* subpixel coordinate               */
 408   typedef int   TCoord;   /* integer scanline/pixel coordinate */
 409   typedef int   TArea;    /* cell areas, coordinate products   */
 410 
 411 
 412   typedef struct TCell_*  PCell;
 413 
 414   typedef struct  TCell_
 415   {
 416     TCoord  x;     /* same with gray_TWorker.ex    */
 417     TCoord  cover; /* same with gray_TWorker.cover */
 418     TArea   area;
 419     PCell   next;
 420 
 421   } TCell;


 499     int  y;
 500 
 501 
 502     for ( y = ras.min_ey; y < ras.max_ey; y++ )
 503     {
 504       PCell  cell = ras.ycells[y - ras.min_ey];
 505 
 506 
 507       printf( "%3d:", y );
 508 
 509       for ( ; cell != NULL; cell = cell->next )
 510         printf( " (%3d, c:%4d, a:%6d)",
 511                 cell->x, cell->cover, cell->area );
 512       printf( "\n" );
 513     }
 514   }
 515 
 516 #endif /* FT_DEBUG_LEVEL_TRACE */
 517 
 518 
 519   /*************************************************************************/
 520   /*                                                                       */
 521   /* Record the current cell in the table.                                 */
 522   /*                                                                       */
 523   static void
 524   gray_record_cell( RAS_ARG )
 525   {
 526     PCell  *pcell, cell;
 527     TCoord  x = ras.ex;
 528 
 529 
 530     pcell = &ras.ycells[ras.ey - ras.min_ey];
 531     for (;;)
 532     {
 533       cell = *pcell;
 534       if ( !cell || cell->x > x )
 535         break;
 536 
 537       if ( cell->x == x )
 538         goto Found;
 539 
 540       pcell = &cell->next;
 541     }
 542 


 544       ft_longjmp( ras.jump_buffer, 1 );
 545 
 546     /* insert new cell */
 547     cell        = ras.cells + ras.num_cells++;
 548     cell->x     = x;
 549     cell->area  = ras.area;
 550     cell->cover = ras.cover;
 551 
 552     cell->next  = *pcell;
 553     *pcell      = cell;
 554 
 555     return;
 556 
 557   Found:
 558     /* update old cell */
 559     cell->area  += ras.area;
 560     cell->cover += ras.cover;
 561   }
 562 
 563 
 564   /*************************************************************************/
 565   /*                                                                       */
 566   /* Set the current cell to a new position.                               */
 567   /*                                                                       */
 568   static void
 569   gray_set_cell( RAS_ARG_ TCoord  ex,
 570                           TCoord  ey )
 571   {
 572     /* Move the cell pointer to a new position.  We set the `invalid'      */
 573     /* flag to indicate that the cell isn't part of those we're interested */
 574     /* in during the render phase.  This means that:                       */
 575     /*                                                                     */
 576     /* . the new vertical position must be within min_ey..max_ey-1.        */
 577     /* . the new horizontal position must be strictly less than max_ex     */
 578     /*                                                                     */
 579     /* Note that if a cell is to the left of the clipping region, it is    */
 580     /* actually set to the (min_ex-1) horizontal position.                 */
 581 
 582     if ( ex < ras.min_ex )
 583       ex = ras.min_ex - 1;
 584 
 585     /* record the current one if it is valid and substantial */
 586     if ( !ras.invalid && ( ras.area || ras.cover ) )
 587       gray_record_cell( RAS_VAR );
 588 
 589     ras.area  = 0;
 590     ras.cover = 0;
 591     ras.ex    = ex;
 592     ras.ey    = ey;
 593 
 594     ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey ||
 595                     ex >= ras.max_ex );
 596   }
 597 
 598 
 599 #ifndef FT_LONG64
 600 
 601   /*************************************************************************/
 602   /*                                                                       */
 603   /* Render a scanline as one or more cells.                               */
 604   /*                                                                       */
 605   static void
 606   gray_render_scanline( RAS_ARG_ TCoord  ey,
 607                                  TPos    x1,
 608                                  TCoord  y1,
 609                                  TPos    x2,
 610                                  TCoord  y2 )
 611   {
 612     TCoord  ex1, ex2, fx1, fx2, first, dy, delta, mod;
 613     TPos    p, dx;
 614     int     incr;
 615 
 616 
 617     ex1 = TRUNC( x1 );
 618     ex2 = TRUNC( x2 );
 619 
 620     /* trivial case.  Happens often */
 621     if ( y1 == y2 )
 622     {
 623       gray_set_cell( RAS_VAR_ ex2, ey );
 624       return;


 679         }
 680 
 681         ras.area  += (TArea)( ONE_PIXEL * delta );
 682         ras.cover += delta;
 683         y1        += delta;
 684         ex1       += incr;
 685         gray_set_cell( RAS_VAR_ ex1, ey );
 686       } while ( ex1 != ex2 );
 687     }
 688 
 689     fx1 = ONE_PIXEL - first;
 690 
 691   End:
 692     dy = y2 - y1;
 693 
 694     ras.area  += (TArea)( ( fx1 + fx2 ) * dy );
 695     ras.cover += dy;
 696   }
 697 
 698 
 699   /*************************************************************************/
 700   /*                                                                       */
 701   /* Render a given line as a series of scanlines.                         */
 702   /*                                                                       */
 703   static void
 704   gray_render_line( RAS_ARG_ TPos  to_x,
 705                              TPos  to_y )
 706   {
 707     TCoord  ey1, ey2, fy1, fy2, first, delta, mod;
 708     TPos    p, dx, dy, x, x2;
 709     int     incr;
 710 
 711 
 712     ey1 = TRUNC( ras.y );
 713     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
 714 
 715     /* perform vertical clipping */
 716     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
 717          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
 718       goto End;
 719 
 720     fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
 721     fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
 722 


 820                                        x, ONE_PIXEL - first,
 821                                        x2, first );
 822         x = x2;
 823 
 824         ey1 += incr;
 825         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
 826       } while ( ey1 != ey2 );
 827     }
 828 
 829     gray_render_scanline( RAS_VAR_ ey1,
 830                                    x, ONE_PIXEL - first,
 831                                    to_x, fy2 );
 832 
 833   End:
 834     ras.x       = to_x;
 835     ras.y       = to_y;
 836   }
 837 
 838 #else
 839 
 840   /*************************************************************************/
 841   /*                                                                       */
 842   /* Render a straight line across multiple cells in any direction.        */
 843   /*                                                                       */
 844   static void
 845   gray_render_line( RAS_ARG_ TPos  to_x,
 846                              TPos  to_y )
 847   {
 848     TPos    dx, dy, fx1, fy1, fx2, fy2;
 849     TCoord  ex1, ex2, ey1, ey2;
 850 
 851 
 852     ey1 = TRUNC( ras.y );
 853     ey2 = TRUNC( to_y );
 854 
 855     /* perform vertical clipping */
 856     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
 857          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
 858       goto End;
 859 
 860     ex1 = TRUNC( ras.x );
 861     ex2 = TRUNC( to_x );
 862 
 863     fx1 = ras.x - SUBPIXELS( ex1 );


1313         if ( cover != 0 && cell->x > x )
1314           gray_hline( RAS_VAR_ x, y, cover, cell->x - x );
1315 
1316         cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
1317         area   = cover - cell->area;
1318 
1319         if ( area != 0 && cell->x >= ras.min_ex )
1320           gray_hline( RAS_VAR_ cell->x, y, area, 1 );
1321 
1322         x = cell->x + 1;
1323       }
1324 
1325       if ( cover != 0 )
1326         gray_hline( RAS_VAR_ x, y, cover, ras.max_ex - x );
1327     }
1328   }
1329 
1330 
1331 #ifdef STANDALONE_
1332 
1333   /*************************************************************************/
1334   /*                                                                       */
1335   /*  The following functions should only compile in stand-alone mode,     */
1336   /*  i.e., when building this component without the rest of FreeType.     */
1337   /*                                                                       */
1338   /*************************************************************************/
1339 
1340   /*************************************************************************/
1341   /*                                                                       */
1342   /* <Function>                                                            */
1343   /*    FT_Outline_Decompose                                               */
1344   /*                                                                       */
1345   /* <Description>                                                         */
1346   /*    Walk over an outline's structure to decompose it into individual   */
1347   /*    segments and Bézier arcs.  This function is also able to emit      */
1348   /*    `move to' and `close to' operations to indicate the start and end  */
1349   /*    of new contours in the outline.                                    */
1350   /*                                                                       */
1351   /* <Input>                                                               */
1352   /*    outline        :: A pointer to the source target.                  */
1353   /*                                                                       */
1354   /*    func_interface :: A table of `emitters', i.e., function pointers   */
1355   /*                      called during decomposition to indicate path     */
1356   /*                      operations.                                      */
1357   /*                                                                       */
1358   /* <InOut>                                                               */
1359   /*    user           :: A typeless pointer which is passed to each       */
1360   /*                      emitter during the decomposition.  It can be     */
1361   /*                      used to store the state during the               */
1362   /*                      decomposition.                                   */
1363   /*                                                                       */
1364   /* <Return>                                                              */
1365   /*    Error code.  0 means success.                                      */
1366   /*                                                                       */



1367   static int
1368   FT_Outline_Decompose( const FT_Outline*        outline,
1369                         const FT_Outline_Funcs*  func_interface,
1370                         void*                    user )
1371   {
1372 #undef SCALED
1373 #define SCALED( x )  ( ( (x) << shift ) - delta )
1374 
1375     FT_Vector   v_last;
1376     FT_Vector   v_control;
1377     FT_Vector   v_start;
1378 
1379     FT_Vector*  point;
1380     FT_Vector*  limit;
1381     char*       tags;
1382 
1383     int         error;
1384 
1385     int   n;         /* index of contour in outline     */
1386     int   first;     /* index of first point in contour */


1593       error = func_interface->line_to( &v_start, user );
1594 
1595    Close:
1596       if ( error )
1597         goto Exit;
1598 
1599       first = last + 1;
1600     }
1601 
1602     FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1603     return 0;
1604 
1605   Exit:
1606     FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error ));
1607     return error;
1608 
1609   Invalid_Outline:
1610     return FT_THROW( Invalid_Outline );
1611   }
1612 
1613 
1614   /*************************************************************************/
1615   /*                                                                       */
1616   /* <Function>                                                            */
1617   /*    FT_Outline_Get_CBox                                                */
1618   /*                                                                       */
1619   /* <Description>                                                         */
1620   /*    Return an outline's `control box'.  The control box encloses all   */
1621   /*    the outline's points, including Bézier control points.  Though it  */
1622   /*    coincides with the exact bounding box for most glyphs, it can be   */
1623   /*    slightly larger in some situations (like when rotating an outline  */
1624   /*    that contains Bézier outside arcs).                                */
1625   /*                                                                       */
1626   /*    Computing the control box is very fast, while getting the bounding */
1627   /*    box can take much more time as it needs to walk over all segments  */
1628   /*    and arcs in the outline.  To get the latter, you can use the       */
1629   /*    `ftbbox' component, which is dedicated to this single task.        */
1630   /*                                                                       */
1631   /* <Input>                                                               */
1632   /*    outline :: A pointer to the source outline descriptor.             */
1633   /*                                                                       */
1634   /* <Output>                                                              */
1635   /*    acbox   :: The outline's control box.                              */
1636   /*                                                                       */
1637   /* <Note>                                                                */
1638   /*    See @FT_Glyph_Get_CBox for a discussion of tricky fonts.           */
1639   /*                                                                       */
1640 
1641   static void
1642   FT_Outline_Get_CBox( const FT_Outline*  outline,
1643                        FT_BBox           *acbox )
1644   {
1645     TPos  xMin, yMin, xMax, yMax;
1646 
1647 
1648     if ( outline && acbox )
1649     {
1650       if ( outline->n_points == 0 )
1651       {
1652         xMin = 0;
1653         yMin = 0;
1654         xMax = 0;
1655         yMax = 0;
1656       }
1657       else
1658       {
1659         FT_Vector*  vec   = outline->points;
1660         FT_Vector*  limit = vec + outline->n_points;
1661 
1662 
1663         xMin = xMax = vec->x;
1664         yMin = yMax = vec->y;
1665         vec++;
1666 
1667         for ( ; vec < limit; vec++ )
1668         {
1669           TPos  x, y;
1670 
1671 
1672           x = vec->x;
1673           if ( x < xMin ) xMin = x;
1674           if ( x > xMax ) xMax = x;
1675 
1676           y = vec->y;
1677           if ( y < yMin ) yMin = y;
1678           if ( y > yMax ) yMax = y;
1679         }
1680       }
1681       acbox->xMin = xMin;
1682       acbox->xMax = xMax;
1683       acbox->yMin = yMin;
1684       acbox->yMax = yMax;
1685     }
1686   }
1687 
1688 #endif /* STANDALONE_ */
1689 
1690 
1691   FT_DEFINE_OUTLINE_FUNCS(
1692     func_interface,
1693 
1694     (FT_Outline_MoveTo_Func) gray_move_to,   /* move_to  */
1695     (FT_Outline_LineTo_Func) gray_line_to,   /* line_to  */
1696     (FT_Outline_ConicTo_Func)gray_conic_to,  /* conic_to */
1697     (FT_Outline_CubicTo_Func)gray_cubic_to,  /* cubic_to */
1698 
1699     0,                                       /* shift    */
1700     0                                        /* delta    */
1701   )
1702 
1703 
1704   static int
1705   gray_convert_glyph_inner( RAS_ARG )

1706   {
1707 
1708     volatile int  error = 0;
1709 
1710 #ifdef FT_CONFIG_OPTION_PIC
1711       FT_Outline_Funcs func_interface;
1712       Init_Class_func_interface(&func_interface);
1713 #endif
1714 
1715     if ( ft_setjmp( ras.jump_buffer ) == 0 )
1716     {


1717       error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );



1718       if ( !ras.invalid )
1719         gray_record_cell( RAS_VAR );
1720 
1721       FT_TRACE7(( "band [%d..%d]: %d cell%s\n",
1722                   ras.min_ey,
1723                   ras.max_ey,
1724                   ras.num_cells,
1725                   ras.num_cells == 1 ? "" : "s" ));
1726     }
1727     else
1728     {
1729       error = FT_THROW( Memory_Overflow );
1730 
1731       FT_TRACE7(( "band [%d..%d]: to be bisected\n",
1732                   ras.min_ey, ras.max_ey ));
1733     }
1734 
1735     return error;
1736   }
1737 
1738 
1739   static int
1740   gray_convert_glyph( RAS_ARG )
1741   {
1742     const TCoord  yMin = ras.min_ey;
1743     const TCoord  yMax = ras.max_ey;
1744     const TCoord  xMin = ras.min_ex;
1745     const TCoord  xMax = ras.max_ex;
1746 
1747     TCell    buffer[FT_MAX_GRAY_POOL];
1748     size_t   height = (size_t)( yMax - yMin );
1749     size_t   n = FT_MAX_GRAY_POOL / 8;
1750     TCoord   y;
1751     TCoord   bands[32];  /* enough to accommodate bisections */
1752     TCoord*  band;
1753 


1754 
1755     /* set up vertical bands */
1756     if ( height > n )
1757     {
1758       /* two divisions rounded up */
1759       n       = ( height + n - 1 ) / n;
1760       height  = ( height + n - 1 ) / n;
1761     }
1762 
1763     /* memory management */
1764     n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell );
1765 
1766     ras.cells     = buffer + n;
1767     ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
1768     ras.ycells    = (PCell*)buffer;
1769 
1770     for ( y = yMin; y < yMax; )
1771     {
1772       ras.min_ey = y;
1773       y         += height;
1774       ras.max_ey = FT_MIN( y, yMax );
1775 
1776       band    = bands;
1777       band[1] = xMin;
1778       band[0] = xMax;
1779 
1780       do
1781       {
1782         TCoord  width = band[0] - band[1];
1783         int     error;
1784 
1785 
1786         FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) );
1787 
1788         ras.num_cells = 0;
1789         ras.invalid   = 1;
1790         ras.min_ex    = band[1];
1791         ras.max_ex    = band[0];
1792 
1793         error = gray_convert_glyph_inner( RAS_VAR );

1794 
1795         if ( !error )
1796         {
1797           gray_sweep( RAS_VAR );
1798           band--;
1799           continue;
1800         }
1801         else if ( error != ErrRaster_Memory_Overflow )
1802           return 1;
1803 
1804         /* render pool overflow; we will reduce the render band by half */
1805         width >>= 1;
1806 
1807         /* this should never happen even with tiny rendering pool */
1808         if ( width == 0 )
1809         {
1810           FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
1811           return 1;
1812         }
1813 
1814         band++;
1815         band[1]  = band[0];
1816         band[0] += width;
1817       } while ( band >= bands );
1818     }
1819 
1820     return 0;
1821   }
1822 
1823 
1824   static int
1825   gray_raster_render( FT_Raster                raster,
1826                       const FT_Raster_Params*  params )
1827   {
1828     const FT_Outline*  outline    = (const FT_Outline*)params->source;
1829     const FT_Bitmap*   target_map = params->target;
1830     FT_BBox            cbox, clip;
1831 
1832 #ifndef FT_STATIC_RASTER
1833     gray_TWorker  worker[1];
1834 #endif
1835 
1836 
1837     if ( !raster )
1838       return FT_THROW( Invalid_Argument );
1839 
1840     /* this version does not support monochrome rendering */
1841     if ( !( params->flags & FT_RASTER_FLAG_AA ) )
1842       return FT_THROW( Invalid_Mode );
1843 
1844     if ( !outline )
1845       return FT_THROW( Invalid_Outline );
1846 
1847     /* return immediately if the outline is empty */
1848     if ( outline->n_points == 0 || outline->n_contours <= 0 )
1849       return 0;
1850 


1873 
1874       /* nothing to do */
1875       if ( !target_map->width || !target_map->rows )
1876         return 0;
1877 
1878       if ( !target_map->buffer )
1879         return FT_THROW( Invalid_Argument );
1880 
1881       if ( target_map->pitch < 0 )
1882         ras.target.origin = target_map->buffer;
1883       else
1884         ras.target.origin = target_map->buffer
1885               + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch;
1886 
1887       ras.target.pitch = target_map->pitch;
1888 
1889       ras.render_span      = (FT_Raster_Span_Func)NULL;
1890       ras.render_span_data = NULL;
1891     }
1892 
1893     FT_Outline_Get_CBox( outline, &cbox );
1894 
1895     /* reject too large outline coordinates */
1896     if ( cbox.xMin < -0x1000000L || cbox.xMax > 0x1000000L ||
1897          cbox.yMin < -0x1000000L || cbox.yMax > 0x1000000L )
1898       return FT_THROW( Invalid_Outline );
1899 
1900     /* truncate the bounding box to integer pixels */
1901     cbox.xMin = cbox.xMin >> 6;
1902     cbox.yMin = cbox.yMin >> 6;
1903     cbox.xMax = ( cbox.xMax + 63 ) >> 6;
1904     cbox.yMax = ( cbox.yMax + 63 ) >> 6;
1905 
1906     /* compute clipping box */
1907     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )



1908     {
1909       /* compute clip box from target pixmap */
1910       clip.xMin = 0;
1911       clip.yMin = 0;
1912       clip.xMax = (FT_Pos)target_map->width;
1913       clip.yMax = (FT_Pos)target_map->rows;
1914     }
1915     else if ( params->flags & FT_RASTER_FLAG_CLIP )
1916       clip = params->clip_box;
1917     else
1918     {
1919       clip.xMin = -32768L;
1920       clip.yMin = -32768L;
1921       clip.xMax =  32767L;
1922       clip.yMax =  32767L;
1923     }
1924 
1925     /* clip to target bitmap, exit if nothing to do */
1926     ras.min_ex = FT_MAX( cbox.xMin, clip.xMin );
1927     ras.min_ey = FT_MAX( cbox.yMin, clip.yMin );
1928     ras.max_ex = FT_MIN( cbox.xMax, clip.xMax );
1929     ras.max_ey = FT_MIN( cbox.yMax, clip.yMax );
1930 
1931     if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
1932       return 0;
1933 
1934     return gray_convert_glyph( RAS_VAR );
1935   }
1936 
1937 
1938   /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
1939   /****                         a static object.                   *****/
1940 
1941 #ifdef STANDALONE_
1942 
1943   static int
1944   gray_raster_new( void*       memory,
1945                    FT_Raster*  araster )
1946   {
1947     static gray_TRaster  the_raster;
1948 
1949     FT_UNUSED( memory );


   1 /****************************************************************************
   2  *
   3  * ftgrays.c
   4  *
   5  *   A new `perfect' anti-aliasing renderer (body).
   6  *
   7  * Copyright (C) 2000-2019 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, LICENSE.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 file can be compiled without the rest of the FreeType engine, by
  21    * defining the STANDALONE_ macro when compiling it.  You also need to
  22    * put the files `ftgrays.h' and `ftimage.h' into the current
  23    * compilation directory.  Typically, you could do something like
  24    *
  25    * - copy `src/smooth/ftgrays.c' (this file) to your current directory
  26    *
  27    * - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the
  28    *   same directory
  29    *
  30    * - compile `ftgrays' with the STANDALONE_ macro defined, as in
  31    *
  32    *     cc -c -DSTANDALONE_ ftgrays.c
  33    *
  34    * The renderer can be initialized with a call to
  35    * `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated
  36    * with a call to `ft_gray_raster.raster_render'.
  37    *
  38    * See the comments and documentation in the file `ftimage.h' for more
  39    * details on how the raster works.
  40    *
  41    */
  42 
  43   /**************************************************************************
  44    *
  45    * This is a new anti-aliasing scan-converter for FreeType 2.  The
  46    * algorithm used here is _very_ different from the one in the standard
  47    * `ftraster' module.  Actually, `ftgrays' computes the _exact_
  48    * coverage of the outline on each pixel cell.
  49    *
  50    * It is based on ideas that I initially found in Raph Levien's
  51    * excellent LibArt graphics library (see https://www.levien.com/libart
  52    * for more information, though the web pages do not tell anything
  53    * about the renderer; you'll have to dive into the source code to
  54    * understand how it works).
  55    *
  56    * Note, however, that this is a _very_ different implementation
  57    * compared to Raph's.  Coverage information is stored in a very
  58    * different way, and I don't use sorted vector paths.  Also, it doesn't
  59    * use floating point values.
  60    *
  61    * This renderer has the following advantages:
  62    *
  63    * - It doesn't need an intermediate bitmap.  Instead, one can supply a
  64    *   callback function that will be called by the renderer to draw gray
  65    *   spans on any target surface.  You can thus do direct composition on
  66    *   any kind of bitmap, provided that you give the renderer the right
  67    *   callback.
  68    *
  69    * - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on
  70    *   each pixel cell.
  71    *
  72    * - It performs a single pass on the outline (the `standard' FT2
  73    *   renderer makes two passes).
  74    *
  75    * - It can easily be modified to render to _any_ number of gray levels
  76    *   cheaply.
  77    *
  78    * - For small (< 20) pixel sizes, it is faster than the standard
  79    *   renderer.
  80    *
  81    */
  82 
  83 
  84   /**************************************************************************
  85    *
  86    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  87    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  88    * messages during execution.
  89    */
  90 #undef  FT_COMPONENT
  91 #define FT_COMPONENT  smooth
  92 
  93 
  94 #ifdef STANDALONE_
  95 
  96 
  97   /* The size in bytes of the render pool used by the scan-line converter  */
  98   /* to do all of its work.                                                */
  99 #define FT_RENDER_POOL_SIZE  16384L
 100 
 101 
 102   /* Auxiliary macros for token concatenation. */
 103 #define FT_ERR_XCAT( x, y )  x ## y
 104 #define FT_ERR_CAT( x, y )   FT_ERR_XCAT( x, y )
 105 
 106 #define FT_BEGIN_STMNT  do {
 107 #define FT_END_STMNT    } while ( 0 )
 108 
 109 #define FT_MIN( a, b )  ( (a) < (b) ? (a) : (b) )
 110 #define FT_MAX( a, b )  ( (a) > (b) ? (a) : (b) )
 111 #define FT_ABS( a )     ( (a) < 0 ? -(a) : (a) )


 205     FT_UNUSED( error );
 206     FT_UNUSED( line );
 207     FT_UNUSED( file );
 208 
 209     return 0;
 210   }
 211 
 212 
 213   /* we don't handle tracing levels in stand-alone mode; */
 214 #ifndef FT_TRACE5
 215 #define FT_TRACE5( varformat )  FT_Message varformat
 216 #endif
 217 #ifndef FT_TRACE7
 218 #define FT_TRACE7( varformat )  FT_Message varformat
 219 #endif
 220 #ifndef FT_ERROR
 221 #define FT_ERROR( varformat )   FT_Message varformat
 222 #endif
 223 
 224 #define FT_THROW( e )                               \
 225           ( FT_Throw( FT_ERR_CAT( ErrRaster_, e ),  \
 226                       __LINE__,                     \
 227                       __FILE__ )                  | \
 228             FT_ERR_CAT( ErrRaster_, e )           )
 229 
 230 #else /* !FT_DEBUG_LEVEL_TRACE */
 231 
 232 #define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
 233 #define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
 234 #define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
 235 #define FT_THROW( e )   FT_ERR_CAT( ErrRaster_, e )
 236 
 237 
 238 #endif /* !FT_DEBUG_LEVEL_TRACE */
 239 
 240 
 241 #define FT_DEFINE_OUTLINE_FUNCS( class_,               \
 242                                  move_to_, line_to_,   \
 243                                  conic_to_, cubic_to_, \
 244                                  shift_, delta_ )      \
 245           static const FT_Outline_Funcs class_ =       \
 246           {                                            \
 247             move_to_,                                  \
 248             line_to_,                                  \


 262             raster_new_,                                          \
 263             raster_reset_,                                        \
 264             raster_set_mode_,                                     \
 265             raster_render_,                                       \
 266             raster_done_                                          \
 267          };
 268 
 269 
 270 #else /* !STANDALONE_ */
 271 
 272 
 273 #include <ft2build.h>
 274 #include "ftgrays.h"
 275 #include FT_INTERNAL_OBJECTS_H
 276 #include FT_INTERNAL_DEBUG_H
 277 #include FT_INTERNAL_CALC_H
 278 #include FT_OUTLINE_H
 279 
 280 #include "ftsmerrs.h"
 281 


 282 #define Smooth_Err_Invalid_Mode     Smooth_Err_Cannot_Render_Glyph
 283 #define Smooth_Err_Memory_Overflow  Smooth_Err_Out_Of_Memory
 284 #define ErrRaster_Memory_Overflow   Smooth_Err_Out_Of_Memory
 285 
 286 
 287 #endif /* !STANDALONE_ */
 288 
 289 
 290 #ifndef FT_MEM_SET
 291 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
 292 #endif
 293 
 294 #ifndef FT_MEM_ZERO
 295 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
 296 #endif
 297 
 298 #ifndef FT_ZERO
 299 #define FT_ZERO( p )  FT_MEM_ZERO( p, sizeof ( *(p) ) )
 300 #endif
 301 


 376     (remainder) = (type)( (dividend) - (quotient) * (divisor) );   \
 377     if ( (remainder) < 0 )                                         \
 378     {                                                              \
 379       (quotient)--;                                                \
 380       (remainder) += (type)(divisor);                              \
 381     }                                                              \
 382   FT_END_STMNT
 383 #endif /* __arm__ */
 384 
 385 
 386   /* These macros speed up repetitive divisions by replacing them */
 387   /* with multiplications and right shifts.                       */
 388 #define FT_UDIVPREP( c, b )                                        \
 389   long  b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \
 390                     : 0
 391 #define FT_UDIV( a, b )                                        \
 392   ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >>   \
 393     ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
 394 
 395 
 396   /**************************************************************************
 397    *
 398    * TYPE DEFINITIONS
 399    */
 400 
 401   /* don't change the following types to FT_Int or FT_Pos, since we might */
 402   /* need to define them to "float" or "double" when experimenting with   */
 403   /* new algorithms                                                       */
 404 
 405   typedef long  TPos;     /* subpixel coordinate               */
 406   typedef int   TCoord;   /* integer scanline/pixel coordinate */
 407   typedef int   TArea;    /* cell areas, coordinate products   */
 408 
 409 
 410   typedef struct TCell_*  PCell;
 411 
 412   typedef struct  TCell_
 413   {
 414     TCoord  x;     /* same with gray_TWorker.ex    */
 415     TCoord  cover; /* same with gray_TWorker.cover */
 416     TArea   area;
 417     PCell   next;
 418 
 419   } TCell;


 497     int  y;
 498 
 499 
 500     for ( y = ras.min_ey; y < ras.max_ey; y++ )
 501     {
 502       PCell  cell = ras.ycells[y - ras.min_ey];
 503 
 504 
 505       printf( "%3d:", y );
 506 
 507       for ( ; cell != NULL; cell = cell->next )
 508         printf( " (%3d, c:%4d, a:%6d)",
 509                 cell->x, cell->cover, cell->area );
 510       printf( "\n" );
 511     }
 512   }
 513 
 514 #endif /* FT_DEBUG_LEVEL_TRACE */
 515 
 516 
 517   /**************************************************************************
 518    *
 519    * Record the current cell in the table.
 520    */
 521   static void
 522   gray_record_cell( RAS_ARG )
 523   {
 524     PCell  *pcell, cell;
 525     TCoord  x = ras.ex;
 526 
 527 
 528     pcell = &ras.ycells[ras.ey - ras.min_ey];
 529     for (;;)
 530     {
 531       cell = *pcell;
 532       if ( !cell || cell->x > x )
 533         break;
 534 
 535       if ( cell->x == x )
 536         goto Found;
 537 
 538       pcell = &cell->next;
 539     }
 540 


 542       ft_longjmp( ras.jump_buffer, 1 );
 543 
 544     /* insert new cell */
 545     cell        = ras.cells + ras.num_cells++;
 546     cell->x     = x;
 547     cell->area  = ras.area;
 548     cell->cover = ras.cover;
 549 
 550     cell->next  = *pcell;
 551     *pcell      = cell;
 552 
 553     return;
 554 
 555   Found:
 556     /* update old cell */
 557     cell->area  += ras.area;
 558     cell->cover += ras.cover;
 559   }
 560 
 561 
 562   /**************************************************************************
 563    *
 564    * Set the current cell to a new position.
 565    */
 566   static void
 567   gray_set_cell( RAS_ARG_ TCoord  ex,
 568                           TCoord  ey )
 569   {
 570     /* Move the cell pointer to a new position.  We set the `invalid'      */
 571     /* flag to indicate that the cell isn't part of those we're interested */
 572     /* in during the render phase.  This means that:                       */
 573     /*                                                                     */
 574     /* . the new vertical position must be within min_ey..max_ey-1.        */
 575     /* . the new horizontal position must be strictly less than max_ex     */
 576     /*                                                                     */
 577     /* Note that if a cell is to the left of the clipping region, it is    */
 578     /* actually set to the (min_ex-1) horizontal position.                 */
 579 
 580     if ( ex < ras.min_ex )
 581       ex = ras.min_ex - 1;
 582 
 583     /* record the current one if it is valid and substantial */
 584     if ( !ras.invalid && ( ras.area || ras.cover ) )
 585       gray_record_cell( RAS_VAR );
 586 
 587     ras.area  = 0;
 588     ras.cover = 0;
 589     ras.ex    = ex;
 590     ras.ey    = ey;
 591 
 592     ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey ||
 593                     ex >= ras.max_ex );
 594   }
 595 
 596 
 597 #ifndef FT_LONG64
 598 
 599   /**************************************************************************
 600    *
 601    * Render a scanline as one or more cells.
 602    */
 603   static void
 604   gray_render_scanline( RAS_ARG_ TCoord  ey,
 605                                  TPos    x1,
 606                                  TCoord  y1,
 607                                  TPos    x2,
 608                                  TCoord  y2 )
 609   {
 610     TCoord  ex1, ex2, fx1, fx2, first, dy, delta, mod;
 611     TPos    p, dx;
 612     int     incr;
 613 
 614 
 615     ex1 = TRUNC( x1 );
 616     ex2 = TRUNC( x2 );
 617 
 618     /* trivial case.  Happens often */
 619     if ( y1 == y2 )
 620     {
 621       gray_set_cell( RAS_VAR_ ex2, ey );
 622       return;


 677         }
 678 
 679         ras.area  += (TArea)( ONE_PIXEL * delta );
 680         ras.cover += delta;
 681         y1        += delta;
 682         ex1       += incr;
 683         gray_set_cell( RAS_VAR_ ex1, ey );
 684       } while ( ex1 != ex2 );
 685     }
 686 
 687     fx1 = ONE_PIXEL - first;
 688 
 689   End:
 690     dy = y2 - y1;
 691 
 692     ras.area  += (TArea)( ( fx1 + fx2 ) * dy );
 693     ras.cover += dy;
 694   }
 695 
 696 
 697   /**************************************************************************
 698    *
 699    * Render a given line as a series of scanlines.
 700    */
 701   static void
 702   gray_render_line( RAS_ARG_ TPos  to_x,
 703                              TPos  to_y )
 704   {
 705     TCoord  ey1, ey2, fy1, fy2, first, delta, mod;
 706     TPos    p, dx, dy, x, x2;
 707     int     incr;
 708 
 709 
 710     ey1 = TRUNC( ras.y );
 711     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
 712 
 713     /* perform vertical clipping */
 714     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
 715          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
 716       goto End;
 717 
 718     fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
 719     fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
 720 


 818                                        x, ONE_PIXEL - first,
 819                                        x2, first );
 820         x = x2;
 821 
 822         ey1 += incr;
 823         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
 824       } while ( ey1 != ey2 );
 825     }
 826 
 827     gray_render_scanline( RAS_VAR_ ey1,
 828                                    x, ONE_PIXEL - first,
 829                                    to_x, fy2 );
 830 
 831   End:
 832     ras.x       = to_x;
 833     ras.y       = to_y;
 834   }
 835 
 836 #else
 837 
 838   /**************************************************************************
 839    *
 840    * Render a straight line across multiple cells in any direction.
 841    */
 842   static void
 843   gray_render_line( RAS_ARG_ TPos  to_x,
 844                              TPos  to_y )
 845   {
 846     TPos    dx, dy, fx1, fy1, fx2, fy2;
 847     TCoord  ex1, ex2, ey1, ey2;
 848 
 849 
 850     ey1 = TRUNC( ras.y );
 851     ey2 = TRUNC( to_y );
 852 
 853     /* perform vertical clipping */
 854     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
 855          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
 856       goto End;
 857 
 858     ex1 = TRUNC( ras.x );
 859     ex2 = TRUNC( to_x );
 860 
 861     fx1 = ras.x - SUBPIXELS( ex1 );


1311         if ( cover != 0 && cell->x > x )
1312           gray_hline( RAS_VAR_ x, y, cover, cell->x - x );
1313 
1314         cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
1315         area   = cover - cell->area;
1316 
1317         if ( area != 0 && cell->x >= ras.min_ex )
1318           gray_hline( RAS_VAR_ cell->x, y, area, 1 );
1319 
1320         x = cell->x + 1;
1321       }
1322 
1323       if ( cover != 0 )
1324         gray_hline( RAS_VAR_ x, y, cover, ras.max_ex - x );
1325     }
1326   }
1327 
1328 
1329 #ifdef STANDALONE_
1330 
1331   /**************************************************************************
1332    *
1333    * The following functions should only compile in stand-alone mode,
1334    * i.e., when building this component without the rest of FreeType.
1335    *
1336    */
1337 
1338   /**************************************************************************
1339    *
1340    * @Function:
1341    *   FT_Outline_Decompose
1342    *
1343    * @Description:
1344    *   Walk over an outline's structure to decompose it into individual
1345    *   segments and Bézier arcs.  This function is also able to emit
1346    *   `move to' and `close to' operations to indicate the start and end
1347    *   of new contours in the outline.
1348    *
1349    * @Input:
1350    *   outline ::
1351    *     A pointer to the source target.
1352    *
1353    *   func_interface ::
1354    *     A table of `emitters', i.e., function pointers
1355    *     called during decomposition to indicate path
1356    *     operations.
1357    *
1358    * @InOut:
1359    *   user ::
1360    *     A typeless pointer which is passed to each
1361    *     emitter during the decomposition.  It can be
1362    *     used to store the state during the
1363    *     decomposition.
1364    *
1365    * @Return:
1366    *   Error code.  0 means success.
1367    */
1368   static int
1369   FT_Outline_Decompose( const FT_Outline*        outline,
1370                         const FT_Outline_Funcs*  func_interface,
1371                         void*                    user )
1372   {
1373 #undef SCALED
1374 #define SCALED( x )  ( ( (x) << shift ) - delta )
1375 
1376     FT_Vector   v_last;
1377     FT_Vector   v_control;
1378     FT_Vector   v_start;
1379 
1380     FT_Vector*  point;
1381     FT_Vector*  limit;
1382     char*       tags;
1383 
1384     int         error;
1385 
1386     int   n;         /* index of contour in outline     */
1387     int   first;     /* index of first point in contour */


1594       error = func_interface->line_to( &v_start, user );
1595 
1596    Close:
1597       if ( error )
1598         goto Exit;
1599 
1600       first = last + 1;
1601     }
1602 
1603     FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1604     return 0;
1605 
1606   Exit:
1607     FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error ));
1608     return error;
1609 
1610   Invalid_Outline:
1611     return FT_THROW( Invalid_Outline );
1612   }
1613 











































































1614 #endif /* STANDALONE_ */
1615 
1616 
1617   FT_DEFINE_OUTLINE_FUNCS(
1618     func_interface,
1619 
1620     (FT_Outline_MoveTo_Func) gray_move_to,   /* move_to  */
1621     (FT_Outline_LineTo_Func) gray_line_to,   /* line_to  */
1622     (FT_Outline_ConicTo_Func)gray_conic_to,  /* conic_to */
1623     (FT_Outline_CubicTo_Func)gray_cubic_to,  /* cubic_to */
1624 
1625     0,                                       /* shift    */
1626     0                                        /* delta    */
1627   )
1628 
1629 
1630   static int
1631   gray_convert_glyph_inner( RAS_ARG,
1632                             int  continued )
1633   {

1634     volatile int  error = 0;
1635 




1636 
1637     if ( ft_setjmp( ras.jump_buffer ) == 0 )
1638     {
1639       if ( continued )
1640         FT_Trace_Disable();
1641       error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
1642       if ( continued )
1643         FT_Trace_Enable();
1644 
1645       if ( !ras.invalid )
1646         gray_record_cell( RAS_VAR );
1647 
1648       FT_TRACE7(( "band [%d..%d]: %d cell%s\n",
1649                   ras.min_ey,
1650                   ras.max_ey,
1651                   ras.num_cells,
1652                   ras.num_cells == 1 ? "" : "s" ));
1653     }
1654     else
1655     {
1656       error = FT_THROW( Memory_Overflow );
1657 
1658       FT_TRACE7(( "band [%d..%d]: to be bisected\n",
1659                   ras.min_ey, ras.max_ey ));
1660     }
1661 
1662     return error;
1663   }
1664 
1665 
1666   static int
1667   gray_convert_glyph( RAS_ARG )
1668   {
1669     const TCoord  yMin = ras.min_ey;
1670     const TCoord  yMax = ras.max_ey;


1671 
1672     TCell    buffer[FT_MAX_GRAY_POOL];
1673     size_t   height = (size_t)( yMax - yMin );
1674     size_t   n = FT_MAX_GRAY_POOL / 8;
1675     TCoord   y;
1676     TCoord   bands[32];  /* enough to accommodate bisections */
1677     TCoord*  band;
1678 
1679     int  continued = 0;
1680 
1681 
1682     /* set up vertical bands */
1683     if ( height > n )
1684     {
1685       /* two divisions rounded up */
1686       n       = ( height + n - 1 ) / n;
1687       height  = ( height + n - 1 ) / n;
1688     }
1689 
1690     /* memory management */
1691     n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell );
1692 
1693     ras.cells     = buffer + n;
1694     ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n );
1695     ras.ycells    = (PCell*)buffer;
1696 
1697     for ( y = yMin; y < yMax; )
1698     {
1699       ras.min_ey = y;
1700       y         += height;
1701       ras.max_ey = FT_MIN( y, yMax );
1702 
1703       band    = bands;
1704       band[1] = ras.min_ey;
1705       band[0] = ras.max_ey;
1706 
1707       do
1708       {
1709         TCoord  width = band[0] - band[1];
1710         int     error;
1711 
1712 
1713         FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) );
1714 
1715         ras.num_cells = 0;
1716         ras.invalid   = 1;
1717         ras.min_ey    = band[1];
1718         ras.max_ey    = band[0];
1719 
1720         error     = gray_convert_glyph_inner( RAS_VAR, continued );
1721         continued = 1;
1722 
1723         if ( !error )
1724         {
1725           gray_sweep( RAS_VAR );
1726           band--;
1727           continue;
1728         }
1729         else if ( error != ErrRaster_Memory_Overflow )
1730           return 1;
1731 
1732         /* render pool overflow; we will reduce the render band by half */
1733         width >>= 1;
1734 
1735         /* this should never happen even with tiny rendering pool */
1736         if ( width == 0 )
1737         {
1738           FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
1739           return 1;
1740         }
1741 
1742         band++;
1743         band[1]  = band[0];
1744         band[0] += width;
1745       } while ( band >= bands );
1746     }
1747 
1748     return 0;
1749   }
1750 
1751 
1752   static int
1753   gray_raster_render( FT_Raster                raster,
1754                       const FT_Raster_Params*  params )
1755   {
1756     const FT_Outline*  outline    = (const FT_Outline*)params->source;
1757     const FT_Bitmap*   target_map = params->target;
1758     FT_BBox            clip;
1759 
1760 #ifndef FT_STATIC_RASTER
1761     gray_TWorker  worker[1];
1762 #endif
1763 
1764 
1765     if ( !raster )
1766       return FT_THROW( Invalid_Argument );
1767 
1768     /* this version does not support monochrome rendering */
1769     if ( !( params->flags & FT_RASTER_FLAG_AA ) )
1770       return FT_THROW( Invalid_Mode );
1771 
1772     if ( !outline )
1773       return FT_THROW( Invalid_Outline );
1774 
1775     /* return immediately if the outline is empty */
1776     if ( outline->n_points == 0 || outline->n_contours <= 0 )
1777       return 0;
1778 


1801 
1802       /* nothing to do */
1803       if ( !target_map->width || !target_map->rows )
1804         return 0;
1805 
1806       if ( !target_map->buffer )
1807         return FT_THROW( Invalid_Argument );
1808 
1809       if ( target_map->pitch < 0 )
1810         ras.target.origin = target_map->buffer;
1811       else
1812         ras.target.origin = target_map->buffer
1813               + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch;
1814 
1815       ras.target.pitch = target_map->pitch;
1816 
1817       ras.render_span      = (FT_Raster_Span_Func)NULL;
1818       ras.render_span_data = NULL;
1819     }
1820 













1821     /* compute clipping box */
1822     if ( params->flags & FT_RASTER_FLAG_DIRECT &&
1823          params->flags & FT_RASTER_FLAG_CLIP   )
1824       clip = params->clip_box;
1825     else
1826     {
1827       /* compute clip box from target pixmap */
1828       clip.xMin = 0;
1829       clip.yMin = 0;
1830       clip.xMax = (FT_Pos)target_map->width;
1831       clip.yMax = (FT_Pos)target_map->rows;
1832     }









1833 
1834     /* clip to target bitmap, exit if nothing to do */
1835     ras.min_ex = clip.xMin;
1836     ras.min_ey = clip.yMin;
1837     ras.max_ex = clip.xMax;
1838     ras.max_ey = clip.yMax;
1839 
1840     if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
1841       return 0;
1842 
1843     return gray_convert_glyph( RAS_VAR );
1844   }
1845 
1846 
1847   /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
1848   /****                         a static object.                   *****/
1849 
1850 #ifdef STANDALONE_
1851 
1852   static int
1853   gray_raster_new( void*       memory,
1854                    FT_Raster*  araster )
1855   {
1856     static gray_TRaster  the_raster;
1857 
1858     FT_UNUSED( memory );


< prev index next >