source: trunk/src/gui/painting/qgrayraster.c@ 460

Last change on this file since 460 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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