source: trunk/poppler/freetype2/src/smooth/ftgrays.c @ 262

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 12 years ago

PDF plugin: freetype library updated to version 2.3.8

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