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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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