1 /***************************************************************************/
5 /* A new `perfect' anti-aliasing renderer (body). */
7 /* Copyright 2000-2003, 2005-2013 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 -D_STANDALONE_ 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 /* Auxiliary macros for token concatenation. */
98 #define FT_ERR_XCAT( x, y ) x ## y
99 #define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y )
102 /* define this to dump debugging information */
103 /* #define FT_DEBUG_LEVEL_TRACE */
106 #ifdef FT_DEBUG_LEVEL_TRACE
115 #define FT_UINT_MAX UINT_MAX
116 #define FT_INT_MAX INT_MAX
118 #define ft_memset memset
120 #define ft_setjmp setjmp
121 #define ft_longjmp longjmp
122 #define ft_jmp_buf jmp_buf
124 typedef ptrdiff_t FT_PtrDist;
127 #define ErrRaster_Invalid_Mode -2
128 #define ErrRaster_Invalid_Outline -1
129 #define ErrRaster_Invalid_Argument -3
130 #define ErrRaster_Memory_Overflow -4
132 #define FT_BEGIN_HEADER
133 #define FT_END_HEADER
139 /* This macro is used to indicate that a function parameter is unused. */
140 /* Its purpose is simply to reduce compiler warnings. Note also that */
141 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
142 /* ANSI compilers (e.g. LCC). */
143 #define FT_UNUSED( x ) (x) = (x)
146 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
148 #ifdef FT_DEBUG_LEVEL_TRACE
151 FT_Message( const char* fmt,
158 vfprintf( stderr, fmt, ap );
163 /* empty function useful for setting a breakpoint to catch errors */
177 /* we don't handle tracing levels in stand-alone mode; */
179 #define FT_TRACE5( varformat ) FT_Message varformat
182 #define FT_TRACE7( varformat ) FT_Message varformat
185 #define FT_ERROR( varformat ) FT_Message varformat
188 #define FT_THROW( e ) \
189 ( FT_Throw( FT_ERR_CAT( ErrRaster, e ), \
192 FT_ERR_CAT( ErrRaster, e ) )
194 #else /* !FT_DEBUG_LEVEL_TRACE */
196 #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */
197 #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */
198 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
199 #define FT_THROW( e ) FT_ERR_CAT( ErrRaster_, e )
202 #endif /* !FT_DEBUG_LEVEL_TRACE */
205 #define FT_DEFINE_OUTLINE_FUNCS( class_, \
206 move_to_, line_to_, \
207 conic_to_, cubic_to_, \
209 static const FT_Outline_Funcs class_ = \
219 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \
220 raster_new_, raster_reset_, \
221 raster_set_mode_, raster_render_, \
223 const FT_Raster_Funcs class_ = \
234 #else /* !_STANDALONE_ */
237 #include <ft2build.h>
239 #include FT_INTERNAL_OBJECTS_H
240 #include FT_INTERNAL_DEBUG_H
241 #include FT_OUTLINE_H
243 #include "ftsmerrs.h"
247 #define Smooth_Err_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
248 #define Smooth_Err_Memory_Overflow Smooth_Err_Out_Of_Memory
249 #define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory
252 #endif /* !_STANDALONE_ */
256 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
260 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
263 /* as usual, for the speed hungry :-) */
270 #ifndef FT_STATIC_RASTER
272 #define RAS_ARG gray_PWorker worker
273 #define RAS_ARG_ gray_PWorker worker,
275 #define RAS_VAR worker
276 #define RAS_VAR_ worker,
278 #else /* FT_STATIC_RASTER */
280 #define RAS_ARG /* empty */
281 #define RAS_ARG_ /* empty */
282 #define RAS_VAR /* empty */
283 #define RAS_VAR_ /* empty */
285 #endif /* FT_STATIC_RASTER */
288 /* must be at least 6 bits! */
296 #define ONE_PIXEL ( 1L << PIXEL_BITS )
297 #define PIXEL_MASK ( -1L << PIXEL_BITS )
298 #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
299 #define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS )
300 #define FLOOR( x ) ( (x) & -ONE_PIXEL )
301 #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
302 #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
305 #define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) )
306 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
308 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
309 #define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
313 /*************************************************************************/
315 /* TYPE DEFINITIONS */
318 /* don't change the following types to FT_Int or FT_Pos, since we might */
319 /* need to define them to "float" or "double" when experimenting with */
322 typedef long TCoord; /* integer scanline/pixel coordinate */
323 typedef long TPos; /* sub-pixel coordinate */
325 /* determine the type used to store cell areas. This normally takes at */
326 /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */
327 /* `long' instead of `int', otherwise bad things happen */
333 #else /* PIXEL_BITS >= 8 */
335 /* approximately determine the size of integers using an ANSI-C header */
336 #if FT_UINT_MAX == 0xFFFFU
342 #endif /* PIXEL_BITS >= 8 */
345 /* maximum number of gray spans in a call to the span callback */
346 #define FT_MAX_GRAY_SPANS 32
349 typedef struct TCell_* PCell;
351 typedef struct TCell_
353 TPos x; /* same with gray_TWorker.ex */
354 TCoord cover; /* same with gray_TWorker.cover */
361 typedef struct gray_TWorker_
366 TPos count_ex, count_ey;
373 FT_PtrDist max_cells;
374 FT_PtrDist num_cells;
381 FT_Vector bez_stack[32 * 3 + 1];
388 FT_Span gray_spans[FT_MAX_GRAY_SPANS];
391 FT_Raster_Span_Func render_span;
392 void* render_span_data;
398 ft_jmp_buf jump_buffer;
406 } gray_TWorker, *gray_PWorker;
409 #ifndef FT_STATIC_RASTER
410 #define ras (*worker)
412 static gray_TWorker ras;
416 typedef struct gray_TRaster_
424 } gray_TRaster, *gray_PRaster;
428 /*************************************************************************/
430 /* Initialize the cells table. */
433 gray_init_cells( RAS_ARG_ void* buffer,
437 ras.buffer_size = byte_size;
439 ras.ycells = (PCell*) buffer;
449 /*************************************************************************/
451 /* Compute the outline bounding box. */
454 gray_compute_cbox( RAS_ARG )
456 FT_Outline* outline = &ras.outline;
457 FT_Vector* vec = outline->points;
458 FT_Vector* limit = vec + outline->n_points;
461 if ( outline->n_points <= 0 )
463 ras.min_ex = ras.max_ex = 0;
464 ras.min_ey = ras.max_ey = 0;
468 ras.min_ex = ras.max_ex = vec->x;
469 ras.min_ey = ras.max_ey = vec->y;
473 for ( ; vec < limit; vec++ )
479 if ( x < ras.min_ex ) ras.min_ex = x;
480 if ( x > ras.max_ex ) ras.max_ex = x;
481 if ( y < ras.min_ey ) ras.min_ey = y;
482 if ( y > ras.max_ey ) ras.max_ey = y;
485 /* truncate the bounding box to integer pixels */
486 ras.min_ex = ras.min_ex >> 6;
487 ras.min_ey = ras.min_ey >> 6;
488 ras.max_ex = ( ras.max_ex + 63 ) >> 6;
489 ras.max_ey = ( ras.max_ey + 63 ) >> 6;
493 /*************************************************************************/
495 /* Record the current cell in the table. */
498 gray_find_cell( RAS_ARG )
504 if ( x > ras.count_ex )
507 pcell = &ras.ycells[ras.ey];
511 if ( cell == NULL || cell->x > x )
520 if ( ras.num_cells >= ras.max_cells )
521 ft_longjmp( ras.jump_buffer, 1 );
523 cell = ras.cells + ras.num_cells++;
537 gray_record_cell( RAS_ARG )
539 if ( !ras.invalid && ( ras.area | ras.cover ) )
541 PCell cell = gray_find_cell( RAS_VAR );
544 cell->area += ras.area;
545 cell->cover += ras.cover;
550 /*************************************************************************/
552 /* Set the current cell to a new position. */
555 gray_set_cell( RAS_ARG_ TCoord ex,
558 /* Move the cell pointer to a new position. We set the `invalid' */
559 /* flag to indicate that the cell isn't part of those we're interested */
560 /* in during the render phase. This means that: */
562 /* . the new vertical position must be within min_ey..max_ey-1. */
563 /* . the new horizontal position must be strictly less than max_ex */
565 /* Note that if a cell is to the left of the clipping region, it is */
566 /* actually set to the (min_ex-1) horizontal position. */
568 /* All cells that are on the left of the clipping region go to the */
569 /* min_ex - 1 horizontal position. */
572 if ( ex > ras.max_ex )
579 /* are we moving to a different cell ? */
580 if ( ex != ras.ex || ey != ras.ey )
582 /* record the current one if it is valid */
584 gray_record_cell( RAS_VAR );
592 ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
593 ex >= ras.count_ex );
597 /*************************************************************************/
599 /* Start a new contour at a given cell. */
602 gray_start_cell( RAS_ARG_ TCoord ex,
605 if ( ex > ras.max_ex )
606 ex = (TCoord)( ras.max_ex );
608 if ( ex < ras.min_ex )
609 ex = (TCoord)( ras.min_ex - 1 );
613 ras.ex = ex - ras.min_ex;
614 ras.ey = ey - ras.min_ey;
615 ras.last_ey = SUBPIXELS( ey );
618 gray_set_cell( RAS_VAR_ ex, ey );
622 /*************************************************************************/
624 /* Render a scanline as one or more cells. */
627 gray_render_scanline( RAS_ARG_ TCoord ey,
633 TCoord ex1, ex2, fx1, fx2, delta, mod, lift, rem;
642 fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
643 fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
645 /* trivial case. Happens often */
648 gray_set_cell( RAS_VAR_ ex2, ey );
652 /* everything is located in a single cell. That is easy! */
657 ras.area += (TArea)(( fx1 + fx2 ) * delta);
662 /* ok, we'll have to render a run of adjacent cells on the same */
665 p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
671 p = fx1 * ( y2 - y1 );
677 delta = (TCoord)( p / dx );
678 mod = (TCoord)( p % dx );
685 ras.area += (TArea)(( fx1 + first ) * delta);
689 gray_set_cell( RAS_VAR_ ex1, ey );
694 p = ONE_PIXEL * ( y2 - y1 + delta );
695 lift = (TCoord)( p / dx );
696 rem = (TCoord)( p % dx );
715 ras.area += (TArea)(ONE_PIXEL * delta);
719 gray_set_cell( RAS_VAR_ ex1, ey );
724 ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
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, mod;
740 int delta, rem, lift, incr;
743 ey1 = TRUNC( ras.last_ey );
744 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
745 fy1 = (TCoord)( ras.y - ras.last_ey );
746 fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
751 /* XXX: we should do something about the trivial case where dx == 0, */
752 /* as it happens very often! */
754 /* perform vertical clipping */
766 if ( min >= ras.max_ey || max < ras.min_ey )
770 /* everything is on a single scanline */
773 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
777 /* vertical line - avoid calling gray_render_scanline */
782 TCoord ex = TRUNC( ras.x );
783 TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
794 delta = (int)( first - fy1 );
795 ras.area += (TArea)two_fx * delta;
799 gray_set_cell( RAS_VAR_ ex, ey1 );
801 delta = (int)( first + first - ONE_PIXEL );
802 area = (TArea)two_fx * delta;
809 gray_set_cell( RAS_VAR_ ex, ey1 );
812 delta = (int)( fy2 - ONE_PIXEL + first );
813 ras.area += (TArea)two_fx * delta;
819 /* ok, we have to render several scanlines */
820 p = ( ONE_PIXEL - fy1 ) * dx;
832 delta = (int)( p / dy );
833 mod = (int)( p % dy );
841 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
844 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
849 lift = (int)( p / dy );
850 rem = (int)( p % dy );
869 gray_render_scanline( RAS_VAR_ ey1, x,
870 (TCoord)( ONE_PIXEL - first ), x2,
875 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
879 gray_render_scanline( RAS_VAR_ ey1, x,
880 (TCoord)( ONE_PIXEL - first ), to_x,
886 ras.last_ey = SUBPIXELS( ey2 );
891 gray_split_conic( FT_Vector* base )
896 base[4].x = base[2].x;
898 a = base[3].x = ( base[2].x + b ) / 2;
899 b = base[1].x = ( base[0].x + b ) / 2;
900 base[2].x = ( a + b ) / 2;
902 base[4].y = base[2].y;
904 a = base[3].y = ( base[2].y + b ) / 2;
905 b = base[1].y = ( base[0].y + b ) / 2;
906 base[2].y = ( a + b ) / 2;
911 gray_render_conic( RAS_ARG_ const FT_Vector* control,
912 const FT_Vector* to )
921 levels = ras.lev_stack;
924 arc[0].x = UPSCALE( to->x );
925 arc[0].y = UPSCALE( to->y );
926 arc[1].x = UPSCALE( control->x );
927 arc[1].y = UPSCALE( control->y );
932 dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
933 dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
937 if ( dx < ONE_PIXEL / 4 )
940 /* short-cut the arc that crosses the current band */
941 min = max = arc[0].y;
944 if ( y < min ) min = y;
945 if ( y > max ) max = y;
948 if ( y < min ) min = y;
949 if ( y > max ) max = y;
951 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
959 } while ( dx > ONE_PIXEL / 4 );
968 gray_split_conic( arc );
971 levels[top] = levels[top - 1] = level - 1;
976 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
980 } while ( top >= 0 );
985 gray_split_cubic( FT_Vector* base )
990 base[6].x = base[3].x;
993 base[1].x = a = ( base[0].x + c ) / 2;
994 base[5].x = b = ( base[3].x + d ) / 2;
996 base[2].x = a = ( a + c ) / 2;
997 base[4].x = b = ( b + c ) / 2;
998 base[3].x = ( a + b ) / 2;
1000 base[6].y = base[3].y;
1003 base[1].y = a = ( base[0].y + c ) / 2;
1004 base[5].y = b = ( base[3].y + d ) / 2;
1006 base[2].y = a = ( a + c ) / 2;
1007 base[4].y = b = ( b + c ) / 2;
1008 base[3].y = ( a + b ) / 2;
1013 gray_render_cubic( RAS_ARG_ const FT_Vector* control1,
1014 const FT_Vector* control2,
1015 const FT_Vector* to )
1021 arc = ras.bez_stack;
1022 arc[0].x = UPSCALE( to->x );
1023 arc[0].y = UPSCALE( to->y );
1024 arc[1].x = UPSCALE( control2->x );
1025 arc[1].y = UPSCALE( control2->y );
1026 arc[2].x = UPSCALE( control1->x );
1027 arc[2].y = UPSCALE( control1->y );
1031 /* Short-cut the arc that crosses the current band. */
1032 min = max = arc[0].y;
1052 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
1057 /* Decide whether to split or draw. See `Rapid Termination */
1058 /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
1060 /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
1063 TPos dx, dy, dx_, dy_;
1064 TPos dx1, dy1, dx2, dy2;
1068 /* dx and dy are x and y components of the P0-P3 chord vector. */
1069 dx = arc[3].x - arc[0].x;
1070 dy = arc[3].y - arc[0].y;
1072 /* L is an (under)estimate of the Euclidean distance P0-P3. */
1074 /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated */
1075 /* with least maximum error by */
1077 /* r_upperbound = dx + (sqrt(2) - 1) * dy , */
1079 /* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */
1080 /* error of no more than 8.4%. */
1082 /* Similarly, some elementary calculus shows that r can be */
1083 /* underestimated with least maximum error by */
1085 /* r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx */
1086 /* + sqrt(2 - sqrt(2)) / 2 * dy . */
1088 /* 236/256 and 97/256 are (under)estimates of the two algebraic */
1089 /* numbers, giving an error of no more than 8.1%. */
1094 /* This is the same as */
1096 /* L = ( 236 * FT_MAX( dx_, dy_ ) */
1097 /* + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */
1098 L = ( dx_ > dy_ ? 236 * dx_ + 97 * dy_
1099 : 97 * dx_ + 236 * dy_ ) >> 8;
1101 /* Avoid possible arithmetic overflow below by splitting. */
1105 /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
1106 s_limit = L * (TPos)( ONE_PIXEL / 6 );
1108 /* s is L * the perpendicular distance from P1 to the line P0-P3. */
1109 dx1 = arc[1].x - arc[0].x;
1110 dy1 = arc[1].y - arc[0].y;
1111 s = FT_ABS( dy * dx1 - dx * dy1 );
1116 /* s is L * the perpendicular distance from P2 to the line P0-P3. */
1117 dx2 = arc[2].x - arc[0].x;
1118 dy2 = arc[2].y - arc[0].y;
1119 s = FT_ABS( dy * dx2 - dx * dy2 );
1124 /* Split super curvy segments where the off points are so far
1125 from the chord that the angles P0-P1-P3 or P0-P2-P3 become
1126 acute as detected by appropriate dot products. */
1127 if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 ||
1128 dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 )
1131 /* No reason to split. */
1136 gray_split_cubic( arc );
1141 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1143 if ( arc == ras.bez_stack )
1152 gray_move_to( const FT_Vector* to,
1153 gray_PWorker worker )
1158 /* record current cell, if any */
1159 gray_record_cell( RAS_VAR );
1161 /* start to a new position */
1162 x = UPSCALE( to->x );
1163 y = UPSCALE( to->y );
1165 gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
1174 gray_line_to( const FT_Vector* to,
1175 gray_PWorker worker )
1177 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
1183 gray_conic_to( const FT_Vector* control,
1184 const FT_Vector* to,
1185 gray_PWorker worker )
1187 gray_render_conic( RAS_VAR_ control, to );
1193 gray_cubic_to( const FT_Vector* control1,
1194 const FT_Vector* control2,
1195 const FT_Vector* to,
1196 gray_PWorker worker )
1198 gray_render_cubic( RAS_VAR_ control1, control2, to );
1204 gray_render_span( int y,
1206 const FT_Span* spans,
1207 gray_PWorker worker )
1210 FT_Bitmap* map = &worker->target;
1213 /* first of all, compute the scanline offset */
1214 p = (unsigned char*)map->buffer - y * map->pitch;
1215 if ( map->pitch >= 0 )
1216 p += (unsigned)( ( map->rows - 1 ) * map->pitch );
1218 for ( ; count > 0; count--, spans++ )
1220 unsigned char coverage = spans->coverage;
1225 /* For small-spans it is faster to do it by ourselves than
1226 * calling `memset'. This is mainly due to the cost of the
1229 if ( spans->len >= 8 )
1230 FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
1233 unsigned char* q = p + spans->x;
1236 switch ( spans->len )
1238 case 7: *q++ = (unsigned char)coverage;
1239 case 6: *q++ = (unsigned char)coverage;
1240 case 5: *q++ = (unsigned char)coverage;
1241 case 4: *q++ = (unsigned char)coverage;
1242 case 3: *q++ = (unsigned char)coverage;
1243 case 2: *q++ = (unsigned char)coverage;
1244 case 1: *q = (unsigned char)coverage;
1255 gray_hline( RAS_ARG_ TCoord x,
1265 /* compute the coverage line's coverage, depending on the */
1266 /* outline fill rule */
1268 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1270 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
1271 /* use range 0..256 */
1273 coverage = -coverage;
1275 if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
1279 if ( coverage > 256 )
1280 coverage = 512 - coverage;
1281 else if ( coverage == 256 )
1286 /* normal non-zero winding rule */
1287 if ( coverage >= 256 )
1291 y += (TCoord)ras.min_ey;
1292 x += (TCoord)ras.min_ex;
1294 /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
1298 /* FT_Span.y is an integer, so limit our coordinates appropriately */
1299 if ( y >= FT_INT_MAX )
1304 /* see whether we can add this span to the current list */
1305 count = ras.num_gray_spans;
1306 span = ras.gray_spans + count - 1;
1309 (int)span->x + span->len == (int)x &&
1310 span->coverage == coverage )
1312 span->len = (unsigned short)( span->len + acount );
1316 if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
1318 if ( ras.render_span && count > 0 )
1319 ras.render_span( ras.span_y, count, ras.gray_spans,
1320 ras.render_span_data );
1322 #ifdef FT_DEBUG_LEVEL_TRACE
1329 FT_TRACE7(( "y = %3d ", ras.span_y ));
1330 span = ras.gray_spans;
1331 for ( n = 0; n < count; n++, span++ )
1332 FT_TRACE7(( "[%d..%d]:%02x ",
1333 span->x, span->x + span->len - 1, span->coverage ));
1334 FT_TRACE7(( "\n" ));
1337 #endif /* FT_DEBUG_LEVEL_TRACE */
1339 ras.num_gray_spans = 0;
1340 ras.span_y = (int)y;
1343 span = ras.gray_spans;
1348 /* add a gray span to the current list */
1350 span->len = (unsigned short)acount;
1351 span->coverage = (unsigned char)coverage;
1353 ras.num_gray_spans++;
1358 #ifdef FT_DEBUG_LEVEL_TRACE
1360 /* to be called while in the debugger -- */
1361 /* this function causes a compiler warning since it is unused otherwise */
1363 gray_dump_cells( RAS_ARG )
1368 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1373 printf( "%3d:", yindex );
1375 for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
1376 printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area );
1381 #endif /* FT_DEBUG_LEVEL_TRACE */
1385 gray_sweep( RAS_ARG_ const FT_Bitmap* target )
1389 FT_UNUSED( target );
1392 if ( ras.num_cells == 0 )
1395 ras.num_gray_spans = 0;
1397 FT_TRACE7(( "gray_sweep: start\n" ));
1399 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1401 PCell cell = ras.ycells[yindex];
1406 for ( ; cell != NULL; cell = cell->next )
1411 if ( cell->x > x && cover != 0 )
1412 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1415 cover += cell->cover;
1416 area = cover * ( ONE_PIXEL * 2 ) - cell->area;
1418 if ( area != 0 && cell->x >= 0 )
1419 gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
1425 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1429 if ( ras.render_span && ras.num_gray_spans > 0 )
1430 ras.render_span( ras.span_y, ras.num_gray_spans,
1431 ras.gray_spans, ras.render_span_data );
1433 #ifdef FT_DEBUG_LEVEL_TRACE
1435 if ( ras.num_gray_spans > 0 )
1441 FT_TRACE7(( "y = %3d ", ras.span_y ));
1442 span = ras.gray_spans;
1443 for ( n = 0; n < ras.num_gray_spans; n++, span++ )
1444 FT_TRACE7(( "[%d..%d]:%02x ",
1445 span->x, span->x + span->len - 1, span->coverage ));
1446 FT_TRACE7(( "\n" ));
1449 FT_TRACE7(( "gray_sweep: end\n" ));
1451 #endif /* FT_DEBUG_LEVEL_TRACE */
1458 /*************************************************************************/
1460 /* The following function should only compile in stand-alone mode, */
1461 /* i.e., when building this component without the rest of FreeType. */
1463 /*************************************************************************/
1465 /*************************************************************************/
1468 /* FT_Outline_Decompose */
1471 /* Walk over an outline's structure to decompose it into individual */
1472 /* segments and Bézier arcs. This function is also able to emit */
1473 /* `move to' and `close to' operations to indicate the start and end */
1474 /* of new contours in the outline. */
1477 /* outline :: A pointer to the source target. */
1479 /* func_interface :: A table of `emitters', i.e., function pointers */
1480 /* called during decomposition to indicate path */
1484 /* user :: A typeless pointer which is passed to each */
1485 /* emitter during the decomposition. It can be */
1486 /* used to store the state during the */
1487 /* decomposition. */
1490 /* Error code. 0 means success. */
1493 FT_Outline_Decompose( const FT_Outline* outline,
1494 const FT_Outline_Funcs* func_interface,
1498 #define SCALED( x ) ( ( (x) << shift ) - delta )
1501 FT_Vector v_control;
1510 int n; /* index of contour in outline */
1511 int first; /* index of first point in contour */
1512 char tag; /* current point's state */
1518 if ( !outline || !func_interface )
1519 return FT_THROW( Invalid_Argument );
1521 shift = func_interface->shift;
1522 delta = func_interface->delta;
1525 for ( n = 0; n < outline->n_contours; n++ )
1527 int last; /* index of last point in contour */
1530 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
1532 last = outline->contours[n];
1534 goto Invalid_Outline;
1535 limit = outline->points + last;
1537 v_start = outline->points[first];
1538 v_start.x = SCALED( v_start.x );
1539 v_start.y = SCALED( v_start.y );
1541 v_last = outline->points[last];
1542 v_last.x = SCALED( v_last.x );
1543 v_last.y = SCALED( v_last.y );
1545 v_control = v_start;
1547 point = outline->points + first;
1548 tags = outline->tags + first;
1549 tag = FT_CURVE_TAG( tags[0] );
1551 /* A contour cannot start with a cubic control point! */
1552 if ( tag == FT_CURVE_TAG_CUBIC )
1553 goto Invalid_Outline;
1555 /* check first point to determine origin */
1556 if ( tag == FT_CURVE_TAG_CONIC )
1558 /* first point is conic control. Yes, this happens. */
1559 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
1561 /* start at last point if it is on the curve */
1567 /* if both first and last points are conic, */
1568 /* start at their middle and record its position */
1570 v_start.x = ( v_start.x + v_last.x ) / 2;
1571 v_start.y = ( v_start.y + v_last.y ) / 2;
1579 FT_TRACE5(( " move to (%.2f, %.2f)\n",
1580 v_start.x / 64.0, v_start.y / 64.0 ));
1581 error = func_interface->move_to( &v_start, user );
1585 while ( point < limit )
1590 tag = FT_CURVE_TAG( tags[0] );
1593 case FT_CURVE_TAG_ON: /* emit a single line_to */
1598 vec.x = SCALED( point->x );
1599 vec.y = SCALED( point->y );
1601 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1602 vec.x / 64.0, vec.y / 64.0 ));
1603 error = func_interface->line_to( &vec, user );
1609 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1610 v_control.x = SCALED( point->x );
1611 v_control.y = SCALED( point->y );
1614 if ( point < limit )
1622 tag = FT_CURVE_TAG( tags[0] );
1624 vec.x = SCALED( point->x );
1625 vec.y = SCALED( point->y );
1627 if ( tag == FT_CURVE_TAG_ON )
1629 FT_TRACE5(( " conic to (%.2f, %.2f)"
1630 " with control (%.2f, %.2f)\n",
1631 vec.x / 64.0, vec.y / 64.0,
1632 v_control.x / 64.0, v_control.y / 64.0 ));
1633 error = func_interface->conic_to( &v_control, &vec, user );
1639 if ( tag != FT_CURVE_TAG_CONIC )
1640 goto Invalid_Outline;
1642 v_middle.x = ( v_control.x + vec.x ) / 2;
1643 v_middle.y = ( v_control.y + vec.y ) / 2;
1645 FT_TRACE5(( " conic to (%.2f, %.2f)"
1646 " with control (%.2f, %.2f)\n",
1647 v_middle.x / 64.0, v_middle.y / 64.0,
1648 v_control.x / 64.0, v_control.y / 64.0 ));
1649 error = func_interface->conic_to( &v_control, &v_middle, user );
1657 FT_TRACE5(( " conic to (%.2f, %.2f)"
1658 " with control (%.2f, %.2f)\n",
1659 v_start.x / 64.0, v_start.y / 64.0,
1660 v_control.x / 64.0, v_control.y / 64.0 ));
1661 error = func_interface->conic_to( &v_control, &v_start, user );
1664 default: /* FT_CURVE_TAG_CUBIC */
1666 FT_Vector vec1, vec2;
1669 if ( point + 1 > limit ||
1670 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1671 goto Invalid_Outline;
1676 vec1.x = SCALED( point[-2].x );
1677 vec1.y = SCALED( point[-2].y );
1679 vec2.x = SCALED( point[-1].x );
1680 vec2.y = SCALED( point[-1].y );
1682 if ( point <= limit )
1687 vec.x = SCALED( point->x );
1688 vec.y = SCALED( point->y );
1690 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1691 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1692 vec.x / 64.0, vec.y / 64.0,
1693 vec1.x / 64.0, vec1.y / 64.0,
1694 vec2.x / 64.0, vec2.y / 64.0 ));
1695 error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
1701 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1702 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1703 v_start.x / 64.0, v_start.y / 64.0,
1704 vec1.x / 64.0, vec1.y / 64.0,
1705 vec2.x / 64.0, vec2.y / 64.0 ));
1706 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
1712 /* close the contour with a line segment */
1713 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1714 v_start.x / 64.0, v_start.y / 64.0 ));
1715 error = func_interface->line_to( &v_start, user );
1724 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1728 FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
1732 return FT_THROW( Invalid_Outline );
1735 #endif /* _STANDALONE_ */
1738 typedef struct gray_TBand_
1744 FT_DEFINE_OUTLINE_FUNCS(func_interface,
1745 (FT_Outline_MoveTo_Func) gray_move_to,
1746 (FT_Outline_LineTo_Func) gray_line_to,
1747 (FT_Outline_ConicTo_Func)gray_conic_to,
1748 (FT_Outline_CubicTo_Func)gray_cubic_to,
1754 gray_convert_glyph_inner( RAS_ARG )
1757 volatile int error = 0;
1759 #ifdef FT_CONFIG_OPTION_PIC
1760 FT_Outline_Funcs func_interface;
1761 Init_Class_func_interface(&func_interface);
1764 if ( ft_setjmp( ras.jump_buffer ) == 0 )
1766 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
1767 gray_record_cell( RAS_VAR );
1770 error = FT_THROW( Memory_Overflow );
1777 gray_convert_glyph( RAS_ARG )
1779 gray_TBand bands[40];
1780 gray_TBand* volatile band;
1781 int volatile n, num_bands;
1782 TPos volatile min, max, max_y;
1786 /* Set up state in the raster object */
1787 gray_compute_cbox( RAS_VAR );
1789 /* clip to target bitmap, exit if nothing to do */
1790 clip = &ras.clip_box;
1792 if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
1793 ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
1796 if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
1797 if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
1799 if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
1800 if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
1802 ras.count_ex = ras.max_ex - ras.min_ex;
1803 ras.count_ey = ras.max_ey - ras.min_ey;
1805 /* set up vertical bands */
1806 num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
1807 if ( num_bands == 0 )
1809 if ( num_bands >= 39 )
1817 for ( n = 0; n < num_bands; n++, min = max )
1819 max = min + ras.band_size;
1820 if ( n == num_bands - 1 || max > max_y )
1827 while ( band >= bands )
1829 TPos bottom, top, middle;
1835 long cell_start, cell_end, cell_mod;
1838 ras.ycells = (PCell*)ras.buffer;
1839 ras.ycount = band->max - band->min;
1841 cell_start = sizeof ( PCell ) * ras.ycount;
1842 cell_mod = cell_start % sizeof ( TCell );
1844 cell_start += sizeof ( TCell ) - cell_mod;
1846 cell_end = ras.buffer_size;
1847 cell_end -= cell_end % sizeof ( TCell );
1849 cells_max = (PCell)( (char*)ras.buffer + cell_end );
1850 ras.cells = (PCell)( (char*)ras.buffer + cell_start );
1851 if ( ras.cells >= cells_max )
1854 ras.max_cells = cells_max - ras.cells;
1855 if ( ras.max_cells < 2 )
1858 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1859 ras.ycells[yindex] = NULL;
1864 ras.min_ey = band->min;
1865 ras.max_ey = band->max;
1866 ras.count_ey = band->max - band->min;
1868 error = gray_convert_glyph_inner( RAS_VAR );
1872 gray_sweep( RAS_VAR_ &ras.target );
1876 else if ( error != ErrRaster_Memory_Overflow )
1880 /* render pool overflow; we will reduce the render band by half */
1883 middle = bottom + ( ( top - bottom ) >> 1 );
1885 /* This is too complex for a single scanline; there must */
1886 /* be some problems. */
1887 if ( middle == bottom )
1889 #ifdef FT_DEBUG_LEVEL_TRACE
1890 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
1895 if ( bottom-top >= ras.band_size )
1898 band[1].min = bottom;
1899 band[1].max = middle;
1900 band[0].min = middle;
1906 if ( ras.band_shoot > 8 && ras.band_size > 16 )
1907 ras.band_size = ras.band_size / 2;
1914 gray_raster_render( gray_PRaster raster,
1915 const FT_Raster_Params* params )
1917 const FT_Outline* outline = (const FT_Outline*)params->source;
1918 const FT_Bitmap* target_map = params->target;
1919 gray_PWorker worker;
1922 if ( !raster || !raster->buffer || !raster->buffer_size )
1923 return FT_THROW( Invalid_Argument );
1926 return FT_THROW( Invalid_Outline );
1928 /* return immediately if the outline is empty */
1929 if ( outline->n_points == 0 || outline->n_contours <= 0 )
1932 if ( !outline->contours || !outline->points )
1933 return FT_THROW( Invalid_Outline );
1935 if ( outline->n_points !=
1936 outline->contours[outline->n_contours - 1] + 1 )
1937 return FT_THROW( Invalid_Outline );
1939 worker = raster->worker;
1941 /* if direct mode is not set, we must have a target bitmap */
1942 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
1945 return FT_THROW( Invalid_Argument );
1948 if ( !target_map->width || !target_map->rows )
1951 if ( !target_map->buffer )
1952 return FT_THROW( Invalid_Argument );
1955 /* this version does not support monochrome rendering */
1956 if ( !( params->flags & FT_RASTER_FLAG_AA ) )
1957 return FT_THROW( Invalid_Mode );
1959 /* compute clipping box */
1960 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
1962 /* compute clip box from target pixmap */
1963 ras.clip_box.xMin = 0;
1964 ras.clip_box.yMin = 0;
1965 ras.clip_box.xMax = target_map->width;
1966 ras.clip_box.yMax = target_map->rows;
1968 else if ( params->flags & FT_RASTER_FLAG_CLIP )
1969 ras.clip_box = params->clip_box;
1972 ras.clip_box.xMin = -32768L;
1973 ras.clip_box.yMin = -32768L;
1974 ras.clip_box.xMax = 32767L;
1975 ras.clip_box.yMax = 32767L;
1978 gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size );
1980 ras.outline = *outline;
1983 ras.band_size = raster->band_size;
1984 ras.num_gray_spans = 0;
1986 if ( params->flags & FT_RASTER_FLAG_DIRECT )
1988 ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
1989 ras.render_span_data = params->user;
1993 ras.target = *target_map;
1994 ras.render_span = (FT_Raster_Span_Func)gray_render_span;
1995 ras.render_span_data = &ras;
1998 return gray_convert_glyph( RAS_VAR );
2002 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
2003 /**** a static object. *****/
2008 gray_raster_new( void* memory,
2009 FT_Raster* araster )
2011 static gray_TRaster the_raster;
2013 FT_UNUSED( memory );
2016 *araster = (FT_Raster)&the_raster;
2017 FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
2024 gray_raster_done( FT_Raster raster )
2027 FT_UNUSED( raster );
2030 #else /* !_STANDALONE_ */
2033 gray_raster_new( FT_Memory memory,
2034 FT_Raster* araster )
2037 gray_PRaster raster = NULL;
2041 if ( !FT_ALLOC( raster, sizeof ( gray_TRaster ) ) )
2043 raster->memory = memory;
2044 *araster = (FT_Raster)raster;
2052 gray_raster_done( FT_Raster raster )
2054 FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory;
2060 #endif /* !_STANDALONE_ */
2064 gray_raster_reset( FT_Raster raster,
2068 gray_PRaster rast = (gray_PRaster)raster;
2073 if ( pool_base && pool_size >= (long)sizeof ( gray_TWorker ) + 2048 )
2075 gray_PWorker worker = (gray_PWorker)pool_base;
2078 rast->worker = worker;
2079 rast->buffer = pool_base +
2080 ( ( sizeof ( gray_TWorker ) +
2081 sizeof ( TCell ) - 1 ) &
2082 ~( sizeof ( TCell ) - 1 ) );
2083 rast->buffer_size = (long)( ( pool_base + pool_size ) -
2084 (char*)rast->buffer ) &
2085 ~( sizeof ( TCell ) - 1 );
2086 rast->band_size = (int)( rast->buffer_size /
2087 ( sizeof ( TCell ) * 8 ) );
2091 rast->buffer = NULL;
2092 rast->buffer_size = 0;
2093 rast->worker = NULL;
2099 FT_DEFINE_RASTER_FUNCS(ft_grays_raster,
2100 FT_GLYPH_FORMAT_OUTLINE,
2102 (FT_Raster_New_Func) gray_raster_new,
2103 (FT_Raster_Reset_Func) gray_raster_reset,
2104 (FT_Raster_Set_Mode_Func)0,
2105 (FT_Raster_Render_Func) gray_raster_render,
2106 (FT_Raster_Done_Func) gray_raster_done
2113 /* Local Variables: */