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