1 /***************************************************************************/
5 /* A new `perfect' anti-aliasing renderer (body). */
7 /* Copyright 2000-2016 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. */
16 /***************************************************************************/
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. */
41 /*************************************************************************/
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. */
50 /* It is based on ideas that I initially found in Raph Levien's */
51 /* excellent LibArt graphics library (see http://www.levien.com/libart */
52 /* for more information, though the web pages do not tell anything */
53 /* about the renderer; you'll have to dive into the source code to */
54 /* understand how it works). */
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 /* This renderer has the following advantages: */
63 /* - It doesn't need an intermediate bitmap. Instead, one can supply a */
64 /* callback function that will be called by the renderer to draw gray */
65 /* spans on any target surface. You can thus do direct composition on */
66 /* any kind of bitmap, provided that you give the renderer the right */
69 /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */
70 /* each pixel cell. */
72 /* - It performs a single pass on the outline (the `standard' FT2 */
73 /* renderer makes two passes). */
75 /* - It can easily be modified to render to _any_ number of gray levels */
78 /* - For small (< 20) pixel sizes, it is faster than the standard */
81 /*************************************************************************/
84 /*************************************************************************/
86 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
87 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
88 /* messages during execution. */
91 #define FT_COMPONENT trace_smooth
97 /* The size in bytes of the render pool used by the scan-line converter */
98 /* to do all of its work. */
99 #define FT_RENDER_POOL_SIZE 16384L
102 /* Auxiliary macros for token concatenation. */
103 #define FT_ERR_XCAT( x, y ) x ## y
104 #define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y )
106 #define FT_BEGIN_STMNT do {
107 #define FT_END_STMNT } while ( 0 )
109 #define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) )
110 #define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) )
111 #define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) )
115 * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
116 * algorithm. We use alpha = 1, beta = 3/8, giving us results with a
117 * largest error less than 7% compared to the exact value.
119 #define FT_HYPOT( x, y ) \
122 x > y ? x + ( 3 * y >> 3 ) \
123 : y + ( 3 * x >> 3 ) )
126 /* define this to dump debugging information */
127 /* #define FT_DEBUG_LEVEL_TRACE */
130 #ifdef FT_DEBUG_LEVEL_TRACE
139 #define FT_CHAR_BIT CHAR_BIT
140 #define FT_UINT_MAX UINT_MAX
141 #define FT_INT_MAX INT_MAX
142 #define FT_ULONG_MAX ULONG_MAX
144 #define ft_memset memset
146 #define ft_setjmp setjmp
147 #define ft_longjmp longjmp
148 #define ft_jmp_buf jmp_buf
150 typedef ptrdiff_t FT_PtrDist
;
153 #define ErrRaster_Invalid_Mode -2
154 #define ErrRaster_Invalid_Outline -1
155 #define ErrRaster_Invalid_Argument -3
156 #define ErrRaster_Memory_Overflow -4
158 #define FT_BEGIN_HEADER
159 #define FT_END_HEADER
165 /* This macro is used to indicate that a function parameter is unused. */
166 /* Its purpose is simply to reduce compiler warnings. Note also that */
167 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
168 /* ANSI compilers (e.g. LCC). */
169 #define FT_UNUSED( x ) (x) = (x)
172 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
174 #ifdef FT_DEBUG_LEVEL_TRACE
177 FT_Message( const char* fmt
,
184 vfprintf( stderr
, fmt
, ap
);
189 /* empty function useful for setting a breakpoint to catch errors */
203 /* we don't handle tracing levels in stand-alone mode; */
205 #define FT_TRACE5( varformat ) FT_Message varformat
208 #define FT_TRACE7( varformat ) FT_Message varformat
211 #define FT_ERROR( varformat ) FT_Message varformat
214 #define FT_THROW( e ) \
215 ( FT_Throw( FT_ERR_CAT( ErrRaster, e ), \
218 FT_ERR_CAT( ErrRaster, e ) )
220 #else /* !FT_DEBUG_LEVEL_TRACE */
222 #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */
223 #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */
224 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
225 #define FT_THROW( e ) FT_ERR_CAT( ErrRaster_, e )
228 #endif /* !FT_DEBUG_LEVEL_TRACE */
231 #define FT_DEFINE_OUTLINE_FUNCS( class_, \
232 move_to_, line_to_, \
233 conic_to_, cubic_to_, \
235 static const FT_Outline_Funcs class_ = \
245 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \
246 raster_new_, raster_reset_, \
247 raster_set_mode_, raster_render_, \
249 const FT_Raster_Funcs class_ = \
260 #else /* !STANDALONE_ */
263 #include <ft2build.h>
265 #include FT_INTERNAL_OBJECTS_H
266 #include FT_INTERNAL_DEBUG_H
267 #include FT_OUTLINE_H
269 #include "ftsmerrs.h"
273 #define Smooth_Err_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
274 #define Smooth_Err_Memory_Overflow Smooth_Err_Out_Of_Memory
275 #define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory
278 #endif /* !STANDALONE_ */
282 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
286 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
290 #define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) )
293 /* as usual, for the speed hungry :-) */
300 #ifndef FT_STATIC_RASTER
302 #define RAS_ARG gray_PWorker worker
303 #define RAS_ARG_ gray_PWorker worker,
305 #define RAS_VAR worker
306 #define RAS_VAR_ worker,
308 #else /* FT_STATIC_RASTER */
311 #define RAS_ARG_ /* empty */
312 #define RAS_VAR /* empty */
313 #define RAS_VAR_ /* empty */
315 #endif /* FT_STATIC_RASTER */
318 /* must be at least 6 bits! */
326 #define ONE_PIXEL ( 1 << PIXEL_BITS )
327 #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
328 #define SUBPIXELS( x ) ( (TPos)(x) * ONE_PIXEL )
329 #define FLOOR( x ) ( (x) & -ONE_PIXEL )
330 #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
331 #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
334 #define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
335 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
337 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
338 #define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) )
342 /* Compute `dividend / divisor' and return both its quotient and */
343 /* remainder, cast to a specific type. This macro also ensures that */
344 /* the remainder is always positive. */
345 #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
347 (quotient) = (type)( (dividend) / (divisor) ); \
348 (remainder) = (type)( (dividend) % (divisor) ); \
349 if ( (remainder) < 0 ) \
352 (remainder) += (type)(divisor); \
357 /* Work around a bug specific to GCC which make the compiler fail to */
358 /* optimize a division and modulo operation on the same parameters */
359 /* into a single call to `__aeabi_idivmod'. See */
361 /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */
363 #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
365 (quotient) = (type)( (dividend) / (divisor) ); \
366 (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \
367 if ( (remainder) < 0 ) \
370 (remainder) += (type)(divisor); \
376 /* These macros speed up repetitive divisions by replacing them */
377 /* with multiplications and right shifts. */
378 #define FT_UDIVPREP( c, b ) \
379 long b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \
381 #define FT_UDIV( a, b ) \
382 ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \
383 ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
386 /*************************************************************************/
388 /* TYPE DEFINITIONS */
391 /* don't change the following types to FT_Int or FT_Pos, since we might */
392 /* need to define them to "float" or "double" when experimenting with */
395 typedef long TPos
; /* sub-pixel coordinate */
396 typedef int TCoord
; /* integer scanline/pixel coordinate */
397 typedef int TArea
; /* cell areas, coordinate products */
400 typedef struct TCell_
* PCell
;
402 typedef struct TCell_
404 TCoord x
; /* same with gray_TWorker.ex */
405 TCoord cover
; /* same with gray_TWorker.cover */
411 typedef struct TPixmap_
413 unsigned char* origin
; /* pixmap origin at the bottom-left */
414 int pitch
; /* pitch to go down one row */
418 /* maximum number of gray cells in the buffer */
419 #if FT_RENDER_POOL_SIZE > 2048
420 #define FT_MAX_GRAY_POOL ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) )
422 #define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) )
426 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
427 /* We disable the warning `structure was padded due to */
428 /* __declspec(align())' in order to compile cleanly with */
429 /* the maximum level of warnings. */
430 #pragma warning( push )
431 #pragma warning( disable : 4324 )
432 #endif /* _MSC_VER */
434 typedef struct gray_TWorker_
436 ft_jmp_buf jump_buffer
;
439 TCoord min_ex
, max_ex
;
440 TCoord min_ey
, max_ey
;
448 FT_PtrDist max_cells
;
449 FT_PtrDist num_cells
;
456 FT_Raster_Span_Func render_span
;
457 void* render_span_data
;
459 } gray_TWorker
, *gray_PWorker
;
461 #if defined( _MSC_VER )
462 #pragma warning( pop )
466 #ifndef FT_STATIC_RASTER
467 #define ras (*worker)
469 static gray_TWorker ras
;
473 typedef struct gray_TRaster_
477 } gray_TRaster
, *gray_PRaster
;
480 #ifdef FT_DEBUG_LEVEL_TRACE
482 /* to be called while in the debugger -- */
483 /* this function causes a compiler warning since it is unused otherwise */
485 gray_dump_cells( RAS_ARG
)
490 for ( y
= ras
.min_ey
; y
< ras
.max_ey
; y
++ )
492 PCell cell
= ras
.ycells
[y
- ras
.min_ey
];
497 for ( ; cell
!= NULL
; cell
= cell
->next
)
498 printf( " (%3d, c:%4d, a:%6d)",
499 cell
->x
, cell
->cover
, cell
->area
);
504 #endif /* FT_DEBUG_LEVEL_TRACE */
507 /*************************************************************************/
509 /* Record the current cell in the table. */
512 gray_record_cell( RAS_ARG
)
518 pcell
= &ras
.ycells
[ras
.ey
- ras
.min_ey
];
522 if ( !cell
|| cell
->x
> x
)
531 if ( ras
.num_cells
>= ras
.max_cells
)
532 ft_longjmp( ras
.jump_buffer
, 1 );
534 /* insert new cell */
535 cell
= ras
.cells
+ ras
.num_cells
++;
537 cell
->area
= ras
.area
;
538 cell
->cover
= ras
.cover
;
546 /* update old cell */
547 cell
->area
+= ras
.area
;
548 cell
->cover
+= ras
.cover
;
552 /*************************************************************************/
554 /* Set the current cell to a new position. */
557 gray_set_cell( RAS_ARG_ TCoord ex
,
560 /* Move the cell pointer to a new position. We set the `invalid' */
561 /* flag to indicate that the cell isn't part of those we're interested */
562 /* in during the render phase. This means that: */
564 /* . the new vertical position must be within min_ey..max_ey-1. */
565 /* . the new horizontal position must be strictly less than max_ex */
567 /* Note that if a cell is to the left of the clipping region, it is */
568 /* actually set to the (min_ex-1) horizontal position. */
570 /* All cells that are on the left of the clipping region go to the */
571 /* min_ex - 1 horizontal position. */
573 if ( ex
< ras
.min_ex
)
576 /* record the current one if it is valid */
578 gray_record_cell( RAS_VAR
);
585 ras
.invalid
= ( ey
>= ras
.max_ey
|| ey
< ras
.min_ey
||
592 /*************************************************************************/
594 /* Render a scanline as one or more cells. */
597 gray_render_scanline( RAS_ARG_ TCoord ey
,
603 TCoord ex1
, ex2
, fx1
, fx2
, first
, delta
, mod
;
611 /* trivial case. Happens often */
614 gray_set_cell( RAS_VAR_ ex2
, ey
);
618 fx1
= (TCoord
)( x1
- SUBPIXELS( ex1
) );
619 fx2
= (TCoord
)( x2
- SUBPIXELS( ex2
) );
622 /* everything is located in a single cell. That is easy! */
626 ras
.area
+= (TArea
)(( fx1
+ fx2
) * delta
);
631 /* ok, we'll have to render a run of adjacent cells on the same */
638 p
= ( ONE_PIXEL
- fx1
) * delta
;
650 FT_DIV_MOD( TCoord
, p
, dx
, delta
, mod
);
652 ras
.area
+= (TArea
)(( fx1
+ first
) * delta
);
656 gray_set_cell( RAS_VAR_ ex1
, ey
);
664 p
= ONE_PIXEL
* ( y2
- y1
+ delta
);
665 FT_DIV_MOD( TCoord
, p
, dx
, lift
, rem
);
679 ras
.area
+= (TArea
)(ONE_PIXEL
* delta
);
683 gray_set_cell( RAS_VAR_ ex1
, ey
);
684 } while ( ex1
!= ex2
);
688 ras
.area
+= (TArea
)(( fx2
+ ONE_PIXEL
- first
) * delta
);
693 /*************************************************************************/
695 /* Render a given line as a series of scanlines. */
698 gray_render_line( RAS_ARG_ TPos to_x
,
701 TCoord ey1
, ey2
, fy1
, fy2
, first
, delta
, mod
;
702 TPos p
, dx
, dy
, x
, x2
;
706 ey1
= TRUNC( ras
.y
);
707 ey2
= TRUNC( to_y
); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
709 /* perform vertical clipping */
710 if ( ( ey1
>= ras
.max_ey
&& ey2
>= ras
.max_ey
) ||
711 ( ey1
< ras
.min_ey
&& ey2
< ras
.min_ey
) )
714 fy1
= (TCoord
)( ras
.y
- SUBPIXELS( ey1
) );
715 fy2
= (TCoord
)( to_y
- SUBPIXELS( ey2
) );
717 /* everything is on a single scanline */
720 gray_render_scanline( RAS_VAR_ ey1
, ras
.x
, fy1
, to_x
, fy2
);
727 /* vertical line - avoid calling gray_render_scanline */
730 TCoord ex
= TRUNC( ras
.x
);
731 TCoord two_fx
= (TCoord
)( ( ras
.x
- SUBPIXELS( ex
) ) << 1 );
747 ras
.area
+= (TArea
)two_fx
* delta
;
751 gray_set_cell( RAS_VAR_ ex
, ey1
);
753 delta
= first
+ first
- ONE_PIXEL
;
754 area
= (TArea
)two_fx
* delta
;
761 gray_set_cell( RAS_VAR_ ex
, ey1
);
764 delta
= fy2
- ONE_PIXEL
+ first
;
765 ras
.area
+= (TArea
)two_fx
* delta
;
771 /* ok, we have to render several scanlines */
774 p
= ( ONE_PIXEL
- fy1
) * dx
;
786 FT_DIV_MOD( TCoord
, p
, dy
, delta
, mod
);
789 gray_render_scanline( RAS_VAR_ ey1
, ras
.x
, fy1
, x
, first
);
792 gray_set_cell( RAS_VAR_
TRUNC( x
), ey1
);
800 FT_DIV_MOD( TCoord
, p
, dy
, lift
, rem
);
814 gray_render_scanline( RAS_VAR_ ey1
,
815 x
, ONE_PIXEL
- first
,
820 gray_set_cell( RAS_VAR_
TRUNC( x
), ey1
);
821 } while ( ey1
!= ey2
);
824 gray_render_scanline( RAS_VAR_ ey1
,
825 x
, ONE_PIXEL
- first
,
835 /*************************************************************************/
837 /* Render a straight line across multiple cells in any direction. */
840 gray_render_line( RAS_ARG_ TPos to_x
,
843 TPos dx
, dy
, fx1
, fy1
, fx2
, fy2
;
844 TCoord ex1
, ex2
, ey1
, ey2
;
847 ey1
= TRUNC( ras
.y
);
850 /* perform vertical clipping */
851 if ( ( ey1
>= ras
.max_ey
&& ey2
>= ras
.max_ey
) ||
852 ( ey1
< ras
.min_ey
&& ey2
< ras
.min_ey
) )
855 ex1
= TRUNC( ras
.x
);
858 fx1
= ras
.x
- SUBPIXELS( ex1
);
859 fy1
= ras
.y
- SUBPIXELS( ey1
);
864 if ( ex1
== ex2
&& ey1
== ey2
) /* inside one cell */
866 else if ( dy
== 0 ) /* ex1 != ex2 */ /* any horizontal line */
869 gray_set_cell( RAS_VAR_ ex1
, ey1
);
873 if ( dy
> 0 ) /* vertical line up */
877 ras
.cover
+= ( fy2
- fy1
);
878 ras
.area
+= ( fy2
- fy1
) * fx1
* 2;
881 gray_set_cell( RAS_VAR_ ex1
, ey1
);
882 } while ( ey1
!= ey2
);
883 else /* vertical line down */
887 ras
.cover
+= ( fy2
- fy1
);
888 ras
.area
+= ( fy2
- fy1
) * fx1
* 2;
891 gray_set_cell( RAS_VAR_ ex1
, ey1
);
892 } while ( ey1
!= ey2
);
894 else /* any other line */
896 TPos prod
= dx
* fy1
- dy
* fx1
;
897 FT_UDIVPREP( ex1
!= ex2
, dx
);
898 FT_UDIVPREP( ey1
!= ey2
, dy
);
901 /* The fundamental value `prod' determines which side and the */
902 /* exact coordinate where the line exits current cell. It is */
903 /* also easily updated when moving from one cell to the next. */
907 prod
- dx
* ONE_PIXEL
> 0 ) /* left */
910 fy2
= (TPos
)FT_UDIV( -prod
, -dx
);
911 prod
-= dy
* ONE_PIXEL
;
912 ras
.cover
+= ( fy2
- fy1
);
913 ras
.area
+= ( fy2
- fy1
) * ( fx1
+ fx2
);
918 else if ( prod
- dx
* ONE_PIXEL
<= 0 &&
919 prod
- dx
* ONE_PIXEL
+ dy
* ONE_PIXEL
> 0 ) /* up */
921 prod
-= dx
* ONE_PIXEL
;
922 fx2
= (TPos
)FT_UDIV( -prod
, dy
);
924 ras
.cover
+= ( fy2
- fy1
);
925 ras
.area
+= ( fy2
- fy1
) * ( fx1
+ fx2
);
930 else if ( prod
- dx
* ONE_PIXEL
+ dy
* ONE_PIXEL
<= 0 &&
931 prod
+ dy
* ONE_PIXEL
>= 0 ) /* right */
933 prod
+= dy
* ONE_PIXEL
;
935 fy2
= (TPos
)FT_UDIV( prod
, dx
);
936 ras
.cover
+= ( fy2
- fy1
);
937 ras
.area
+= ( fy2
- fy1
) * ( fx1
+ fx2
);
942 else /* ( prod + dy * ONE_PIXEL < 0 &&
945 fx2
= (TPos
)FT_UDIV( prod
, -dy
);
947 prod
+= dx
* ONE_PIXEL
;
948 ras
.cover
+= ( fy2
- fy1
);
949 ras
.area
+= ( fy2
- fy1
) * ( fx1
+ fx2
);
955 gray_set_cell( RAS_VAR_ ex1
, ey1
);
956 } while ( ex1
!= ex2
|| ey1
!= ey2
);
959 fx2
= to_x
- SUBPIXELS( ex2
);
960 fy2
= to_y
- SUBPIXELS( ey2
);
962 ras
.cover
+= ( fy2
- fy1
);
963 ras
.area
+= ( fy2
- fy1
) * ( fx1
+ fx2
);
973 gray_split_conic( FT_Vector
* base
)
978 base
[4].x
= base
[2].x
;
980 a
= base
[3].x
= ( base
[2].x
+ b
) / 2;
981 b
= base
[1].x
= ( base
[0].x
+ b
) / 2;
982 base
[2].x
= ( a
+ b
) / 2;
984 base
[4].y
= base
[2].y
;
986 a
= base
[3].y
= ( base
[2].y
+ b
) / 2;
987 b
= base
[1].y
= ( base
[0].y
+ b
) / 2;
988 base
[2].y
= ( a
+ b
) / 2;
993 gray_render_conic( RAS_ARG_
const FT_Vector
* control
,
994 const FT_Vector
* to
)
996 FT_Vector bez_stack
[16 * 2 + 1]; /* enough to accommodate bisections */
997 FT_Vector
* arc
= bez_stack
;
1002 arc
[0].x
= UPSCALE( to
->x
);
1003 arc
[0].y
= UPSCALE( to
->y
);
1004 arc
[1].x
= UPSCALE( control
->x
);
1005 arc
[1].y
= UPSCALE( control
->y
);
1009 /* short-cut the arc that crosses the current band */
1010 if ( ( TRUNC( arc
[0].y
) >= ras
.max_ey
&&
1011 TRUNC( arc
[1].y
) >= ras
.max_ey
&&
1012 TRUNC( arc
[2].y
) >= ras
.max_ey
) ||
1013 ( TRUNC( arc
[0].y
) < ras
.min_ey
&&
1014 TRUNC( arc
[1].y
) < ras
.min_ey
&&
1015 TRUNC( arc
[2].y
) < ras
.min_ey
) )
1022 dx
= FT_ABS( arc
[2].x
+ arc
[0].x
- 2 * arc
[1].x
);
1023 dy
= FT_ABS( arc
[2].y
+ arc
[0].y
- 2 * arc
[1].y
);
1027 /* We can calculate the number of necessary bisections because */
1028 /* each bisection predictably reduces deviation exactly 4-fold. */
1029 /* Even 32-bit deviation would vanish after 16 bisections. */
1031 while ( dx
> ONE_PIXEL
/ 4 )
1037 /* We use decrement counter to count the total number of segments */
1038 /* to draw starting from 2^level. Before each draw we split as */
1039 /* many times as there are trailing zeros in the counter. */
1043 while ( ( draw
& split
) == 0 )
1045 gray_split_conic( arc
);
1050 gray_render_line( RAS_VAR_ arc
[0].x
, arc
[0].y
);
1058 gray_split_cubic( FT_Vector
* base
)
1063 base
[6].x
= base
[3].x
;
1066 base
[1].x
= a
= ( base
[0].x
+ c
) / 2;
1067 base
[5].x
= b
= ( base
[3].x
+ d
) / 2;
1069 base
[2].x
= a
= ( a
+ c
) / 2;
1070 base
[4].x
= b
= ( b
+ c
) / 2;
1071 base
[3].x
= ( a
+ b
) / 2;
1073 base
[6].y
= base
[3].y
;
1076 base
[1].y
= a
= ( base
[0].y
+ c
) / 2;
1077 base
[5].y
= b
= ( base
[3].y
+ d
) / 2;
1079 base
[2].y
= a
= ( a
+ c
) / 2;
1080 base
[4].y
= b
= ( b
+ c
) / 2;
1081 base
[3].y
= ( a
+ b
) / 2;
1086 gray_render_cubic( RAS_ARG_
const FT_Vector
* control1
,
1087 const FT_Vector
* control2
,
1088 const FT_Vector
* to
)
1090 FT_Vector bez_stack
[16 * 3 + 1]; /* enough to accommodate bisections */
1091 FT_Vector
* arc
= bez_stack
;
1092 TPos dx
, dy
, dx_
, dy_
;
1093 TPos dx1
, dy1
, dx2
, dy2
;
1097 arc
[0].x
= UPSCALE( to
->x
);
1098 arc
[0].y
= UPSCALE( to
->y
);
1099 arc
[1].x
= UPSCALE( control2
->x
);
1100 arc
[1].y
= UPSCALE( control2
->y
);
1101 arc
[2].x
= UPSCALE( control1
->x
);
1102 arc
[2].y
= UPSCALE( control1
->y
);
1106 /* short-cut the arc that crosses the current band */
1107 if ( ( TRUNC( arc
[0].y
) >= ras
.max_ey
&&
1108 TRUNC( arc
[1].y
) >= ras
.max_ey
&&
1109 TRUNC( arc
[2].y
) >= ras
.max_ey
&&
1110 TRUNC( arc
[3].y
) >= ras
.max_ey
) ||
1111 ( TRUNC( arc
[0].y
) < ras
.min_ey
&&
1112 TRUNC( arc
[1].y
) < ras
.min_ey
&&
1113 TRUNC( arc
[2].y
) < ras
.min_ey
&&
1114 TRUNC( arc
[3].y
) < ras
.min_ey
) )
1123 /* Decide whether to split or draw. See `Rapid Termination */
1124 /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
1126 /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
1128 /* dx and dy are x and y components of the P0-P3 chord vector. */
1129 dx
= dx_
= arc
[3].x
- arc
[0].x
;
1130 dy
= dy_
= arc
[3].y
- arc
[0].y
;
1132 L
= FT_HYPOT( dx_
, dy_
);
1134 /* Avoid possible arithmetic overflow below by splitting. */
1138 /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
1139 s_limit
= L
* (TPos
)( ONE_PIXEL
/ 6 );
1141 /* s is L * the perpendicular distance from P1 to the line P0-P3. */
1142 dx1
= arc
[1].x
- arc
[0].x
;
1143 dy1
= arc
[1].y
- arc
[0].y
;
1144 s
= FT_ABS( dy
* dx1
- dx
* dy1
);
1149 /* s is L * the perpendicular distance from P2 to the line P0-P3. */
1150 dx2
= arc
[2].x
- arc
[0].x
;
1151 dy2
= arc
[2].y
- arc
[0].y
;
1152 s
= FT_ABS( dy
* dx2
- dx
* dy2
);
1157 /* Split super curvy segments where the off points are so far
1158 from the chord that the angles P0-P1-P3 or P0-P2-P3 become
1159 acute as detected by appropriate dot products. */
1160 if ( dx1
* ( dx1
- dx
) + dy1
* ( dy1
- dy
) > 0 ||
1161 dx2
* ( dx2
- dx
) + dy2
* ( dy2
- dy
) > 0 )
1164 gray_render_line( RAS_VAR_ arc
[0].x
, arc
[0].y
);
1166 if ( arc
== bez_stack
)
1173 gray_split_cubic( arc
);
1180 gray_move_to( const FT_Vector
* to
,
1181 gray_PWorker worker
)
1186 /* start to a new position */
1187 x
= UPSCALE( to
->x
);
1188 y
= UPSCALE( to
->y
);
1190 gray_set_cell( RAS_VAR_
TRUNC( x
), TRUNC( y
) );
1199 gray_line_to( const FT_Vector
* to
,
1200 gray_PWorker worker
)
1202 gray_render_line( RAS_VAR_
UPSCALE( to
->x
), UPSCALE( to
->y
) );
1208 gray_conic_to( const FT_Vector
* control
,
1209 const FT_Vector
* to
,
1210 gray_PWorker worker
)
1212 gray_render_conic( RAS_VAR_ control
, to
);
1218 gray_cubic_to( const FT_Vector
* control1
,
1219 const FT_Vector
* control2
,
1220 const FT_Vector
* to
,
1221 gray_PWorker worker
)
1223 gray_render_cubic( RAS_VAR_ control1
, control2
, to
);
1229 gray_hline( RAS_ARG_ TCoord x
,
1238 /* compute the coverage line's coverage, depending on the */
1239 /* outline fill rule */
1241 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1243 coverage
= (int)( area
>> ( PIXEL_BITS
* 2 + 1 - 8 ) );
1244 /* use range 0..256 */
1246 coverage
= -coverage
;
1248 if ( ras
.outline
.flags
& FT_OUTLINE_EVEN_ODD_FILL
)
1252 if ( coverage
> 256 )
1253 coverage
= 512 - coverage
;
1254 else if ( coverage
== 256 )
1259 /* normal non-zero winding rule */
1260 if ( coverage
>= 256 )
1264 if ( ras
.render_span
) /* for FT_RASTER_FLAG_DIRECT only */
1267 span
.len
= (unsigned short)acount
;
1268 span
.coverage
= (unsigned char)coverage
;
1270 ras
.render_span( y
, 1, &span
, ras
.render_span_data
);
1274 unsigned char* q
= ras
.target
.origin
- ras
.target
.pitch
* y
+ x
;
1275 unsigned char c
= (unsigned char)coverage
;
1278 /* For small-spans it is faster to do it by ourselves than
1279 * calling `memset'. This is mainly due to the cost of the
1293 FT_MEM_SET( q
, c
, acount
);
1300 gray_sweep( RAS_ARG
)
1305 FT_TRACE7(( "gray_sweep: start\n" ));
1307 for ( y
= ras
.min_ey
; y
< ras
.max_ey
; y
++ )
1309 PCell cell
= ras
.ycells
[y
- ras
.min_ey
];
1311 TCoord x
= ras
.min_ex
;
1314 for ( ; cell
!= NULL
; cell
= cell
->next
)
1319 if ( cover
!= 0 && cell
->x
> x
)
1320 gray_hline( RAS_VAR_ x
, y
, (TArea
)cover
* ( ONE_PIXEL
* 2 ),
1323 cover
+= cell
->cover
;
1324 area
= (TArea
)cover
* ( ONE_PIXEL
* 2 ) - cell
->area
;
1326 if ( area
!= 0 && cell
->x
>= ras
.min_ex
)
1327 gray_hline( RAS_VAR_ cell
->x
, y
, area
, 1 );
1333 gray_hline( RAS_VAR_ x
, y
, (TArea
)cover
* ( ONE_PIXEL
* 2 ),
1337 FT_TRACE7(( "gray_sweep: end\n" ));
1343 /*************************************************************************/
1345 /* The following functions should only compile in stand-alone mode, */
1346 /* i.e., when building this component without the rest of FreeType. */
1348 /*************************************************************************/
1350 /*************************************************************************/
1353 /* FT_Outline_Decompose */
1356 /* Walk over an outline's structure to decompose it into individual */
1357 /* segments and Bézier arcs. This function is also able to emit */
1358 /* `move to' and `close to' operations to indicate the start and end */
1359 /* of new contours in the outline. */
1362 /* outline :: A pointer to the source target. */
1364 /* func_interface :: A table of `emitters', i.e., function pointers */
1365 /* called during decomposition to indicate path */
1369 /* user :: A typeless pointer which is passed to each */
1370 /* emitter during the decomposition. It can be */
1371 /* used to store the state during the */
1372 /* decomposition. */
1375 /* Error code. 0 means success. */
1378 FT_Outline_Decompose( const FT_Outline
* outline
,
1379 const FT_Outline_Funcs
* func_interface
,
1383 #define SCALED( x ) ( ( (x) << shift ) - delta )
1386 FT_Vector v_control
;
1395 int n
; /* index of contour in outline */
1396 int first
; /* index of first point in contour */
1397 char tag
; /* current point's state */
1404 return FT_THROW( Invalid_Outline
);
1406 if ( !func_interface
)
1407 return FT_THROW( Invalid_Argument
);
1409 shift
= func_interface
->shift
;
1410 delta
= func_interface
->delta
;
1413 for ( n
= 0; n
< outline
->n_contours
; n
++ )
1415 int last
; /* index of last point in contour */
1418 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n
));
1420 last
= outline
->contours
[n
];
1422 goto Invalid_Outline
;
1423 limit
= outline
->points
+ last
;
1425 v_start
= outline
->points
[first
];
1426 v_start
.x
= SCALED( v_start
.x
);
1427 v_start
.y
= SCALED( v_start
.y
);
1429 v_last
= outline
->points
[last
];
1430 v_last
.x
= SCALED( v_last
.x
);
1431 v_last
.y
= SCALED( v_last
.y
);
1433 v_control
= v_start
;
1435 point
= outline
->points
+ first
;
1436 tags
= outline
->tags
+ first
;
1437 tag
= FT_CURVE_TAG( tags
[0] );
1439 /* A contour cannot start with a cubic control point! */
1440 if ( tag
== FT_CURVE_TAG_CUBIC
)
1441 goto Invalid_Outline
;
1443 /* check first point to determine origin */
1444 if ( tag
== FT_CURVE_TAG_CONIC
)
1446 /* first point is conic control. Yes, this happens. */
1447 if ( FT_CURVE_TAG( outline
->tags
[last
] ) == FT_CURVE_TAG_ON
)
1449 /* start at last point if it is on the curve */
1455 /* if both first and last points are conic, */
1456 /* start at their middle and record its position */
1458 v_start
.x
= ( v_start
.x
+ v_last
.x
) / 2;
1459 v_start
.y
= ( v_start
.y
+ v_last
.y
) / 2;
1467 FT_TRACE5(( " move to (%.2f, %.2f)\n",
1468 v_start
.x
/ 64.0, v_start
.y
/ 64.0 ));
1469 error
= func_interface
->move_to( &v_start
, user
);
1473 while ( point
< limit
)
1478 tag
= FT_CURVE_TAG( tags
[0] );
1481 case FT_CURVE_TAG_ON
: /* emit a single line_to */
1486 vec
.x
= SCALED( point
->x
);
1487 vec
.y
= SCALED( point
->y
);
1489 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1490 vec
.x
/ 64.0, vec
.y
/ 64.0 ));
1491 error
= func_interface
->line_to( &vec
, user
);
1497 case FT_CURVE_TAG_CONIC
: /* consume conic arcs */
1498 v_control
.x
= SCALED( point
->x
);
1499 v_control
.y
= SCALED( point
->y
);
1502 if ( point
< limit
)
1510 tag
= FT_CURVE_TAG( tags
[0] );
1512 vec
.x
= SCALED( point
->x
);
1513 vec
.y
= SCALED( point
->y
);
1515 if ( tag
== FT_CURVE_TAG_ON
)
1517 FT_TRACE5(( " conic to (%.2f, %.2f)"
1518 " with control (%.2f, %.2f)\n",
1519 vec
.x
/ 64.0, vec
.y
/ 64.0,
1520 v_control
.x
/ 64.0, v_control
.y
/ 64.0 ));
1521 error
= func_interface
->conic_to( &v_control
, &vec
, user
);
1527 if ( tag
!= FT_CURVE_TAG_CONIC
)
1528 goto Invalid_Outline
;
1530 v_middle
.x
= ( v_control
.x
+ vec
.x
) / 2;
1531 v_middle
.y
= ( v_control
.y
+ vec
.y
) / 2;
1533 FT_TRACE5(( " conic to (%.2f, %.2f)"
1534 " with control (%.2f, %.2f)\n",
1535 v_middle
.x
/ 64.0, v_middle
.y
/ 64.0,
1536 v_control
.x
/ 64.0, v_control
.y
/ 64.0 ));
1537 error
= func_interface
->conic_to( &v_control
, &v_middle
, user
);
1545 FT_TRACE5(( " conic to (%.2f, %.2f)"
1546 " with control (%.2f, %.2f)\n",
1547 v_start
.x
/ 64.0, v_start
.y
/ 64.0,
1548 v_control
.x
/ 64.0, v_control
.y
/ 64.0 ));
1549 error
= func_interface
->conic_to( &v_control
, &v_start
, user
);
1552 default: /* FT_CURVE_TAG_CUBIC */
1554 FT_Vector vec1
, vec2
;
1557 if ( point
+ 1 > limit
||
1558 FT_CURVE_TAG( tags
[1] ) != FT_CURVE_TAG_CUBIC
)
1559 goto Invalid_Outline
;
1564 vec1
.x
= SCALED( point
[-2].x
);
1565 vec1
.y
= SCALED( point
[-2].y
);
1567 vec2
.x
= SCALED( point
[-1].x
);
1568 vec2
.y
= SCALED( point
[-1].y
);
1570 if ( point
<= limit
)
1575 vec
.x
= SCALED( point
->x
);
1576 vec
.y
= SCALED( point
->y
);
1578 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1579 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1580 vec
.x
/ 64.0, vec
.y
/ 64.0,
1581 vec1
.x
/ 64.0, vec1
.y
/ 64.0,
1582 vec2
.x
/ 64.0, vec2
.y
/ 64.0 ));
1583 error
= func_interface
->cubic_to( &vec1
, &vec2
, &vec
, user
);
1589 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1590 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1591 v_start
.x
/ 64.0, v_start
.y
/ 64.0,
1592 vec1
.x
/ 64.0, vec1
.y
/ 64.0,
1593 vec2
.x
/ 64.0, vec2
.y
/ 64.0 ));
1594 error
= func_interface
->cubic_to( &vec1
, &vec2
, &v_start
, user
);
1600 /* close the contour with a line segment */
1601 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1602 v_start
.x
/ 64.0, v_start
.y
/ 64.0 ));
1603 error
= func_interface
->line_to( &v_start
, user
);
1612 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n
));
1616 FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error
));
1620 return FT_THROW( Invalid_Outline
);
1624 /*************************************************************************/
1627 /* FT_Outline_Get_CBox */
1630 /* Return an outline's `control box'. The control box encloses all */
1631 /* the outline's points, including Bézier control points. Though it */
1632 /* coincides with the exact bounding box for most glyphs, it can be */
1633 /* slightly larger in some situations (like when rotating an outline */
1634 /* that contains Bézier outside arcs). */
1636 /* Computing the control box is very fast, while getting the bounding */
1637 /* box can take much more time as it needs to walk over all segments */
1638 /* and arcs in the outline. To get the latter, you can use the */
1639 /* `ftbbox' component, which is dedicated to this single task. */
1642 /* outline :: A pointer to the source outline descriptor. */
1645 /* acbox :: The outline's control box. */
1648 /* See @FT_Glyph_Get_CBox for a discussion of tricky fonts. */
1652 FT_Outline_Get_CBox( const FT_Outline
* outline
,
1655 TPos xMin
, yMin
, xMax
, yMax
;
1658 if ( outline
&& acbox
)
1660 if ( outline
->n_points
== 0 )
1669 FT_Vector
* vec
= outline
->points
;
1670 FT_Vector
* limit
= vec
+ outline
->n_points
;
1673 xMin
= xMax
= vec
->x
;
1674 yMin
= yMax
= vec
->y
;
1677 for ( ; vec
< limit
; vec
++ )
1683 if ( x
< xMin
) xMin
= x
;
1684 if ( x
> xMax
) xMax
= x
;
1687 if ( y
< yMin
) yMin
= y
;
1688 if ( y
> yMax
) yMax
= y
;
1698 #endif /* STANDALONE_ */
1701 FT_DEFINE_OUTLINE_FUNCS(
1704 (FT_Outline_MoveTo_Func
) gray_move_to
, /* move_to */
1705 (FT_Outline_LineTo_Func
) gray_line_to
, /* line_to */
1706 (FT_Outline_ConicTo_Func
)gray_conic_to
, /* conic_to */
1707 (FT_Outline_CubicTo_Func
)gray_cubic_to
, /* cubic_to */
1715 gray_convert_glyph_inner( RAS_ARG
)
1718 volatile int error
= 0;
1720 #ifdef FT_CONFIG_OPTION_PIC
1721 FT_Outline_Funcs func_interface
;
1722 Init_Class_func_interface(&func_interface
);
1725 if ( ft_setjmp( ras
.jump_buffer
) == 0 )
1727 error
= FT_Outline_Decompose( &ras
.outline
, &func_interface
, &ras
);
1729 gray_record_cell( RAS_VAR
);
1731 FT_TRACE7(( "band [%d..%d]: %d cells\n",
1732 ras
.min_ey
, ras
.max_ey
, ras
.num_cells
));
1736 error
= FT_THROW( Memory_Overflow
);
1738 FT_TRACE7(( "band [%d..%d]: to be bisected\n",
1739 ras
.min_ey
, ras
.max_ey
));
1747 gray_convert_glyph( RAS_ARG
)
1752 TCell buffer
[FT_MAX_GRAY_POOL
];
1754 TCoord band_size
= FT_MAX_GRAY_POOL
/ 8;
1755 TCoord count
= ras
.max_ey
- ras
.min_ey
;
1757 TCoord min
, max
, max_y
;
1758 TCoord bands
[32]; /* enough to accommodate bisections */
1762 buffer
= malloc(FT_MAX(FT_RENDER_POOL_SIZE
, 2048));
1765 /* set up vertical bands */
1766 if ( count
> band_size
)
1768 /* two divisions rounded up */
1769 num_bands
= (int)( ( count
+ band_size
- 1) / band_size
);
1770 band_size
= ( count
+ num_bands
- 1 ) / num_bands
;
1776 for ( ; min
< max_y
; min
= max
)
1778 max
= min
+ band_size
;
1788 TCoord width
= band
[0] - band
[1];
1792 /* memory management */
1794 size_t ycount
= (size_t)width
;
1798 cell_start
= ( ycount
* sizeof ( PCell
) + sizeof ( TCell
) - 1 ) /
1801 ras
.cells
= buffer
+ cell_start
;
1802 ras
.max_cells
= (FT_PtrDist
)( FT_MAX_GRAY_POOL
- cell_start
);
1805 ras
.ycells
= (PCell
*)buffer
;
1807 ras
.ycells
[--ycount
] = NULL
;
1811 ras
.min_ey
= band
[1];
1812 ras
.max_ey
= band
[0];
1814 error
= gray_convert_glyph_inner( RAS_VAR
);
1818 gray_sweep( RAS_VAR
);
1822 else if ( error
!= ErrRaster_Memory_Overflow
)
1830 /* render pool overflow; we will reduce the render band by half */
1833 /* This is too complex for a single scanline; there must */
1834 /* be some problems. */
1837 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
1847 } while ( band
>= bands
);
1859 gray_raster_render( FT_Raster raster
,
1860 const FT_Raster_Params
* params
)
1862 const FT_Outline
* outline
= (const FT_Outline
*)params
->source
;
1863 const FT_Bitmap
* target_map
= params
->target
;
1866 #ifndef FT_STATIC_RASTER
1867 gray_TWorker worker
[1];
1872 return FT_THROW( Invalid_Argument
);
1874 /* this version does not support monochrome rendering */
1875 if ( !( params
->flags
& FT_RASTER_FLAG_AA
) )
1876 return FT_THROW( Invalid_Mode
);
1879 return FT_THROW( Invalid_Outline
);
1881 /* return immediately if the outline is empty */
1882 if ( outline
->n_points
== 0 || outline
->n_contours
<= 0 )
1885 if ( !outline
->contours
|| !outline
->points
)
1886 return FT_THROW( Invalid_Outline
);
1888 if ( outline
->n_points
!=
1889 outline
->contours
[outline
->n_contours
- 1] + 1 )
1890 return FT_THROW( Invalid_Outline
);
1892 ras
.outline
= *outline
;
1894 if ( params
->flags
& FT_RASTER_FLAG_DIRECT
)
1896 if ( !params
->gray_spans
)
1899 ras
.render_span
= (FT_Raster_Span_Func
)params
->gray_spans
;
1900 ras
.render_span_data
= params
->user
;
1904 /* if direct mode is not set, we must have a target bitmap */
1906 return FT_THROW( Invalid_Argument
);
1909 if ( !target_map
->width
|| !target_map
->rows
)
1912 if ( !target_map
->buffer
)
1913 return FT_THROW( Invalid_Argument
);
1915 if ( target_map
->pitch
< 0 )
1916 ras
.target
.origin
= target_map
->buffer
;
1918 ras
.target
.origin
= target_map
->buffer
1919 + ( target_map
->rows
- 1 ) * (unsigned int)target_map
->pitch
;
1921 ras
.target
.pitch
= target_map
->pitch
;
1923 ras
.render_span
= (FT_Raster_Span_Func
)NULL
;
1924 ras
.render_span_data
= NULL
;
1927 FT_Outline_Get_CBox( outline
, &cbox
);
1929 /* reject too large outline coordinates */
1930 if ( cbox
.xMin
< -0x1000000L
|| cbox
.xMax
> 0x1000000L
||
1931 cbox
.yMin
< -0x1000000L
|| cbox
.yMax
> 0x1000000L
)
1932 return FT_THROW( Invalid_Outline
);
1934 /* truncate the bounding box to integer pixels */
1935 cbox
.xMin
= cbox
.xMin
>> 6;
1936 cbox
.yMin
= cbox
.yMin
>> 6;
1937 cbox
.xMax
= ( cbox
.xMax
+ 63 ) >> 6;
1938 cbox
.yMax
= ( cbox
.yMax
+ 63 ) >> 6;
1940 /* compute clipping box */
1941 if ( !( params
->flags
& FT_RASTER_FLAG_DIRECT
) )
1943 /* compute clip box from target pixmap */
1946 clip
.xMax
= (FT_Pos
)target_map
->width
;
1947 clip
.yMax
= (FT_Pos
)target_map
->rows
;
1949 else if ( params
->flags
& FT_RASTER_FLAG_CLIP
)
1950 clip
= params
->clip_box
;
1953 clip
.xMin
= -32768L;
1954 clip
.yMin
= -32768L;
1959 /* clip to target bitmap, exit if nothing to do */
1960 ras
.min_ex
= FT_MAX( cbox
.xMin
, clip
.xMin
);
1961 ras
.min_ey
= FT_MAX( cbox
.yMin
, clip
.yMin
);
1962 ras
.max_ex
= FT_MIN( cbox
.xMax
, clip
.xMax
);
1963 ras
.max_ey
= FT_MIN( cbox
.yMax
, clip
.yMax
);
1965 if ( ras
.max_ex
<= ras
.min_ex
|| ras
.max_ey
<= ras
.min_ey
)
1968 return gray_convert_glyph( RAS_VAR
);
1972 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
1973 /**** a static object. *****/
1978 gray_raster_new( void* memory
,
1979 FT_Raster
* araster
)
1981 static gray_TRaster the_raster
;
1983 FT_UNUSED( memory
);
1986 *araster
= (FT_Raster
)&the_raster
;
1987 FT_ZERO( &the_raster
);
1994 gray_raster_done( FT_Raster raster
)
1997 FT_UNUSED( raster
);
2000 #else /* !STANDALONE_ */
2003 gray_raster_new( FT_Memory memory
,
2004 FT_Raster
* araster
)
2007 gray_PRaster raster
= NULL
;
2011 if ( !FT_ALLOC( raster
, sizeof ( gray_TRaster
) ) )
2013 raster
->memory
= memory
;
2014 *araster
= (FT_Raster
)raster
;
2022 gray_raster_done( FT_Raster raster
)
2024 FT_Memory memory
= (FT_Memory
)((gray_PRaster
)raster
)->memory
;
2030 #endif /* !STANDALONE_ */
2034 gray_raster_reset( FT_Raster raster
,
2035 unsigned char* pool_base
,
2036 unsigned long pool_size
)
2038 FT_UNUSED( raster
);
2039 FT_UNUSED( pool_base
);
2040 FT_UNUSED( pool_size
);
2045 gray_raster_set_mode( FT_Raster raster
,
2049 FT_UNUSED( raster
);
2054 return 0; /* nothing to do */
2058 FT_DEFINE_RASTER_FUNCS(
2061 FT_GLYPH_FORMAT_OUTLINE
,
2063 (FT_Raster_New_Func
) gray_raster_new
, /* raster_new */
2064 (FT_Raster_Reset_Func
) gray_raster_reset
, /* raster_reset */
2065 (FT_Raster_Set_Mode_Func
)gray_raster_set_mode
, /* raster_set_mode */
2066 (FT_Raster_Render_Func
) gray_raster_render
, /* raster_render */
2067 (FT_Raster_Done_Func
) gray_raster_done
/* raster_done */
2074 /* Local Variables: */