• 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-2023 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_INT( a, b )                                  \
153           (int)( (unsigned int)(a) + (unsigned int)(b) )
154 
155 #define FT_STATIC_BYTE_CAST( type, var )  (type)(unsigned char)(var)
156 
157 
158 #define ft_memset   memset
159 
160 #define ft_setjmp   setjmp
161 #define ft_longjmp  longjmp
162 #define ft_jmp_buf  jmp_buf
163 
164 typedef ptrdiff_t  FT_PtrDist;
165 
166 
167 #define Smooth_Err_Ok                    0
168 #define Smooth_Err_Invalid_Outline      -1
169 #define Smooth_Err_Cannot_Render_Glyph  -2
170 #define Smooth_Err_Invalid_Argument     -3
171 #define Smooth_Err_Raster_Overflow      -4
172 
173 #define FT_BEGIN_HEADER
174 #define FT_END_HEADER
175 
176 #include "ftimage.h"
177 #include "ftgrays.h"
178 
179 
180   /* This macro is used to indicate that a function parameter is unused. */
181   /* Its purpose is simply to reduce compiler warnings.  Note also that  */
182   /* simply defining it as `(void)x' doesn't avoid warnings with certain */
183   /* ANSI compilers (e.g. LCC).                                          */
184 #define FT_UNUSED( x )  (x) = (x)
185 
186 
187   /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
188 
189 #ifdef FT_DEBUG_LEVEL_TRACE
190 
191   void
FT_Message(const char * fmt,...)192   FT_Message( const char*  fmt,
193               ... )
194   {
195     va_list  ap;
196 
197 
198     va_start( ap, fmt );
199     vfprintf( stderr, fmt, ap );
200     va_end( ap );
201   }
202 
203 
204   /* empty function useful for setting a breakpoint to catch errors */
205   int
FT_Throw(int error,int line,const char * file)206   FT_Throw( int          error,
207             int          line,
208             const char*  file )
209   {
210     FT_UNUSED( error );
211     FT_UNUSED( line );
212     FT_UNUSED( file );
213 
214     return 0;
215   }
216 
217 
218   /* we don't handle tracing levels in stand-alone mode; */
219 #ifndef FT_TRACE5
220 #define FT_TRACE5( varformat )  FT_Message varformat
221 #endif
222 #ifndef FT_TRACE7
223 #define FT_TRACE7( varformat )  FT_Message varformat
224 #endif
225 #ifndef FT_ERROR
226 #define FT_ERROR( varformat )   FT_Message varformat
227 #endif
228 
229 #define FT_THROW( e )                                \
230           ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ),  \
231                       __LINE__,                      \
232                       __FILE__ )                   | \
233             FT_ERR_CAT( Smooth_Err_, e )           )
234 
235 #else /* !FT_DEBUG_LEVEL_TRACE */
236 
237 #define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
238 #define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
239 #define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
240 #define FT_THROW( e )   FT_ERR_CAT( Smooth_Err_, e )
241 
242 #endif /* !FT_DEBUG_LEVEL_TRACE */
243 
244 
245 #define FT_Trace_Enable()   do { } while ( 0 )  /* nothing */
246 #define FT_Trace_Disable()  do { } while ( 0 )  /* nothing */
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 <ft2build.h>
282 #include FT_CONFIG_CONFIG_H
283 #include "ftgrays.h"
284 #include <freetype/internal/ftobjs.h>
285 #include <freetype/internal/ftdebug.h>
286 #include <freetype/internal/ftcalc.h>
287 #include <freetype/ftoutln.h>
288 
289 #include "ftsmerrs.h"
290 
291 
292 #endif /* !STANDALONE_ */
293 
294 
295 #ifndef FT_MEM_SET
296 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
297 #endif
298 
299 #ifndef FT_MEM_ZERO
300 #define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
301 #endif
302 
303 #ifndef FT_ZERO
304 #define FT_ZERO( p )  FT_MEM_ZERO( p, sizeof ( *(p) ) )
305 #endif
306 
307   /* as usual, for the speed hungry :-) */
308 
309 #undef RAS_ARG
310 #undef RAS_ARG_
311 #undef RAS_VAR
312 #undef RAS_VAR_
313 
314 #ifndef FT_STATIC_RASTER
315 
316 #define RAS_ARG   gray_PWorker  worker
317 #define RAS_ARG_  gray_PWorker  worker,
318 
319 #define RAS_VAR   worker
320 #define RAS_VAR_  worker,
321 
322 #else /* FT_STATIC_RASTER */
323 
324 #define RAS_ARG   void
325 #define RAS_ARG_  /* empty */
326 #define RAS_VAR   /* empty */
327 #define RAS_VAR_  /* empty */
328 
329 #endif /* FT_STATIC_RASTER */
330 
331 
332   /* must be at least 6 bits! */
333 #define PIXEL_BITS  8
334 
335 #define ONE_PIXEL       ( 1 << PIXEL_BITS )
336 #undef TRUNC
337 #define TRUNC( x )      (TCoord)( (x) >> PIXEL_BITS )
338 #undef FRACT
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 #if defined( __GNUC__ ) && __GNUC__ < 7 && defined( __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   /* Calculating coverages for a slanted line requires a division each */
386   /* time the line crosses from cell to cell.  These macros speed up   */
387   /* the repetitive divisions by replacing them with multiplications   */
388   /* and right shifts so that at most two divisions are performed for  */
389   /* each slanted line.  Nevertheless, these divisions are noticeable  */
390   /* in the overall performance because flattened curves produce a     */
391   /* very large number of slanted lines.                               */
392   /*                                                                   */
393   /* The division results here are always within ONE_PIXEL.  Therefore */
394   /* the shift magnitude should be at least PIXEL_BITS wider than the  */
395   /* divisors to provide sufficient accuracy of the multiply-shift.    */
396   /* It should not exceed (64 - PIXEL_BITS) to prevent overflowing and */
397   /* leave enough room for 64-bit unsigned multiplication however.     */
398 #define FT_UDIVPREP( c, b )                                \
399   FT_Int64  b ## _r = c ? (FT_Int64)0xFFFFFFFF / ( b ) : 0
400 #define FT_UDIV( a, b )                                           \
401   (TCoord)( ( (FT_UInt64)( a ) * (FT_UInt64)( b ## _r ) ) >> 32 )
402 
403 
404   /* Scale area and apply fill rule to calculate the coverage byte. */
405   /* The top fill bit is used for the non-zero rule. The eighth     */
406   /* fill bit is used for the even-odd rule.  The higher coverage   */
407   /* bytes are either clamped for the non-zero-rule or discarded    */
408   /* later for the even-odd rule.                                   */
409 #define FT_FILL_RULE( coverage, area, fill )                \
410   FT_BEGIN_STMNT                                            \
411     coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \
412     if ( coverage & fill )                                  \
413       coverage = ~coverage;                                 \
414     if ( coverage > 255 && fill & INT_MIN )                 \
415       coverage = 255;                                       \
416   FT_END_STMNT
417 
418 
419   /* It is faster to write small spans byte-by-byte than calling     */
420   /* `memset'.  This is mainly due to the cost of the function call. */
421 #define FT_GRAY_SET( d, s, count )                   \
422   FT_BEGIN_STMNT                                     \
423     unsigned char* q = d;                            \
424     switch ( count )                                 \
425     {                                                \
426       case 7: *q++ = (unsigned char)s; FALL_THROUGH; \
427       case 6: *q++ = (unsigned char)s; FALL_THROUGH; \
428       case 5: *q++ = (unsigned char)s; FALL_THROUGH; \
429       case 4: *q++ = (unsigned char)s; FALL_THROUGH; \
430       case 3: *q++ = (unsigned char)s; FALL_THROUGH; \
431       case 2: *q++ = (unsigned char)s; FALL_THROUGH; \
432       case 1: *q   = (unsigned char)s; FALL_THROUGH; \
433       case 0: break;                                 \
434       default: FT_MEM_SET( d, s, count );            \
435     }                                                \
436   FT_END_STMNT
437 
438 
439   /**************************************************************************
440    *
441    * TYPE DEFINITIONS
442    */
443 
444   /* don't change the following types to FT_Int or FT_Pos, since we might */
445   /* need to define them to "float" or "double" when experimenting with   */
446   /* new algorithms                                                       */
447 
448   typedef long  TPos;     /* subpixel coordinate               */
449   typedef int   TCoord;   /* integer scanline/pixel coordinate */
450   typedef int   TArea;    /* cell areas, coordinate products   */
451 
452 
453   typedef struct TCell_*  PCell;
454 
455   typedef struct  TCell_
456   {
457     TCoord  x;     /* same with gray_TWorker.ex    */
458     TCoord  cover; /* same with gray_TWorker.cover */
459     TArea   area;
460     PCell   next;
461 
462   } TCell;
463 
464   typedef struct TPixmap_
465   {
466     unsigned char*  origin;  /* pixmap origin at the bottom-left */
467     int             pitch;   /* pitch to go down one row */
468 
469   } TPixmap;
470 
471   /* maximum number of gray cells in the buffer */
472 #if FT_RENDER_POOL_SIZE > 2048
473 #define FT_MAX_GRAY_POOL  ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) )
474 #else
475 #define FT_MAX_GRAY_POOL  ( 2048 / sizeof ( TCell ) )
476 #endif
477 
478   /* FT_Span buffer size for direct rendering only */
479 #define FT_MAX_GRAY_SPANS  16
480 
481 
482 #if defined( _MSC_VER )      /* Visual C++ (and Intel C++) */
483   /* We disable the warning `structure was padded due to   */
484   /* __declspec(align())' in order to compile cleanly with */
485   /* the maximum level of warnings.                        */
486 #pragma warning( push )
487 #pragma warning( disable : 4324 )
488 #endif /* _MSC_VER */
489 
490   typedef struct  gray_TWorker_
491   {
492     ft_jmp_buf  jump_buffer;
493 
494     TCoord  min_ex, max_ex;  /* min and max integer pixel coordinates */
495     TCoord  min_ey, max_ey;
496     TCoord  count_ey;        /* same as (max_ey - min_ey) */
497 
498     PCell       cell;        /* current cell                             */
499     PCell       cell_free;   /* call allocation next free slot           */
500     PCell       cell_null;   /* last cell, used as dumpster and limit    */
501 
502     PCell*      ycells;      /* array of cell linked-lists; one per      */
503                              /* vertical coordinate in the current band  */
504 
505     TPos        x,  y;       /* last point position */
506 
507     FT_Outline  outline;     /* input outline */
508     TPixmap     target;      /* target pixmap */
509 
510     FT_Raster_Span_Func  render_span;
511     void*                render_span_data;
512 
513   } gray_TWorker, *gray_PWorker;
514 
515 #if defined( _MSC_VER )
516 #pragma warning( pop )
517 #endif
518 
519 #ifndef FT_STATIC_RASTER
520 #define ras  (*worker)
521 #else
522   static gray_TWorker  ras;
523 #endif
524 
525   /* The |x| value of the null cell.  Must be the largest possible */
526   /* integer value stored in a `TCell.x` field.                    */
527 #define CELL_MAX_X_VALUE    INT_MAX
528 
529 
530 #define FT_INTEGRATE( ras, a, b )                                       \
531           ras.cell->cover = ADD_INT( ras.cell->cover, a ),              \
532           ras.cell->area  = ADD_INT( ras.cell->area, (a) * (TArea)(b) )
533 
534 
535   typedef struct gray_TRaster_
536   {
537     void*  memory;
538 
539   } gray_TRaster, *gray_PRaster;
540 
541 
542 #ifdef FT_DEBUG_LEVEL_TRACE
543 
544   /* to be called while in the debugger --                                */
545   /* this function causes a compiler warning since it is unused otherwise */
546   static void
gray_dump_cells(RAS_ARG)547   gray_dump_cells( RAS_ARG )
548   {
549     int  y;
550 
551 
552     for ( y = ras.min_ey; y < ras.max_ey; y++ )
553     {
554       PCell  cell = ras.ycells[y - ras.min_ey];
555 
556 
557       printf( "%3d:", y );
558 
559       for ( ; cell != ras.cell_null; cell = cell->next )
560         printf( " (%3d, c:%4d, a:%6d)",
561                 cell->x, cell->cover, cell->area );
562       printf( "\n" );
563     }
564   }
565 
566 #endif /* FT_DEBUG_LEVEL_TRACE */
567 
568 
569   /**************************************************************************
570    *
571    * Set the current cell to a new position.
572    */
573   static void
gray_set_cell(RAS_ARG_ TCoord ex,TCoord ey)574   gray_set_cell( RAS_ARG_ TCoord  ex,
575                           TCoord  ey )
576   {
577     /* Move the cell pointer to a new position in the linked list. We use  */
578     /* a dumpster null cell for everything outside of the clipping region  */
579     /* during the render phase.  This means that:                          */
580     /*                                                                     */
581     /* . the new vertical position must be within min_ey..max_ey-1.        */
582     /* . the new horizontal position must be strictly less than max_ex     */
583     /*                                                                     */
584     /* Note that if a cell is to the left of the clipping region, it is    */
585     /* actually set to the (min_ex-1) horizontal position.                 */
586 
587     TCoord  ey_index = ey - ras.min_ey;
588 
589 
590     if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex )
591       ras.cell = ras.cell_null;
592     else
593     {
594       PCell*  pcell = ras.ycells + ey_index;
595       PCell   cell;
596 
597 
598       ex = FT_MAX( ex, ras.min_ex - 1 );
599 
600       while ( 1 )
601       {
602         cell = *pcell;
603 
604         if ( cell->x > ex )
605           break;
606 
607         if ( cell->x == ex )
608           goto Found;
609 
610         pcell = &cell->next;
611       }
612 
613       /* insert new cell */
614       cell = ras.cell_free++;
615       if ( cell >= ras.cell_null )
616         ft_longjmp( ras.jump_buffer, 1 );
617 
618       cell->x     = ex;
619       cell->area  = 0;
620       cell->cover = 0;
621 
622       cell->next  = *pcell;
623       *pcell      = cell;
624 
625     Found:
626       ras.cell = cell;
627     }
628   }
629 
630 
631 #ifndef FT_INT64
632 
633   /**************************************************************************
634    *
635    * Render a scanline as one or more cells.
636    */
637   static void
gray_render_scanline(RAS_ARG_ TCoord ey,TPos x1,TCoord y1,TPos x2,TCoord y2)638   gray_render_scanline( RAS_ARG_ TCoord  ey,
639                                  TPos    x1,
640                                  TCoord  y1,
641                                  TPos    x2,
642                                  TCoord  y2 )
643   {
644     TCoord  ex1, ex2, fx1, fx2, first, dy, delta, mod;
645     TPos    p, dx;
646     int     incr;
647 
648 
649     ex1 = TRUNC( x1 );
650     ex2 = TRUNC( x2 );
651 
652     /* trivial case.  Happens often */
653     if ( y1 == y2 )
654     {
655       gray_set_cell( RAS_VAR_ ex2, ey );
656       return;
657     }
658 
659     fx1 = FRACT( x1 );
660     fx2 = FRACT( x2 );
661 
662     /* everything is located in a single cell.  That is easy! */
663     /*                                                        */
664     if ( ex1 == ex2 )
665       goto End;
666 
667     /* ok, we'll have to render a run of adjacent cells on the same */
668     /* scanline...                                                  */
669     /*                                                              */
670     dx = x2 - x1;
671     dy = y2 - y1;
672 
673     if ( dx > 0 )
674     {
675       p     = ( ONE_PIXEL - fx1 ) * dy;
676       first = ONE_PIXEL;
677       incr  = 1;
678     }
679     else
680     {
681       p     = fx1 * dy;
682       first = 0;
683       incr  = -1;
684       dx    = -dx;
685     }
686 
687     /* the fractional part of y-delta is mod/dx. It is essential to */
688     /* keep track of its accumulation for accurate rendering.       */
689     /* XXX: y-delta and x-delta below should be related.            */
690     FT_DIV_MOD( TCoord, p, dx, delta, mod );
691 
692     FT_INTEGRATE( ras, delta, fx1 + first );
693     y1  += delta;
694     ex1 += incr;
695     gray_set_cell( RAS_VAR_ ex1, ey );
696 
697     if ( ex1 != ex2 )
698     {
699       TCoord  lift, rem;
700 
701 
702       p = ONE_PIXEL * dy;
703       FT_DIV_MOD( TCoord, p, dx, lift, rem );
704 
705       do
706       {
707         delta = lift;
708         mod  += rem;
709         if ( mod >= (TCoord)dx )
710         {
711           mod -= (TCoord)dx;
712           delta++;
713         }
714 
715         FT_INTEGRATE( ras, delta, ONE_PIXEL );
716         y1  += delta;
717         ex1 += incr;
718         gray_set_cell( RAS_VAR_ ex1, ey );
719       } while ( ex1 != ex2 );
720     }
721 
722     fx1 = ONE_PIXEL - first;
723 
724   End:
725     FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 );
726   }
727 
728 
729   /**************************************************************************
730    *
731    * Render a given line as a series of scanlines.
732    */
733   static void
gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)734   gray_render_line( RAS_ARG_ TPos  to_x,
735                              TPos  to_y )
736   {
737     TCoord  ey1, ey2, fy1, fy2, first, delta, mod;
738     TPos    p, dx, dy, x, x2;
739     int     incr;
740 
741 
742     ey1 = TRUNC( ras.y );
743     ey2 = TRUNC( to_y );     /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
744 
745     /* perform vertical clipping */
746     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
747          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
748       goto End;
749 
750     fy1 = FRACT( ras.y );
751     fy2 = FRACT( to_y );
752 
753     /* everything is on a single scanline */
754     if ( ey1 == ey2 )
755     {
756       gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
757       goto End;
758     }
759 
760     dx = to_x - ras.x;
761     dy = to_y - ras.y;
762 
763     /* vertical line - avoid calling gray_render_scanline */
764     if ( dx == 0 )
765     {
766       TCoord  ex     = TRUNC( ras.x );
767       TCoord  two_fx = FRACT( ras.x ) << 1;
768 
769 
770       if ( dy > 0)
771       {
772         first = ONE_PIXEL;
773         incr  = 1;
774       }
775       else
776       {
777         first = 0;
778         incr  = -1;
779       }
780 
781       delta = first - fy1;
782       FT_INTEGRATE( ras, delta, two_fx);
783       ey1 += incr;
784 
785       gray_set_cell( RAS_VAR_ ex, ey1 );
786 
787       delta = first + first - ONE_PIXEL;
788       while ( ey1 != ey2 )
789       {
790         FT_INTEGRATE( ras, delta, two_fx);
791         ey1 += incr;
792 
793         gray_set_cell( RAS_VAR_ ex, ey1 );
794       }
795 
796       delta = fy2 - ONE_PIXEL + first;
797       FT_INTEGRATE( ras, delta, two_fx);
798 
799       goto End;
800     }
801 
802     /* ok, we have to render several scanlines */
803     if ( dy > 0)
804     {
805       p     = ( ONE_PIXEL - fy1 ) * dx;
806       first = ONE_PIXEL;
807       incr  = 1;
808     }
809     else
810     {
811       p     = fy1 * dx;
812       first = 0;
813       incr  = -1;
814       dy    = -dy;
815     }
816 
817     /* the fractional part of x-delta is mod/dy. It is essential to */
818     /* keep track of its accumulation for accurate rendering.       */
819     FT_DIV_MOD( TCoord, p, dy, delta, mod );
820 
821     x = ras.x + delta;
822     gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
823 
824     ey1 += incr;
825     gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
826 
827     if ( ey1 != ey2 )
828     {
829       TCoord  lift, rem;
830 
831 
832       p    = ONE_PIXEL * dx;
833       FT_DIV_MOD( TCoord, p, dy, lift, rem );
834 
835       do
836       {
837         delta = lift;
838         mod  += rem;
839         if ( mod >= (TCoord)dy )
840         {
841           mod -= (TCoord)dy;
842           delta++;
843         }
844 
845         x2 = x + delta;
846         gray_render_scanline( RAS_VAR_ ey1,
847                                        x, ONE_PIXEL - first,
848                                        x2, first );
849         x = x2;
850 
851         ey1 += incr;
852         gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
853       } while ( ey1 != ey2 );
854     }
855 
856     gray_render_scanline( RAS_VAR_ ey1,
857                                    x, ONE_PIXEL - first,
858                                    to_x, fy2 );
859 
860   End:
861     ras.x       = to_x;
862     ras.y       = to_y;
863   }
864 
865 #else
866 
867   /**************************************************************************
868    *
869    * Render a straight line across multiple cells in any direction.
870    */
871   static void
gray_render_line(RAS_ARG_ TPos to_x,TPos to_y)872   gray_render_line( RAS_ARG_ TPos  to_x,
873                              TPos  to_y )
874   {
875     TPos    dx, dy;
876     TCoord  fx1, fy1, fx2, fy2;
877     TCoord  ex1, ey1, ex2, ey2;
878 
879 
880     ey1 = TRUNC( ras.y );
881     ey2 = TRUNC( to_y );
882 
883     /* perform vertical clipping */
884     if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
885          ( ey1 <  ras.min_ey && ey2 <  ras.min_ey ) )
886       goto End;
887 
888     ex1 = TRUNC( ras.x );
889     ex2 = TRUNC( to_x );
890 
891     fx1 = FRACT( ras.x );
892     fy1 = FRACT( ras.y );
893 
894     dx = to_x - ras.x;
895     dy = to_y - ras.y;
896 
897     if ( ex1 == ex2 && ey1 == ey2 )       /* inside one cell */
898       ;
899     else if ( dy == 0 ) /* ex1 != ex2 */  /* any horizontal line */
900     {
901       gray_set_cell( RAS_VAR_ ex2, ey2 );
902       goto End;
903     }
904     else if ( dx == 0 )
905     {
906       if ( dy > 0 )                       /* vertical line up */
907         do
908         {
909           fy2 = ONE_PIXEL;
910           FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 );
911           fy1 = 0;
912           ey1++;
913           gray_set_cell( RAS_VAR_ ex1, ey1 );
914         } while ( ey1 != ey2 );
915       else                                /* vertical line down */
916         do
917         {
918           fy2 = 0;
919           FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 );
920           fy1 = ONE_PIXEL;
921           ey1--;
922           gray_set_cell( RAS_VAR_ ex1, ey1 );
923         } while ( ey1 != ey2 );
924     }
925     else                                  /* any other line */
926     {
927       FT_Int64  prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1;
928       FT_UDIVPREP( ex1 != ex2, dx );
929       FT_UDIVPREP( ey1 != ey2, dy );
930 
931 
932       /* The fundamental value `prod' determines which side and the  */
933       /* exact coordinate where the line exits current cell.  It is  */
934       /* also easily updated when moving from one cell to the next.  */
935       do
936       {
937         if      ( prod - dx * ONE_PIXEL                  >  0 &&
938                   prod                                   <= 0 ) /* left */
939         {
940           fx2 = 0;
941           fy2 = FT_UDIV( -prod, -dx );
942           prod -= dy * ONE_PIXEL;
943           FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
944           fx1 = ONE_PIXEL;
945           fy1 = fy2;
946           ex1--;
947         }
948         else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL >  0 &&
949                   prod - dx * ONE_PIXEL                  <= 0 ) /* up */
950         {
951           prod -= dx * ONE_PIXEL;
952           fx2 = FT_UDIV( -prod, dy );
953           fy2 = ONE_PIXEL;
954           FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
955           fx1 = fx2;
956           fy1 = 0;
957           ey1++;
958         }
959         else if ( prod                  + dy * ONE_PIXEL >= 0 &&
960                   prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */
961         {
962           prod += dy * ONE_PIXEL;
963           fx2 = ONE_PIXEL;
964           fy2 = FT_UDIV( prod, dx );
965           FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
966           fx1 = 0;
967           fy1 = fy2;
968           ex1++;
969         }
970         else /* ( prod                                   >  0 &&
971                   prod                  + dy * ONE_PIXEL <  0 )    down */
972         {
973           fx2 = FT_UDIV( prod, -dy );
974           fy2 = 0;
975           prod += dx * ONE_PIXEL;
976           FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
977           fx1 = fx2;
978           fy1 = ONE_PIXEL;
979           ey1--;
980         }
981 
982         gray_set_cell( RAS_VAR_ ex1, ey1 );
983 
984       } while ( ex1 != ex2 || ey1 != ey2 );
985     }
986 
987     fx2 = FRACT( to_x );
988     fy2 = FRACT( to_y );
989 
990     FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
991 
992   End:
993     ras.x = to_x;
994     ras.y = to_y;
995   }
996 
997 #endif
998 
999   /*
1000    * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs
1001    * is slightly faster in the following cases:
1002    *
1003    *   - When the host CPU is 64-bit.
1004    *   - When SSE2 SIMD registers and instructions are available (even on
1005    *     x86).
1006    *
1007    * For other cases, using binary splits is actually slightly faster.
1008    */
1009 #if defined( __SSE2__ )                          || \
1010     defined( __x86_64__ )                        || \
1011     defined( _M_AMD64 )                          || \
1012     ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 )
1013 #  define FT_SSE2 1
1014 #else
1015 #  define FT_SSE2 0
1016 #endif
1017 
1018 #if FT_SSE2                || \
1019     defined( __aarch64__ ) || \
1020     defined( _M_ARM64 )
1021 #  define BEZIER_USE_DDA  1
1022 #else
1023 #  define BEZIER_USE_DDA  0
1024 #endif
1025 
1026   /*
1027    * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64`
1028    * to be defined.  If `FT_INT64` is not defined, meaning there is no
1029    * 64-bit type available, disable it to avoid compilation errors.  See for
1030    * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071.
1031    */
1032 #if !defined( FT_INT64 )
1033 #  undef BEZIER_USE_DDA
1034 #  define BEZIER_USE_DDA  0
1035 #endif
1036 
1037 #if BEZIER_USE_DDA
1038 
1039 #if FT_SSE2
1040 #  include <emmintrin.h>
1041 #endif
1042 
1043 #define LEFT_SHIFT( a, b )  (FT_Int64)( (FT_UInt64)(a) << (b) )
1044 
1045 
1046   static void
gray_render_conic(RAS_ARG_ const FT_Vector * control,const FT_Vector * to)1047   gray_render_conic( RAS_ARG_ const FT_Vector*  control,
1048                               const FT_Vector*  to )
1049   {
1050     FT_Vector  p0, p1, p2;
1051     TPos       ax, ay, bx, by, dx, dy;
1052     int        shift;
1053 
1054     FT_Int64  rx, ry;
1055     FT_Int64  qx, qy;
1056     FT_Int64  px, py;
1057 
1058     FT_UInt  count;
1059 
1060 
1061     p0.x = ras.x;
1062     p0.y = ras.y;
1063     p1.x = UPSCALE( control->x );
1064     p1.y = UPSCALE( control->y );
1065     p2.x = UPSCALE( to->x );
1066     p2.y = UPSCALE( to->y );
1067 
1068     /* short-cut the arc that crosses the current band */
1069     if ( ( TRUNC( p0.y ) >= ras.max_ey &&
1070            TRUNC( p1.y ) >= ras.max_ey &&
1071            TRUNC( p2.y ) >= ras.max_ey ) ||
1072          ( TRUNC( p0.y ) <  ras.min_ey &&
1073            TRUNC( p1.y ) <  ras.min_ey &&
1074            TRUNC( p2.y ) <  ras.min_ey ) )
1075     {
1076       ras.x = p2.x;
1077       ras.y = p2.y;
1078       return;
1079     }
1080 
1081     bx = p1.x - p0.x;
1082     by = p1.y - p0.y;
1083     ax = p2.x - p1.x - bx;  /* p0.x + p2.x - 2 * p1.x */
1084     ay = p2.y - p1.y - by;  /* p0.y + p2.y - 2 * p1.y */
1085 
1086     dx = FT_ABS( ax );
1087     dy = FT_ABS( ay );
1088     if ( dx < dy )
1089       dx = dy;
1090 
1091     if ( dx <= ONE_PIXEL / 4 )
1092     {
1093       gray_render_line( RAS_VAR_ p2.x, p2.y );
1094       return;
1095     }
1096 
1097     /* We can calculate the number of necessary bisections because  */
1098     /* each bisection predictably reduces deviation exactly 4-fold. */
1099     /* Even 32-bit deviation would vanish after 16 bisections.      */
1100     shift = 0;
1101     do
1102     {
1103       dx   >>= 2;
1104       shift += 1;
1105 
1106     } while ( dx > ONE_PIXEL / 4 );
1107 
1108     /*
1109      * The (P0,P1,P2) arc equation, for t in [0,1] range:
1110      *
1111      * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2
1112      *
1113      * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2
1114      *      = P0 + 2*B*t + A*t^2
1115      *
1116      *    for A = P0 + P2 - 2*P1
1117      *    and B = P1 - P0
1118      *
1119      * Let's consider the difference when advancing by a small
1120      * parameter h:
1121      *
1122      *    Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t
1123      *
1124      * And then its own difference:
1125      *
1126      *    R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant)
1127      *
1128      * Since R is always a constant, it is possible to compute
1129      * successive positions with:
1130      *
1131      *     P = P0
1132      *     Q = Q(h,0) = 2*B*h + A*h*h
1133      *     R = 2*A*h*h
1134      *
1135      *   loop:
1136      *     P += Q
1137      *     Q += R
1138      *     EMIT(P)
1139      *
1140      * To ensure accurate results, perform computations on 64-bit
1141      * values, after scaling them by 2^32.
1142      *
1143      *           h = 1 / 2^N
1144      *
1145      *     R << 32 = 2 * A << (32 - N - N)
1146      *             = A << (33 - 2*N)
1147      *
1148      *     Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N))
1149      *             = (B << (33 - N)) + (A << (32 - 2*N))
1150      */
1151 
1152 #if FT_SSE2
1153     /* Experience shows that for small shift values, */
1154     /* SSE2 is actually slower.                      */
1155     if ( shift > 2 )
1156     {
1157       union
1158       {
1159         struct { FT_Int64  ax, ay, bx, by; }  i;
1160         struct { __m128i  a, b; }  vec;
1161 
1162       } u;
1163 
1164       union
1165       {
1166         struct { FT_Int32  px_lo, px_hi, py_lo, py_hi; }  i;
1167         __m128i  vec;
1168 
1169       } v;
1170 
1171       __m128i  a, b;
1172       __m128i  r, q, q2;
1173       __m128i  p;
1174 
1175 
1176       u.i.ax = ax;
1177       u.i.ay = ay;
1178       u.i.bx = bx;
1179       u.i.by = by;
1180 
1181       a = _mm_load_si128( &u.vec.a );
1182       b = _mm_load_si128( &u.vec.b );
1183 
1184       r  = _mm_slli_epi64( a, 33 - 2 * shift );
1185       q  = _mm_slli_epi64( b, 33 - shift );
1186       q2 = _mm_slli_epi64( a, 32 - 2 * shift );
1187 
1188       q = _mm_add_epi64( q2, q );
1189 
1190       v.i.px_lo = 0;
1191       v.i.px_hi = p0.x;
1192       v.i.py_lo = 0;
1193       v.i.py_hi = p0.y;
1194 
1195       p = _mm_load_si128( &v.vec );
1196 
1197       for ( count = 1U << shift; count > 0; count-- )
1198       {
1199         p = _mm_add_epi64( p, q );
1200         q = _mm_add_epi64( q, r );
1201 
1202         _mm_store_si128( &v.vec, p );
1203 
1204         gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi );
1205       }
1206 
1207       return;
1208     }
1209 #endif  /* FT_SSE2 */
1210 
1211     rx = LEFT_SHIFT( ax, 33 - 2 * shift );
1212     ry = LEFT_SHIFT( ay, 33 - 2 * shift );
1213 
1214     qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift );
1215     qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift );
1216 
1217     px = LEFT_SHIFT( p0.x, 32 );
1218     py = LEFT_SHIFT( p0.y, 32 );
1219 
1220     for ( count = 1U << shift; count > 0; count-- )
1221     {
1222       px += qx;
1223       py += qy;
1224       qx += rx;
1225       qy += ry;
1226 
1227       gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ),
1228                                  (FT_Pos)( py >> 32 ) );
1229     }
1230   }
1231 
1232 #else  /* !BEZIER_USE_DDA */
1233 
1234   /*
1235    * Note that multiple attempts to speed up the function below
1236    * with SSE2 intrinsics, using various data layouts, have turned
1237    * out to be slower than the non-SIMD code below.
1238    */
1239   static void
gray_split_conic(FT_Vector * base)1240   gray_split_conic( FT_Vector*  base )
1241   {
1242     TPos  a, b;
1243 
1244 
1245     base[4].x = base[2].x;
1246     a = base[0].x + base[1].x;
1247     b = base[1].x + base[2].x;
1248     base[3].x = b >> 1;
1249     base[2].x = ( a + b ) >> 2;
1250     base[1].x = a >> 1;
1251 
1252     base[4].y = base[2].y;
1253     a = base[0].y + base[1].y;
1254     b = base[1].y + base[2].y;
1255     base[3].y = b >> 1;
1256     base[2].y = ( a + b ) >> 2;
1257     base[1].y = a >> 1;
1258   }
1259 
1260 
1261   static void
gray_render_conic(RAS_ARG_ const FT_Vector * control,const FT_Vector * to)1262   gray_render_conic( RAS_ARG_ const FT_Vector*  control,
1263                               const FT_Vector*  to )
1264   {
1265     FT_Vector   bez_stack[16 * 2 + 1];  /* enough to accommodate bisections */
1266     FT_Vector*  arc = bez_stack;
1267     TPos        dx, dy;
1268     int         draw;
1269 
1270 
1271     arc[0].x = UPSCALE( to->x );
1272     arc[0].y = UPSCALE( to->y );
1273     arc[1].x = UPSCALE( control->x );
1274     arc[1].y = UPSCALE( control->y );
1275     arc[2].x = ras.x;
1276     arc[2].y = ras.y;
1277 
1278     /* short-cut the arc that crosses the current band */
1279     if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
1280            TRUNC( arc[1].y ) >= ras.max_ey &&
1281            TRUNC( arc[2].y ) >= ras.max_ey ) ||
1282          ( TRUNC( arc[0].y ) <  ras.min_ey &&
1283            TRUNC( arc[1].y ) <  ras.min_ey &&
1284            TRUNC( arc[2].y ) <  ras.min_ey ) )
1285     {
1286       ras.x = arc[0].x;
1287       ras.y = arc[0].y;
1288       return;
1289     }
1290 
1291     dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
1292     dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
1293     if ( dx < dy )
1294       dx = dy;
1295 
1296     /* We can calculate the number of necessary bisections because  */
1297     /* each bisection predictably reduces deviation exactly 4-fold. */
1298     /* Even 32-bit deviation would vanish after 16 bisections.      */
1299     draw = 1;
1300     while ( dx > ONE_PIXEL / 4 )
1301     {
1302       dx   >>= 2;
1303       draw <<= 1;
1304     }
1305 
1306     /* We use decrement counter to count the total number of segments */
1307     /* to draw starting from 2^level. Before each draw we split as    */
1308     /* many times as there are trailing zeros in the counter.         */
1309     do
1310     {
1311       int  split = draw & ( -draw );  /* isolate the rightmost 1-bit */
1312 
1313 
1314       while ( ( split >>= 1 ) )
1315       {
1316         gray_split_conic( arc );
1317         arc += 2;
1318       }
1319 
1320       gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1321       arc -= 2;
1322 
1323     } while ( --draw );
1324   }
1325 
1326 #endif  /* !BEZIER_USE_DDA */
1327 
1328 
1329   /*
1330    * For cubic Bézier, binary splits are still faster than DDA
1331    * because the splits are adaptive to how quickly each sub-arc
1332    * approaches their chord trisection points.
1333    *
1334    * It might be useful to experiment with SSE2 to speed up
1335    * `gray_split_cubic`, though.
1336    */
1337   static void
gray_split_cubic(FT_Vector * base)1338   gray_split_cubic( FT_Vector*  base )
1339   {
1340     TPos  a, b, c;
1341 
1342 
1343     base[6].x = base[3].x;
1344     a = base[0].x + base[1].x;
1345     b = base[1].x + base[2].x;
1346     c = base[2].x + base[3].x;
1347     base[5].x = c >> 1;
1348     c += b;
1349     base[4].x = c >> 2;
1350     base[1].x = a >> 1;
1351     a += b;
1352     base[2].x = a >> 2;
1353     base[3].x = ( a + c ) >> 3;
1354 
1355     base[6].y = base[3].y;
1356     a = base[0].y + base[1].y;
1357     b = base[1].y + base[2].y;
1358     c = base[2].y + base[3].y;
1359     base[5].y = c >> 1;
1360     c += b;
1361     base[4].y = c >> 2;
1362     base[1].y = a >> 1;
1363     a += b;
1364     base[2].y = a >> 2;
1365     base[3].y = ( a + c ) >> 3;
1366   }
1367 
1368 
1369   static void
gray_render_cubic(RAS_ARG_ const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to)1370   gray_render_cubic( RAS_ARG_ const FT_Vector*  control1,
1371                               const FT_Vector*  control2,
1372                               const FT_Vector*  to )
1373   {
1374     FT_Vector   bez_stack[16 * 3 + 1];  /* enough to accommodate bisections */
1375     FT_Vector*  arc = bez_stack;
1376 
1377 
1378     arc[0].x = UPSCALE( to->x );
1379     arc[0].y = UPSCALE( to->y );
1380     arc[1].x = UPSCALE( control2->x );
1381     arc[1].y = UPSCALE( control2->y );
1382     arc[2].x = UPSCALE( control1->x );
1383     arc[2].y = UPSCALE( control1->y );
1384     arc[3].x = ras.x;
1385     arc[3].y = ras.y;
1386 
1387     /* short-cut the arc that crosses the current band */
1388     if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
1389            TRUNC( arc[1].y ) >= ras.max_ey &&
1390            TRUNC( arc[2].y ) >= ras.max_ey &&
1391            TRUNC( arc[3].y ) >= ras.max_ey ) ||
1392          ( TRUNC( arc[0].y ) <  ras.min_ey &&
1393            TRUNC( arc[1].y ) <  ras.min_ey &&
1394            TRUNC( arc[2].y ) <  ras.min_ey &&
1395            TRUNC( arc[3].y ) <  ras.min_ey ) )
1396     {
1397       ras.x = arc[0].x;
1398       ras.y = arc[0].y;
1399       return;
1400     }
1401 
1402     for (;;)
1403     {
1404       /* with each split, control points quickly converge towards  */
1405       /* chord trisection points and the vanishing distances below */
1406       /* indicate when the segment is flat enough to draw          */
1407       if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 ||
1408            FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 ||
1409            FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 ||
1410            FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 )
1411         goto Split;
1412 
1413       gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1414 
1415       if ( arc == bez_stack )
1416         return;
1417 
1418       arc -= 3;
1419       continue;
1420 
1421     Split:
1422       gray_split_cubic( arc );
1423       arc += 3;
1424     }
1425   }
1426 
1427 
1428   static int
gray_move_to(const FT_Vector * to,gray_PWorker worker)1429   gray_move_to( const FT_Vector*  to,
1430                 gray_PWorker      worker )
1431   {
1432     TPos  x, y;
1433 
1434 
1435     /* start to a new position */
1436     x = UPSCALE( to->x );
1437     y = UPSCALE( to->y );
1438 
1439     gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
1440 
1441     ras.x = x;
1442     ras.y = y;
1443     return 0;
1444   }
1445 
1446 
1447   static int
gray_line_to(const FT_Vector * to,gray_PWorker worker)1448   gray_line_to( const FT_Vector*  to,
1449                 gray_PWorker      worker )
1450   {
1451     gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
1452     return 0;
1453   }
1454 
1455 
1456   static int
gray_conic_to(const FT_Vector * control,const FT_Vector * to,gray_PWorker worker)1457   gray_conic_to( const FT_Vector*  control,
1458                  const FT_Vector*  to,
1459                  gray_PWorker      worker )
1460   {
1461     gray_render_conic( RAS_VAR_ control, to );
1462     return 0;
1463   }
1464 
1465 
1466   static int
gray_cubic_to(const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to,gray_PWorker worker)1467   gray_cubic_to( const FT_Vector*  control1,
1468                  const FT_Vector*  control2,
1469                  const FT_Vector*  to,
1470                  gray_PWorker      worker )
1471   {
1472     gray_render_cubic( RAS_VAR_ control1, control2, to );
1473     return 0;
1474   }
1475 
1476 
1477   static void
gray_sweep(RAS_ARG)1478   gray_sweep( RAS_ARG )
1479   {
1480     int  fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100
1481                                                                  : INT_MIN;
1482     int  coverage;
1483     int  y;
1484 
1485 
1486     for ( y = ras.min_ey; y < ras.max_ey; y++ )
1487     {
1488       PCell   cell  = ras.ycells[y - ras.min_ey];
1489       TCoord  x     = ras.min_ex;
1490       TArea   cover = 0;
1491 
1492       unsigned char*  line = ras.target.origin - ras.target.pitch * y;
1493 
1494 
1495       for ( ; cell != ras.cell_null; cell = cell->next )
1496       {
1497         TArea  area;
1498 
1499 
1500         if ( cover != 0 && cell->x > x )
1501         {
1502           FT_FILL_RULE( coverage, cover, fill );
1503           FT_GRAY_SET( line + x, coverage, cell->x - x );
1504         }
1505 
1506         cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
1507         area   = cover - cell->area;
1508 
1509         if ( area != 0 && cell->x >= ras.min_ex )
1510         {
1511           FT_FILL_RULE( coverage, area, fill );
1512           line[cell->x] = (unsigned char)coverage;
1513         }
1514 
1515         x = cell->x + 1;
1516       }
1517 
1518       if ( cover != 0 )  /* only if cropped */
1519       {
1520         FT_FILL_RULE( coverage, cover, fill );
1521         FT_GRAY_SET( line + x, coverage, ras.max_ex - x );
1522       }
1523     }
1524   }
1525 
1526 
1527   static void
gray_sweep_direct(RAS_ARG)1528   gray_sweep_direct( RAS_ARG )
1529   {
1530     int  fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100
1531                                                                  : INT_MIN;
1532     int  coverage;
1533     int  y;
1534 
1535     FT_Span  span[FT_MAX_GRAY_SPANS];
1536     int      n = 0;
1537 
1538 
1539     for ( y = ras.min_ey; y < ras.max_ey; y++ )
1540     {
1541       PCell   cell  = ras.ycells[y - ras.min_ey];
1542       TCoord  x     = ras.min_ex;
1543       TArea   cover = 0;
1544 
1545 
1546       for ( ; cell != ras.cell_null; cell = cell->next )
1547       {
1548         TArea  area;
1549 
1550 
1551         if ( cover != 0 && cell->x > x )
1552         {
1553           FT_FILL_RULE( coverage, cover, fill );
1554 
1555           span[n].coverage = (unsigned char)coverage;
1556           span[n].x        = (short)x;
1557           span[n].len      = (unsigned short)( cell->x - x );
1558 
1559           if ( ++n == FT_MAX_GRAY_SPANS )
1560           {
1561             /* flush the span buffer and reset the count */
1562             ras.render_span( y, n, span, ras.render_span_data );
1563             n = 0;
1564           }
1565         }
1566 
1567         cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
1568         area   = cover - cell->area;
1569 
1570         if ( area != 0 && cell->x >= ras.min_ex )
1571         {
1572           FT_FILL_RULE( coverage, area, fill );
1573 
1574           span[n].coverage = (unsigned char)coverage;
1575           span[n].x        = (short)cell->x;
1576           span[n].len      = 1;
1577 
1578           if ( ++n == FT_MAX_GRAY_SPANS )
1579           {
1580             /* flush the span buffer and reset the count */
1581             ras.render_span( y, n, span, ras.render_span_data );
1582             n = 0;
1583           }
1584         }
1585 
1586         x = cell->x + 1;
1587       }
1588 
1589       if ( cover != 0 )  /* only if cropped */
1590       {
1591         FT_FILL_RULE( coverage, cover, fill );
1592 
1593         span[n].coverage = (unsigned char)coverage;
1594         span[n].x        = (short)x;
1595         span[n].len      = (unsigned short)( ras.max_ex - x );
1596 
1597         ++n;
1598       }
1599 
1600       if ( n )
1601       {
1602         /* flush the span buffer and reset the count */
1603         ras.render_span( y, n, span, ras.render_span_data );
1604         n = 0;
1605       }
1606     }
1607   }
1608 
1609 
1610 #ifdef STANDALONE_
1611 
1612   /**************************************************************************
1613    *
1614    * The following functions should only compile in stand-alone mode,
1615    * i.e., when building this component without the rest of FreeType.
1616    *
1617    */
1618 
1619   /**************************************************************************
1620    *
1621    * @Function:
1622    *   FT_Outline_Decompose
1623    *
1624    * @Description:
1625    *   Walk over an outline's structure to decompose it into individual
1626    *   segments and Bézier arcs.  This function is also able to emit
1627    *   `move to' and `close to' operations to indicate the start and end
1628    *   of new contours in the outline.
1629    *
1630    * @Input:
1631    *   outline ::
1632    *     A pointer to the source target.
1633    *
1634    *   func_interface ::
1635    *     A table of `emitters', i.e., function pointers
1636    *     called during decomposition to indicate path
1637    *     operations.
1638    *
1639    * @InOut:
1640    *   user ::
1641    *     A typeless pointer which is passed to each
1642    *     emitter during the decomposition.  It can be
1643    *     used to store the state during the
1644    *     decomposition.
1645    *
1646    * @Return:
1647    *   Error code.  0 means success.
1648    */
1649   static int
FT_Outline_Decompose(const FT_Outline * outline,const FT_Outline_Funcs * func_interface,void * user)1650   FT_Outline_Decompose( const FT_Outline*        outline,
1651                         const FT_Outline_Funcs*  func_interface,
1652                         void*                    user )
1653   {
1654 #undef SCALED
1655 #define SCALED( x )  ( (x) * ( 1L << shift ) - delta )
1656 
1657     FT_Vector   v_last;
1658     FT_Vector   v_control;
1659     FT_Vector   v_start;
1660 
1661     FT_Vector*  point;
1662     FT_Vector*  limit;
1663     char*       tags;
1664 
1665     int         error;
1666 
1667     int   n;         /* index of contour in outline     */
1668     int   first;     /* index of first point in contour */
1669     char  tag;       /* current point's state           */
1670 
1671     int   shift;
1672     TPos  delta;
1673 
1674 
1675     if ( !outline )
1676       return FT_THROW( Invalid_Outline );
1677 
1678     if ( !func_interface )
1679       return FT_THROW( Invalid_Argument );
1680 
1681     shift = func_interface->shift;
1682     delta = func_interface->delta;
1683     first = 0;
1684 
1685     for ( n = 0; n < outline->n_contours; n++ )
1686     {
1687       int  last;  /* index of last point in contour */
1688 
1689 
1690       FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
1691 
1692       last  = outline->contours[n];
1693       if ( last < 0 )
1694         goto Invalid_Outline;
1695       limit = outline->points + last;
1696 
1697       v_start   = outline->points[first];
1698       v_start.x = SCALED( v_start.x );
1699       v_start.y = SCALED( v_start.y );
1700 
1701       v_last   = outline->points[last];
1702       v_last.x = SCALED( v_last.x );
1703       v_last.y = SCALED( v_last.y );
1704 
1705       v_control = v_start;
1706 
1707       point = outline->points + first;
1708       tags  = outline->tags   + first;
1709       tag   = FT_CURVE_TAG( tags[0] );
1710 
1711       /* A contour cannot start with a cubic control point! */
1712       if ( tag == FT_CURVE_TAG_CUBIC )
1713         goto Invalid_Outline;
1714 
1715       /* check first point to determine origin */
1716       if ( tag == FT_CURVE_TAG_CONIC )
1717       {
1718         /* first point is conic control.  Yes, this happens. */
1719         if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
1720         {
1721           /* start at last point if it is on the curve */
1722           v_start = v_last;
1723           limit--;
1724         }
1725         else
1726         {
1727           /* if both first and last points are conic,         */
1728           /* start at their middle and record its position    */
1729           /* for closure                                      */
1730           v_start.x = ( v_start.x + v_last.x ) / 2;
1731           v_start.y = ( v_start.y + v_last.y ) / 2;
1732 
1733           v_last = v_start;
1734         }
1735         point--;
1736         tags--;
1737       }
1738 
1739       FT_TRACE5(( "  move to (%.2f, %.2f)\n",
1740                   v_start.x / 64.0, v_start.y / 64.0 ));
1741       error = func_interface->move_to( &v_start, user );
1742       if ( error )
1743         goto Exit;
1744 
1745       while ( point < limit )
1746       {
1747         point++;
1748         tags++;
1749 
1750         tag = FT_CURVE_TAG( tags[0] );
1751         switch ( tag )
1752         {
1753         case FT_CURVE_TAG_ON:  /* emit a single line_to */
1754           {
1755             FT_Vector  vec;
1756 
1757 
1758             vec.x = SCALED( point->x );
1759             vec.y = SCALED( point->y );
1760 
1761             FT_TRACE5(( "  line to (%.2f, %.2f)\n",
1762                         vec.x / 64.0, vec.y / 64.0 ));
1763             error = func_interface->line_to( &vec, user );
1764             if ( error )
1765               goto Exit;
1766             continue;
1767           }
1768 
1769         case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
1770           v_control.x = SCALED( point->x );
1771           v_control.y = SCALED( point->y );
1772 
1773         Do_Conic:
1774           if ( point < limit )
1775           {
1776             FT_Vector  vec;
1777             FT_Vector  v_middle;
1778 
1779 
1780             point++;
1781             tags++;
1782             tag = FT_CURVE_TAG( tags[0] );
1783 
1784             vec.x = SCALED( point->x );
1785             vec.y = SCALED( point->y );
1786 
1787             if ( tag == FT_CURVE_TAG_ON )
1788             {
1789               FT_TRACE5(( "  conic to (%.2f, %.2f)"
1790                           " with control (%.2f, %.2f)\n",
1791                           vec.x / 64.0, vec.y / 64.0,
1792                           v_control.x / 64.0, v_control.y / 64.0 ));
1793               error = func_interface->conic_to( &v_control, &vec, user );
1794               if ( error )
1795                 goto Exit;
1796               continue;
1797             }
1798 
1799             if ( tag != FT_CURVE_TAG_CONIC )
1800               goto Invalid_Outline;
1801 
1802             v_middle.x = ( v_control.x + vec.x ) / 2;
1803             v_middle.y = ( v_control.y + vec.y ) / 2;
1804 
1805             FT_TRACE5(( "  conic to (%.2f, %.2f)"
1806                         " with control (%.2f, %.2f)\n",
1807                         v_middle.x / 64.0, v_middle.y / 64.0,
1808                         v_control.x / 64.0, v_control.y / 64.0 ));
1809             error = func_interface->conic_to( &v_control, &v_middle, user );
1810             if ( error )
1811               goto Exit;
1812 
1813             v_control = vec;
1814             goto Do_Conic;
1815           }
1816 
1817           FT_TRACE5(( "  conic to (%.2f, %.2f)"
1818                       " with control (%.2f, %.2f)\n",
1819                       v_start.x / 64.0, v_start.y / 64.0,
1820                       v_control.x / 64.0, v_control.y / 64.0 ));
1821           error = func_interface->conic_to( &v_control, &v_start, user );
1822           goto Close;
1823 
1824         default:  /* FT_CURVE_TAG_CUBIC */
1825           {
1826             FT_Vector  vec1, vec2;
1827 
1828 
1829             if ( point + 1 > limit                             ||
1830                  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1831               goto Invalid_Outline;
1832 
1833             point += 2;
1834             tags  += 2;
1835 
1836             vec1.x = SCALED( point[-2].x );
1837             vec1.y = SCALED( point[-2].y );
1838 
1839             vec2.x = SCALED( point[-1].x );
1840             vec2.y = SCALED( point[-1].y );
1841 
1842             if ( point <= limit )
1843             {
1844               FT_Vector  vec;
1845 
1846 
1847               vec.x = SCALED( point->x );
1848               vec.y = SCALED( point->y );
1849 
1850               FT_TRACE5(( "  cubic to (%.2f, %.2f)"
1851                           " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1852                           vec.x / 64.0, vec.y / 64.0,
1853                           vec1.x / 64.0, vec1.y / 64.0,
1854                           vec2.x / 64.0, vec2.y / 64.0 ));
1855               error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
1856               if ( error )
1857                 goto Exit;
1858               continue;
1859             }
1860 
1861             FT_TRACE5(( "  cubic to (%.2f, %.2f)"
1862                         " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1863                         v_start.x / 64.0, v_start.y / 64.0,
1864                         vec1.x / 64.0, vec1.y / 64.0,
1865                         vec2.x / 64.0, vec2.y / 64.0 ));
1866             error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
1867             goto Close;
1868           }
1869         }
1870       }
1871 
1872       /* close the contour with a line segment */
1873       FT_TRACE5(( "  line to (%.2f, %.2f)\n",
1874                   v_start.x / 64.0, v_start.y / 64.0 ));
1875       error = func_interface->line_to( &v_start, user );
1876 
1877    Close:
1878       if ( error )
1879         goto Exit;
1880 
1881       first = last + 1;
1882     }
1883 
1884     FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1885     return Smooth_Err_Ok;
1886 
1887   Exit:
1888     FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error ));
1889     return error;
1890 
1891   Invalid_Outline:
1892     return FT_THROW( Invalid_Outline );
1893   }
1894 
1895 #endif /* STANDALONE_ */
1896 
1897 
1898   FT_DEFINE_OUTLINE_FUNCS(
1899     func_interface,
1900 
1901     (FT_Outline_MoveTo_Func) gray_move_to,   /* move_to  */
1902     (FT_Outline_LineTo_Func) gray_line_to,   /* line_to  */
1903     (FT_Outline_ConicTo_Func)gray_conic_to,  /* conic_to */
1904     (FT_Outline_CubicTo_Func)gray_cubic_to,  /* cubic_to */
1905 
1906     0,                                       /* shift    */
1907     0                                        /* delta    */
1908   )
1909 
1910 
1911   static int
gray_convert_glyph_inner(RAS_ARG_ int continued)1912   gray_convert_glyph_inner( RAS_ARG_
1913                             int  continued )
1914   {
1915     volatile int  error;
1916 
1917 
1918     if ( ft_setjmp( ras.jump_buffer ) == 0 )
1919     {
1920       if ( continued )
1921         FT_Trace_Disable();
1922       error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
1923       if ( continued )
1924         FT_Trace_Enable();
1925 
1926       FT_TRACE7(( "band [%d..%d]: %ld cell%s remaining/\n",
1927                   ras.min_ey,
1928                   ras.max_ey,
1929                   ras.cell_null - ras.cell_free,
1930                   ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
1931     }
1932     else
1933     {
1934       error = FT_THROW( Raster_Overflow );
1935 
1936       FT_TRACE7(( "band [%d..%d]: to be bisected\n",
1937                   ras.min_ey, ras.max_ey ));
1938     }
1939 
1940     return error;
1941   }
1942 
1943 
1944   static int
gray_convert_glyph(RAS_ARG)1945   gray_convert_glyph( RAS_ARG )
1946   {
1947     const TCoord  yMin = ras.min_ey;
1948     const TCoord  yMax = ras.max_ey;
1949 
1950     TCell    buffer[FT_MAX_GRAY_POOL];
1951     size_t   height = (size_t)( yMax - yMin );
1952     size_t   n = FT_MAX_GRAY_POOL / 8;
1953     TCoord   y;
1954     TCoord   bands[32];  /* enough to accommodate bisections */
1955     TCoord*  band;
1956 
1957     int  continued = 0;
1958 
1959 
1960     /* Initialize the null cell at the end of the poll. */
1961     ras.cell_null        = buffer + FT_MAX_GRAY_POOL - 1;
1962     ras.cell_null->x     = CELL_MAX_X_VALUE;
1963     ras.cell_null->area  = 0;
1964     ras.cell_null->cover = 0;
1965     ras.cell_null->next  = NULL;
1966 
1967     /* set up vertical bands */
1968     ras.ycells     = (PCell*)buffer;
1969 
1970     if ( height > n )
1971     {
1972       /* two divisions rounded up */
1973       n       = ( height + n - 1 ) / n;
1974       height  = ( height + n - 1 ) / n;
1975     }
1976 
1977     for ( y = yMin; y < yMax; )
1978     {
1979       ras.min_ey = y;
1980       y         += height;
1981       ras.max_ey = FT_MIN( y, yMax );
1982 
1983       band    = bands;
1984       band[1] = ras.min_ey;
1985       band[0] = ras.max_ey;
1986 
1987       do
1988       {
1989         TCoord  width = band[0] - band[1];
1990         TCoord  w;
1991         int     error;
1992 
1993 
1994         for ( w = 0; w < width; ++w )
1995           ras.ycells[w] = ras.cell_null;
1996 
1997         /* memory management: skip ycells */
1998         n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) /
1999               sizeof ( TCell );
2000 
2001         ras.cell_free = buffer + n;
2002         ras.cell      = ras.cell_null;
2003         ras.min_ey    = band[1];
2004         ras.max_ey    = band[0];
2005         ras.count_ey  = width;
2006 
2007         error     = gray_convert_glyph_inner( RAS_VAR_ continued );
2008         continued = 1;
2009 
2010         if ( !error )
2011         {
2012           if ( ras.render_span )  /* for FT_RASTER_FLAG_DIRECT only */
2013             gray_sweep_direct( RAS_VAR );
2014           else
2015             gray_sweep( RAS_VAR );
2016           band--;
2017           continue;
2018         }
2019         else if ( error != Smooth_Err_Raster_Overflow )
2020           return error;
2021 
2022         /* render pool overflow; we will reduce the render band by half */
2023         width >>= 1;
2024 
2025         /* this should never happen even with tiny rendering pool */
2026         if ( width == 0 )
2027         {
2028           FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
2029           return FT_THROW( Raster_Overflow );
2030         }
2031 
2032         band++;
2033         band[1]  = band[0];
2034         band[0] += width;
2035       } while ( band >= bands );
2036     }
2037 
2038     return Smooth_Err_Ok;
2039   }
2040 
2041 
2042   static int
gray_raster_render(FT_Raster raster,const FT_Raster_Params * params)2043   gray_raster_render( FT_Raster                raster,
2044                       const FT_Raster_Params*  params )
2045   {
2046     const FT_Outline*  outline    = (const FT_Outline*)params->source;
2047     const FT_Bitmap*   target_map = params->target;
2048 
2049 #ifndef FT_STATIC_RASTER
2050     gray_TWorker  worker[1];
2051 #endif
2052 
2053 
2054     if ( !raster )
2055       return FT_THROW( Invalid_Argument );
2056 
2057     /* this version does not support monochrome rendering */
2058     if ( !( params->flags & FT_RASTER_FLAG_AA ) )
2059       return FT_THROW( Cannot_Render_Glyph );
2060 
2061     if ( !outline )
2062       return FT_THROW( Invalid_Outline );
2063 
2064     /* return immediately if the outline is empty */
2065     if ( outline->n_points == 0 || outline->n_contours <= 0 )
2066       return Smooth_Err_Ok;
2067 
2068     if ( !outline->contours || !outline->points )
2069       return FT_THROW( Invalid_Outline );
2070 
2071     if ( outline->n_points !=
2072            outline->contours[outline->n_contours - 1] + 1 )
2073       return FT_THROW( Invalid_Outline );
2074 
2075     ras.outline = *outline;
2076 
2077     if ( params->flags & FT_RASTER_FLAG_DIRECT )
2078     {
2079       if ( !params->gray_spans )
2080         return Smooth_Err_Ok;
2081 
2082       ras.render_span      = (FT_Raster_Span_Func)params->gray_spans;
2083       ras.render_span_data = params->user;
2084 
2085       ras.min_ex = params->clip_box.xMin;
2086       ras.min_ey = params->clip_box.yMin;
2087       ras.max_ex = params->clip_box.xMax;
2088       ras.max_ey = params->clip_box.yMax;
2089     }
2090     else
2091     {
2092       /* if direct mode is not set, we must have a target bitmap */
2093       if ( !target_map )
2094         return FT_THROW( Invalid_Argument );
2095 
2096       /* nothing to do */
2097       if ( !target_map->width || !target_map->rows )
2098         return Smooth_Err_Ok;
2099 
2100       if ( !target_map->buffer )
2101         return FT_THROW( Invalid_Argument );
2102 
2103       if ( target_map->pitch < 0 )
2104         ras.target.origin = target_map->buffer;
2105       else
2106         ras.target.origin = target_map->buffer
2107               + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch;
2108 
2109       ras.target.pitch = target_map->pitch;
2110 
2111       ras.render_span      = (FT_Raster_Span_Func)NULL;
2112       ras.render_span_data = NULL;
2113 
2114       ras.min_ex = 0;
2115       ras.min_ey = 0;
2116       ras.max_ex = (FT_Pos)target_map->width;
2117       ras.max_ey = (FT_Pos)target_map->rows;
2118     }
2119 
2120     /* exit if nothing to do */
2121     if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
2122       return Smooth_Err_Ok;
2123 
2124     return gray_convert_glyph( RAS_VAR );
2125   }
2126 
2127 
2128   /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
2129   /****                         a static object.                   *****/
2130 
2131 #ifdef STANDALONE_
2132 
2133   static int
gray_raster_new(void * memory,FT_Raster * araster)2134   gray_raster_new( void*       memory,
2135                    FT_Raster*  araster )
2136   {
2137     static gray_TRaster  the_raster;
2138 
2139     FT_UNUSED( memory );
2140 
2141 
2142     *araster = (FT_Raster)&the_raster;
2143     FT_ZERO( &the_raster );
2144 
2145     return 0;
2146   }
2147 
2148 
2149   static void
gray_raster_done(FT_Raster raster)2150   gray_raster_done( FT_Raster  raster )
2151   {
2152     /* nothing */
2153     FT_UNUSED( raster );
2154   }
2155 
2156 #else /* !STANDALONE_ */
2157 
2158   static int
gray_raster_new(FT_Memory memory,gray_PRaster * araster)2159   gray_raster_new( FT_Memory      memory,
2160                    gray_PRaster*  araster )
2161   {
2162     FT_Error      error;
2163     gray_PRaster  raster = NULL;
2164 
2165 
2166     if ( !FT_NEW( raster ) )
2167       raster->memory = memory;
2168 
2169     *araster = raster;
2170 
2171     return error;
2172   }
2173 
2174 
2175   static void
gray_raster_done(FT_Raster raster)2176   gray_raster_done( FT_Raster  raster )
2177   {
2178     FT_Memory  memory = (FT_Memory)((gray_PRaster)raster)->memory;
2179 
2180 
2181     FT_FREE( raster );
2182   }
2183 
2184 #endif /* !STANDALONE_ */
2185 
2186 
2187   static void
gray_raster_reset(FT_Raster raster,unsigned char * pool_base,unsigned long pool_size)2188   gray_raster_reset( FT_Raster       raster,
2189                      unsigned char*  pool_base,
2190                      unsigned long   pool_size )
2191   {
2192     FT_UNUSED( raster );
2193     FT_UNUSED( pool_base );
2194     FT_UNUSED( pool_size );
2195   }
2196 
2197 
2198   static int
gray_raster_set_mode(FT_Raster raster,unsigned long mode,void * args)2199   gray_raster_set_mode( FT_Raster      raster,
2200                         unsigned long  mode,
2201                         void*          args )
2202   {
2203     FT_UNUSED( raster );
2204     FT_UNUSED( mode );
2205     FT_UNUSED( args );
2206 
2207 
2208     return 0; /* nothing to do */
2209   }
2210 
2211 
2212   FT_DEFINE_RASTER_FUNCS(
2213     ft_grays_raster,
2214 
2215     FT_GLYPH_FORMAT_OUTLINE,
2216 
2217     (FT_Raster_New_Func)     gray_raster_new,       /* raster_new      */
2218     (FT_Raster_Reset_Func)   gray_raster_reset,     /* raster_reset    */
2219     (FT_Raster_Set_Mode_Func)gray_raster_set_mode,  /* raster_set_mode */
2220     (FT_Raster_Render_Func)  gray_raster_render,    /* raster_render   */
2221     (FT_Raster_Done_Func)    gray_raster_done       /* raster_done     */
2222   )
2223 
2224 
2225 /* END */
2226 
2227 
2228 /* Local Variables: */
2229 /* coding: utf-8    */
2230 /* End:             */
2231