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