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