PageRenderTime 1014ms CodeModel.GetById 263ms app.highlight 589ms RepoModel.GetById 144ms app.codeStats 1ms

/src/compiler/android-ndk/jni/freetype/src/smooth/ftgrays.c

http://ftk.googlecode.com/
C | 2090 lines | 1383 code | 458 blank | 249 comment | 219 complexity | 9b2d254de9b785e1aff0414e1395ab81 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/***************************************************************************/
   2/*                                                                         */
   3/*  ftgrays.c                                                              */
   4/*                                                                         */
   5/*    A new `perfect' anti-aliasing renderer (body).                       */
   6/*                                                                         */
   7/*  Copyright 2000-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009 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 -D_STANDALONE_ 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  /* define this to dump debugging information */
  98/* #define FT_DEBUG_LEVEL_TRACE */
  99
 100
 101#ifdef FT_DEBUG_LEVEL_TRACE
 102#include <stdio.h>
 103#include <stdarg.h>
 104#endif
 105
 106#include <string.h>
 107#include <setjmp.h>
 108#include <limits.h>
 109#define FT_UINT_MAX  UINT_MAX
 110
 111#define ft_memset   memset
 112
 113#define ft_setjmp   setjmp
 114#define ft_longjmp  longjmp
 115#define ft_jmp_buf  jmp_buf
 116
 117
 118#define ErrRaster_Invalid_Mode      -2
 119#define ErrRaster_Invalid_Outline   -1
 120#define ErrRaster_Invalid_Argument  -3
 121#define ErrRaster_Memory_Overflow   -4
 122
 123#define FT_BEGIN_HEADER
 124#define FT_END_HEADER
 125
 126#include "ftimage.h"
 127#include "ftgrays.h"
 128
 129
 130  /* This macro is used to indicate that a function parameter is unused. */
 131  /* Its purpose is simply to reduce compiler warnings.  Note also that  */
 132  /* simply defining it as `(void)x' doesn't avoid warnings with certain */
 133  /* ANSI compilers (e.g. LCC).                                          */
 134#define FT_UNUSED( x )  (x) = (x)
 135
 136
 137  /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
 138
 139#ifdef FT_DEBUG_LEVEL_TRACE
 140
 141  void
 142  FT_Message( const char*  fmt,
 143              ... )
 144  {
 145    va_list  ap;
 146
 147
 148    va_start( ap, fmt );
 149    vfprintf( stderr, fmt, ap );
 150    va_end( ap );
 151  }
 152
 153  /* we don't handle tracing levels in stand-alone mode; */
 154#ifndef FT_TRACE5
 155#define FT_TRACE5( varformat )  FT_Message varformat
 156#endif
 157#ifndef FT_TRACE7
 158#define FT_TRACE7( varformat )  FT_Message varformat
 159#endif
 160#ifndef FT_ERROR
 161#define FT_ERROR( varformat )   FT_Message varformat
 162#endif
 163
 164#else /* !FT_DEBUG_LEVEL_TRACE */
 165
 166#define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
 167#define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
 168#define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
 169
 170#endif /* !FT_DEBUG_LEVEL_TRACE */
 171
 172
 173#define FT_DEFINE_OUTLINE_FUNCS( class_,               \
 174                                 move_to_, line_to_,   \
 175                                 conic_to_, cubic_to_, \
 176                                 shift_, delta_ )      \
 177          static const FT_Outline_Funcs class_ =       \
 178          {                                            \
 179            move_to_,                                  \
 180            line_to_,                                  \
 181            conic_to_,                                 \
 182            cubic_to_,                                 \
 183            shift_,                                    \
 184            delta_                                     \
 185         };
 186                                          
 187#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_,            \
 188                                raster_new_, raster_reset_,       \
 189                                raster_set_mode_, raster_render_, \
 190                                raster_done_ )                    \
 191          const FT_Raster_Funcs class_ =                          \
 192          {                                                       \
 193            glyph_format_,                                        \
 194            raster_new_,                                          \
 195            raster_reset_,                                        \
 196            raster_set_mode_,                                     \
 197            raster_render_,                                       \
 198            raster_done_                                          \
 199         };
 200
 201#else /* !_STANDALONE_ */
 202
 203
 204#include <ft2build.h>
 205#include "ftgrays.h"
 206#include FT_INTERNAL_OBJECTS_H
 207#include FT_INTERNAL_DEBUG_H
 208#include FT_OUTLINE_H
 209
 210#include "ftsmerrs.h"
 211
 212#include "ftspic.h"
 213
 214#define ErrRaster_Invalid_Mode      Smooth_Err_Cannot_Render_Glyph
 215#define ErrRaster_Invalid_Outline   Smooth_Err_Invalid_Outline
 216#define ErrRaster_Memory_Overflow   Smooth_Err_Out_Of_Memory
 217#define ErrRaster_Invalid_Argument  Smooth_Err_Invalid_Argument
 218
 219#endif /* !_STANDALONE_ */
 220
 221#ifndef FT_MEM_SET
 222#define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
 223#endif
 224
 225#ifndef FT_MEM_ZERO
 226#define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
 227#endif
 228
 229  /* as usual, for the speed hungry :-) */
 230
 231#ifndef FT_STATIC_RASTER
 232
 233#define RAS_ARG   PWorker  worker
 234#define RAS_ARG_  PWorker  worker,
 235
 236#define RAS_VAR   worker
 237#define RAS_VAR_  worker,
 238
 239#else /* FT_STATIC_RASTER */
 240
 241#define RAS_ARG   /* empty */
 242#define RAS_ARG_  /* empty */
 243#define RAS_VAR   /* empty */
 244#define RAS_VAR_  /* empty */
 245
 246#endif /* FT_STATIC_RASTER */
 247
 248
 249  /* must be at least 6 bits! */
 250#define PIXEL_BITS  8
 251
 252#define ONE_PIXEL       ( 1L << PIXEL_BITS )
 253#define PIXEL_MASK      ( -1L << PIXEL_BITS )
 254#define TRUNC( x )      ( (TCoord)( (x) >> PIXEL_BITS ) )
 255#define SUBPIXELS( x )  ( (TPos)(x) << PIXEL_BITS )
 256#define FLOOR( x )      ( (x) & -ONE_PIXEL )
 257#define CEILING( x )    ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
 258#define ROUND( x )      ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
 259
 260#if PIXEL_BITS >= 6
 261#define UPSCALE( x )    ( (x) << ( PIXEL_BITS - 6 ) )
 262#define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
 263#else
 264#define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
 265#define DOWNSCALE( x )  ( (x) << ( 6 - PIXEL_BITS ) )
 266#endif
 267
 268
 269  /*************************************************************************/
 270  /*                                                                       */
 271  /*   TYPE DEFINITIONS                                                    */
 272  /*                                                                       */
 273
 274  /* don't change the following types to FT_Int or FT_Pos, since we might */
 275  /* need to define them to "float" or "double" when experimenting with   */
 276  /* new algorithms                                                       */
 277
 278  typedef long  TCoord;   /* integer scanline/pixel coordinate */
 279  typedef long  TPos;     /* sub-pixel coordinate              */
 280
 281  /* determine the type used to store cell areas.  This normally takes at */
 282  /* least PIXEL_BITS*2 + 1 bits.  On 16-bit systems, we need to use      */
 283  /* `long' instead of `int', otherwise bad things happen                 */
 284
 285#if PIXEL_BITS <= 7
 286
 287  typedef int  TArea;
 288
 289#else /* PIXEL_BITS >= 8 */
 290
 291  /* approximately determine the size of integers using an ANSI-C header */
 292#if FT_UINT_MAX == 0xFFFFU
 293  typedef long  TArea;
 294#else
 295  typedef int   TArea;
 296#endif
 297
 298#endif /* PIXEL_BITS >= 8 */
 299
 300
 301  /* maximal number of gray spans in a call to the span callback */
 302#define FT_MAX_GRAY_SPANS  32
 303
 304
 305  typedef struct TCell_*  PCell;
 306
 307  typedef struct  TCell_
 308  {
 309    TPos   x;     /* same with TWorker.ex */
 310    TCoord cover; /* same with TWorker.cover */
 311    TArea  area;
 312    PCell  next;
 313
 314  } TCell;
 315
 316
 317  typedef struct  TWorker_
 318  {
 319    TCoord  ex, ey;
 320    TPos    min_ex, max_ex;
 321    TPos    min_ey, max_ey;
 322    TPos    count_ex, count_ey;
 323
 324    TArea   area;
 325    TCoord  cover;
 326    int     invalid;
 327
 328    PCell   cells;
 329    FT_PtrDist  max_cells;
 330    FT_PtrDist  num_cells;
 331
 332    TCoord  cx, cy;
 333    TPos    x,  y;
 334
 335    TPos    last_ey;
 336
 337    FT_Vector   bez_stack[32 * 3 + 1];
 338    int         lev_stack[32];
 339
 340    FT_Outline  outline;
 341    FT_Bitmap   target;
 342    FT_BBox     clip_box;
 343
 344    FT_Span     gray_spans[FT_MAX_GRAY_SPANS];
 345    int         num_gray_spans;
 346
 347    FT_Raster_Span_Func  render_span;
 348    void*                render_span_data;
 349    int                  span_y;
 350
 351    int  band_size;
 352    int  band_shoot;
 353    int  conic_level;
 354    int  cubic_level;
 355
 356    ft_jmp_buf  jump_buffer;
 357
 358    void*       buffer;
 359    long        buffer_size;
 360
 361    PCell*     ycells;
 362    TPos       ycount;
 363
 364  } TWorker, *PWorker;
 365
 366
 367#ifndef FT_STATIC_RASTER
 368#define ras  (*worker)
 369#else
 370  static TWorker  ras;
 371#endif
 372
 373
 374  typedef struct TRaster_
 375  {
 376    void*    buffer;
 377    long     buffer_size;
 378    int      band_size;
 379    void*    memory;
 380    PWorker  worker;
 381
 382  } TRaster, *PRaster;
 383
 384
 385
 386  /*************************************************************************/
 387  /*                                                                       */
 388  /* Initialize the cells table.                                           */
 389  /*                                                                       */
 390  static void
 391  gray_init_cells( RAS_ARG_ void*  buffer,
 392                   long            byte_size )
 393  {
 394    ras.buffer      = buffer;
 395    ras.buffer_size = byte_size;
 396
 397    ras.ycells      = (PCell*) buffer;
 398    ras.cells       = NULL;
 399    ras.max_cells   = 0;
 400    ras.num_cells   = 0;
 401    ras.area        = 0;
 402    ras.cover       = 0;
 403    ras.invalid     = 1;
 404  }
 405
 406
 407  /*************************************************************************/
 408  /*                                                                       */
 409  /* Compute the outline bounding box.                                     */
 410  /*                                                                       */
 411  static void
 412  gray_compute_cbox( RAS_ARG )
 413  {
 414    FT_Outline*  outline = &ras.outline;
 415    FT_Vector*   vec     = outline->points;
 416    FT_Vector*   limit   = vec + outline->n_points;
 417
 418
 419    if ( outline->n_points <= 0 )
 420    {
 421      ras.min_ex = ras.max_ex = 0;
 422      ras.min_ey = ras.max_ey = 0;
 423      return;
 424    }
 425
 426    ras.min_ex = ras.max_ex = vec->x;
 427    ras.min_ey = ras.max_ey = vec->y;
 428
 429    vec++;
 430
 431    for ( ; vec < limit; vec++ )
 432    {
 433      TPos  x = vec->x;
 434      TPos  y = vec->y;
 435
 436
 437      if ( x < ras.min_ex ) ras.min_ex = x;
 438      if ( x > ras.max_ex ) ras.max_ex = x;
 439      if ( y < ras.min_ey ) ras.min_ey = y;
 440      if ( y > ras.max_ey ) ras.max_ey = y;
 441    }
 442
 443    /* truncate the bounding box to integer pixels */
 444    ras.min_ex = ras.min_ex >> 6;
 445    ras.min_ey = ras.min_ey >> 6;
 446    ras.max_ex = ( ras.max_ex + 63 ) >> 6;
 447    ras.max_ey = ( ras.max_ey + 63 ) >> 6;
 448  }
 449
 450
 451  /*************************************************************************/
 452  /*                                                                       */
 453  /* Record the current cell in the table.                                 */
 454  /*                                                                       */
 455  static PCell
 456  gray_find_cell( RAS_ARG )
 457  {
 458    PCell  *pcell, cell;
 459    TPos    x = ras.ex;
 460
 461
 462    if ( x > ras.count_ex )
 463      x = ras.count_ex;
 464
 465    pcell = &ras.ycells[ras.ey];
 466    for (;;)
 467    {
 468      cell = *pcell;
 469      if ( cell == NULL || cell->x > x )
 470        break;
 471
 472      if ( cell->x == x )
 473        goto Exit;
 474
 475      pcell = &cell->next;
 476    }
 477
 478    if ( ras.num_cells >= ras.max_cells )
 479      ft_longjmp( ras.jump_buffer, 1 );
 480
 481    cell        = ras.cells + ras.num_cells++;
 482    cell->x     = x;
 483    cell->area  = 0;
 484    cell->cover = 0;
 485
 486    cell->next  = *pcell;
 487    *pcell      = cell;
 488
 489  Exit:
 490    return cell;
 491  }
 492
 493
 494  static void
 495  gray_record_cell( RAS_ARG )
 496  {
 497    if ( !ras.invalid && ( ras.area | ras.cover ) )
 498    {
 499      PCell  cell = gray_find_cell( RAS_VAR );
 500
 501
 502      cell->area  += ras.area;
 503      cell->cover += ras.cover;
 504    }
 505  }
 506
 507
 508  /*************************************************************************/
 509  /*                                                                       */
 510  /* Set the current cell to a new position.                               */
 511  /*                                                                       */
 512  static void
 513  gray_set_cell( RAS_ARG_ TCoord  ex,
 514                          TCoord  ey )
 515  {
 516    /* Move the cell pointer to a new position.  We set the `invalid'      */
 517    /* flag to indicate that the cell isn't part of those we're interested */
 518    /* in during the render phase.  This means that:                       */
 519    /*                                                                     */
 520    /* . the new vertical position must be within min_ey..max_ey-1.        */
 521    /* . the new horizontal position must be strictly less than max_ex     */
 522    /*                                                                     */
 523    /* Note that if a cell is to the left of the clipping region, it is    */
 524    /* actually set to the (min_ex-1) horizontal position.                 */
 525
 526    /* All cells that are on the left of the clipping region go to the */
 527    /* min_ex - 1 horizontal position.                                 */
 528    ey -= ras.min_ey;
 529
 530    if ( ex > ras.max_ex )
 531      ex = ras.max_ex;
 532
 533    ex -= ras.min_ex;
 534    if ( ex < 0 )
 535      ex = -1;
 536
 537    /* are we moving to a different cell ? */
 538    if ( ex != ras.ex || ey != ras.ey )
 539    {
 540      /* record the current one if it is valid */
 541      if ( !ras.invalid )
 542        gray_record_cell( RAS_VAR );
 543
 544      ras.area  = 0;
 545      ras.cover = 0;
 546    }
 547
 548    ras.ex      = ex;
 549    ras.ey      = ey;
 550    ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
 551                              ex >= ras.count_ex           );
 552  }
 553
 554
 555  /*************************************************************************/
 556  /*                                                                       */
 557  /* Start a new contour at a given cell.                                  */
 558  /*                                                                       */
 559  static void
 560  gray_start_cell( RAS_ARG_ TCoord  ex,
 561                            TCoord  ey )
 562  {
 563    if ( ex > ras.max_ex )
 564      ex = (TCoord)( ras.max_ex );
 565
 566    if ( ex < ras.min_ex )
 567      ex = (TCoord)( ras.min_ex - 1 );
 568
 569    ras.area    = 0;
 570    ras.cover   = 0;
 571    ras.ex      = ex - ras.min_ex;
 572    ras.ey      = ey - ras.min_ey;
 573    ras.last_ey = SUBPIXELS( ey );
 574    ras.invalid = 0;
 575
 576    gray_set_cell( RAS_VAR_ ex, ey );
 577  }
 578
 579
 580  /*************************************************************************/
 581  /*                                                                       */
 582  /* Render a scanline as one or more cells.                               */
 583  /*                                                                       */
 584  static void
 585  gray_render_scanline( RAS_ARG_ TCoord  ey,
 586                                 TPos    x1,
 587                                 TCoord  y1,
 588                                 TPos    x2,
 589                                 TCoord  y2 )
 590  {
 591    TCoord  ex1, ex2, fx1, fx2, delta, mod, lift, rem;
 592    long    p, first, dx;
 593    int     incr;
 594
 595
 596    dx = x2 - x1;
 597
 598    ex1 = TRUNC( x1 );
 599    ex2 = TRUNC( x2 );
 600    fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
 601    fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
 602
 603    /* trivial case.  Happens often */
 604    if ( y1 == y2 )
 605    {
 606      gray_set_cell( RAS_VAR_ ex2, ey );
 607      return;
 608    }
 609
 610    /* everything is located in a single cell.  That is easy! */
 611    /*                                                        */
 612    if ( ex1 == ex2 )
 613    {
 614      delta      = y2 - y1;
 615      ras.area  += (TArea)(( fx1 + fx2 ) * delta);
 616      ras.cover += delta;
 617      return;
 618    }
 619
 620    /* ok, we'll have to render a run of adjacent cells on the same */
 621    /* scanline...                                                  */
 622    /*                                                              */
 623    p     = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
 624    first = ONE_PIXEL;
 625    incr  = 1;
 626
 627    if ( dx < 0 )
 628    {
 629      p     = fx1 * ( y2 - y1 );
 630      first = 0;
 631      incr  = -1;
 632      dx    = -dx;
 633    }
 634
 635    delta = (TCoord)( p / dx );
 636    mod   = (TCoord)( p % dx );
 637    if ( mod < 0 )
 638    {
 639      delta--;
 640      mod += (TCoord)dx;
 641    }
 642
 643    ras.area  += (TArea)(( fx1 + first ) * delta);
 644    ras.cover += delta;
 645
 646    ex1 += incr;
 647    gray_set_cell( RAS_VAR_ ex1, ey );
 648    y1  += delta;
 649
 650    if ( ex1 != ex2 )
 651    {
 652      p    = ONE_PIXEL * ( y2 - y1 + delta );
 653      lift = (TCoord)( p / dx );
 654      rem  = (TCoord)( p % dx );
 655      if ( rem < 0 )
 656      {
 657        lift--;
 658        rem += (TCoord)dx;
 659      }
 660
 661      mod -= (int)dx;
 662
 663      while ( ex1 != ex2 )
 664      {
 665        delta = lift;
 666        mod  += rem;
 667        if ( mod >= 0 )
 668        {
 669          mod -= (TCoord)dx;
 670          delta++;
 671        }
 672
 673        ras.area  += (TArea)(ONE_PIXEL * delta);
 674        ras.cover += delta;
 675        y1        += delta;
 676        ex1       += incr;
 677        gray_set_cell( RAS_VAR_ ex1, ey );
 678      }
 679    }
 680
 681    delta      = y2 - y1;
 682    ras.area  += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
 683    ras.cover += delta;
 684  }
 685
 686
 687  /*************************************************************************/
 688  /*                                                                       */
 689  /* Render a given line as a series of scanlines.                         */
 690  /*                                                                       */
 691  static void
 692  gray_render_line( RAS_ARG_ TPos  to_x,
 693                             TPos  to_y )
 694  {
 695    TCoord  ey1, ey2, fy1, fy2, mod;
 696    TPos    dx, dy, x, x2;
 697    long    p, first;
 698    int     delta, rem, lift, incr;
 699
 700
 701    ey1 = TRUNC( ras.last_ey );
 702    ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
 703    fy1 = (TCoord)( ras.y - ras.last_ey );
 704    fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
 705
 706    dx = to_x - ras.x;
 707    dy = to_y - ras.y;
 708
 709    /* XXX: we should do something about the trivial case where dx == 0, */
 710    /*      as it happens very often!                                    */
 711
 712    /* perform vertical clipping */
 713    {
 714      TCoord  min, max;
 715
 716
 717      min = ey1;
 718      max = ey2;
 719      if ( ey1 > ey2 )
 720      {
 721        min = ey2;
 722        max = ey1;
 723      }
 724      if ( min >= ras.max_ey || max < ras.min_ey )
 725        goto End;
 726    }
 727
 728    /* everything is on a single scanline */
 729    if ( ey1 == ey2 )
 730    {
 731      gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
 732      goto End;
 733    }
 734
 735    /* vertical line - avoid calling gray_render_scanline */
 736    incr = 1;
 737
 738    if ( dx == 0 )
 739    {
 740      TCoord  ex     = TRUNC( ras.x );
 741      TCoord  two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
 742      TArea   area;
 743
 744
 745      first = ONE_PIXEL;
 746      if ( dy < 0 )
 747      {
 748        first = 0;
 749        incr  = -1;
 750      }
 751
 752      delta      = (int)( first - fy1 );
 753      ras.area  += (TArea)two_fx * delta;
 754      ras.cover += delta;
 755      ey1       += incr;
 756
 757      gray_set_cell( RAS_VAR_ ex, ey1 );
 758
 759      delta = (int)( first + first - ONE_PIXEL );
 760      area  = (TArea)two_fx * delta;
 761      while ( ey1 != ey2 )
 762      {
 763        ras.area  += area;
 764        ras.cover += delta;
 765        ey1       += incr;
 766
 767        gray_set_cell( RAS_VAR_ ex, ey1 );
 768      }
 769
 770      delta      = (int)( fy2 - ONE_PIXEL + first );
 771      ras.area  += (TArea)two_fx * delta;
 772      ras.cover += delta;
 773
 774      goto End;
 775    }
 776
 777    /* ok, we have to render several scanlines */
 778    p     = ( ONE_PIXEL - fy1 ) * dx;
 779    first = ONE_PIXEL;
 780    incr  = 1;
 781
 782    if ( dy < 0 )
 783    {
 784      p     = fy1 * dx;
 785      first = 0;
 786      incr  = -1;
 787      dy    = -dy;
 788    }
 789
 790    delta = (int)( p / dy );
 791    mod   = (int)( p % dy );
 792    if ( mod < 0 )
 793    {
 794      delta--;
 795      mod += (TCoord)dy;
 796    }
 797
 798    x = ras.x + delta;
 799    gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
 800
 801    ey1 += incr;
 802    gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
 803
 804    if ( ey1 != ey2 )
 805    {
 806      p     = ONE_PIXEL * dx;
 807      lift  = (int)( p / dy );
 808      rem   = (int)( p % dy );
 809      if ( rem < 0 )
 810      {
 811        lift--;
 812        rem += (int)dy;
 813      }
 814      mod -= (int)dy;
 815
 816      while ( ey1 != ey2 )
 817      {
 818        delta = lift;
 819        mod  += rem;
 820        if ( mod >= 0 )
 821        {
 822          mod -= (int)dy;
 823          delta++;
 824        }
 825
 826        x2 = x + delta;
 827        gray_render_scanline( RAS_VAR_ ey1, x,
 828                                       (TCoord)( ONE_PIXEL - first ), x2,
 829                                       (TCoord)first );
 830        x = x2;
 831
 832        ey1 += incr;
 833        gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
 834      }
 835    }
 836
 837    gray_render_scanline( RAS_VAR_ ey1, x,
 838                                   (TCoord)( ONE_PIXEL - first ), to_x,
 839                                   fy2 );
 840
 841  End:
 842    ras.x       = to_x;
 843    ras.y       = to_y;
 844    ras.last_ey = SUBPIXELS( ey2 );
 845  }
 846
 847
 848  static void
 849  gray_split_conic( FT_Vector*  base )
 850  {
 851    TPos  a, b;
 852
 853
 854    base[4].x = base[2].x;
 855    b = base[1].x;
 856    a = base[3].x = ( base[2].x + b ) / 2;
 857    b = base[1].x = ( base[0].x + b ) / 2;
 858    base[2].x = ( a + b ) / 2;
 859
 860    base[4].y = base[2].y;
 861    b = base[1].y;
 862    a = base[3].y = ( base[2].y + b ) / 2;
 863    b = base[1].y = ( base[0].y + b ) / 2;
 864    base[2].y = ( a + b ) / 2;
 865  }
 866
 867
 868  static void
 869  gray_render_conic( RAS_ARG_ const FT_Vector*  control,
 870                              const FT_Vector*  to )
 871  {
 872    TPos        dx, dy;
 873    int         top, level;
 874    int*        levels;
 875    FT_Vector*  arc;
 876
 877
 878    dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
 879    if ( dx < 0 )
 880      dx = -dx;
 881    dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
 882    if ( dy < 0 )
 883      dy = -dy;
 884    if ( dx < dy )
 885      dx = dy;
 886
 887    level = 1;
 888    dx = dx / ras.conic_level;
 889    while ( dx > 0 )
 890    {
 891      dx >>= 2;
 892      level++;
 893    }
 894
 895    /* a shortcut to speed things up */
 896    if ( level <= 1 )
 897    {
 898      /* we compute the mid-point directly in order to avoid */
 899      /* calling gray_split_conic()                          */
 900      TPos  to_x, to_y, mid_x, mid_y;
 901
 902
 903      to_x  = UPSCALE( to->x );
 904      to_y  = UPSCALE( to->y );
 905      mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
 906      mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
 907
 908      gray_render_line( RAS_VAR_ mid_x, mid_y );
 909      gray_render_line( RAS_VAR_ to_x, to_y );
 910
 911      return;
 912    }
 913
 914    arc       = ras.bez_stack;
 915    levels    = ras.lev_stack;
 916    top       = 0;
 917    levels[0] = level;
 918
 919    arc[0].x = UPSCALE( to->x );
 920    arc[0].y = UPSCALE( to->y );
 921    arc[1].x = UPSCALE( control->x );
 922    arc[1].y = UPSCALE( control->y );
 923    arc[2].x = ras.x;
 924    arc[2].y = ras.y;
 925
 926    while ( top >= 0 )
 927    {
 928      level = levels[top];
 929      if ( level > 1 )
 930      {
 931        /* check that the arc crosses the current band */
 932        TPos  min, max, y;
 933
 934
 935        min = max = arc[0].y;
 936
 937        y = arc[1].y;
 938        if ( y < min ) min = y;
 939        if ( y > max ) max = y;
 940
 941        y = arc[2].y;
 942        if ( y < min ) min = y;
 943        if ( y > max ) max = y;
 944
 945        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
 946          goto Draw;
 947
 948        gray_split_conic( arc );
 949        arc += 2;
 950        top++;
 951        levels[top] = levels[top - 1] = level - 1;
 952        continue;
 953      }
 954
 955    Draw:
 956      {
 957        TPos  to_x, to_y, mid_x, mid_y;
 958
 959
 960        to_x  = arc[0].x;
 961        to_y  = arc[0].y;
 962        mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
 963        mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
 964
 965        gray_render_line( RAS_VAR_ mid_x, mid_y );
 966        gray_render_line( RAS_VAR_ to_x, to_y );
 967
 968        top--;
 969        arc -= 2;
 970      }
 971    }
 972
 973    return;
 974  }
 975
 976
 977  static void
 978  gray_split_cubic( FT_Vector*  base )
 979  {
 980    TPos  a, b, c, d;
 981
 982
 983    base[6].x = base[3].x;
 984    c = base[1].x;
 985    d = base[2].x;
 986    base[1].x = a = ( base[0].x + c ) / 2;
 987    base[5].x = b = ( base[3].x + d ) / 2;
 988    c = ( c + d ) / 2;
 989    base[2].x = a = ( a + c ) / 2;
 990    base[4].x = b = ( b + c ) / 2;
 991    base[3].x = ( a + b ) / 2;
 992
 993    base[6].y = base[3].y;
 994    c = base[1].y;
 995    d = base[2].y;
 996    base[1].y = a = ( base[0].y + c ) / 2;
 997    base[5].y = b = ( base[3].y + d ) / 2;
 998    c = ( c + d ) / 2;
 999    base[2].y = a = ( a + c ) / 2;
1000    base[4].y = b = ( b + c ) / 2;
1001    base[3].y = ( a + b ) / 2;
1002  }
1003
1004
1005  static void
1006  gray_render_cubic( RAS_ARG_ const FT_Vector*  control1,
1007                              const FT_Vector*  control2,
1008                              const FT_Vector*  to )
1009  {
1010    TPos        dx, dy, da, db;
1011    int         top, level;
1012    int*        levels;
1013    FT_Vector*  arc;
1014
1015
1016    dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
1017    if ( dx < 0 )
1018      dx = -dx;
1019    dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
1020    if ( dy < 0 )
1021      dy = -dy;
1022    if ( dx < dy )
1023      dx = dy;
1024    da = dx;
1025
1026    dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
1027    if ( dx < 0 )
1028      dx = -dx;
1029    dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
1030    if ( dy < 0 )
1031      dy = -dy;
1032    if ( dx < dy )
1033      dx = dy;
1034    db = dx;
1035
1036    level = 1;
1037    da    = da / ras.cubic_level;
1038    db    = db / ras.conic_level;
1039    while ( da > 0 || db > 0 )
1040    {
1041      da >>= 2;
1042      db >>= 3;
1043      level++;
1044    }
1045
1046    if ( level <= 1 )
1047    {
1048      TPos   to_x, to_y, mid_x, mid_y;
1049
1050
1051      to_x  = UPSCALE( to->x );
1052      to_y  = UPSCALE( to->y );
1053      mid_x = ( ras.x + to_x +
1054                3 * UPSCALE( control1->x + control2->x ) ) / 8;
1055      mid_y = ( ras.y + to_y +
1056                3 * UPSCALE( control1->y + control2->y ) ) / 8;
1057
1058      gray_render_line( RAS_VAR_ mid_x, mid_y );
1059      gray_render_line( RAS_VAR_ to_x, to_y );
1060      return;
1061    }
1062
1063    arc      = ras.bez_stack;
1064    arc[0].x = UPSCALE( to->x );
1065    arc[0].y = UPSCALE( to->y );
1066    arc[1].x = UPSCALE( control2->x );
1067    arc[1].y = UPSCALE( control2->y );
1068    arc[2].x = UPSCALE( control1->x );
1069    arc[2].y = UPSCALE( control1->y );
1070    arc[3].x = ras.x;
1071    arc[3].y = ras.y;
1072
1073    levels    = ras.lev_stack;
1074    top       = 0;
1075    levels[0] = level;
1076
1077    while ( top >= 0 )
1078    {
1079      level = levels[top];
1080      if ( level > 1 )
1081      {
1082        /* check that the arc crosses the current band */
1083        TPos  min, max, y;
1084
1085
1086        min = max = arc[0].y;
1087        y = arc[1].y;
1088        if ( y < min ) min = y;
1089        if ( y > max ) max = y;
1090        y = arc[2].y;
1091        if ( y < min ) min = y;
1092        if ( y > max ) max = y;
1093        y = arc[3].y;
1094        if ( y < min ) min = y;
1095        if ( y > max ) max = y;
1096        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
1097          goto Draw;
1098        gray_split_cubic( arc );
1099        arc += 3;
1100        top ++;
1101        levels[top] = levels[top - 1] = level - 1;
1102        continue;
1103      }
1104
1105    Draw:
1106      {
1107        TPos  to_x, to_y, mid_x, mid_y;
1108
1109
1110        to_x  = arc[0].x;
1111        to_y  = arc[0].y;
1112        mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
1113        mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
1114
1115        gray_render_line( RAS_VAR_ mid_x, mid_y );
1116        gray_render_line( RAS_VAR_ to_x, to_y );
1117        top --;
1118        arc -= 3;
1119      }
1120    }
1121
1122    return;
1123  }
1124
1125
1126
1127  static int
1128  gray_move_to( const FT_Vector*  to,
1129                PWorker           worker )
1130  {
1131    TPos  x, y;
1132
1133
1134    /* record current cell, if any */
1135    gray_record_cell( RAS_VAR );
1136
1137    /* start to a new position */
1138    x = UPSCALE( to->x );
1139    y = UPSCALE( to->y );
1140
1141    gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
1142
1143    worker->x = x;
1144    worker->y = y;
1145    return 0;
1146  }
1147
1148
1149  static int
1150  gray_line_to( const FT_Vector*  to,
1151                PWorker           worker )
1152  {
1153    gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
1154    return 0;
1155  }
1156
1157
1158  static int
1159  gray_conic_to( const FT_Vector*  control,
1160                 const FT_Vector*  to,
1161                 PWorker           worker )
1162  {
1163    gray_render_conic( RAS_VAR_ control, to );
1164    return 0;
1165  }
1166
1167
1168  static int
1169  gray_cubic_to( const FT_Vector*  control1,
1170                 const FT_Vector*  control2,
1171                 const FT_Vector*  to,
1172                 PWorker           worker )
1173  {
1174    gray_render_cubic( RAS_VAR_ control1, control2, to );
1175    return 0;
1176  }
1177
1178
1179  static void
1180  gray_render_span( int             y,
1181                    int             count,
1182                    const FT_Span*  spans,
1183                    PWorker         worker )
1184  {
1185    unsigned char*  p;
1186    FT_Bitmap*      map = &worker->target;
1187
1188
1189    /* first of all, compute the scanline offset */
1190    p = (unsigned char*)map->buffer - y * map->pitch;
1191    if ( map->pitch >= 0 )
1192      p += ( map->rows - 1 ) * map->pitch;
1193
1194    for ( ; count > 0; count--, spans++ )
1195    {
1196      unsigned char  coverage = spans->coverage;
1197
1198
1199      if ( coverage )
1200      {
1201        /* For small-spans it is faster to do it by ourselves than
1202         * calling `memset'.  This is mainly due to the cost of the
1203         * function call.
1204         */
1205        if ( spans->len >= 8 )
1206          FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
1207        else
1208        {
1209          unsigned char*  q = p + spans->x;
1210
1211
1212          switch ( spans->len )
1213          {
1214          case 7: *q++ = (unsigned char)coverage;
1215          case 6: *q++ = (unsigned char)coverage;
1216          case 5: *q++ = (unsigned char)coverage;
1217          case 4: *q++ = (unsigned char)coverage;
1218          case 3: *q++ = (unsigned char)coverage;
1219          case 2: *q++ = (unsigned char)coverage;
1220          case 1: *q   = (unsigned char)coverage;
1221          default:
1222            ;
1223          }
1224        }
1225      }
1226    }
1227  }
1228
1229
1230  static void
1231  gray_hline( RAS_ARG_ TCoord  x,
1232                       TCoord  y,
1233                       TPos    area,
1234                       TCoord  acount )
1235  {
1236    FT_Span*  span;
1237    int       count;
1238    int       coverage;
1239
1240
1241    /* compute the coverage line's coverage, depending on the    */
1242    /* outline fill rule                                         */
1243    /*                                                           */
1244    /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1245    /*                                                           */
1246    coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
1247                                                    /* use range 0..256 */
1248    if ( coverage < 0 )
1249      coverage = -coverage;
1250
1251    if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
1252    {
1253      coverage &= 511;
1254
1255      if ( coverage > 256 )
1256        coverage = 512 - coverage;
1257      else if ( coverage == 256 )
1258        coverage = 255;
1259    }
1260    else
1261    {
1262      /* normal non-zero winding rule */
1263      if ( coverage >= 256 )
1264        coverage = 255;
1265    }
1266
1267    y += (TCoord)ras.min_ey;
1268    x += (TCoord)ras.min_ex;
1269
1270    /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
1271    if ( x >= 32767 )
1272      x = 32767;
1273
1274    /* FT_Span.y is an integer, so limit our coordinates appropriately */
1275    if ( y >= FT_INT_MAX )
1276      y = FT_INT_MAX;
1277
1278    if ( coverage )
1279    {
1280      /* see whether we can add this span to the current list */
1281      count = ras.num_gray_spans;
1282      span  = ras.gray_spans + count - 1;
1283      if ( count > 0                          &&
1284           ras.span_y == y                    &&
1285           (int)span->x + span->len == (int)x &&
1286           span->coverage == coverage         )
1287      {
1288        span->len = (unsigned short)( span->len + acount );
1289        return;
1290      }
1291
1292      if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
1293      {
1294        if ( ras.render_span && count > 0 )
1295          ras.render_span( ras.span_y, count, ras.gray_spans,
1296                           ras.render_span_data );
1297
1298#ifdef FT_DEBUG_LEVEL_TRACE
1299
1300        if ( count > 0 )
1301        {
1302          int  n;
1303
1304
1305          FT_TRACE7(( "y = %3d ", ras.span_y ));
1306          span = ras.gray_spans;
1307          for ( n = 0; n < count; n++, span++ )
1308            FT_TRACE7(( "[%d..%d]:%02x ",
1309                        span->x, span->x + span->len - 1, span->coverage ));
1310          FT_TRACE7(( "\n" ));
1311        }
1312
1313#endif /* FT_DEBUG_LEVEL_TRACE */
1314
1315        ras.num_gray_spans = 0;
1316        ras.span_y         = (int)y;
1317
1318        count = 0;
1319        span  = ras.gray_spans;
1320      }
1321      else
1322        span++;
1323
1324      /* add a gray span to the current list */
1325      span->x        = (short)x;
1326      span->len      = (unsigned short)acount;
1327      span->coverage = (unsigned char)coverage;
1328
1329      ras.num_gray_spans++;
1330    }
1331  }
1332
1333
1334#ifdef FT_DEBUG_LEVEL_TRACE
1335
1336  /* to be called while in the debugger --                                */
1337  /* this function causes a compiler warning since it is unused otherwise */
1338  static void
1339  gray_dump_cells( RAS_ARG )
1340  {
1341    int  yindex;
1342
1343
1344    for ( yindex = 0; yindex < ras.ycount; yindex++ )
1345    {
1346      PCell  cell;
1347
1348
1349      printf( "%3d:", yindex );
1350
1351      for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
1352        printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area );
1353      printf( "\n" );
1354    }
1355  }
1356
1357#endif /* FT_DEBUG_LEVEL_TRACE */
1358
1359
1360  static void
1361  gray_sweep( RAS_ARG_ const FT_Bitmap*  target )
1362  {
1363    int  yindex;
1364
1365    FT_UNUSED( target );
1366
1367
1368    if ( ras.num_cells == 0 )
1369      return;
1370
1371    ras.num_gray_spans = 0;
1372
1373    FT_TRACE7(( "gray_sweep: start\n" ));
1374
1375    for ( yindex = 0; yindex < ras.ycount; yindex++ )
1376    {
1377      PCell   cell  = ras.ycells[yindex];
1378      TCoord  cover = 0;
1379      TCoord  x     = 0;
1380
1381
1382      for ( ; cell != NULL; cell = cell->next )
1383      {
1384        TPos  area;
1385
1386
1387        if ( cell->x > x && cover != 0 )
1388          gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1389                      cell->x - x );
1390
1391        cover += cell->cover;
1392        area   = cover * ( ONE_PIXEL * 2 ) - cell->area;
1393
1394        if ( area != 0 && cell->x >= 0 )
1395          gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
1396
1397        x = cell->x + 1;
1398      }
1399
1400      if ( cover != 0 )
1401        gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1402                    ras.count_ex - x );
1403    }
1404
1405    if ( ras.render_span && ras.num_gray_spans > 0 )
1406      ras.render_span( ras.span_y, ras.num_gray_spans,
1407                       ras.gray_spans, ras.render_span_data );
1408
1409    FT_TRACE7(( "gray_sweep: end\n" ));
1410  }
1411
1412
1413#ifdef _STANDALONE_
1414
1415  /*************************************************************************/
1416  /*                                                                       */
1417  /*  The following function should only compile in stand-alone mode,      */
1418  /*  i.e., when building this component without the rest of FreeType.     */
1419  /*                                                                       */
1420  /*************************************************************************/
1421
1422  /*************************************************************************/
1423  /*                                                                       */
1424  /* <Function>                                                            */
1425  /*    FT_Outline_Decompose                                               */
1426  /*                                                                       */
1427  /* <Description>                                                         */
1428  /*    Walk over an outline's structure to decompose it into individual   */
1429  /*    segments and B?Šzier arcs.  This function is also able to emit      */
1430  /*    `move to' and `close to' operations to indicate the start and end  */
1431  /*    of new contours in the outline.                                    */
1432  /*                                                                       */
1433  /* <Input>                                                               */
1434  /*    outline        :: A pointer to the source target.                  */
1435  /*                                                                       */
1436  /*    func_interface :: A table of `emitters', i.e., function pointers   */
1437  /*                      called during decomposition to indicate path     */
1438  /*                      operations.                                      */
1439  /*                                                                       */
1440  /* <InOut>                                                               */
1441  /*    user           :: A typeless pointer which is passed to each       */
1442  /*                      emitter during the decomposition.  It can be     */
1443  /*                      used to store the state during the               */
1444  /*                      decomposition.                                   */
1445  /*                                                                       */
1446  /* <Return>                                                              */
1447  /*    Error code.  0 means success.                                      */
1448  /*                                                                       */
1449  static int
1450  FT_Outline_Decompose( const FT_Outline*        outline,
1451                        const FT_Outline_Funcs*  func_interface,
1452                        void*                    user )
1453  {
1454#undef SCALED
1455#define SCALED( x )  ( ( (x) << shift ) - delta )
1456
1457    FT_Vector   v_last;
1458    FT_Vector   v_control;
1459    FT_Vector   v_start;
1460
1461    FT_Vector*  point;
1462    FT_Vector*  limit;
1463    char*       tags;
1464
1465    int         error;
1466
1467    int   n;         /* index of contour in outline     */
1468    int   first;     /* index of first point in contour */
1469    char  tag;       /* current point's state           */
1470
1471    int   shift;
1472    TPos  delta;
1473
1474
1475    if ( !outline || !func_interface )
1476      return ErrRaster_Invalid_Argument;
1477
1478    shift = func_interface->shift;
1479    delta = func_interface->delta;
1480    first = 0;
1481
1482    for ( n = 0; n < outline->n_contours; n++ )
1483    {
1484      int  last;  /* index of last point in contour */
1485
1486
1487      FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
1488
1489      last  = outline->contours[n];
1490      if ( last < 0 )
1491        goto Invalid_Outline;
1492      limit = outline->points + last;
1493
1494      v_start   = outline->points[first];
1495      v_start.x = SCALED( v_start.x );
1496      v_start.y = SCALED( v_start.y );
1497
1498      v_last   = outline->points[last];
1499      v_last.x = SCALED( v_last.x );
1500      v_last.y = SCALED( v_last.y );
1501
1502      v_control = v_start;
1503
1504      point = outline->points + first;
1505      tags  = outline->tags   + first;
1506      tag   = FT_CURVE_TAG( tags[0] );
1507
1508      /* A contour cannot start with a cubic control point! */
1509      if ( tag == FT_CURVE_TAG_CUBIC )
1510        goto Invalid_Outline;
1511
1512      /* check first point to determine origin */
1513      if ( tag == FT_CURVE_TAG_CONIC )
1514      {
1515        /* first point is conic control.  Yes, this happens. */
1516        if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
1517        {
1518          /* start at last point if it is on the curve */
1519          v_start = v_last;
1520          limit--;
1521        }
1522        else
1523        {
1524          /* if both first and last points are conic,         */
1525          /* start at their middle and record its position    */
1526          /* for closure                                      */
1527          v_start.x = ( v_start.x + v_last.x ) / 2;
1528          v_start.y = ( v_start.y + v_last.y ) / 2;
1529
1530          v_last = v_start;
1531        }
1532        point--;
1533        tags--;
1534      }
1535
1536      FT_TRACE5(( "  move to (%.2f, %.2f)\n",
1537                  v_start.x / 64.0, v_start.y / 64.0 ));
1538      error = func_interface->move_to( &v_start, user );
1539      if ( error )
1540        goto Exit;
1541
1542      while ( point < limit )
1543      {
1544        point++;
1545        tags++;
1546
1547        tag = FT_CURVE_TAG( tags[0] );
1548        switch ( tag )
1549        {
1550        case FT_CURVE_TAG_ON:  /* emit a single line_to */
1551          {
1552            FT_Vector  vec;
1553
1554
1555            vec.x = SCALED( point->x );
1556            vec.y = SCALED( point->y );
1557
1558            FT_TRACE5(( "  line to (%.2f, %.2f)\n",
1559                        vec.x / 64.0, vec.y / 64.0 ));
1560            error = func_interface->line_to( &vec, user );
1561            if ( error )
1562              goto Exit;
1563            continue;
1564          }
1565
1566        case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
1567          v_control.x = SCALED( point->x );
1568          v_control.y = SCALED( point->y );
1569
1570        Do_Conic:
1571          if ( point < limit )
1572          {
1573            FT_Vector  vec;
1574            FT_Vector  v_middle;
1575
1576
1577            point++;
1578            tags++;
1579            tag = FT_CURVE_TAG( tags[0] );
1580
1581            vec.x = SCALED( point->x );
1582            vec.y = SCALED( point->y );
1583
1584            if ( tag == FT_CURVE_TAG_ON )
1585            {
1586              FT_TRACE5(( "  conic to (%.2f, %.2f)"
1587                          " with control (%.2f, %.2f)\n",
1588                          vec.x / 64.0, vec.y / 64.0,
1589                          v_control.x / 64.0, v_control.y / 64.0 ));
1590              error = func_interface->conic_to( &v_control, &vec, user );
1591              if ( error )
1592                goto Exit;
1593              continue;
1594            }
1595
1596            if ( tag != FT_CURVE_TAG_CONIC )
1597              goto Invalid_Outline;
1598
1599            v_middle.x = ( v_control.x + vec.x ) / 2;
1600            v_middle.y = ( v_control.y + vec.y ) / 2;
1601
1602            FT_TRACE5(( "  conic to (%.2f, %.2f)"
1603                        " with control (%.2f, %.2f)\n",
1604                        v_middle.x / 64.0, v_middle.y / 64.0,
1605                        v_control.x / 64.0, v_control.y / 64.0 ));
1606            error = func_interface->conic_to( &v_control, &v_middle, user );
1607            if ( error )
1608              goto Exit;
1609
1610            v_control = vec;
1611            goto Do_Conic;
1612          }
1613
1614          FT_TRACE5(( "  conic to (%.2f, %.2f)"
1615                      " with control (%.2f, %.2f)\n",
1616                      v_start.x / 64.0, v_start.y / 64.0,
1617                      v_control.x / 64.0, v_control.y / 64.0 ));
1618          error = func_interface->conic_to( &v_control, &v_start, user );
1619          goto Close;
1620
1621        default:  /* FT_CURVE_TAG_CUBIC */
1622          {
1623            FT_Vector  vec1, vec2;
1624
1625
1626            if ( point + 1 > limit                             ||
1627                 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1628              goto Invalid_Outline;
1629
1630            point += 2;
1631            tags  += 2;
1632
1633            vec1.x = SCALED( point[-2].x );
1634            vec1.y = SCALED( point[-2].y );
1635
1636            vec2.x = SCALED( point[-1].x );
1637            vec2.y = SCALED( point[-1].y );
1638
1639            if ( point <= limit )
1640            {
1641              FT_Vector  vec;
1642
1643
1644              vec.x = SCALED( point->x );
1645              vec.y = SCALED( point->y );
1646
1647              FT_TRACE5(( "  cubic to (%.2f, %.2f)"
1648                          " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1649                          vec.x / 64.0, vec.y / 64.0,
1650                          vec1.x / 64.0, vec1.y / 64.0,
1651                          vec2.x / 64.0, vec2.y / 64.0 ));
1652              error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
1653              if ( error )
1654                goto Exit;
1655              continue;
1656            }
1657
1658            FT_TRACE5(( "  cubic to (%.2f, %.2f)"
1659                        " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1660                        v_start.x / 64.0, v_start.y / 64.0,
1661                        vec1.x / 64.0, vec1.y / 64.0,
1662                        vec2.x / 64.0, vec2.y / 64.0 ));
1663            error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
1664            goto Close;
1665          }
1666        }
1667      }
1668
1669      /* close the contour with a line segment */
1670      FT_TRACE5(( "  line to (%.2f, %.2f)\n",
1671                  v_start.x / 64.0, v_start.y / 64.0 ));
1672      error = func_interface->line_to( &v_start, user );
1673
1674   Close:
1675      if ( error )
1676        goto Exit;
1677
1678      first = last + 1;
1679    }
1680
1681    FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1682    return 0;
1683
1684  Exit:
1685    FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
1686    return error;
1687
1688  Invalid_Outline:
1689    return ErrRaster_Invalid_Outline;
1690  }
1691
1692#endif /* _STANDALONE_ */
1693
1694
1695  typedef struct  TBand_
1696  {
1697    TPos  min, max;
1698
1699  } TBand;
1700
1701    FT_DEFINE_OUTLINE_FUNCS(func_interface,
1702      (FT_Outline_MoveTo_Func) gray_move_to,
1703      (FT_Outline_LineTo_Func) gray_line_to,
1704      (FT_Outline_ConicTo_Func)gray_conic_to,
1705      (FT_Outline_CubicTo_Func)gray_cubic_to,
1706      0,
1707      0
1708    )
1709
1710  static int
1711  gray_convert_glyph_inner( RAS_ARG )
1712  {
1713
1714    volatile int  error = 0;
1715
1716#ifdef FT_CONFIG_OPTION_PIC
1717      FT_Outline_Funcs func_interface;
1718      Init_Class

Large files files are truncated, but you can click here to view the full file