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

Last change on this file since 200 was 200, checked in by Eugene Romanenko, 14 years ago

PDF plugin: update freetype to 2.3.1 release

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