1 /****************************************************************************
5 * A new `perfect' anti-aliasing renderer (body).
7 * Copyright (C) 2000-2023 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
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.
18 /**************************************************************************
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
25 * - copy `src/smooth/ftgrays.c' (this file) to your current directory
27 * - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the
30 * - compile `ftgrays' with the STANDALONE_ macro defined, as in
32 * cc -c -DSTANDALONE_ ftgrays.c
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'.
38 * See the comments and documentation in the file `ftimage.h' for more
39 * details on how the raster works.
43 /**************************************************************************
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.
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).
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.
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.
69 * This renderer has the following advantages:
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
77 * - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on
78 * each pixel cell by straight segments.
80 * - It performs a single pass on the outline (the `standard' FT2
81 * renderer makes two passes).
83 * - It can easily be modified to render to _any_ number of gray levels
86 * - For small (< 80) pixel sizes, it is faster than the standard
92 /**************************************************************************
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.
99 #define FT_COMPONENT smooth
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
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 )
114 #define FT_BEGIN_STMNT do {
115 #define FT_END_STMNT } while ( 0 )
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) )
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.
127 #define FT_HYPOT( x, y ) \
130 x > y ? x + ( 3 * y >> 3 ) \
131 : y + ( 3 * x >> 3 ) )
134 /* define this to dump debugging information */
135 /* #define FT_DEBUG_LEVEL_TRACE */
138 #ifdef FT_DEBUG_LEVEL_TRACE
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
152 #define ADD_INT( a, b ) \
153 (int)( (unsigned int)(a) + (unsigned int)(b) )
155 #define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var)
158 #define ft_memset memset
160 #define ft_setjmp setjmp
161 #define ft_longjmp longjmp
162 #define ft_jmp_buf jmp_buf
164 typedef ptrdiff_t FT_PtrDist;
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
173 #define FT_BEGIN_HEADER
174 #define FT_END_HEADER
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)
187 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
189 #ifdef FT_DEBUG_LEVEL_TRACE
192 FT_Message( const char* fmt,
199 vfprintf( stderr, fmt, ap );
204 /* empty function useful for setting a breakpoint to catch errors */
218 /* we don't handle tracing levels in stand-alone mode; */
220 #define FT_TRACE5( varformat ) FT_Message varformat
223 #define FT_TRACE7( varformat ) FT_Message varformat
226 #define FT_ERROR( varformat ) FT_Message varformat
229 #define FT_THROW( e ) \
230 ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \
233 FT_ERR_CAT( Smooth_Err_, e ) )
235 #else /* !FT_DEBUG_LEVEL_TRACE */
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 )
242 #endif /* !FT_DEBUG_LEVEL_TRACE */
245 #define FT_Trace_Enable() do { } while ( 0 ) /* nothing */
246 #define FT_Trace_Disable() do { } while ( 0 ) /* nothing */
249 #define FT_DEFINE_OUTLINE_FUNCS( class_, \
250 move_to_, line_to_, \
251 conic_to_, cubic_to_, \
253 static const FT_Outline_Funcs class_ = \
263 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \
264 raster_new_, raster_reset_, \
265 raster_set_mode_, raster_render_, \
267 const FT_Raster_Funcs class_ = \
278 #else /* !STANDALONE_ */
281 #include <ft2build.h>
282 #include FT_CONFIG_CONFIG_H
284 #include <freetype/internal/ftobjs.h>
285 #include <freetype/internal/ftdebug.h>
286 #include <freetype/internal/ftcalc.h>
287 #include <freetype/ftoutln.h>
289 #include "ftsmerrs.h"
292 #endif /* !STANDALONE_ */
296 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
300 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
304 #define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) )
307 /* as usual, for the speed hungry :-) */
314 #ifndef FT_STATIC_RASTER
316 #define RAS_ARG gray_PWorker worker
317 #define RAS_ARG_ gray_PWorker worker,
319 #define RAS_VAR worker
320 #define RAS_VAR_ worker,
322 #else /* FT_STATIC_RASTER */
325 #define RAS_ARG_ /* empty */
326 #define RAS_VAR /* empty */
327 #define RAS_VAR_ /* empty */
329 #endif /* FT_STATIC_RASTER */
332 /* must be at least 6 bits! */
335 #define ONE_PIXEL ( 1 << PIXEL_BITS )
337 #define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS )
339 #define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) )
342 #define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
343 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
345 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
346 #define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) )
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 ) \
356 (quotient) = (type)( (dividend) / (divisor) ); \
357 (remainder) = (type)( (dividend) % (divisor) ); \
358 if ( (remainder) < 0 ) \
361 (remainder) += (type)(divisor); \
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 */
370 /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */
372 #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
374 (quotient) = (type)( (dividend) / (divisor) ); \
375 (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \
376 if ( (remainder) < 0 ) \
379 (remainder) += (type)(divisor); \
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. */
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 )
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 ) \
411 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \
412 if ( coverage & fill ) \
413 coverage = ~coverage; \
414 if ( coverage > 255 && fill & INT_MIN ) \
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 ) \
423 unsigned char* q = d; \
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; \
434 default: FT_MEM_SET( d, s, count ); \
439 /**************************************************************************
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 */
448 typedef long TPos; /* subpixel coordinate */
449 typedef int TCoord; /* integer scanline/pixel coordinate */
450 typedef int TArea; /* cell areas, coordinate products */
453 typedef struct TCell_* PCell;
455 typedef struct TCell_
457 TCoord x; /* same with gray_TWorker.ex */
458 TCoord cover; /* same with gray_TWorker.cover */
464 typedef struct TPixmap_
466 unsigned char* origin; /* pixmap origin at the bottom-left */
467 int pitch; /* pitch to go down one row */
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 ) )
475 #define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) )
478 /* FT_Span buffer size for direct rendering only */
479 #define FT_MAX_GRAY_SPANS 16
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 */
490 typedef struct gray_TWorker_
492 ft_jmp_buf jump_buffer;
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) */
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 */
502 PCell* ycells; /* array of cell linked-lists; one per */
503 /* vertical coordinate in the current band */
505 TPos x, y; /* last point position */
507 FT_Outline outline; /* input outline */
508 TPixmap target; /* target pixmap */
510 FT_Raster_Span_Func render_span;
511 void* render_span_data;
513 } gray_TWorker, *gray_PWorker;
515 #if defined( _MSC_VER )
516 #pragma warning( pop )
519 #ifndef FT_STATIC_RASTER
520 #define ras (*worker)
522 static gray_TWorker ras;
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
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) )
535 typedef struct gray_TRaster_
539 } gray_TRaster, *gray_PRaster;
542 #ifdef FT_DEBUG_LEVEL_TRACE
544 /* to be called while in the debugger -- */
545 /* this function causes a compiler warning since it is unused otherwise */
547 gray_dump_cells( RAS_ARG )
552 for ( y = ras.min_ey; y < ras.max_ey; y++ )
554 PCell cell = ras.ycells[y - ras.min_ey];
559 for ( ; cell != ras.cell_null; cell = cell->next )
560 printf( " (%3d, c:%4d, a:%6d)",
561 cell->x, cell->cover, cell->area );
566 #endif /* FT_DEBUG_LEVEL_TRACE */
569 /**************************************************************************
571 * Set the current cell to a new position.
574 gray_set_cell( RAS_ARG_ TCoord ex,
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: */
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 */
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. */
587 TCoord ey_index = ey - ras.min_ey;
590 if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex )
591 ras.cell = ras.cell_null;
594 PCell* pcell = ras.ycells + ey_index;
598 ex = FT_MAX( ex, ras.min_ex - 1 );
613 /* insert new cell */
614 cell = ras.cell_free++;
615 if ( cell >= ras.cell_null )
616 ft_longjmp( ras.jump_buffer, 1 );
633 /**************************************************************************
635 * Render a scanline as one or more cells.
638 gray_render_scanline( RAS_ARG_ TCoord ey,
644 TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod;
652 /* trivial case. Happens often */
655 gray_set_cell( RAS_VAR_ ex2, ey );
662 /* everything is located in a single cell. That is easy! */
667 /* ok, we'll have to render a run of adjacent cells on the same */
675 p = ( ONE_PIXEL - fx1 ) * dy;
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 );
692 FT_INTEGRATE( ras, delta, fx1 + first );
695 gray_set_cell( RAS_VAR_ ex1, ey );
703 FT_DIV_MOD( TCoord, p, dx, lift, rem );
709 if ( mod >= (TCoord)dx )
715 FT_INTEGRATE( ras, delta, ONE_PIXEL );
718 gray_set_cell( RAS_VAR_ ex1, ey );
719 } while ( ex1 != ex2 );
722 fx1 = ONE_PIXEL - first;
725 FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 );
729 /**************************************************************************
731 * Render a given line as a series of scanlines.
734 gray_render_line( RAS_ARG_ TPos to_x,
737 TCoord ey1, ey2, fy1, fy2, first, delta, mod;
738 TPos p, dx, dy, x, x2;
742 ey1 = TRUNC( ras.y );
743 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
745 /* perform vertical clipping */
746 if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
747 ( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
750 fy1 = FRACT( ras.y );
753 /* everything is on a single scanline */
756 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
763 /* vertical line - avoid calling gray_render_scanline */
766 TCoord ex = TRUNC( ras.x );
767 TCoord two_fx = FRACT( ras.x ) << 1;
782 FT_INTEGRATE( ras, delta, two_fx);
785 gray_set_cell( RAS_VAR_ ex, ey1 );
787 delta = first + first - ONE_PIXEL;
790 FT_INTEGRATE( ras, delta, two_fx);
793 gray_set_cell( RAS_VAR_ ex, ey1 );
796 delta = fy2 - ONE_PIXEL + first;
797 FT_INTEGRATE( ras, delta, two_fx);
802 /* ok, we have to render several scanlines */
805 p = ( ONE_PIXEL - fy1 ) * dx;
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 );
822 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
825 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
833 FT_DIV_MOD( TCoord, p, dy, lift, rem );
839 if ( mod >= (TCoord)dy )
846 gray_render_scanline( RAS_VAR_ ey1,
847 x, ONE_PIXEL - first,
852 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
853 } while ( ey1 != ey2 );
856 gray_render_scanline( RAS_VAR_ ey1,
857 x, ONE_PIXEL - first,
867 /**************************************************************************
869 * Render a straight line across multiple cells in any direction.
872 gray_render_line( RAS_ARG_ TPos to_x,
876 TCoord fx1, fy1, fx2, fy2;
877 TCoord ex1, ey1, ex2, ey2;
880 ey1 = TRUNC( ras.y );
883 /* perform vertical clipping */
884 if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
885 ( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
888 ex1 = TRUNC( ras.x );
891 fx1 = FRACT( ras.x );
892 fy1 = FRACT( ras.y );
897 if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */
899 else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */
901 gray_set_cell( RAS_VAR_ ex2, ey2 );
906 if ( dy > 0 ) /* vertical line up */
910 FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 );
913 gray_set_cell( RAS_VAR_ ex1, ey1 );
914 } while ( ey1 != ey2 );
915 else /* vertical line down */
919 FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 );
922 gray_set_cell( RAS_VAR_ ex1, ey1 );
923 } while ( ey1 != ey2 );
925 else /* any other line */
927 FT_Int64 prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1;
928 FT_UDIVPREP( ex1 != ex2, dx );
929 FT_UDIVPREP( ey1 != ey2, dy );
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. */
937 if ( prod - dx * ONE_PIXEL > 0 &&
938 prod <= 0 ) /* left */
941 fy2 = FT_UDIV( -prod, -dx );
942 prod -= dy * ONE_PIXEL;
943 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
948 else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 &&
949 prod - dx * ONE_PIXEL <= 0 ) /* up */
951 prod -= dx * ONE_PIXEL;
952 fx2 = FT_UDIV( -prod, dy );
954 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
959 else if ( prod + dy * ONE_PIXEL >= 0 &&
960 prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */
962 prod += dy * ONE_PIXEL;
964 fy2 = FT_UDIV( prod, dx );
965 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
970 else /* ( prod > 0 &&
971 prod + dy * ONE_PIXEL < 0 ) down */
973 fx2 = FT_UDIV( prod, -dy );
975 prod += dx * ONE_PIXEL;
976 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
982 gray_set_cell( RAS_VAR_ ex1, ey1 );
984 } while ( ex1 != ex2 || ey1 != ey2 );
990 FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 );
1000 * Benchmarking shows that using DDA to flatten the quadratic Bézier arcs
1001 * is slightly faster in the following cases:
1003 * - When the host CPU is 64-bit.
1004 * - When SSE2 SIMD registers and instructions are available (even on
1007 * For other cases, using binary splits is actually slightly faster.
1009 #if ( defined( __SSE2__ ) || \
1010 defined( __x86_64__ ) || \
1011 defined( _M_AMD64 ) || \
1012 ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) ) && \
1020 defined( __aarch64__ ) || \
1022 # define BEZIER_USE_DDA 1
1024 # define BEZIER_USE_DDA 0
1028 * For now, the code that depends on `BEZIER_USE_DDA` requires `FT_Int64`
1029 * to be defined. If `FT_INT64` is not defined, meaning there is no
1030 * 64-bit type available, disable it to avoid compilation errors. See for
1031 * example https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071.
1033 #if !defined( FT_INT64 )
1034 # undef BEZIER_USE_DDA
1035 # define BEZIER_USE_DDA 0
1041 # include <emmintrin.h>
1044 #define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) )
1048 gray_render_conic( RAS_ARG_ const FT_Vector* control,
1049 const FT_Vector* to )
1051 FT_Vector p0, p1, p2;
1052 TPos ax, ay, bx, by, dx, dy;
1064 p1.x = UPSCALE( control->x );
1065 p1.y = UPSCALE( control->y );
1066 p2.x = UPSCALE( to->x );
1067 p2.y = UPSCALE( to->y );
1069 /* short-cut the arc that crosses the current band */
1070 if ( ( TRUNC( p0.y ) >= ras.max_ey &&
1071 TRUNC( p1.y ) >= ras.max_ey &&
1072 TRUNC( p2.y ) >= ras.max_ey ) ||
1073 ( TRUNC( p0.y ) < ras.min_ey &&
1074 TRUNC( p1.y ) < ras.min_ey &&
1075 TRUNC( p2.y ) < ras.min_ey ) )
1084 ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */
1085 ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */
1092 if ( dx <= ONE_PIXEL / 4 )
1094 gray_render_line( RAS_VAR_ p2.x, p2.y );
1098 /* We can calculate the number of necessary bisections because */
1099 /* each bisection predictably reduces deviation exactly 4-fold. */
1100 /* Even 32-bit deviation would vanish after 16 bisections. */
1107 } while ( dx > ONE_PIXEL / 4 );
1110 * The (P0,P1,P2) arc equation, for t in [0,1] range:
1112 * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2
1114 * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2
1115 * = P0 + 2*B*t + A*t^2
1117 * for A = P0 + P2 - 2*P1
1120 * Let's consider the difference when advancing by a small
1123 * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t
1125 * And then its own difference:
1127 * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant)
1129 * Since R is always a constant, it is possible to compute
1130 * successive positions with:
1133 * Q = Q(h,0) = 2*B*h + A*h*h
1141 * To ensure accurate results, perform computations on 64-bit
1142 * values, after scaling them by 2^32.
1146 * R << 32 = 2 * A << (32 - N - N)
1149 * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N))
1150 * = (B << (33 - N)) + (A << (32 - 2*N))
1154 /* Experience shows that for small shift values, */
1155 /* SSE2 is actually slower. */
1160 struct { FT_Int64 ax, ay, bx, by; } i;
1161 struct { __m128i a, b; } vec;
1167 struct { FT_Int32 px_lo, px_hi, py_lo, py_hi; } i;
1182 a = _mm_load_si128( &u.vec.a );
1183 b = _mm_load_si128( &u.vec.b );
1185 r = _mm_slli_epi64( a, 33 - 2 * shift );
1186 q = _mm_slli_epi64( b, 33 - shift );
1187 q2 = _mm_slli_epi64( a, 32 - 2 * shift );
1189 q = _mm_add_epi64( q2, q );
1196 p = _mm_load_si128( &v.vec );
1198 for ( count = 1U << shift; count > 0; count-- )
1200 p = _mm_add_epi64( p, q );
1201 q = _mm_add_epi64( q, r );
1203 _mm_store_si128( &v.vec, p );
1205 gray_render_line( RAS_VAR_ v.i.px_hi, v.i.py_hi );
1210 #endif /* FT_SSE2 */
1212 rx = LEFT_SHIFT( ax, 33 - 2 * shift );
1213 ry = LEFT_SHIFT( ay, 33 - 2 * shift );
1215 qx = LEFT_SHIFT( bx, 33 - shift ) + LEFT_SHIFT( ax, 32 - 2 * shift );
1216 qy = LEFT_SHIFT( by, 33 - shift ) + LEFT_SHIFT( ay, 32 - 2 * shift );
1218 px = LEFT_SHIFT( p0.x, 32 );
1219 py = LEFT_SHIFT( p0.y, 32 );
1221 for ( count = 1U << shift; count > 0; count-- )
1228 gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ),
1229 (FT_Pos)( py >> 32 ) );
1233 #else /* !BEZIER_USE_DDA */
1236 * Note that multiple attempts to speed up the function below
1237 * with SSE2 intrinsics, using various data layouts, have turned
1238 * out to be slower than the non-SIMD code below.
1241 gray_split_conic( FT_Vector* base )
1246 base[4].x = base[2].x;
1247 a = base[0].x + base[1].x;
1248 b = base[1].x + base[2].x;
1250 base[2].x = ( a + b ) >> 2;
1253 base[4].y = base[2].y;
1254 a = base[0].y + base[1].y;
1255 b = base[1].y + base[2].y;
1257 base[2].y = ( a + b ) >> 2;
1263 gray_render_conic( RAS_ARG_ const FT_Vector* control,
1264 const FT_Vector* to )
1266 FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */
1267 FT_Vector* arc = bez_stack;
1272 arc[0].x = UPSCALE( to->x );
1273 arc[0].y = UPSCALE( to->y );
1274 arc[1].x = UPSCALE( control->x );
1275 arc[1].y = UPSCALE( control->y );
1279 /* short-cut the arc that crosses the current band */
1280 if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
1281 TRUNC( arc[1].y ) >= ras.max_ey &&
1282 TRUNC( arc[2].y ) >= ras.max_ey ) ||
1283 ( TRUNC( arc[0].y ) < ras.min_ey &&
1284 TRUNC( arc[1].y ) < ras.min_ey &&
1285 TRUNC( arc[2].y ) < ras.min_ey ) )
1292 dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
1293 dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
1297 /* We can calculate the number of necessary bisections because */
1298 /* each bisection predictably reduces deviation exactly 4-fold. */
1299 /* Even 32-bit deviation would vanish after 16 bisections. */
1301 while ( dx > ONE_PIXEL / 4 )
1307 /* We use decrement counter to count the total number of segments */
1308 /* to draw starting from 2^level. Before each draw we split as */
1309 /* many times as there are trailing zeros in the counter. */
1312 int split = draw & ( -draw ); /* isolate the rightmost 1-bit */
1315 while ( ( split >>= 1 ) )
1317 gray_split_conic( arc );
1321 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1327 #endif /* !BEZIER_USE_DDA */
1331 * For cubic Bézier, binary splits are still faster than DDA
1332 * because the splits are adaptive to how quickly each sub-arc
1333 * approaches their chord trisection points.
1335 * It might be useful to experiment with SSE2 to speed up
1336 * `gray_split_cubic`, though.
1339 gray_split_cubic( FT_Vector* base )
1344 base[6].x = base[3].x;
1345 a = base[0].x + base[1].x;
1346 b = base[1].x + base[2].x;
1347 c = base[2].x + base[3].x;
1354 base[3].x = ( a + c ) >> 3;
1356 base[6].y = base[3].y;
1357 a = base[0].y + base[1].y;
1358 b = base[1].y + base[2].y;
1359 c = base[2].y + base[3].y;
1366 base[3].y = ( a + c ) >> 3;
1371 gray_render_cubic( RAS_ARG_ const FT_Vector* control1,
1372 const FT_Vector* control2,
1373 const FT_Vector* to )
1375 FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */
1376 FT_Vector* arc = bez_stack;
1379 arc[0].x = UPSCALE( to->x );
1380 arc[0].y = UPSCALE( to->y );
1381 arc[1].x = UPSCALE( control2->x );
1382 arc[1].y = UPSCALE( control2->y );
1383 arc[2].x = UPSCALE( control1->x );
1384 arc[2].y = UPSCALE( control1->y );
1388 /* short-cut the arc that crosses the current band */
1389 if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
1390 TRUNC( arc[1].y ) >= ras.max_ey &&
1391 TRUNC( arc[2].y ) >= ras.max_ey &&
1392 TRUNC( arc[3].y ) >= ras.max_ey ) ||
1393 ( TRUNC( arc[0].y ) < ras.min_ey &&
1394 TRUNC( arc[1].y ) < ras.min_ey &&
1395 TRUNC( arc[2].y ) < ras.min_ey &&
1396 TRUNC( arc[3].y ) < ras.min_ey ) )
1405 /* with each split, control points quickly converge towards */
1406 /* chord trisection points and the vanishing distances below */
1407 /* indicate when the segment is flat enough to draw */
1408 if ( FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 ||
1409 FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 ||
1410 FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 ||
1411 FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 )
1414 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1416 if ( arc == bez_stack )
1423 gray_split_cubic( arc );
1430 gray_move_to( const FT_Vector* to,
1431 void* worker_ ) /* gray_PWorker */
1433 gray_PWorker worker = (gray_PWorker)worker_;
1438 /* start to a new position */
1439 x = UPSCALE( to->x );
1440 y = UPSCALE( to->y );
1442 gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
1451 gray_line_to( const FT_Vector* to,
1452 void* worker_ ) /* gray_PWorker */
1454 gray_PWorker worker = (gray_PWorker)worker_;
1457 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
1463 gray_conic_to( const FT_Vector* control,
1464 const FT_Vector* to,
1465 void* worker_ ) /* gray_PWorker */
1467 gray_PWorker worker = (gray_PWorker)worker_;
1470 gray_render_conic( RAS_VAR_ control, to );
1476 gray_cubic_to( const FT_Vector* control1,
1477 const FT_Vector* control2,
1478 const FT_Vector* to,
1479 void* worker_ ) /* gray_PWorker */
1481 gray_PWorker worker = (gray_PWorker)worker_;
1484 gray_render_cubic( RAS_VAR_ control1, control2, to );
1490 gray_sweep( RAS_ARG )
1492 int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100
1498 for ( y = ras.min_ey; y < ras.max_ey; y++ )
1500 PCell cell = ras.ycells[y - ras.min_ey];
1501 TCoord x = ras.min_ex;
1504 unsigned char* line = ras.target.origin - ras.target.pitch * y;
1507 for ( ; cell != ras.cell_null; cell = cell->next )
1512 if ( cover != 0 && cell->x > x )
1514 FT_FILL_RULE( coverage, cover, fill );
1515 FT_GRAY_SET( line + x, coverage, cell->x - x );
1518 cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
1519 area = cover - cell->area;
1521 if ( area != 0 && cell->x >= ras.min_ex )
1523 FT_FILL_RULE( coverage, area, fill );
1524 line[cell->x] = (unsigned char)coverage;
1530 if ( cover != 0 ) /* only if cropped */
1532 FT_FILL_RULE( coverage, cover, fill );
1533 FT_GRAY_SET( line + x, coverage, ras.max_ex - x );
1540 gray_sweep_direct( RAS_ARG )
1542 int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100
1547 FT_Span span[FT_MAX_GRAY_SPANS];
1551 for ( y = ras.min_ey; y < ras.max_ey; y++ )
1553 PCell cell = ras.ycells[y - ras.min_ey];
1554 TCoord x = ras.min_ex;
1558 for ( ; cell != ras.cell_null; cell = cell->next )
1563 if ( cover != 0 && cell->x > x )
1565 FT_FILL_RULE( coverage, cover, fill );
1567 span[n].coverage = (unsigned char)coverage;
1568 span[n].x = (short)x;
1569 span[n].len = (unsigned short)( cell->x - x );
1571 if ( ++n == FT_MAX_GRAY_SPANS )
1573 /* flush the span buffer and reset the count */
1574 ras.render_span( y, n, span, ras.render_span_data );
1579 cover += (TArea)cell->cover * ( ONE_PIXEL * 2 );
1580 area = cover - cell->area;
1582 if ( area != 0 && cell->x >= ras.min_ex )
1584 FT_FILL_RULE( coverage, area, fill );
1586 span[n].coverage = (unsigned char)coverage;
1587 span[n].x = (short)cell->x;
1590 if ( ++n == FT_MAX_GRAY_SPANS )
1592 /* flush the span buffer and reset the count */
1593 ras.render_span( y, n, span, ras.render_span_data );
1601 if ( cover != 0 ) /* only if cropped */
1603 FT_FILL_RULE( coverage, cover, fill );
1605 span[n].coverage = (unsigned char)coverage;
1606 span[n].x = (short)x;
1607 span[n].len = (unsigned short)( ras.max_ex - x );
1614 /* flush the span buffer and reset the count */
1615 ras.render_span( y, n, span, ras.render_span_data );
1624 /**************************************************************************
1626 * The following functions should only compile in stand-alone mode,
1627 * i.e., when building this component without the rest of FreeType.
1631 /**************************************************************************
1634 * FT_Outline_Decompose
1637 * Walk over an outline's structure to decompose it into individual
1638 * segments and Bézier arcs. This function is also able to emit
1639 * `move to' and `close to' operations to indicate the start and end
1640 * of new contours in the outline.
1644 * A pointer to the source target.
1647 * A table of `emitters', i.e., function pointers
1648 * called during decomposition to indicate path
1653 * A typeless pointer which is passed to each
1654 * emitter during the decomposition. It can be
1655 * used to store the state during the
1659 * Error code. 0 means success.
1662 FT_Outline_Decompose( const FT_Outline* outline,
1663 const FT_Outline_Funcs* func_interface,
1667 #define SCALED( x ) ( (x) * ( 1L << shift ) - delta )
1670 FT_Vector v_control;
1679 int n; /* index of contour in outline */
1680 int first; /* index of first point in contour */
1681 int last; /* index of last point in contour */
1683 char tag; /* current point's state */
1690 return FT_THROW( Invalid_Outline );
1692 if ( !func_interface )
1693 return FT_THROW( Invalid_Argument );
1695 shift = func_interface->shift;
1696 delta = func_interface->delta;
1699 for ( n = 0; n < outline->n_contours; n++ )
1701 FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
1704 last = outline->contours[n];
1706 goto Invalid_Outline;
1708 limit = outline->points + last;
1710 v_start = outline->points[first];
1711 v_start.x = SCALED( v_start.x );
1712 v_start.y = SCALED( v_start.y );
1714 v_last = outline->points[last];
1715 v_last.x = SCALED( v_last.x );
1716 v_last.y = SCALED( v_last.y );
1718 v_control = v_start;
1720 point = outline->points + first;
1721 tags = outline->tags + first;
1722 tag = FT_CURVE_TAG( tags[0] );
1724 /* A contour cannot start with a cubic control point! */
1725 if ( tag == FT_CURVE_TAG_CUBIC )
1726 goto Invalid_Outline;
1728 /* check first point to determine origin */
1729 if ( tag == FT_CURVE_TAG_CONIC )
1731 /* first point is conic control. Yes, this happens. */
1732 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
1734 /* start at last point if it is on the curve */
1740 /* if both first and last points are conic, */
1741 /* start at their middle and record its position */
1743 v_start.x = ( v_start.x + v_last.x ) / 2;
1744 v_start.y = ( v_start.y + v_last.y ) / 2;
1752 FT_TRACE5(( " move to (%.2f, %.2f)\n",
1753 v_start.x / 64.0, v_start.y / 64.0 ));
1754 error = func_interface->move_to( &v_start, user );
1758 while ( point < limit )
1763 tag = FT_CURVE_TAG( tags[0] );
1766 case FT_CURVE_TAG_ON: /* emit a single line_to */
1771 vec.x = SCALED( point->x );
1772 vec.y = SCALED( point->y );
1774 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1775 vec.x / 64.0, vec.y / 64.0 ));
1776 error = func_interface->line_to( &vec, user );
1782 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1783 v_control.x = SCALED( point->x );
1784 v_control.y = SCALED( point->y );
1787 if ( point < limit )
1795 tag = FT_CURVE_TAG( tags[0] );
1797 vec.x = SCALED( point->x );
1798 vec.y = SCALED( point->y );
1800 if ( tag == FT_CURVE_TAG_ON )
1802 FT_TRACE5(( " conic to (%.2f, %.2f)"
1803 " with control (%.2f, %.2f)\n",
1804 vec.x / 64.0, vec.y / 64.0,
1805 v_control.x / 64.0, v_control.y / 64.0 ));
1806 error = func_interface->conic_to( &v_control, &vec, user );
1812 if ( tag != FT_CURVE_TAG_CONIC )
1813 goto Invalid_Outline;
1815 v_middle.x = ( v_control.x + vec.x ) / 2;
1816 v_middle.y = ( v_control.y + vec.y ) / 2;
1818 FT_TRACE5(( " conic to (%.2f, %.2f)"
1819 " with control (%.2f, %.2f)\n",
1820 v_middle.x / 64.0, v_middle.y / 64.0,
1821 v_control.x / 64.0, v_control.y / 64.0 ));
1822 error = func_interface->conic_to( &v_control, &v_middle, user );
1830 FT_TRACE5(( " conic to (%.2f, %.2f)"
1831 " with control (%.2f, %.2f)\n",
1832 v_start.x / 64.0, v_start.y / 64.0,
1833 v_control.x / 64.0, v_control.y / 64.0 ));
1834 error = func_interface->conic_to( &v_control, &v_start, user );
1837 default: /* FT_CURVE_TAG_CUBIC */
1839 FT_Vector vec1, vec2;
1842 if ( point + 1 > limit ||
1843 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1844 goto Invalid_Outline;
1849 vec1.x = SCALED( point[-2].x );
1850 vec1.y = SCALED( point[-2].y );
1852 vec2.x = SCALED( point[-1].x );
1853 vec2.y = SCALED( point[-1].y );
1855 if ( point <= limit )
1860 vec.x = SCALED( point->x );
1861 vec.y = SCALED( point->y );
1863 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1864 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1865 vec.x / 64.0, vec.y / 64.0,
1866 vec1.x / 64.0, vec1.y / 64.0,
1867 vec2.x / 64.0, vec2.y / 64.0 ));
1868 error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
1874 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1875 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1876 v_start.x / 64.0, v_start.y / 64.0,
1877 vec1.x / 64.0, vec1.y / 64.0,
1878 vec2.x / 64.0, vec2.y / 64.0 ));
1879 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
1885 /* close the contour with a line segment */
1886 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1887 v_start.x / 64.0, v_start.y / 64.0 ));
1888 error = func_interface->line_to( &v_start, user );
1895 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1896 return Smooth_Err_Ok;
1899 FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error ));
1903 return FT_THROW( Invalid_Outline );
1906 #endif /* STANDALONE_ */
1909 FT_DEFINE_OUTLINE_FUNCS(
1912 (FT_Outline_MoveTo_Func) gray_move_to, /* move_to */
1913 (FT_Outline_LineTo_Func) gray_line_to, /* line_to */
1914 (FT_Outline_ConicTo_Func)gray_conic_to, /* conic_to */
1915 (FT_Outline_CubicTo_Func)gray_cubic_to, /* cubic_to */
1923 gray_convert_glyph_inner( RAS_ARG_
1929 if ( ft_setjmp( ras.jump_buffer ) == 0 )
1933 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
1937 FT_TRACE7(( "band [%d..%d]: %td cell%s remaining/\n",
1940 ras.cell_null - ras.cell_free,
1941 ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
1945 error = FT_THROW( Raster_Overflow );
1947 FT_TRACE7(( "band [%d..%d]: to be bisected\n",
1948 ras.min_ey, ras.max_ey ));
1956 gray_convert_glyph( RAS_ARG )
1958 const TCoord yMin = ras.min_ey;
1959 const TCoord yMax = ras.max_ey;
1961 TCell buffer[FT_MAX_GRAY_POOL];
1962 size_t height = (size_t)( yMax - yMin );
1963 size_t n = FT_MAX_GRAY_POOL / 8;
1965 TCoord bands[32]; /* enough to accommodate bisections */
1971 /* Initialize the null cell at the end of the poll. */
1972 ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1;
1973 ras.cell_null->x = CELL_MAX_X_VALUE;
1974 ras.cell_null->area = 0;
1975 ras.cell_null->cover = 0;
1976 ras.cell_null->next = NULL;
1978 /* set up vertical bands */
1979 ras.ycells = (PCell*)buffer;
1983 /* two divisions rounded up */
1984 n = ( height + n - 1 ) / n;
1985 height = ( height + n - 1 ) / n;
1988 for ( y = yMin; y < yMax; )
1992 ras.max_ey = FT_MIN( y, yMax );
1995 band[1] = ras.min_ey;
1996 band[0] = ras.max_ey;
2000 TCoord width = band[0] - band[1];
2005 for ( w = 0; w < width; ++w )
2006 ras.ycells[w] = ras.cell_null;
2008 /* memory management: skip ycells */
2009 n = ( (size_t)width * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) /
2012 ras.cell_free = buffer + n;
2013 ras.cell = ras.cell_null;
2014 ras.min_ey = band[1];
2015 ras.max_ey = band[0];
2016 ras.count_ey = width;
2018 error = gray_convert_glyph_inner( RAS_VAR_ continued );
2023 if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */
2024 gray_sweep_direct( RAS_VAR );
2026 gray_sweep( RAS_VAR );
2030 else if ( error != Smooth_Err_Raster_Overflow )
2033 /* render pool overflow; we will reduce the render band by half */
2036 /* this should never happen even with tiny rendering pool */
2039 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
2040 return FT_THROW( Raster_Overflow );
2046 } while ( band >= bands );
2049 return Smooth_Err_Ok;
2054 gray_raster_render( FT_Raster raster,
2055 const FT_Raster_Params* params )
2057 const FT_Outline* outline = (const FT_Outline*)params->source;
2058 const FT_Bitmap* target_map = params->target;
2060 #ifndef FT_STATIC_RASTER
2061 gray_TWorker worker[1];
2066 return FT_THROW( Invalid_Argument );
2068 /* this version does not support monochrome rendering */
2069 if ( !( params->flags & FT_RASTER_FLAG_AA ) )
2070 return FT_THROW( Cannot_Render_Glyph );
2073 return FT_THROW( Invalid_Outline );
2075 /* return immediately if the outline is empty */
2076 if ( outline->n_points == 0 || outline->n_contours <= 0 )
2077 return Smooth_Err_Ok;
2079 if ( !outline->contours || !outline->points )
2080 return FT_THROW( Invalid_Outline );
2082 if ( outline->n_points !=
2083 outline->contours[outline->n_contours - 1] + 1 )
2084 return FT_THROW( Invalid_Outline );
2086 ras.outline = *outline;
2088 if ( params->flags & FT_RASTER_FLAG_DIRECT )
2090 if ( !params->gray_spans )
2091 return Smooth_Err_Ok;
2093 ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
2094 ras.render_span_data = params->user;
2096 ras.min_ex = params->clip_box.xMin;
2097 ras.min_ey = params->clip_box.yMin;
2098 ras.max_ex = params->clip_box.xMax;
2099 ras.max_ey = params->clip_box.yMax;
2103 /* if direct mode is not set, we must have a target bitmap */
2105 return FT_THROW( Invalid_Argument );
2108 if ( !target_map->width || !target_map->rows )
2109 return Smooth_Err_Ok;
2111 if ( !target_map->buffer )
2112 return FT_THROW( Invalid_Argument );
2114 if ( target_map->pitch < 0 )
2115 ras.target.origin = target_map->buffer;
2117 ras.target.origin = target_map->buffer
2118 + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch;
2120 ras.target.pitch = target_map->pitch;
2122 ras.render_span = (FT_Raster_Span_Func)NULL;
2123 ras.render_span_data = NULL;
2127 ras.max_ex = (FT_Pos)target_map->width;
2128 ras.max_ey = (FT_Pos)target_map->rows;
2131 /* exit if nothing to do */
2132 if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
2133 return Smooth_Err_Ok;
2135 return gray_convert_glyph( RAS_VAR );
2139 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
2140 /**** a static object. *****/
2145 gray_raster_new( void* memory,
2146 FT_Raster* araster )
2148 static gray_TRaster the_raster;
2150 FT_UNUSED( memory );
2153 *araster = (FT_Raster)&the_raster;
2154 FT_ZERO( &the_raster );
2161 gray_raster_done( FT_Raster raster )
2164 FT_UNUSED( raster );
2167 #else /* !STANDALONE_ */
2170 gray_raster_new( void* memory_,
2171 FT_Raster* araster_ )
2173 FT_Memory memory = (FT_Memory)memory_;
2174 gray_PRaster* araster = (gray_PRaster*)araster_;
2177 gray_PRaster raster = NULL;
2180 if ( !FT_NEW( raster ) )
2181 raster->memory = memory;
2190 gray_raster_done( FT_Raster raster )
2192 FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory;
2198 #endif /* !STANDALONE_ */
2202 gray_raster_reset( FT_Raster raster,
2203 unsigned char* pool_base,
2204 unsigned long pool_size )
2206 FT_UNUSED( raster );
2207 FT_UNUSED( pool_base );
2208 FT_UNUSED( pool_size );
2213 gray_raster_set_mode( FT_Raster raster,
2217 FT_UNUSED( raster );
2222 return 0; /* nothing to do */
2226 FT_DEFINE_RASTER_FUNCS(
2229 FT_GLYPH_FORMAT_OUTLINE,
2231 (FT_Raster_New_Func) gray_raster_new, /* raster_new */
2232 (FT_Raster_Reset_Func) gray_raster_reset, /* raster_reset */
2233 (FT_Raster_Set_Mode_Func)gray_raster_set_mode, /* raster_set_mode */
2234 (FT_Raster_Render_Func) gray_raster_render, /* raster_render */
2235 (FT_Raster_Done_Func) gray_raster_done /* raster_done */
2242 /* Local Variables: */