[FREETYPE] Update to v2.7.1. Patch by Katayama Hirofumi MZ, verified by me. CORE...
[reactos.git] / reactos / sdk / lib / 3rdparty / freetype / src / smooth / ftgrays.c
1 /***************************************************************************/
2 /* */
3 /* ftgrays.c */
4 /* */
5 /* A new `perfect' anti-aliasing renderer (body). */
6 /* */
7 /* Copyright 2000-2016 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17
18 /*************************************************************************/
19 /* */
20 /* This file can be compiled without the rest of the FreeType engine, by */
21 /* defining the STANDALONE_ macro when compiling it. You also need to */
22 /* put the files `ftgrays.h' and `ftimage.h' into the current */
23 /* compilation directory. Typically, you could do something like */
24 /* */
25 /* - copy `src/smooth/ftgrays.c' (this file) to your current directory */
26 /* */
27 /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
28 /* same directory */
29 /* */
30 /* - compile `ftgrays' with the STANDALONE_ macro defined, as in */
31 /* */
32 /* cc -c -DSTANDALONE_ ftgrays.c */
33 /* */
34 /* The renderer can be initialized with a call to */
35 /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */
36 /* with a call to `ft_gray_raster.raster_render'. */
37 /* */
38 /* See the comments and documentation in the file `ftimage.h' for more */
39 /* details on how the raster works. */
40 /* */
41 /*************************************************************************/
42
43 /*************************************************************************/
44 /* */
45 /* This is a new anti-aliasing scan-converter for FreeType 2. The */
46 /* algorithm used here is _very_ different from the one in the standard */
47 /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */
48 /* coverage of the outline on each pixel cell. */
49 /* */
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). */
55 /* */
56 /* Note, however, that this is a _very_ different implementation */
57 /* compared to Raph's. Coverage information is stored in a very */
58 /* different way, and I don't use sorted vector paths. Also, it doesn't */
59 /* use floating point values. */
60 /* */
61 /* This renderer has the following advantages: */
62 /* */
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 */
67 /* callback. */
68 /* */
69 /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */
70 /* each pixel cell. */
71 /* */
72 /* - It performs a single pass on the outline (the `standard' FT2 */
73 /* renderer makes two passes). */
74 /* */
75 /* - It can easily be modified to render to _any_ number of gray levels */
76 /* cheaply. */
77 /* */
78 /* - For small (< 20) pixel sizes, it is faster than the standard */
79 /* renderer. */
80 /* */
81 /*************************************************************************/
82
83
84 /*************************************************************************/
85 /* */
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. */
89 /* */
90 #undef FT_COMPONENT
91 #define FT_COMPONENT trace_smooth
92
93
94 #ifdef STANDALONE_
95
96
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
100
101
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 )
105
106 #define FT_BEGIN_STMNT do {
107 #define FT_END_STMNT } while ( 0 )
108
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) )
112
113
114 /*
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.
118 */
119 #define FT_HYPOT( x, y ) \
120 ( x = FT_ABS( x ), \
121 y = FT_ABS( y ), \
122 x > y ? x + ( 3 * y >> 3 ) \
123 : y + ( 3 * x >> 3 ) )
124
125
126 /* define this to dump debugging information */
127 /* #define FT_DEBUG_LEVEL_TRACE */
128
129
130 #ifdef FT_DEBUG_LEVEL_TRACE
131 #include <stdio.h>
132 #include <stdarg.h>
133 #endif
134
135 #include <stddef.h>
136 #include <string.h>
137 #include <setjmp.h>
138 #include <limits.h>
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
143
144 #define ft_memset memset
145
146 #define ft_setjmp setjmp
147 #define ft_longjmp longjmp
148 #define ft_jmp_buf jmp_buf
149
150 typedef ptrdiff_t FT_PtrDist;
151
152
153 #define ErrRaster_Invalid_Mode -2
154 #define ErrRaster_Invalid_Outline -1
155 #define ErrRaster_Invalid_Argument -3
156 #define ErrRaster_Memory_Overflow -4
157
158 #define FT_BEGIN_HEADER
159 #define FT_END_HEADER
160
161 #include "ftimage.h"
162 #include "ftgrays.h"
163
164
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)
170
171
172 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
173
174 #ifdef FT_DEBUG_LEVEL_TRACE
175
176 void
177 FT_Message( const char* fmt,
178 ... )
179 {
180 va_list ap;
181
182
183 va_start( ap, fmt );
184 vfprintf( stderr, fmt, ap );
185 va_end( ap );
186 }
187
188
189 /* empty function useful for setting a breakpoint to catch errors */
190 int
191 FT_Throw( int error,
192 int line,
193 const char* file )
194 {
195 FT_UNUSED( error );
196 FT_UNUSED( line );
197 FT_UNUSED( file );
198
199 return 0;
200 }
201
202
203 /* we don't handle tracing levels in stand-alone mode; */
204 #ifndef FT_TRACE5
205 #define FT_TRACE5( varformat ) FT_Message varformat
206 #endif
207 #ifndef FT_TRACE7
208 #define FT_TRACE7( varformat ) FT_Message varformat
209 #endif
210 #ifndef FT_ERROR
211 #define FT_ERROR( varformat ) FT_Message varformat
212 #endif
213
214 #define FT_THROW( e ) \
215 ( FT_Throw( FT_ERR_CAT( ErrRaster, e ), \
216 __LINE__, \
217 __FILE__ ) | \
218 FT_ERR_CAT( ErrRaster, e ) )
219
220 #else /* !FT_DEBUG_LEVEL_TRACE */
221
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 )
226
227
228 #endif /* !FT_DEBUG_LEVEL_TRACE */
229
230
231 #define FT_DEFINE_OUTLINE_FUNCS( class_, \
232 move_to_, line_to_, \
233 conic_to_, cubic_to_, \
234 shift_, delta_ ) \
235 static const FT_Outline_Funcs class_ = \
236 { \
237 move_to_, \
238 line_to_, \
239 conic_to_, \
240 cubic_to_, \
241 shift_, \
242 delta_ \
243 };
244
245 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \
246 raster_new_, raster_reset_, \
247 raster_set_mode_, raster_render_, \
248 raster_done_ ) \
249 const FT_Raster_Funcs class_ = \
250 { \
251 glyph_format_, \
252 raster_new_, \
253 raster_reset_, \
254 raster_set_mode_, \
255 raster_render_, \
256 raster_done_ \
257 };
258
259
260 #else /* !STANDALONE_ */
261
262
263 #include <ft2build.h>
264 #include "ftgrays.h"
265 #include FT_INTERNAL_OBJECTS_H
266 #include FT_INTERNAL_DEBUG_H
267 #include FT_OUTLINE_H
268
269 #include "ftsmerrs.h"
270
271 #include "ftspic.h"
272
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
276
277
278 #endif /* !STANDALONE_ */
279
280
281 #ifndef FT_MEM_SET
282 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
283 #endif
284
285 #ifndef FT_MEM_ZERO
286 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
287 #endif
288
289 #ifndef FT_ZERO
290 #define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) )
291 #endif
292
293 /* as usual, for the speed hungry :-) */
294
295 #undef RAS_ARG
296 #undef RAS_ARG_
297 #undef RAS_VAR
298 #undef RAS_VAR_
299
300 #ifndef FT_STATIC_RASTER
301
302 #define RAS_ARG gray_PWorker worker
303 #define RAS_ARG_ gray_PWorker worker,
304
305 #define RAS_VAR worker
306 #define RAS_VAR_ worker,
307
308 #else /* FT_STATIC_RASTER */
309
310 #define RAS_ARG void
311 #define RAS_ARG_ /* empty */
312 #define RAS_VAR /* empty */
313 #define RAS_VAR_ /* empty */
314
315 #endif /* FT_STATIC_RASTER */
316
317
318 /* must be at least 6 bits! */
319 #define PIXEL_BITS 8
320
321 #undef FLOOR
322 #undef CEILING
323 #undef TRUNC
324 #undef SCALED
325
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 )
332
333 #if PIXEL_BITS >= 6
334 #define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
335 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
336 #else
337 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
338 #define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) )
339 #endif
340
341
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 ) \
346 FT_BEGIN_STMNT \
347 (quotient) = (type)( (dividend) / (divisor) ); \
348 (remainder) = (type)( (dividend) % (divisor) ); \
349 if ( (remainder) < 0 ) \
350 { \
351 (quotient)--; \
352 (remainder) += (type)(divisor); \
353 } \
354 FT_END_STMNT
355
356 #ifdef __arm__
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 */
360 /* */
361 /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */
362 #undef FT_DIV_MOD
363 #define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
364 FT_BEGIN_STMNT \
365 (quotient) = (type)( (dividend) / (divisor) ); \
366 (remainder) = (type)( (dividend) - (quotient) * (divisor) ); \
367 if ( (remainder) < 0 ) \
368 { \
369 (quotient)--; \
370 (remainder) += (type)(divisor); \
371 } \
372 FT_END_STMNT
373 #endif /* __arm__ */
374
375
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 ) \
380 : 0
381 #define FT_UDIV( a, b ) \
382 ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \
383 ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) )
384
385
386 /*************************************************************************/
387 /* */
388 /* TYPE DEFINITIONS */
389 /* */
390
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 */
393 /* new algorithms */
394
395 typedef long TPos; /* sub-pixel coordinate */
396 typedef int TCoord; /* integer scanline/pixel coordinate */
397 typedef int TArea; /* cell areas, coordinate products */
398
399
400 typedef struct TCell_* PCell;
401
402 typedef struct TCell_
403 {
404 TCoord x; /* same with gray_TWorker.ex */
405 TCoord cover; /* same with gray_TWorker.cover */
406 TArea area;
407 PCell next;
408
409 } TCell;
410
411 typedef struct TPixmap_
412 {
413 unsigned char* origin; /* pixmap origin at the bottom-left */
414 int pitch; /* pitch to go down one row */
415
416 } TPixmap;
417
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 ) )
421 #else
422 #define FT_MAX_GRAY_POOL ( 2048 / sizeof ( TCell ) )
423 #endif
424
425
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 */
433
434 typedef struct gray_TWorker_
435 {
436 ft_jmp_buf jump_buffer;
437
438 TCoord ex, ey;
439 TCoord min_ex, max_ex;
440 TCoord min_ey, max_ey;
441
442 TArea area;
443 TCoord cover;
444 int invalid;
445
446 PCell* ycells;
447 PCell cells;
448 FT_PtrDist max_cells;
449 FT_PtrDist num_cells;
450
451 TPos x, y;
452
453 FT_Outline outline;
454 TPixmap target;
455
456 FT_Raster_Span_Func render_span;
457 void* render_span_data;
458
459 } gray_TWorker, *gray_PWorker;
460
461 #if defined( _MSC_VER )
462 #pragma warning( pop )
463 #endif
464
465
466 #ifndef FT_STATIC_RASTER
467 #define ras (*worker)
468 #else
469 static gray_TWorker ras;
470 #endif
471
472
473 typedef struct gray_TRaster_
474 {
475 void* memory;
476
477 } gray_TRaster, *gray_PRaster;
478
479
480 #ifdef FT_DEBUG_LEVEL_TRACE
481
482 /* to be called while in the debugger -- */
483 /* this function causes a compiler warning since it is unused otherwise */
484 static void
485 gray_dump_cells( RAS_ARG )
486 {
487 int y;
488
489
490 for ( y = ras.min_ey; y < ras.max_ey; y++ )
491 {
492 PCell cell = ras.ycells[y - ras.min_ey];
493
494
495 printf( "%3d:", y );
496
497 for ( ; cell != NULL; cell = cell->next )
498 printf( " (%3d, c:%4d, a:%6d)",
499 cell->x, cell->cover, cell->area );
500 printf( "\n" );
501 }
502 }
503
504 #endif /* FT_DEBUG_LEVEL_TRACE */
505
506
507 /*************************************************************************/
508 /* */
509 /* Record the current cell in the table. */
510 /* */
511 static void
512 gray_record_cell( RAS_ARG )
513 {
514 PCell *pcell, cell;
515 TCoord x = ras.ex;
516
517
518 pcell = &ras.ycells[ras.ey - ras.min_ey];
519 for (;;)
520 {
521 cell = *pcell;
522 if ( !cell || cell->x > x )
523 break;
524
525 if ( cell->x == x )
526 goto Found;
527
528 pcell = &cell->next;
529 }
530
531 if ( ras.num_cells >= ras.max_cells )
532 ft_longjmp( ras.jump_buffer, 1 );
533
534 /* insert new cell */
535 cell = ras.cells + ras.num_cells++;
536 cell->x = x;
537 cell->area = ras.area;
538 cell->cover = ras.cover;
539
540 cell->next = *pcell;
541 *pcell = cell;
542
543 return;
544
545 Found:
546 /* update old cell */
547 cell->area += ras.area;
548 cell->cover += ras.cover;
549 }
550
551
552 /*************************************************************************/
553 /* */
554 /* Set the current cell to a new position. */
555 /* */
556 static void
557 gray_set_cell( RAS_ARG_ TCoord ex,
558 TCoord ey )
559 {
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: */
563 /* */
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 */
566 /* */
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. */
569
570 /* All cells that are on the left of the clipping region go to the */
571 /* min_ex - 1 horizontal position. */
572
573 if ( ex < ras.min_ex )
574 ex = ras.min_ex - 1;
575
576 /* record the current one if it is valid */
577 if ( !ras.invalid )
578 gray_record_cell( RAS_VAR );
579
580 ras.area = 0;
581 ras.cover = 0;
582 ras.ex = ex;
583 ras.ey = ey;
584
585 ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey ||
586 ex >= ras.max_ex );
587 }
588
589
590 #ifndef FT_LONG64
591
592 /*************************************************************************/
593 /* */
594 /* Render a scanline as one or more cells. */
595 /* */
596 static void
597 gray_render_scanline( RAS_ARG_ TCoord ey,
598 TPos x1,
599 TCoord y1,
600 TPos x2,
601 TCoord y2 )
602 {
603 TCoord ex1, ex2, fx1, fx2, first, delta, mod;
604 TPos p, dx;
605 int incr;
606
607
608 ex1 = TRUNC( x1 );
609 ex2 = TRUNC( x2 );
610
611 /* trivial case. Happens often */
612 if ( y1 == y2 )
613 {
614 gray_set_cell( RAS_VAR_ ex2, ey );
615 return;
616 }
617
618 fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
619 fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
620 delta = y2 - y1;
621
622 /* everything is located in a single cell. That is easy! */
623 /* */
624 if ( ex1 == ex2 )
625 {
626 ras.area += (TArea)(( fx1 + fx2 ) * delta);
627 ras.cover += delta;
628 return;
629 }
630
631 /* ok, we'll have to render a run of adjacent cells on the same */
632 /* scanline... */
633 /* */
634 dx = x2 - x1;
635
636 if ( dx > 0 )
637 {
638 p = ( ONE_PIXEL - fx1 ) * delta;
639 first = ONE_PIXEL;
640 incr = 1;
641 }
642 else
643 {
644 p = fx1 * delta;
645 first = 0;
646 incr = -1;
647 dx = -dx;
648 }
649
650 FT_DIV_MOD( TCoord, p, dx, delta, mod );
651
652 ras.area += (TArea)(( fx1 + first ) * delta);
653 ras.cover += delta;
654
655 ex1 += incr;
656 gray_set_cell( RAS_VAR_ ex1, ey );
657 y1 += delta;
658
659 if ( ex1 != ex2 )
660 {
661 TCoord lift, rem;
662
663
664 p = ONE_PIXEL * ( y2 - y1 + delta );
665 FT_DIV_MOD( TCoord, p, dx, lift, rem );
666
667 mod -= (int)dx;
668
669 do
670 {
671 delta = lift;
672 mod += rem;
673 if ( mod >= 0 )
674 {
675 mod -= (TCoord)dx;
676 delta++;
677 }
678
679 ras.area += (TArea)(ONE_PIXEL * delta);
680 ras.cover += delta;
681 y1 += delta;
682 ex1 += incr;
683 gray_set_cell( RAS_VAR_ ex1, ey );
684 } while ( ex1 != ex2 );
685 }
686
687 delta = y2 - y1;
688 ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
689 ras.cover += delta;
690 }
691
692
693 /*************************************************************************/
694 /* */
695 /* Render a given line as a series of scanlines. */
696 /* */
697 static void
698 gray_render_line( RAS_ARG_ TPos to_x,
699 TPos to_y )
700 {
701 TCoord ey1, ey2, fy1, fy2, first, delta, mod;
702 TPos p, dx, dy, x, x2;
703 int incr;
704
705
706 ey1 = TRUNC( ras.y );
707 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
708
709 /* perform vertical clipping */
710 if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
711 ( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
712 goto End;
713
714 fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
715 fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
716
717 /* everything is on a single scanline */
718 if ( ey1 == ey2 )
719 {
720 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
721 goto End;
722 }
723
724 dx = to_x - ras.x;
725 dy = to_y - ras.y;
726
727 /* vertical line - avoid calling gray_render_scanline */
728 if ( dx == 0 )
729 {
730 TCoord ex = TRUNC( ras.x );
731 TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
732 TArea area;
733
734
735 if ( dy > 0)
736 {
737 first = ONE_PIXEL;
738 incr = 1;
739 }
740 else
741 {
742 first = 0;
743 incr = -1;
744 }
745
746 delta = first - fy1;
747 ras.area += (TArea)two_fx * delta;
748 ras.cover += delta;
749 ey1 += incr;
750
751 gray_set_cell( RAS_VAR_ ex, ey1 );
752
753 delta = first + first - ONE_PIXEL;
754 area = (TArea)two_fx * delta;
755 while ( ey1 != ey2 )
756 {
757 ras.area += area;
758 ras.cover += delta;
759 ey1 += incr;
760
761 gray_set_cell( RAS_VAR_ ex, ey1 );
762 }
763
764 delta = fy2 - ONE_PIXEL + first;
765 ras.area += (TArea)two_fx * delta;
766 ras.cover += delta;
767
768 goto End;
769 }
770
771 /* ok, we have to render several scanlines */
772 if ( dy > 0)
773 {
774 p = ( ONE_PIXEL - fy1 ) * dx;
775 first = ONE_PIXEL;
776 incr = 1;
777 }
778 else
779 {
780 p = fy1 * dx;
781 first = 0;
782 incr = -1;
783 dy = -dy;
784 }
785
786 FT_DIV_MOD( TCoord, p, dy, delta, mod );
787
788 x = ras.x + delta;
789 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
790
791 ey1 += incr;
792 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
793
794 if ( ey1 != ey2 )
795 {
796 TCoord lift, rem;
797
798
799 p = ONE_PIXEL * dx;
800 FT_DIV_MOD( TCoord, p, dy, lift, rem );
801 mod -= (TCoord)dy;
802
803 do
804 {
805 delta = lift;
806 mod += rem;
807 if ( mod >= 0 )
808 {
809 mod -= (TCoord)dy;
810 delta++;
811 }
812
813 x2 = x + delta;
814 gray_render_scanline( RAS_VAR_ ey1,
815 x, ONE_PIXEL - first,
816 x2, first );
817 x = x2;
818
819 ey1 += incr;
820 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
821 } while ( ey1 != ey2 );
822 }
823
824 gray_render_scanline( RAS_VAR_ ey1,
825 x, ONE_PIXEL - first,
826 to_x, fy2 );
827
828 End:
829 ras.x = to_x;
830 ras.y = to_y;
831 }
832
833 #else
834
835 /*************************************************************************/
836 /* */
837 /* Render a straight line across multiple cells in any direction. */
838 /* */
839 static void
840 gray_render_line( RAS_ARG_ TPos to_x,
841 TPos to_y )
842 {
843 TPos dx, dy, fx1, fy1, fx2, fy2;
844 TCoord ex1, ex2, ey1, ey2;
845
846
847 ey1 = TRUNC( ras.y );
848 ey2 = TRUNC( to_y );
849
850 /* perform vertical clipping */
851 if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
852 ( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
853 goto End;
854
855 ex1 = TRUNC( ras.x );
856 ex2 = TRUNC( to_x );
857
858 fx1 = ras.x - SUBPIXELS( ex1 );
859 fy1 = ras.y - SUBPIXELS( ey1 );
860
861 dx = to_x - ras.x;
862 dy = to_y - ras.y;
863
864 if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */
865 ;
866 else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */
867 {
868 ex1 = ex2;
869 gray_set_cell( RAS_VAR_ ex1, ey1 );
870 }
871 else if ( dx == 0 )
872 {
873 if ( dy > 0 ) /* vertical line up */
874 do
875 {
876 fy2 = ONE_PIXEL;
877 ras.cover += ( fy2 - fy1 );
878 ras.area += ( fy2 - fy1 ) * fx1 * 2;
879 fy1 = 0;
880 ey1++;
881 gray_set_cell( RAS_VAR_ ex1, ey1 );
882 } while ( ey1 != ey2 );
883 else /* vertical line down */
884 do
885 {
886 fy2 = 0;
887 ras.cover += ( fy2 - fy1 );
888 ras.area += ( fy2 - fy1 ) * fx1 * 2;
889 fy1 = ONE_PIXEL;
890 ey1--;
891 gray_set_cell( RAS_VAR_ ex1, ey1 );
892 } while ( ey1 != ey2 );
893 }
894 else /* any other line */
895 {
896 TPos prod = dx * fy1 - dy * fx1;
897 FT_UDIVPREP( ex1 != ex2, dx );
898 FT_UDIVPREP( ey1 != ey2, dy );
899
900
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. */
904 do
905 {
906 if ( prod <= 0 &&
907 prod - dx * ONE_PIXEL > 0 ) /* left */
908 {
909 fx2 = 0;
910 fy2 = (TPos)FT_UDIV( -prod, -dx );
911 prod -= dy * ONE_PIXEL;
912 ras.cover += ( fy2 - fy1 );
913 ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
914 fx1 = ONE_PIXEL;
915 fy1 = fy2;
916 ex1--;
917 }
918 else if ( prod - dx * ONE_PIXEL <= 0 &&
919 prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */
920 {
921 prod -= dx * ONE_PIXEL;
922 fx2 = (TPos)FT_UDIV( -prod, dy );
923 fy2 = ONE_PIXEL;
924 ras.cover += ( fy2 - fy1 );
925 ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
926 fx1 = fx2;
927 fy1 = 0;
928 ey1++;
929 }
930 else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
931 prod + dy * ONE_PIXEL >= 0 ) /* right */
932 {
933 prod += dy * ONE_PIXEL;
934 fx2 = ONE_PIXEL;
935 fy2 = (TPos)FT_UDIV( prod, dx );
936 ras.cover += ( fy2 - fy1 );
937 ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
938 fx1 = 0;
939 fy1 = fy2;
940 ex1++;
941 }
942 else /* ( prod + dy * ONE_PIXEL < 0 &&
943 prod > 0 ) down */
944 {
945 fx2 = (TPos)FT_UDIV( prod, -dy );
946 fy2 = 0;
947 prod += dx * ONE_PIXEL;
948 ras.cover += ( fy2 - fy1 );
949 ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
950 fx1 = fx2;
951 fy1 = ONE_PIXEL;
952 ey1--;
953 }
954
955 gray_set_cell( RAS_VAR_ ex1, ey1 );
956 } while ( ex1 != ex2 || ey1 != ey2 );
957 }
958
959 fx2 = to_x - SUBPIXELS( ex2 );
960 fy2 = to_y - SUBPIXELS( ey2 );
961
962 ras.cover += ( fy2 - fy1 );
963 ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
964
965 End:
966 ras.x = to_x;
967 ras.y = to_y;
968 }
969
970 #endif
971
972 static void
973 gray_split_conic( FT_Vector* base )
974 {
975 TPos a, b;
976
977
978 base[4].x = base[2].x;
979 b = base[1].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;
983
984 base[4].y = base[2].y;
985 b = base[1].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;
989 }
990
991
992 static void
993 gray_render_conic( RAS_ARG_ const FT_Vector* control,
994 const FT_Vector* to )
995 {
996 FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */
997 FT_Vector* arc = bez_stack;
998 TPos dx, dy;
999 int draw, split;
1000
1001
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 );
1006 arc[2].x = ras.x;
1007 arc[2].y = ras.y;
1008
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 ) )
1016 {
1017 ras.x = arc[0].x;
1018 ras.y = arc[0].y;
1019 return;
1020 }
1021
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 );
1024 if ( dx < dy )
1025 dx = dy;
1026
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. */
1030 draw = 1;
1031 while ( dx > ONE_PIXEL / 4 )
1032 {
1033 dx >>= 2;
1034 draw <<= 1;
1035 }
1036
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. */
1040 do
1041 {
1042 split = 1;
1043 while ( ( draw & split ) == 0 )
1044 {
1045 gray_split_conic( arc );
1046 arc += 2;
1047 split <<= 1;
1048 }
1049
1050 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1051 arc -= 2;
1052
1053 } while ( --draw );
1054 }
1055
1056
1057 static void
1058 gray_split_cubic( FT_Vector* base )
1059 {
1060 TPos a, b, c, d;
1061
1062
1063 base[6].x = base[3].x;
1064 c = base[1].x;
1065 d = base[2].x;
1066 base[1].x = a = ( base[0].x + c ) / 2;
1067 base[5].x = b = ( base[3].x + d ) / 2;
1068 c = ( c + 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;
1072
1073 base[6].y = base[3].y;
1074 c = base[1].y;
1075 d = base[2].y;
1076 base[1].y = a = ( base[0].y + c ) / 2;
1077 base[5].y = b = ( base[3].y + d ) / 2;
1078 c = ( c + 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;
1082 }
1083
1084
1085 static void
1086 gray_render_cubic( RAS_ARG_ const FT_Vector* control1,
1087 const FT_Vector* control2,
1088 const FT_Vector* to )
1089 {
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;
1094 TPos L, s, s_limit;
1095
1096
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 );
1103 arc[3].x = ras.x;
1104 arc[3].y = ras.y;
1105
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 ) )
1115 {
1116 ras.x = arc[0].x;
1117 ras.y = arc[0].y;
1118 return;
1119 }
1120
1121 for (;;)
1122 {
1123 /* Decide whether to split or draw. See `Rapid Termination */
1124 /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
1125 /* F. Hain, at */
1126 /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
1127
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;
1131
1132 L = FT_HYPOT( dx_, dy_ );
1133
1134 /* Avoid possible arithmetic overflow below by splitting. */
1135 if ( L > 32767 )
1136 goto Split;
1137
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 );
1140
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 );
1145
1146 if ( s > s_limit )
1147 goto Split;
1148
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 );
1153
1154 if ( s > s_limit )
1155 goto Split;
1156
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 )
1162 goto Split;
1163
1164 gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
1165
1166 if ( arc == bez_stack )
1167 return;
1168
1169 arc -= 3;
1170 continue;
1171
1172 Split:
1173 gray_split_cubic( arc );
1174 arc += 3;
1175 }
1176 }
1177
1178
1179 static int
1180 gray_move_to( const FT_Vector* to,
1181 gray_PWorker worker )
1182 {
1183 TPos x, y;
1184
1185
1186 /* start to a new position */
1187 x = UPSCALE( to->x );
1188 y = UPSCALE( to->y );
1189
1190 gray_set_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
1191
1192 ras.x = x;
1193 ras.y = y;
1194 return 0;
1195 }
1196
1197
1198 static int
1199 gray_line_to( const FT_Vector* to,
1200 gray_PWorker worker )
1201 {
1202 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
1203 return 0;
1204 }
1205
1206
1207 static int
1208 gray_conic_to( const FT_Vector* control,
1209 const FT_Vector* to,
1210 gray_PWorker worker )
1211 {
1212 gray_render_conic( RAS_VAR_ control, to );
1213 return 0;
1214 }
1215
1216
1217 static int
1218 gray_cubic_to( const FT_Vector* control1,
1219 const FT_Vector* control2,
1220 const FT_Vector* to,
1221 gray_PWorker worker )
1222 {
1223 gray_render_cubic( RAS_VAR_ control1, control2, to );
1224 return 0;
1225 }
1226
1227
1228 static void
1229 gray_hline( RAS_ARG_ TCoord x,
1230 TCoord y,
1231 TArea area,
1232 TCoord acount )
1233 {
1234 int coverage;
1235 FT_Span span;
1236
1237
1238 /* compute the coverage line's coverage, depending on the */
1239 /* outline fill rule */
1240 /* */
1241 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1242 /* */
1243 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
1244 /* use range 0..256 */
1245 if ( coverage < 0 )
1246 coverage = -coverage;
1247
1248 if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
1249 {
1250 coverage &= 511;
1251
1252 if ( coverage > 256 )
1253 coverage = 512 - coverage;
1254 else if ( coverage == 256 )
1255 coverage = 255;
1256 }
1257 else
1258 {
1259 /* normal non-zero winding rule */
1260 if ( coverage >= 256 )
1261 coverage = 255;
1262 }
1263
1264 if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */
1265 {
1266 span.x = (short)x;
1267 span.len = (unsigned short)acount;
1268 span.coverage = (unsigned char)coverage;
1269
1270 ras.render_span( y, 1, &span, ras.render_span_data );
1271 }
1272 else
1273 {
1274 unsigned char* q = ras.target.origin - ras.target.pitch * y + x;
1275 unsigned char c = (unsigned char)coverage;
1276
1277
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
1280 * function call.
1281 */
1282 switch ( acount )
1283 {
1284 case 7: *q++ = c;
1285 case 6: *q++ = c;
1286 case 5: *q++ = c;
1287 case 4: *q++ = c;
1288 case 3: *q++ = c;
1289 case 2: *q++ = c;
1290 case 1: *q = c;
1291 case 0: break;
1292 default:
1293 FT_MEM_SET( q, c, acount );
1294 }
1295 }
1296 }
1297
1298
1299 static void
1300 gray_sweep( RAS_ARG )
1301 {
1302 int y;
1303
1304
1305 FT_TRACE7(( "gray_sweep: start\n" ));
1306
1307 for ( y = ras.min_ey; y < ras.max_ey; y++ )
1308 {
1309 PCell cell = ras.ycells[y - ras.min_ey];
1310 TCoord cover = 0;
1311 TCoord x = ras.min_ex;
1312
1313
1314 for ( ; cell != NULL; cell = cell->next )
1315 {
1316 TArea area;
1317
1318
1319 if ( cover != 0 && cell->x > x )
1320 gray_hline( RAS_VAR_ x, y, (TArea)cover * ( ONE_PIXEL * 2 ),
1321 cell->x - x );
1322
1323 cover += cell->cover;
1324 area = (TArea)cover * ( ONE_PIXEL * 2 ) - cell->area;
1325
1326 if ( area != 0 && cell->x >= ras.min_ex )
1327 gray_hline( RAS_VAR_ cell->x, y, area, 1 );
1328
1329 x = cell->x + 1;
1330 }
1331
1332 if ( cover != 0 )
1333 gray_hline( RAS_VAR_ x, y, (TArea)cover * ( ONE_PIXEL * 2 ),
1334 ras.max_ex - x );
1335 }
1336
1337 FT_TRACE7(( "gray_sweep: end\n" ));
1338 }
1339
1340
1341 #ifdef STANDALONE_
1342
1343 /*************************************************************************/
1344 /* */
1345 /* The following functions should only compile in stand-alone mode, */
1346 /* i.e., when building this component without the rest of FreeType. */
1347 /* */
1348 /*************************************************************************/
1349
1350 /*************************************************************************/
1351 /* */
1352 /* <Function> */
1353 /* FT_Outline_Decompose */
1354 /* */
1355 /* <Description> */
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. */
1360 /* */
1361 /* <Input> */
1362 /* outline :: A pointer to the source target. */
1363 /* */
1364 /* func_interface :: A table of `emitters', i.e., function pointers */
1365 /* called during decomposition to indicate path */
1366 /* operations. */
1367 /* */
1368 /* <InOut> */
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. */
1373 /* */
1374 /* <Return> */
1375 /* Error code. 0 means success. */
1376 /* */
1377 static int
1378 FT_Outline_Decompose( const FT_Outline* outline,
1379 const FT_Outline_Funcs* func_interface,
1380 void* user )
1381 {
1382 #undef SCALED
1383 #define SCALED( x ) ( ( (x) << shift ) - delta )
1384
1385 FT_Vector v_last;
1386 FT_Vector v_control;
1387 FT_Vector v_start;
1388
1389 FT_Vector* point;
1390 FT_Vector* limit;
1391 char* tags;
1392
1393 int error;
1394
1395 int n; /* index of contour in outline */
1396 int first; /* index of first point in contour */
1397 char tag; /* current point's state */
1398
1399 int shift;
1400 TPos delta;
1401
1402
1403 if ( !outline )
1404 return FT_THROW( Invalid_Outline );
1405
1406 if ( !func_interface )
1407 return FT_THROW( Invalid_Argument );
1408
1409 shift = func_interface->shift;
1410 delta = func_interface->delta;
1411 first = 0;
1412
1413 for ( n = 0; n < outline->n_contours; n++ )
1414 {
1415 int last; /* index of last point in contour */
1416
1417
1418 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
1419
1420 last = outline->contours[n];
1421 if ( last < 0 )
1422 goto Invalid_Outline;
1423 limit = outline->points + last;
1424
1425 v_start = outline->points[first];
1426 v_start.x = SCALED( v_start.x );
1427 v_start.y = SCALED( v_start.y );
1428
1429 v_last = outline->points[last];
1430 v_last.x = SCALED( v_last.x );
1431 v_last.y = SCALED( v_last.y );
1432
1433 v_control = v_start;
1434
1435 point = outline->points + first;
1436 tags = outline->tags + first;
1437 tag = FT_CURVE_TAG( tags[0] );
1438
1439 /* A contour cannot start with a cubic control point! */
1440 if ( tag == FT_CURVE_TAG_CUBIC )
1441 goto Invalid_Outline;
1442
1443 /* check first point to determine origin */
1444 if ( tag == FT_CURVE_TAG_CONIC )
1445 {
1446 /* first point is conic control. Yes, this happens. */
1447 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
1448 {
1449 /* start at last point if it is on the curve */
1450 v_start = v_last;
1451 limit--;
1452 }
1453 else
1454 {
1455 /* if both first and last points are conic, */
1456 /* start at their middle and record its position */
1457 /* for closure */
1458 v_start.x = ( v_start.x + v_last.x ) / 2;
1459 v_start.y = ( v_start.y + v_last.y ) / 2;
1460
1461 v_last = v_start;
1462 }
1463 point--;
1464 tags--;
1465 }
1466
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 );
1470 if ( error )
1471 goto Exit;
1472
1473 while ( point < limit )
1474 {
1475 point++;
1476 tags++;
1477
1478 tag = FT_CURVE_TAG( tags[0] );
1479 switch ( tag )
1480 {
1481 case FT_CURVE_TAG_ON: /* emit a single line_to */
1482 {
1483 FT_Vector vec;
1484
1485
1486 vec.x = SCALED( point->x );
1487 vec.y = SCALED( point->y );
1488
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 );
1492 if ( error )
1493 goto Exit;
1494 continue;
1495 }
1496
1497 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1498 v_control.x = SCALED( point->x );
1499 v_control.y = SCALED( point->y );
1500
1501 Do_Conic:
1502 if ( point < limit )
1503 {
1504 FT_Vector vec;
1505 FT_Vector v_middle;
1506
1507
1508 point++;
1509 tags++;
1510 tag = FT_CURVE_TAG( tags[0] );
1511
1512 vec.x = SCALED( point->x );
1513 vec.y = SCALED( point->y );
1514
1515 if ( tag == FT_CURVE_TAG_ON )
1516 {
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 );
1522 if ( error )
1523 goto Exit;
1524 continue;
1525 }
1526
1527 if ( tag != FT_CURVE_TAG_CONIC )
1528 goto Invalid_Outline;
1529
1530 v_middle.x = ( v_control.x + vec.x ) / 2;
1531 v_middle.y = ( v_control.y + vec.y ) / 2;
1532
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 );
1538 if ( error )
1539 goto Exit;
1540
1541 v_control = vec;
1542 goto Do_Conic;
1543 }
1544
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 );
1550 goto Close;
1551
1552 default: /* FT_CURVE_TAG_CUBIC */
1553 {
1554 FT_Vector vec1, vec2;
1555
1556
1557 if ( point + 1 > limit ||
1558 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1559 goto Invalid_Outline;
1560
1561 point += 2;
1562 tags += 2;
1563
1564 vec1.x = SCALED( point[-2].x );
1565 vec1.y = SCALED( point[-2].y );
1566
1567 vec2.x = SCALED( point[-1].x );
1568 vec2.y = SCALED( point[-1].y );
1569
1570 if ( point <= limit )
1571 {
1572 FT_Vector vec;
1573
1574
1575 vec.x = SCALED( point->x );
1576 vec.y = SCALED( point->y );
1577
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 );
1584 if ( error )
1585 goto Exit;
1586 continue;
1587 }
1588
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 );
1595 goto Close;
1596 }
1597 }
1598 }
1599
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 );
1604
1605 Close:
1606 if ( error )
1607 goto Exit;
1608
1609 first = last + 1;
1610 }
1611
1612 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1613 return 0;
1614
1615 Exit:
1616 FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
1617 return error;
1618
1619 Invalid_Outline:
1620 return FT_THROW( Invalid_Outline );
1621 }
1622
1623
1624 /*************************************************************************/
1625 /* */
1626 /* <Function> */
1627 /* FT_Outline_Get_CBox */
1628 /* */
1629 /* <Description> */
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). */
1635 /* */
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. */
1640 /* */
1641 /* <Input> */
1642 /* outline :: A pointer to the source outline descriptor. */
1643 /* */
1644 /* <Output> */
1645 /* acbox :: The outline's control box. */
1646 /* */
1647 /* <Note> */
1648 /* See @FT_Glyph_Get_CBox for a discussion of tricky fonts. */
1649 /* */
1650
1651 static void
1652 FT_Outline_Get_CBox( const FT_Outline* outline,
1653 FT_BBox *acbox )
1654 {
1655 TPos xMin, yMin, xMax, yMax;
1656
1657
1658 if ( outline && acbox )
1659 {
1660 if ( outline->n_points == 0 )
1661 {
1662 xMin = 0;
1663 yMin = 0;
1664 xMax = 0;
1665 yMax = 0;
1666 }
1667 else
1668 {
1669 FT_Vector* vec = outline->points;
1670 FT_Vector* limit = vec + outline->n_points;
1671
1672
1673 xMin = xMax = vec->x;
1674 yMin = yMax = vec->y;
1675 vec++;
1676
1677 for ( ; vec < limit; vec++ )
1678 {
1679 TPos x, y;
1680
1681
1682 x = vec->x;
1683 if ( x < xMin ) xMin = x;
1684 if ( x > xMax ) xMax = x;
1685
1686 y = vec->y;
1687 if ( y < yMin ) yMin = y;
1688 if ( y > yMax ) yMax = y;
1689 }
1690 }
1691 acbox->xMin = xMin;
1692 acbox->xMax = xMax;
1693 acbox->yMin = yMin;
1694 acbox->yMax = yMax;
1695 }
1696 }
1697
1698 #endif /* STANDALONE_ */
1699
1700
1701 FT_DEFINE_OUTLINE_FUNCS(
1702 func_interface,
1703
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 */
1708
1709 0, /* shift */
1710 0 /* delta */
1711 )
1712
1713
1714 static int
1715 gray_convert_glyph_inner( RAS_ARG )
1716 {
1717
1718 volatile int error = 0;
1719
1720 #ifdef FT_CONFIG_OPTION_PIC
1721 FT_Outline_Funcs func_interface;
1722 Init_Class_func_interface(&func_interface);
1723 #endif
1724
1725 if ( ft_setjmp( ras.jump_buffer ) == 0 )
1726 {
1727 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
1728 if ( !ras.invalid )
1729 gray_record_cell( RAS_VAR );
1730
1731 FT_TRACE7(( "band [%d..%d]: %d cells\n",
1732 ras.min_ey, ras.max_ey, ras.num_cells ));
1733 }
1734 else
1735 {
1736 error = FT_THROW( Memory_Overflow );
1737
1738 FT_TRACE7(( "band [%d..%d]: to be bisected\n",
1739 ras.min_ey, ras.max_ey ));
1740 }
1741
1742 return error;
1743 }
1744
1745
1746 static int
1747 gray_convert_glyph( RAS_ARG )
1748 {
1749 #ifdef __REACTOS__
1750 TCell *buffer;
1751 #else
1752 TCell buffer[FT_MAX_GRAY_POOL];
1753 #endif
1754 TCoord band_size = FT_MAX_GRAY_POOL / 8;
1755 TCoord count = ras.max_ey - ras.min_ey;
1756 int num_bands;
1757 TCoord min, max, max_y;
1758 TCoord bands[32]; /* enough to accommodate bisections */
1759 TCoord* band;
1760
1761 #ifdef __REACTOS__
1762 buffer = malloc(FT_MAX(FT_RENDER_POOL_SIZE, 2048));
1763 #endif
1764
1765 /* set up vertical bands */
1766 if ( count > band_size )
1767 {
1768 /* two divisions rounded up */
1769 num_bands = (int)( ( count + band_size - 1) / band_size );
1770 band_size = ( count + num_bands - 1 ) / num_bands;
1771 }
1772
1773 min = ras.min_ey;
1774 max_y = ras.max_ey;
1775
1776 for ( ; min < max_y; min = max )
1777 {
1778 max = min + band_size;
1779 if ( max > max_y )
1780 max = max_y;
1781
1782 band = bands;
1783 band[1] = min;
1784 band[0] = max;
1785
1786 do
1787 {
1788 TCoord width = band[0] - band[1];
1789 int error;
1790
1791
1792 /* memory management */
1793 {
1794 size_t ycount = (size_t)width;
1795 size_t cell_start;
1796
1797
1798 cell_start = ( ycount * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) /
1799 sizeof ( TCell );
1800
1801 ras.cells = buffer + cell_start;
1802 ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - cell_start );
1803 ras.num_cells = 0;
1804
1805 ras.ycells = (PCell*)buffer;
1806 while ( ycount )
1807 ras.ycells[--ycount] = NULL;
1808 }
1809
1810 ras.invalid = 1;
1811 ras.min_ey = band[1];
1812 ras.max_ey = band[0];
1813
1814 error = gray_convert_glyph_inner( RAS_VAR );
1815
1816 if ( !error )
1817 {
1818 gray_sweep( RAS_VAR );
1819 band--;
1820 continue;
1821 }
1822 else if ( error != ErrRaster_Memory_Overflow )
1823 {
1824 #ifdef __REACTOS__
1825 free(buffer);
1826 #endif
1827 return 1;
1828 }
1829
1830 /* render pool overflow; we will reduce the render band by half */
1831 width >>= 1;
1832
1833 /* This is too complex for a single scanline; there must */
1834 /* be some problems. */
1835 if ( width == 0 )
1836 {
1837 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
1838 #ifdef __REACTOS__
1839 free(buffer);
1840 #endif
1841 return 1;
1842 }
1843
1844 band++;
1845 band[1] = band[0];
1846 band[0] += width;
1847 } while ( band >= bands );
1848 }
1849
1850 #ifdef __REACTOS__
1851 free(buffer);
1852 #endif
1853
1854 return 0;
1855 }
1856
1857
1858 static int
1859 gray_raster_render( FT_Raster raster,
1860 const FT_Raster_Params* params )
1861 {
1862 const FT_Outline* outline = (const FT_Outline*)params->source;
1863 const FT_Bitmap* target_map = params->target;
1864 FT_BBox cbox, clip;
1865
1866 #ifndef FT_STATIC_RASTER
1867 gray_TWorker worker[1];
1868 #endif
1869
1870
1871 if ( !raster )
1872 return FT_THROW( Invalid_Argument );
1873
1874 /* this version does not support monochrome rendering */
1875 if ( !( params->flags & FT_RASTER_FLAG_AA ) )
1876 return FT_THROW( Invalid_Mode );
1877
1878 if ( !outline )
1879 return FT_THROW( Invalid_Outline );
1880
1881 /* return immediately if the outline is empty */
1882 if ( outline->n_points == 0 || outline->n_contours <= 0 )
1883 return 0;
1884
1885 if ( !outline->contours || !outline->points )
1886 return FT_THROW( Invalid_Outline );
1887
1888 if ( outline->n_points !=
1889 outline->contours[outline->n_contours - 1] + 1 )
1890 return FT_THROW( Invalid_Outline );
1891
1892 ras.outline = *outline;
1893
1894 if ( params->flags & FT_RASTER_FLAG_DIRECT )
1895 {
1896 if ( !params->gray_spans )
1897 return 0;
1898
1899 ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
1900 ras.render_span_data = params->user;
1901 }
1902 else
1903 {
1904 /* if direct mode is not set, we must have a target bitmap */
1905 if ( !target_map )
1906 return FT_THROW( Invalid_Argument );
1907
1908 /* nothing to do */
1909 if ( !target_map->width || !target_map->rows )
1910 return 0;
1911
1912 if ( !target_map->buffer )
1913 return FT_THROW( Invalid_Argument );
1914
1915 if ( target_map->pitch < 0 )
1916 ras.target.origin = target_map->buffer;
1917 else
1918 ras.target.origin = target_map->buffer
1919 + ( target_map->rows - 1 ) * (unsigned int)target_map->pitch;
1920
1921 ras.target.pitch = target_map->pitch;
1922
1923 ras.render_span = (FT_Raster_Span_Func)NULL;
1924 ras.render_span_data = NULL;
1925 }
1926
1927 FT_Outline_Get_CBox( outline, &cbox );
1928
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 );
1933
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;
1939
1940 /* compute clipping box */
1941 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
1942 {
1943 /* compute clip box from target pixmap */
1944 clip.xMin = 0;
1945 clip.yMin = 0;
1946 clip.xMax = (FT_Pos)target_map->width;
1947 clip.yMax = (FT_Pos)target_map->rows;
1948 }
1949 else if ( params->flags & FT_RASTER_FLAG_CLIP )
1950 clip = params->clip_box;
1951 else
1952 {
1953 clip.xMin = -32768L;
1954 clip.yMin = -32768L;
1955 clip.xMax = 32767L;
1956 clip.yMax = 32767L;
1957 }
1958
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 );
1964
1965 if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey )
1966 return 0;
1967
1968 return gray_convert_glyph( RAS_VAR );
1969 }
1970
1971
1972 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
1973 /**** a static object. *****/
1974
1975 #ifdef STANDALONE_
1976
1977 static int
1978 gray_raster_new( void* memory,
1979 FT_Raster* araster )
1980 {
1981 static gray_TRaster the_raster;
1982
1983 FT_UNUSED( memory );
1984
1985
1986 *araster = (FT_Raster)&the_raster;
1987 FT_ZERO( &the_raster );
1988
1989 return 0;
1990 }
1991
1992
1993 static void
1994 gray_raster_done( FT_Raster raster )
1995 {
1996 /* nothing */
1997 FT_UNUSED( raster );
1998 }
1999
2000 #else /* !STANDALONE_ */
2001
2002 static int
2003 gray_raster_new( FT_Memory memory,
2004 FT_Raster* araster )
2005 {
2006 FT_Error error;
2007 gray_PRaster raster = NULL;
2008
2009
2010 *araster = 0;
2011 if ( !FT_ALLOC( raster, sizeof ( gray_TRaster ) ) )
2012 {
2013 raster->memory = memory;
2014 *araster = (FT_Raster)raster;
2015 }
2016
2017 return error;
2018 }
2019
2020
2021 static void
2022 gray_raster_done( FT_Raster raster )
2023 {
2024 FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory;
2025
2026
2027 FT_FREE( raster );
2028 }
2029
2030 #endif /* !STANDALONE_ */
2031
2032
2033 static void
2034 gray_raster_reset( FT_Raster raster,
2035 unsigned char* pool_base,
2036 unsigned long pool_size )
2037 {
2038 FT_UNUSED( raster );
2039 FT_UNUSED( pool_base );
2040 FT_UNUSED( pool_size );
2041 }
2042
2043
2044 static int
2045 gray_raster_set_mode( FT_Raster raster,
2046 unsigned long mode,
2047 void* args )
2048 {
2049 FT_UNUSED( raster );
2050 FT_UNUSED( mode );
2051 FT_UNUSED( args );
2052
2053
2054 return 0; /* nothing to do */
2055 }
2056
2057
2058 FT_DEFINE_RASTER_FUNCS(
2059 ft_grays_raster,
2060
2061 FT_GLYPH_FORMAT_OUTLINE,
2062
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 */
2068 )
2069
2070
2071 /* END */
2072
2073
2074 /* Local Variables: */
2075 /* coding: utf-8 */
2076 /* End: */