Sync with trunk (r49303)
[reactos.git] / 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-2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009 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 -D_STANDALONE_ 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 /* define this to dump debugging information */
98 /* #define FT_DEBUG_LEVEL_TRACE */
99
100
101 #ifdef FT_DEBUG_LEVEL_TRACE
102 #include <stdio.h>
103 #include <stdarg.h>
104 #endif
105
106 #include <string.h>
107 #include <setjmp.h>
108 #include <limits.h>
109 #define FT_UINT_MAX UINT_MAX
110
111 #define ft_memset memset
112
113 #define ft_setjmp setjmp
114 #define ft_longjmp longjmp
115 #define ft_jmp_buf jmp_buf
116
117
118 #define ErrRaster_Invalid_Mode -2
119 #define ErrRaster_Invalid_Outline -1
120 #define ErrRaster_Invalid_Argument -3
121 #define ErrRaster_Memory_Overflow -4
122
123 #define FT_BEGIN_HEADER
124 #define FT_END_HEADER
125
126 #include "ftimage.h"
127 #include "ftgrays.h"
128
129
130 /* This macro is used to indicate that a function parameter is unused. */
131 /* Its purpose is simply to reduce compiler warnings. Note also that */
132 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
133 /* ANSI compilers (e.g. LCC). */
134 #define FT_UNUSED( x ) (x) = (x)
135
136
137 /* we only use level 5 & 7 tracing messages; cf. ftdebug.h */
138
139 #ifdef FT_DEBUG_LEVEL_TRACE
140
141 void
142 FT_Message( const char* fmt,
143 ... )
144 {
145 va_list ap;
146
147
148 va_start( ap, fmt );
149 vfprintf( stderr, fmt, ap );
150 va_end( ap );
151 }
152
153 /* we don't handle tracing levels in stand-alone mode; */
154 #ifndef FT_TRACE5
155 #define FT_TRACE5( varformat ) FT_Message varformat
156 #endif
157 #ifndef FT_TRACE7
158 #define FT_TRACE7( varformat ) FT_Message varformat
159 #endif
160 #ifndef FT_ERROR
161 #define FT_ERROR( varformat ) FT_Message varformat
162 #endif
163
164 #else /* !FT_DEBUG_LEVEL_TRACE */
165
166 #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */
167 #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */
168 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
169
170 #endif /* !FT_DEBUG_LEVEL_TRACE */
171
172
173 #define FT_DEFINE_OUTLINE_FUNCS( class_, \
174 move_to_, line_to_, \
175 conic_to_, cubic_to_, \
176 shift_, delta_ ) \
177 static const FT_Outline_Funcs class_ = \
178 { \
179 move_to_, \
180 line_to_, \
181 conic_to_, \
182 cubic_to_, \
183 shift_, \
184 delta_ \
185 };
186
187 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \
188 raster_new_, raster_reset_, \
189 raster_set_mode_, raster_render_, \
190 raster_done_ ) \
191 const FT_Raster_Funcs class_ = \
192 { \
193 glyph_format_, \
194 raster_new_, \
195 raster_reset_, \
196 raster_set_mode_, \
197 raster_render_, \
198 raster_done_ \
199 };
200
201 #else /* !_STANDALONE_ */
202
203
204 #include <ft2build.h>
205 #include "ftgrays.h"
206 #include FT_INTERNAL_OBJECTS_H
207 #include FT_INTERNAL_DEBUG_H
208 #include FT_OUTLINE_H
209
210 #include "ftsmerrs.h"
211
212 #include "ftspic.h"
213
214 #define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
215 #define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline
216 #define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory
217 #define ErrRaster_Invalid_Argument Smooth_Err_Invalid_Argument
218
219 #endif /* !_STANDALONE_ */
220
221 #ifndef FT_MEM_SET
222 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
223 #endif
224
225 #ifndef FT_MEM_ZERO
226 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
227 #endif
228
229 /* as usual, for the speed hungry :-) */
230
231 #ifndef FT_STATIC_RASTER
232
233 #define RAS_ARG PWorker worker
234 #define RAS_ARG_ PWorker worker,
235
236 #define RAS_VAR worker
237 #define RAS_VAR_ worker,
238
239 #else /* FT_STATIC_RASTER */
240
241 #define RAS_ARG /* empty */
242 #define RAS_ARG_ /* empty */
243 #define RAS_VAR /* empty */
244 #define RAS_VAR_ /* empty */
245
246 #endif /* FT_STATIC_RASTER */
247
248
249 /* must be at least 6 bits! */
250 #define PIXEL_BITS 8
251
252 #define ONE_PIXEL ( 1L << PIXEL_BITS )
253 #define PIXEL_MASK ( -1L << PIXEL_BITS )
254 #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
255 #define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS )
256 #define FLOOR( x ) ( (x) & -ONE_PIXEL )
257 #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
258 #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
259
260 #if PIXEL_BITS >= 6
261 #define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) )
262 #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
263 #else
264 #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
265 #define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
266 #endif
267
268
269 /*************************************************************************/
270 /* */
271 /* TYPE DEFINITIONS */
272 /* */
273
274 /* don't change the following types to FT_Int or FT_Pos, since we might */
275 /* need to define them to "float" or "double" when experimenting with */
276 /* new algorithms */
277
278 typedef long TCoord; /* integer scanline/pixel coordinate */
279 typedef long TPos; /* sub-pixel coordinate */
280
281 /* determine the type used to store cell areas. This normally takes at */
282 /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */
283 /* `long' instead of `int', otherwise bad things happen */
284
285 #if PIXEL_BITS <= 7
286
287 typedef int TArea;
288
289 #else /* PIXEL_BITS >= 8 */
290
291 /* approximately determine the size of integers using an ANSI-C header */
292 #if FT_UINT_MAX == 0xFFFFU
293 typedef long TArea;
294 #else
295 typedef int TArea;
296 #endif
297
298 #endif /* PIXEL_BITS >= 8 */
299
300
301 /* maximal number of gray spans in a call to the span callback */
302 #define FT_MAX_GRAY_SPANS 32
303
304
305 typedef struct TCell_* PCell;
306
307 typedef struct TCell_
308 {
309 TPos x; /* same with TWorker.ex */
310 TCoord cover; /* same with TWorker.cover */
311 TArea area;
312 PCell next;
313
314 } TCell;
315
316
317 typedef struct TWorker_
318 {
319 TCoord ex, ey;
320 TPos min_ex, max_ex;
321 TPos min_ey, max_ey;
322 TPos count_ex, count_ey;
323
324 TArea area;
325 TCoord cover;
326 int invalid;
327
328 PCell cells;
329 FT_PtrDist max_cells;
330 FT_PtrDist num_cells;
331
332 TCoord cx, cy;
333 TPos x, y;
334
335 TPos last_ey;
336
337 FT_Vector bez_stack[32 * 3 + 1];
338 int lev_stack[32];
339
340 FT_Outline outline;
341 FT_Bitmap target;
342 FT_BBox clip_box;
343
344 FT_Span gray_spans[FT_MAX_GRAY_SPANS];
345 int num_gray_spans;
346
347 FT_Raster_Span_Func render_span;
348 void* render_span_data;
349 int span_y;
350
351 int band_size;
352 int band_shoot;
353 int conic_level;
354 int cubic_level;
355
356 ft_jmp_buf jump_buffer;
357
358 void* buffer;
359 long buffer_size;
360
361 PCell* ycells;
362 TPos ycount;
363
364 } TWorker, *PWorker;
365
366
367 #ifndef FT_STATIC_RASTER
368 #define ras (*worker)
369 #else
370 static TWorker ras;
371 #endif
372
373
374 typedef struct TRaster_
375 {
376 void* buffer;
377 long buffer_size;
378 int band_size;
379 void* memory;
380 PWorker worker;
381
382 } TRaster, *PRaster;
383
384
385
386 /*************************************************************************/
387 /* */
388 /* Initialize the cells table. */
389 /* */
390 static void
391 gray_init_cells( RAS_ARG_ void* buffer,
392 long byte_size )
393 {
394 ras.buffer = buffer;
395 ras.buffer_size = byte_size;
396
397 ras.ycells = (PCell*) buffer;
398 ras.cells = NULL;
399 ras.max_cells = 0;
400 ras.num_cells = 0;
401 ras.area = 0;
402 ras.cover = 0;
403 ras.invalid = 1;
404 }
405
406
407 /*************************************************************************/
408 /* */
409 /* Compute the outline bounding box. */
410 /* */
411 static void
412 gray_compute_cbox( RAS_ARG )
413 {
414 FT_Outline* outline = &ras.outline;
415 FT_Vector* vec = outline->points;
416 FT_Vector* limit = vec + outline->n_points;
417
418
419 if ( outline->n_points <= 0 )
420 {
421 ras.min_ex = ras.max_ex = 0;
422 ras.min_ey = ras.max_ey = 0;
423 return;
424 }
425
426 ras.min_ex = ras.max_ex = vec->x;
427 ras.min_ey = ras.max_ey = vec->y;
428
429 vec++;
430
431 for ( ; vec < limit; vec++ )
432 {
433 TPos x = vec->x;
434 TPos y = vec->y;
435
436
437 if ( x < ras.min_ex ) ras.min_ex = x;
438 if ( x > ras.max_ex ) ras.max_ex = x;
439 if ( y < ras.min_ey ) ras.min_ey = y;
440 if ( y > ras.max_ey ) ras.max_ey = y;
441 }
442
443 /* truncate the bounding box to integer pixels */
444 ras.min_ex = ras.min_ex >> 6;
445 ras.min_ey = ras.min_ey >> 6;
446 ras.max_ex = ( ras.max_ex + 63 ) >> 6;
447 ras.max_ey = ( ras.max_ey + 63 ) >> 6;
448 }
449
450
451 /*************************************************************************/
452 /* */
453 /* Record the current cell in the table. */
454 /* */
455 static PCell
456 gray_find_cell( RAS_ARG )
457 {
458 PCell *pcell, cell;
459 TPos x = ras.ex;
460
461
462 if ( x > ras.count_ex )
463 x = ras.count_ex;
464
465 pcell = &ras.ycells[ras.ey];
466 for (;;)
467 {
468 cell = *pcell;
469 if ( cell == NULL || cell->x > x )
470 break;
471
472 if ( cell->x == x )
473 goto Exit;
474
475 pcell = &cell->next;
476 }
477
478 if ( ras.num_cells >= ras.max_cells )
479 ft_longjmp( ras.jump_buffer, 1 );
480
481 cell = ras.cells + ras.num_cells++;
482 cell->x = x;
483 cell->area = 0;
484 cell->cover = 0;
485
486 cell->next = *pcell;
487 *pcell = cell;
488
489 Exit:
490 return cell;
491 }
492
493
494 static void
495 gray_record_cell( RAS_ARG )
496 {
497 if ( !ras.invalid && ( ras.area | ras.cover ) )
498 {
499 PCell cell = gray_find_cell( RAS_VAR );
500
501
502 cell->area += ras.area;
503 cell->cover += ras.cover;
504 }
505 }
506
507
508 /*************************************************************************/
509 /* */
510 /* Set the current cell to a new position. */
511 /* */
512 static void
513 gray_set_cell( RAS_ARG_ TCoord ex,
514 TCoord ey )
515 {
516 /* Move the cell pointer to a new position. We set the `invalid' */
517 /* flag to indicate that the cell isn't part of those we're interested */
518 /* in during the render phase. This means that: */
519 /* */
520 /* . the new vertical position must be within min_ey..max_ey-1. */
521 /* . the new horizontal position must be strictly less than max_ex */
522 /* */
523 /* Note that if a cell is to the left of the clipping region, it is */
524 /* actually set to the (min_ex-1) horizontal position. */
525
526 /* All cells that are on the left of the clipping region go to the */
527 /* min_ex - 1 horizontal position. */
528 ey -= ras.min_ey;
529
530 if ( ex > ras.max_ex )
531 ex = ras.max_ex;
532
533 ex -= ras.min_ex;
534 if ( ex < 0 )
535 ex = -1;
536
537 /* are we moving to a different cell ? */
538 if ( ex != ras.ex || ey != ras.ey )
539 {
540 /* record the current one if it is valid */
541 if ( !ras.invalid )
542 gray_record_cell( RAS_VAR );
543
544 ras.area = 0;
545 ras.cover = 0;
546 }
547
548 ras.ex = ex;
549 ras.ey = ey;
550 ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
551 ex >= ras.count_ex );
552 }
553
554
555 /*************************************************************************/
556 /* */
557 /* Start a new contour at a given cell. */
558 /* */
559 static void
560 gray_start_cell( RAS_ARG_ TCoord ex,
561 TCoord ey )
562 {
563 if ( ex > ras.max_ex )
564 ex = (TCoord)( ras.max_ex );
565
566 if ( ex < ras.min_ex )
567 ex = (TCoord)( ras.min_ex - 1 );
568
569 ras.area = 0;
570 ras.cover = 0;
571 ras.ex = ex - ras.min_ex;
572 ras.ey = ey - ras.min_ey;
573 ras.last_ey = SUBPIXELS( ey );
574 ras.invalid = 0;
575
576 gray_set_cell( RAS_VAR_ ex, ey );
577 }
578
579
580 /*************************************************************************/
581 /* */
582 /* Render a scanline as one or more cells. */
583 /* */
584 static void
585 gray_render_scanline( RAS_ARG_ TCoord ey,
586 TPos x1,
587 TCoord y1,
588 TPos x2,
589 TCoord y2 )
590 {
591 TCoord ex1, ex2, fx1, fx2, delta, mod, lift, rem;
592 long p, first, dx;
593 int incr;
594
595
596 dx = x2 - x1;
597
598 ex1 = TRUNC( x1 );
599 ex2 = TRUNC( x2 );
600 fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
601 fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
602
603 /* trivial case. Happens often */
604 if ( y1 == y2 )
605 {
606 gray_set_cell( RAS_VAR_ ex2, ey );
607 return;
608 }
609
610 /* everything is located in a single cell. That is easy! */
611 /* */
612 if ( ex1 == ex2 )
613 {
614 delta = y2 - y1;
615 ras.area += (TArea)(( fx1 + fx2 ) * delta);
616 ras.cover += delta;
617 return;
618 }
619
620 /* ok, we'll have to render a run of adjacent cells on the same */
621 /* scanline... */
622 /* */
623 p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
624 first = ONE_PIXEL;
625 incr = 1;
626
627 if ( dx < 0 )
628 {
629 p = fx1 * ( y2 - y1 );
630 first = 0;
631 incr = -1;
632 dx = -dx;
633 }
634
635 delta = (TCoord)( p / dx );
636 mod = (TCoord)( p % dx );
637 if ( mod < 0 )
638 {
639 delta--;
640 mod += (TCoord)dx;
641 }
642
643 ras.area += (TArea)(( fx1 + first ) * delta);
644 ras.cover += delta;
645
646 ex1 += incr;
647 gray_set_cell( RAS_VAR_ ex1, ey );
648 y1 += delta;
649
650 if ( ex1 != ex2 )
651 {
652 p = ONE_PIXEL * ( y2 - y1 + delta );
653 lift = (TCoord)( p / dx );
654 rem = (TCoord)( p % dx );
655 if ( rem < 0 )
656 {
657 lift--;
658 rem += (TCoord)dx;
659 }
660
661 mod -= (int)dx;
662
663 while ( ex1 != ex2 )
664 {
665 delta = lift;
666 mod += rem;
667 if ( mod >= 0 )
668 {
669 mod -= (TCoord)dx;
670 delta++;
671 }
672
673 ras.area += (TArea)(ONE_PIXEL * delta);
674 ras.cover += delta;
675 y1 += delta;
676 ex1 += incr;
677 gray_set_cell( RAS_VAR_ ex1, ey );
678 }
679 }
680
681 delta = y2 - y1;
682 ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta);
683 ras.cover += delta;
684 }
685
686
687 /*************************************************************************/
688 /* */
689 /* Render a given line as a series of scanlines. */
690 /* */
691 static void
692 gray_render_line( RAS_ARG_ TPos to_x,
693 TPos to_y )
694 {
695 TCoord ey1, ey2, fy1, fy2, mod;
696 TPos dx, dy, x, x2;
697 long p, first;
698 int delta, rem, lift, incr;
699
700
701 ey1 = TRUNC( ras.last_ey );
702 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
703 fy1 = (TCoord)( ras.y - ras.last_ey );
704 fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
705
706 dx = to_x - ras.x;
707 dy = to_y - ras.y;
708
709 /* XXX: we should do something about the trivial case where dx == 0, */
710 /* as it happens very often! */
711
712 /* perform vertical clipping */
713 {
714 TCoord min, max;
715
716
717 min = ey1;
718 max = ey2;
719 if ( ey1 > ey2 )
720 {
721 min = ey2;
722 max = ey1;
723 }
724 if ( min >= ras.max_ey || max < ras.min_ey )
725 goto End;
726 }
727
728 /* everything is on a single scanline */
729 if ( ey1 == ey2 )
730 {
731 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
732 goto End;
733 }
734
735 /* vertical line - avoid calling gray_render_scanline */
736 incr = 1;
737
738 if ( dx == 0 )
739 {
740 TCoord ex = TRUNC( ras.x );
741 TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
742 TArea area;
743
744
745 first = ONE_PIXEL;
746 if ( dy < 0 )
747 {
748 first = 0;
749 incr = -1;
750 }
751
752 delta = (int)( first - fy1 );
753 ras.area += (TArea)two_fx * delta;
754 ras.cover += delta;
755 ey1 += incr;
756
757 gray_set_cell( RAS_VAR_ ex, ey1 );
758
759 delta = (int)( first + first - ONE_PIXEL );
760 area = (TArea)two_fx * delta;
761 while ( ey1 != ey2 )
762 {
763 ras.area += area;
764 ras.cover += delta;
765 ey1 += incr;
766
767 gray_set_cell( RAS_VAR_ ex, ey1 );
768 }
769
770 delta = (int)( fy2 - ONE_PIXEL + first );
771 ras.area += (TArea)two_fx * delta;
772 ras.cover += delta;
773
774 goto End;
775 }
776
777 /* ok, we have to render several scanlines */
778 p = ( ONE_PIXEL - fy1 ) * dx;
779 first = ONE_PIXEL;
780 incr = 1;
781
782 if ( dy < 0 )
783 {
784 p = fy1 * dx;
785 first = 0;
786 incr = -1;
787 dy = -dy;
788 }
789
790 delta = (int)( p / dy );
791 mod = (int)( p % dy );
792 if ( mod < 0 )
793 {
794 delta--;
795 mod += (TCoord)dy;
796 }
797
798 x = ras.x + delta;
799 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
800
801 ey1 += incr;
802 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
803
804 if ( ey1 != ey2 )
805 {
806 p = ONE_PIXEL * dx;
807 lift = (int)( p / dy );
808 rem = (int)( p % dy );
809 if ( rem < 0 )
810 {
811 lift--;
812 rem += (int)dy;
813 }
814 mod -= (int)dy;
815
816 while ( ey1 != ey2 )
817 {
818 delta = lift;
819 mod += rem;
820 if ( mod >= 0 )
821 {
822 mod -= (int)dy;
823 delta++;
824 }
825
826 x2 = x + delta;
827 gray_render_scanline( RAS_VAR_ ey1, x,
828 (TCoord)( ONE_PIXEL - first ), x2,
829 (TCoord)first );
830 x = x2;
831
832 ey1 += incr;
833 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
834 }
835 }
836
837 gray_render_scanline( RAS_VAR_ ey1, x,
838 (TCoord)( ONE_PIXEL - first ), to_x,
839 fy2 );
840
841 End:
842 ras.x = to_x;
843 ras.y = to_y;
844 ras.last_ey = SUBPIXELS( ey2 );
845 }
846
847
848 static void
849 gray_split_conic( FT_Vector* base )
850 {
851 TPos a, b;
852
853
854 base[4].x = base[2].x;
855 b = base[1].x;
856 a = base[3].x = ( base[2].x + b ) / 2;
857 b = base[1].x = ( base[0].x + b ) / 2;
858 base[2].x = ( a + b ) / 2;
859
860 base[4].y = base[2].y;
861 b = base[1].y;
862 a = base[3].y = ( base[2].y + b ) / 2;
863 b = base[1].y = ( base[0].y + b ) / 2;
864 base[2].y = ( a + b ) / 2;
865 }
866
867
868 static void
869 gray_render_conic( RAS_ARG_ const FT_Vector* control,
870 const FT_Vector* to )
871 {
872 TPos dx, dy;
873 int top, level;
874 int* levels;
875 FT_Vector* arc;
876
877
878 dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
879 if ( dx < 0 )
880 dx = -dx;
881 dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
882 if ( dy < 0 )
883 dy = -dy;
884 if ( dx < dy )
885 dx = dy;
886
887 level = 1;
888 dx = dx / ras.conic_level;
889 while ( dx > 0 )
890 {
891 dx >>= 2;
892 level++;
893 }
894
895 /* a shortcut to speed things up */
896 if ( level <= 1 )
897 {
898 /* we compute the mid-point directly in order to avoid */
899 /* calling gray_split_conic() */
900 TPos to_x, to_y, mid_x, mid_y;
901
902
903 to_x = UPSCALE( to->x );
904 to_y = UPSCALE( to->y );
905 mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
906 mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
907
908 gray_render_line( RAS_VAR_ mid_x, mid_y );
909 gray_render_line( RAS_VAR_ to_x, to_y );
910
911 return;
912 }
913
914 arc = ras.bez_stack;
915 levels = ras.lev_stack;
916 top = 0;
917 levels[0] = level;
918
919 arc[0].x = UPSCALE( to->x );
920 arc[0].y = UPSCALE( to->y );
921 arc[1].x = UPSCALE( control->x );
922 arc[1].y = UPSCALE( control->y );
923 arc[2].x = ras.x;
924 arc[2].y = ras.y;
925
926 while ( top >= 0 )
927 {
928 level = levels[top];
929 if ( level > 1 )
930 {
931 /* check that the arc crosses the current band */
932 TPos min, max, y;
933
934
935 min = max = arc[0].y;
936
937 y = arc[1].y;
938 if ( y < min ) min = y;
939 if ( y > max ) max = y;
940
941 y = arc[2].y;
942 if ( y < min ) min = y;
943 if ( y > max ) max = y;
944
945 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
946 goto Draw;
947
948 gray_split_conic( arc );
949 arc += 2;
950 top++;
951 levels[top] = levels[top - 1] = level - 1;
952 continue;
953 }
954
955 Draw:
956 {
957 TPos to_x, to_y, mid_x, mid_y;
958
959
960 to_x = arc[0].x;
961 to_y = arc[0].y;
962 mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
963 mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
964
965 gray_render_line( RAS_VAR_ mid_x, mid_y );
966 gray_render_line( RAS_VAR_ to_x, to_y );
967
968 top--;
969 arc -= 2;
970 }
971 }
972
973 return;
974 }
975
976
977 static void
978 gray_split_cubic( FT_Vector* base )
979 {
980 TPos a, b, c, d;
981
982
983 base[6].x = base[3].x;
984 c = base[1].x;
985 d = base[2].x;
986 base[1].x = a = ( base[0].x + c ) / 2;
987 base[5].x = b = ( base[3].x + d ) / 2;
988 c = ( c + d ) / 2;
989 base[2].x = a = ( a + c ) / 2;
990 base[4].x = b = ( b + c ) / 2;
991 base[3].x = ( a + b ) / 2;
992
993 base[6].y = base[3].y;
994 c = base[1].y;
995 d = base[2].y;
996 base[1].y = a = ( base[0].y + c ) / 2;
997 base[5].y = b = ( base[3].y + d ) / 2;
998 c = ( c + d ) / 2;
999 base[2].y = a = ( a + c ) / 2;
1000 base[4].y = b = ( b + c ) / 2;
1001 base[3].y = ( a + b ) / 2;
1002 }
1003
1004
1005 static void
1006 gray_render_cubic( RAS_ARG_ const FT_Vector* control1,
1007 const FT_Vector* control2,
1008 const FT_Vector* to )
1009 {
1010 TPos dx, dy, da, db;
1011 int top, level;
1012 int* levels;
1013 FT_Vector* arc;
1014
1015
1016 dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
1017 if ( dx < 0 )
1018 dx = -dx;
1019 dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
1020 if ( dy < 0 )
1021 dy = -dy;
1022 if ( dx < dy )
1023 dx = dy;
1024 da = dx;
1025
1026 dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
1027 if ( dx < 0 )
1028 dx = -dx;
1029 dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
1030 if ( dy < 0 )
1031 dy = -dy;
1032 if ( dx < dy )
1033 dx = dy;
1034 db = dx;
1035
1036 level = 1;
1037 da = da / ras.cubic_level;
1038 db = db / ras.conic_level;
1039 while ( da > 0 || db > 0 )
1040 {
1041 da >>= 2;
1042 db >>= 3;
1043 level++;
1044 }
1045
1046 if ( level <= 1 )
1047 {
1048 TPos to_x, to_y, mid_x, mid_y;
1049
1050
1051 to_x = UPSCALE( to->x );
1052 to_y = UPSCALE( to->y );
1053 mid_x = ( ras.x + to_x +
1054 3 * UPSCALE( control1->x + control2->x ) ) / 8;
1055 mid_y = ( ras.y + to_y +
1056 3 * UPSCALE( control1->y + control2->y ) ) / 8;
1057
1058 gray_render_line( RAS_VAR_ mid_x, mid_y );
1059 gray_render_line( RAS_VAR_ to_x, to_y );
1060 return;
1061 }
1062
1063 arc = ras.bez_stack;
1064 arc[0].x = UPSCALE( to->x );
1065 arc[0].y = UPSCALE( to->y );
1066 arc[1].x = UPSCALE( control2->x );
1067 arc[1].y = UPSCALE( control2->y );
1068 arc[2].x = UPSCALE( control1->x );
1069 arc[2].y = UPSCALE( control1->y );
1070 arc[3].x = ras.x;
1071 arc[3].y = ras.y;
1072
1073 levels = ras.lev_stack;
1074 top = 0;
1075 levels[0] = level;
1076
1077 while ( top >= 0 )
1078 {
1079 level = levels[top];
1080 if ( level > 1 )
1081 {
1082 /* check that the arc crosses the current band */
1083 TPos min, max, y;
1084
1085
1086 min = max = arc[0].y;
1087 y = arc[1].y;
1088 if ( y < min ) min = y;
1089 if ( y > max ) max = y;
1090 y = arc[2].y;
1091 if ( y < min ) min = y;
1092 if ( y > max ) max = y;
1093 y = arc[3].y;
1094 if ( y < min ) min = y;
1095 if ( y > max ) max = y;
1096 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
1097 goto Draw;
1098 gray_split_cubic( arc );
1099 arc += 3;
1100 top ++;
1101 levels[top] = levels[top - 1] = level - 1;
1102 continue;
1103 }
1104
1105 Draw:
1106 {
1107 TPos to_x, to_y, mid_x, mid_y;
1108
1109
1110 to_x = arc[0].x;
1111 to_y = arc[0].y;
1112 mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
1113 mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
1114
1115 gray_render_line( RAS_VAR_ mid_x, mid_y );
1116 gray_render_line( RAS_VAR_ to_x, to_y );
1117 top --;
1118 arc -= 3;
1119 }
1120 }
1121
1122 return;
1123 }
1124
1125
1126
1127 static int
1128 gray_move_to( const FT_Vector* to,
1129 PWorker worker )
1130 {
1131 TPos x, y;
1132
1133
1134 /* record current cell, if any */
1135 gray_record_cell( RAS_VAR );
1136
1137 /* start to a new position */
1138 x = UPSCALE( to->x );
1139 y = UPSCALE( to->y );
1140
1141 gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) );
1142
1143 worker->x = x;
1144 worker->y = y;
1145 return 0;
1146 }
1147
1148
1149 static int
1150 gray_line_to( const FT_Vector* to,
1151 PWorker worker )
1152 {
1153 gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
1154 return 0;
1155 }
1156
1157
1158 static int
1159 gray_conic_to( const FT_Vector* control,
1160 const FT_Vector* to,
1161 PWorker worker )
1162 {
1163 gray_render_conic( RAS_VAR_ control, to );
1164 return 0;
1165 }
1166
1167
1168 static int
1169 gray_cubic_to( const FT_Vector* control1,
1170 const FT_Vector* control2,
1171 const FT_Vector* to,
1172 PWorker worker )
1173 {
1174 gray_render_cubic( RAS_VAR_ control1, control2, to );
1175 return 0;
1176 }
1177
1178
1179 static void
1180 gray_render_span( int y,
1181 int count,
1182 const FT_Span* spans,
1183 PWorker worker )
1184 {
1185 unsigned char* p;
1186 FT_Bitmap* map = &worker->target;
1187
1188
1189 /* first of all, compute the scanline offset */
1190 p = (unsigned char*)map->buffer - y * map->pitch;
1191 if ( map->pitch >= 0 )
1192 p += ( map->rows - 1 ) * map->pitch;
1193
1194 for ( ; count > 0; count--, spans++ )
1195 {
1196 unsigned char coverage = spans->coverage;
1197
1198
1199 if ( coverage )
1200 {
1201 /* For small-spans it is faster to do it by ourselves than
1202 * calling `memset'. This is mainly due to the cost of the
1203 * function call.
1204 */
1205 if ( spans->len >= 8 )
1206 FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
1207 else
1208 {
1209 unsigned char* q = p + spans->x;
1210
1211
1212 switch ( spans->len )
1213 {
1214 case 7: *q++ = (unsigned char)coverage;
1215 case 6: *q++ = (unsigned char)coverage;
1216 case 5: *q++ = (unsigned char)coverage;
1217 case 4: *q++ = (unsigned char)coverage;
1218 case 3: *q++ = (unsigned char)coverage;
1219 case 2: *q++ = (unsigned char)coverage;
1220 case 1: *q = (unsigned char)coverage;
1221 default:
1222 ;
1223 }
1224 }
1225 }
1226 }
1227 }
1228
1229
1230 static void
1231 gray_hline( RAS_ARG_ TCoord x,
1232 TCoord y,
1233 TPos area,
1234 TCoord acount )
1235 {
1236 FT_Span* span;
1237 int count;
1238 int coverage;
1239
1240
1241 /* compute the coverage line's coverage, depending on the */
1242 /* outline fill rule */
1243 /* */
1244 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1245 /* */
1246 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
1247 /* use range 0..256 */
1248 if ( coverage < 0 )
1249 coverage = -coverage;
1250
1251 if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
1252 {
1253 coverage &= 511;
1254
1255 if ( coverage > 256 )
1256 coverage = 512 - coverage;
1257 else if ( coverage == 256 )
1258 coverage = 255;
1259 }
1260 else
1261 {
1262 /* normal non-zero winding rule */
1263 if ( coverage >= 256 )
1264 coverage = 255;
1265 }
1266
1267 y += (TCoord)ras.min_ey;
1268 x += (TCoord)ras.min_ex;
1269
1270 /* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
1271 if ( x >= 32767 )
1272 x = 32767;
1273
1274 /* FT_Span.y is an integer, so limit our coordinates appropriately */
1275 if ( y >= FT_INT_MAX )
1276 y = FT_INT_MAX;
1277
1278 if ( coverage )
1279 {
1280 /* see whether we can add this span to the current list */
1281 count = ras.num_gray_spans;
1282 span = ras.gray_spans + count - 1;
1283 if ( count > 0 &&
1284 ras.span_y == y &&
1285 (int)span->x + span->len == (int)x &&
1286 span->coverage == coverage )
1287 {
1288 span->len = (unsigned short)( span->len + acount );
1289 return;
1290 }
1291
1292 if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
1293 {
1294 if ( ras.render_span && count > 0 )
1295 ras.render_span( ras.span_y, count, ras.gray_spans,
1296 ras.render_span_data );
1297
1298 #ifdef FT_DEBUG_LEVEL_TRACE
1299
1300 if ( count > 0 )
1301 {
1302 int n;
1303
1304
1305 FT_TRACE7(( "y = %3d ", ras.span_y ));
1306 span = ras.gray_spans;
1307 for ( n = 0; n < count; n++, span++ )
1308 FT_TRACE7(( "[%d..%d]:%02x ",
1309 span->x, span->x + span->len - 1, span->coverage ));
1310 FT_TRACE7(( "\n" ));
1311 }
1312
1313 #endif /* FT_DEBUG_LEVEL_TRACE */
1314
1315 ras.num_gray_spans = 0;
1316 ras.span_y = (int)y;
1317
1318 count = 0;
1319 span = ras.gray_spans;
1320 }
1321 else
1322 span++;
1323
1324 /* add a gray span to the current list */
1325 span->x = (short)x;
1326 span->len = (unsigned short)acount;
1327 span->coverage = (unsigned char)coverage;
1328
1329 ras.num_gray_spans++;
1330 }
1331 }
1332
1333
1334 #ifdef FT_DEBUG_LEVEL_TRACE
1335
1336 /* to be called while in the debugger -- */
1337 /* this function causes a compiler warning since it is unused otherwise */
1338 static void
1339 gray_dump_cells( RAS_ARG )
1340 {
1341 int yindex;
1342
1343
1344 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1345 {
1346 PCell cell;
1347
1348
1349 printf( "%3d:", yindex );
1350
1351 for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
1352 printf( " (%3ld, c:%4ld, a:%6d)", cell->x, cell->cover, cell->area );
1353 printf( "\n" );
1354 }
1355 }
1356
1357 #endif /* FT_DEBUG_LEVEL_TRACE */
1358
1359
1360 static void
1361 gray_sweep( RAS_ARG_ const FT_Bitmap* target )
1362 {
1363 int yindex;
1364
1365 FT_UNUSED( target );
1366
1367
1368 if ( ras.num_cells == 0 )
1369 return;
1370
1371 ras.num_gray_spans = 0;
1372
1373 FT_TRACE7(( "gray_sweep: start\n" ));
1374
1375 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1376 {
1377 PCell cell = ras.ycells[yindex];
1378 TCoord cover = 0;
1379 TCoord x = 0;
1380
1381
1382 for ( ; cell != NULL; cell = cell->next )
1383 {
1384 TPos area;
1385
1386
1387 if ( cell->x > x && cover != 0 )
1388 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1389 cell->x - x );
1390
1391 cover += cell->cover;
1392 area = cover * ( ONE_PIXEL * 2 ) - cell->area;
1393
1394 if ( area != 0 && cell->x >= 0 )
1395 gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
1396
1397 x = cell->x + 1;
1398 }
1399
1400 if ( cover != 0 )
1401 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1402 ras.count_ex - x );
1403 }
1404
1405 if ( ras.render_span && ras.num_gray_spans > 0 )
1406 ras.render_span( ras.span_y, ras.num_gray_spans,
1407 ras.gray_spans, ras.render_span_data );
1408
1409 FT_TRACE7(( "gray_sweep: end\n" ));
1410 }
1411
1412
1413 #ifdef _STANDALONE_
1414
1415 /*************************************************************************/
1416 /* */
1417 /* The following function should only compile in stand-alone mode, */
1418 /* i.e., when building this component without the rest of FreeType. */
1419 /* */
1420 /*************************************************************************/
1421
1422 /*************************************************************************/
1423 /* */
1424 /* <Function> */
1425 /* FT_Outline_Decompose */
1426 /* */
1427 /* <Description> */
1428 /* Walk over an outline's structure to decompose it into individual */
1429 /* segments and Bézier arcs. This function is also able to emit */
1430 /* `move to' and `close to' operations to indicate the start and end */
1431 /* of new contours in the outline. */
1432 /* */
1433 /* <Input> */
1434 /* outline :: A pointer to the source target. */
1435 /* */
1436 /* func_interface :: A table of `emitters', i.e., function pointers */
1437 /* called during decomposition to indicate path */
1438 /* operations. */
1439 /* */
1440 /* <InOut> */
1441 /* user :: A typeless pointer which is passed to each */
1442 /* emitter during the decomposition. It can be */
1443 /* used to store the state during the */
1444 /* decomposition. */
1445 /* */
1446 /* <Return> */
1447 /* Error code. 0 means success. */
1448 /* */
1449 static int
1450 FT_Outline_Decompose( const FT_Outline* outline,
1451 const FT_Outline_Funcs* func_interface,
1452 void* user )
1453 {
1454 #undef SCALED
1455 #define SCALED( x ) ( ( (x) << shift ) - delta )
1456
1457 FT_Vector v_last;
1458 FT_Vector v_control;
1459 FT_Vector v_start;
1460
1461 FT_Vector* point;
1462 FT_Vector* limit;
1463 char* tags;
1464
1465 int error;
1466
1467 int n; /* index of contour in outline */
1468 int first; /* index of first point in contour */
1469 char tag; /* current point's state */
1470
1471 int shift;
1472 TPos delta;
1473
1474
1475 if ( !outline || !func_interface )
1476 return ErrRaster_Invalid_Argument;
1477
1478 shift = func_interface->shift;
1479 delta = func_interface->delta;
1480 first = 0;
1481
1482 for ( n = 0; n < outline->n_contours; n++ )
1483 {
1484 int last; /* index of last point in contour */
1485
1486
1487 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
1488
1489 last = outline->contours[n];
1490 if ( last < 0 )
1491 goto Invalid_Outline;
1492 limit = outline->points + last;
1493
1494 v_start = outline->points[first];
1495 v_start.x = SCALED( v_start.x );
1496 v_start.y = SCALED( v_start.y );
1497
1498 v_last = outline->points[last];
1499 v_last.x = SCALED( v_last.x );
1500 v_last.y = SCALED( v_last.y );
1501
1502 v_control = v_start;
1503
1504 point = outline->points + first;
1505 tags = outline->tags + first;
1506 tag = FT_CURVE_TAG( tags[0] );
1507
1508 /* A contour cannot start with a cubic control point! */
1509 if ( tag == FT_CURVE_TAG_CUBIC )
1510 goto Invalid_Outline;
1511
1512 /* check first point to determine origin */
1513 if ( tag == FT_CURVE_TAG_CONIC )
1514 {
1515 /* first point is conic control. Yes, this happens. */
1516 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
1517 {
1518 /* start at last point if it is on the curve */
1519 v_start = v_last;
1520 limit--;
1521 }
1522 else
1523 {
1524 /* if both first and last points are conic, */
1525 /* start at their middle and record its position */
1526 /* for closure */
1527 v_start.x = ( v_start.x + v_last.x ) / 2;
1528 v_start.y = ( v_start.y + v_last.y ) / 2;
1529
1530 v_last = v_start;
1531 }
1532 point--;
1533 tags--;
1534 }
1535
1536 FT_TRACE5(( " move to (%.2f, %.2f)\n",
1537 v_start.x / 64.0, v_start.y / 64.0 ));
1538 error = func_interface->move_to( &v_start, user );
1539 if ( error )
1540 goto Exit;
1541
1542 while ( point < limit )
1543 {
1544 point++;
1545 tags++;
1546
1547 tag = FT_CURVE_TAG( tags[0] );
1548 switch ( tag )
1549 {
1550 case FT_CURVE_TAG_ON: /* emit a single line_to */
1551 {
1552 FT_Vector vec;
1553
1554
1555 vec.x = SCALED( point->x );
1556 vec.y = SCALED( point->y );
1557
1558 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1559 vec.x / 64.0, vec.y / 64.0 ));
1560 error = func_interface->line_to( &vec, user );
1561 if ( error )
1562 goto Exit;
1563 continue;
1564 }
1565
1566 case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1567 v_control.x = SCALED( point->x );
1568 v_control.y = SCALED( point->y );
1569
1570 Do_Conic:
1571 if ( point < limit )
1572 {
1573 FT_Vector vec;
1574 FT_Vector v_middle;
1575
1576
1577 point++;
1578 tags++;
1579 tag = FT_CURVE_TAG( tags[0] );
1580
1581 vec.x = SCALED( point->x );
1582 vec.y = SCALED( point->y );
1583
1584 if ( tag == FT_CURVE_TAG_ON )
1585 {
1586 FT_TRACE5(( " conic to (%.2f, %.2f)"
1587 " with control (%.2f, %.2f)\n",
1588 vec.x / 64.0, vec.y / 64.0,
1589 v_control.x / 64.0, v_control.y / 64.0 ));
1590 error = func_interface->conic_to( &v_control, &vec, user );
1591 if ( error )
1592 goto Exit;
1593 continue;
1594 }
1595
1596 if ( tag != FT_CURVE_TAG_CONIC )
1597 goto Invalid_Outline;
1598
1599 v_middle.x = ( v_control.x + vec.x ) / 2;
1600 v_middle.y = ( v_control.y + vec.y ) / 2;
1601
1602 FT_TRACE5(( " conic to (%.2f, %.2f)"
1603 " with control (%.2f, %.2f)\n",
1604 v_middle.x / 64.0, v_middle.y / 64.0,
1605 v_control.x / 64.0, v_control.y / 64.0 ));
1606 error = func_interface->conic_to( &v_control, &v_middle, user );
1607 if ( error )
1608 goto Exit;
1609
1610 v_control = vec;
1611 goto Do_Conic;
1612 }
1613
1614 FT_TRACE5(( " conic to (%.2f, %.2f)"
1615 " with control (%.2f, %.2f)\n",
1616 v_start.x / 64.0, v_start.y / 64.0,
1617 v_control.x / 64.0, v_control.y / 64.0 ));
1618 error = func_interface->conic_to( &v_control, &v_start, user );
1619 goto Close;
1620
1621 default: /* FT_CURVE_TAG_CUBIC */
1622 {
1623 FT_Vector vec1, vec2;
1624
1625
1626 if ( point + 1 > limit ||
1627 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1628 goto Invalid_Outline;
1629
1630 point += 2;
1631 tags += 2;
1632
1633 vec1.x = SCALED( point[-2].x );
1634 vec1.y = SCALED( point[-2].y );
1635
1636 vec2.x = SCALED( point[-1].x );
1637 vec2.y = SCALED( point[-1].y );
1638
1639 if ( point <= limit )
1640 {
1641 FT_Vector vec;
1642
1643
1644 vec.x = SCALED( point->x );
1645 vec.y = SCALED( point->y );
1646
1647 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1648 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1649 vec.x / 64.0, vec.y / 64.0,
1650 vec1.x / 64.0, vec1.y / 64.0,
1651 vec2.x / 64.0, vec2.y / 64.0 ));
1652 error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
1653 if ( error )
1654 goto Exit;
1655 continue;
1656 }
1657
1658 FT_TRACE5(( " cubic to (%.2f, %.2f)"
1659 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
1660 v_start.x / 64.0, v_start.y / 64.0,
1661 vec1.x / 64.0, vec1.y / 64.0,
1662 vec2.x / 64.0, vec2.y / 64.0 ));
1663 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
1664 goto Close;
1665 }
1666 }
1667 }
1668
1669 /* close the contour with a line segment */
1670 FT_TRACE5(( " line to (%.2f, %.2f)\n",
1671 v_start.x / 64.0, v_start.y / 64.0 ));
1672 error = func_interface->line_to( &v_start, user );
1673
1674 Close:
1675 if ( error )
1676 goto Exit;
1677
1678 first = last + 1;
1679 }
1680
1681 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
1682 return 0;
1683
1684 Exit:
1685 FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
1686 return error;
1687
1688 Invalid_Outline:
1689 return ErrRaster_Invalid_Outline;
1690 }
1691
1692 #endif /* _STANDALONE_ */
1693
1694
1695 typedef struct TBand_
1696 {
1697 TPos min, max;
1698
1699 } TBand;
1700
1701 FT_DEFINE_OUTLINE_FUNCS(func_interface,
1702 (FT_Outline_MoveTo_Func) gray_move_to,
1703 (FT_Outline_LineTo_Func) gray_line_to,
1704 (FT_Outline_ConicTo_Func)gray_conic_to,
1705 (FT_Outline_CubicTo_Func)gray_cubic_to,
1706 0,
1707 0
1708 )
1709
1710 static int
1711 gray_convert_glyph_inner( RAS_ARG )
1712 {
1713
1714 volatile int error = 0;
1715
1716 #ifdef FT_CONFIG_OPTION_PIC
1717 FT_Outline_Funcs func_interface;
1718 Init_Class_func_interface(&func_interface);
1719 #endif
1720
1721 if ( ft_setjmp( ras.jump_buffer ) == 0 )
1722 {
1723 error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
1724 gray_record_cell( RAS_VAR );
1725 }
1726 else
1727 error = ErrRaster_Memory_Overflow;
1728
1729 return error;
1730 }
1731
1732
1733 static int
1734 gray_convert_glyph( RAS_ARG )
1735 {
1736 TBand bands[40];
1737 TBand* volatile band;
1738 int volatile n, num_bands;
1739 TPos volatile min, max, max_y;
1740 FT_BBox* clip;
1741
1742
1743 /* Set up state in the raster object */
1744 gray_compute_cbox( RAS_VAR );
1745
1746 /* clip to target bitmap, exit if nothing to do */
1747 clip = &ras.clip_box;
1748
1749 if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
1750 ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
1751 return 0;
1752
1753 if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
1754 if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
1755
1756 if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
1757 if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
1758
1759 ras.count_ex = ras.max_ex - ras.min_ex;
1760 ras.count_ey = ras.max_ey - ras.min_ey;
1761
1762 /* simple heuristic used to speed up the bezier decomposition -- see */
1763 /* the code in gray_render_conic() and gray_render_cubic() for more */
1764 /* details */
1765 ras.conic_level = 32;
1766 ras.cubic_level = 16;
1767
1768 {
1769 int level = 0;
1770
1771
1772 if ( ras.count_ex > 24 || ras.count_ey > 24 )
1773 level++;
1774 if ( ras.count_ex > 120 || ras.count_ey > 120 )
1775 level++;
1776
1777 ras.conic_level <<= level;
1778 ras.cubic_level <<= level;
1779 }
1780
1781 /* set up vertical bands */
1782 num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
1783 if ( num_bands == 0 )
1784 num_bands = 1;
1785 if ( num_bands >= 39 )
1786 num_bands = 39;
1787
1788 ras.band_shoot = 0;
1789
1790 min = ras.min_ey;
1791 max_y = ras.max_ey;
1792
1793 for ( n = 0; n < num_bands; n++, min = max )
1794 {
1795 max = min + ras.band_size;
1796 if ( n == num_bands - 1 || max > max_y )
1797 max = max_y;
1798
1799 bands[0].min = min;
1800 bands[0].max = max;
1801 band = bands;
1802
1803 while ( band >= bands )
1804 {
1805 TPos bottom, top, middle;
1806 int error;
1807
1808 {
1809 PCell cells_max;
1810 int yindex;
1811 long cell_start, cell_end, cell_mod;
1812
1813
1814 ras.ycells = (PCell*)ras.buffer;
1815 ras.ycount = band->max - band->min;
1816
1817 cell_start = sizeof ( PCell ) * ras.ycount;
1818 cell_mod = cell_start % sizeof ( TCell );
1819 if ( cell_mod > 0 )
1820 cell_start += sizeof ( TCell ) - cell_mod;
1821
1822 cell_end = ras.buffer_size;
1823 cell_end -= cell_end % sizeof( TCell );
1824
1825 cells_max = (PCell)( (char*)ras.buffer + cell_end );
1826 ras.cells = (PCell)( (char*)ras.buffer + cell_start );
1827 if ( ras.cells >= cells_max )
1828 goto ReduceBands;
1829
1830 ras.max_cells = cells_max - ras.cells;
1831 if ( ras.max_cells < 2 )
1832 goto ReduceBands;
1833
1834 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1835 ras.ycells[yindex] = NULL;
1836 }
1837
1838 ras.num_cells = 0;
1839 ras.invalid = 1;
1840 ras.min_ey = band->min;
1841 ras.max_ey = band->max;
1842 ras.count_ey = band->max - band->min;
1843
1844 error = gray_convert_glyph_inner( RAS_VAR );
1845
1846 if ( !error )
1847 {
1848 gray_sweep( RAS_VAR_ &ras.target );
1849 band--;
1850 continue;
1851 }
1852 else if ( error != ErrRaster_Memory_Overflow )
1853 return 1;
1854
1855 ReduceBands:
1856 /* render pool overflow; we will reduce the render band by half */
1857 bottom = band->min;
1858 top = band->max;
1859 middle = bottom + ( ( top - bottom ) >> 1 );
1860
1861 /* This is too complex for a single scanline; there must */
1862 /* be some problems. */
1863 if ( middle == bottom )
1864 {
1865 #ifdef FT_DEBUG_LEVEL_TRACE
1866 FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" ));
1867 #endif
1868 return 1;
1869 }
1870
1871 if ( bottom-top >= ras.band_size )
1872 ras.band_shoot++;
1873
1874 band[1].min = bottom;
1875 band[1].max = middle;
1876 band[0].min = middle;
1877 band[0].max = top;
1878 band++;
1879 }
1880 }
1881
1882 if ( ras.band_shoot > 8 && ras.band_size > 16 )
1883 ras.band_size = ras.band_size / 2;
1884
1885 return 0;
1886 }
1887
1888
1889 static int
1890 gray_raster_render( PRaster raster,
1891 const FT_Raster_Params* params )
1892 {
1893 const FT_Outline* outline = (const FT_Outline*)params->source;
1894 const FT_Bitmap* target_map = params->target;
1895 PWorker worker;
1896
1897
1898 if ( !raster || !raster->buffer || !raster->buffer_size )
1899 return ErrRaster_Invalid_Argument;
1900
1901 if ( !outline )
1902 return ErrRaster_Invalid_Outline;
1903
1904 /* return immediately if the outline is empty */
1905 if ( outline->n_points == 0 || outline->n_contours <= 0 )
1906 return 0;
1907
1908 if ( !outline->contours || !outline->points )
1909 return ErrRaster_Invalid_Outline;
1910
1911 if ( outline->n_points !=
1912 outline->contours[outline->n_contours - 1] + 1 )
1913 return ErrRaster_Invalid_Outline;
1914
1915 worker = raster->worker;
1916
1917 /* if direct mode is not set, we must have a target bitmap */
1918 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
1919 {
1920 if ( !target_map )
1921 return ErrRaster_Invalid_Argument;
1922
1923 /* nothing to do */
1924 if ( !target_map->width || !target_map->rows )
1925 return 0;
1926
1927 if ( !target_map->buffer )
1928 return ErrRaster_Invalid_Argument;
1929 }
1930
1931 /* this version does not support monochrome rendering */
1932 if ( !( params->flags & FT_RASTER_FLAG_AA ) )
1933 return ErrRaster_Invalid_Mode;
1934
1935 /* compute clipping box */
1936 if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
1937 {
1938 /* compute clip box from target pixmap */
1939 ras.clip_box.xMin = 0;
1940 ras.clip_box.yMin = 0;
1941 ras.clip_box.xMax = target_map->width;
1942 ras.clip_box.yMax = target_map->rows;
1943 }
1944 else if ( params->flags & FT_RASTER_FLAG_CLIP )
1945 ras.clip_box = params->clip_box;
1946 else
1947 {
1948 ras.clip_box.xMin = -32768L;
1949 ras.clip_box.yMin = -32768L;
1950 ras.clip_box.xMax = 32767L;
1951 ras.clip_box.yMax = 32767L;
1952 }
1953
1954 gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size );
1955
1956 ras.outline = *outline;
1957 ras.num_cells = 0;
1958 ras.invalid = 1;
1959 ras.band_size = raster->band_size;
1960 ras.num_gray_spans = 0;
1961
1962 if ( params->flags & FT_RASTER_FLAG_DIRECT )
1963 {
1964 ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
1965 ras.render_span_data = params->user;
1966 }
1967 else
1968 {
1969 ras.target = *target_map;
1970 ras.render_span = (FT_Raster_Span_Func)gray_render_span;
1971 ras.render_span_data = &ras;
1972 }
1973
1974 return gray_convert_glyph( RAS_VAR );
1975 }
1976
1977
1978 /**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/
1979 /**** a static object. *****/
1980
1981 #ifdef _STANDALONE_
1982
1983 static int
1984 gray_raster_new( void* memory,
1985 FT_Raster* araster )
1986 {
1987 static TRaster the_raster;
1988
1989 FT_UNUSED( memory );
1990
1991
1992 *araster = (FT_Raster)&the_raster;
1993 FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
1994
1995 return 0;
1996 }
1997
1998
1999 static void
2000 gray_raster_done( FT_Raster raster )
2001 {
2002 /* nothing */
2003 FT_UNUSED( raster );
2004 }
2005
2006 #else /* _STANDALONE_ */
2007
2008 static int
2009 gray_raster_new( FT_Memory memory,
2010 FT_Raster* araster )
2011 {
2012 FT_Error error;
2013 PRaster raster;
2014
2015
2016 *araster = 0;
2017 if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) )
2018 {
2019 raster->memory = memory;
2020 *araster = (FT_Raster)raster;
2021 }
2022
2023 return error;
2024 }
2025
2026
2027 static void
2028 gray_raster_done( FT_Raster raster )
2029 {
2030 FT_Memory memory = (FT_Memory)((PRaster)raster)->memory;
2031
2032
2033 FT_FREE( raster );
2034 }
2035
2036 #endif /* _STANDALONE_ */
2037
2038
2039 static void
2040 gray_raster_reset( FT_Raster raster,
2041 char* pool_base,
2042 long pool_size )
2043 {
2044 PRaster rast = (PRaster)raster;
2045
2046
2047 if ( raster )
2048 {
2049 if ( pool_base && pool_size >= (long)sizeof ( TWorker ) + 2048 )
2050 {
2051 PWorker worker = (PWorker)pool_base;
2052
2053
2054 rast->worker = worker;
2055 rast->buffer = pool_base +
2056 ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) &
2057 ~( sizeof ( TCell ) - 1 ) );
2058 rast->buffer_size = (long)( ( pool_base + pool_size ) -
2059 (char*)rast->buffer ) &
2060 ~( sizeof ( TCell ) - 1 );
2061 rast->band_size = (int)( rast->buffer_size /
2062 ( sizeof ( TCell ) * 8 ) );
2063 }
2064 else
2065 {
2066 rast->buffer = NULL;
2067 rast->buffer_size = 0;
2068 rast->worker = NULL;
2069 }
2070 }
2071 }
2072
2073
2074 FT_DEFINE_RASTER_FUNCS(ft_grays_raster,
2075 FT_GLYPH_FORMAT_OUTLINE,
2076
2077 (FT_Raster_New_Func) gray_raster_new,
2078 (FT_Raster_Reset_Func) gray_raster_reset,
2079 (FT_Raster_Set_Mode_Func)0,
2080 (FT_Raster_Render_Func) gray_raster_render,
2081 (FT_Raster_Done_Func) gray_raster_done
2082 )
2083
2084
2085 /* END */
2086
2087
2088 /* Local Variables: */
2089 /* coding: utf-8 */
2090 /* End: */