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