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

Last change on this file since 1034 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 55.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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#define ErrRaster_OutOfMemory -6
160
161#define QT_FT_BEGIN_HEADER
162#define QT_FT_END_HEADER
163
164#include <private/qrasterdefs_p.h>
165#include <private/qgrayraster_p.h>
166
167#include <stdlib.h>
168#include <stdio.h>
169
170 /* This macro is used to indicate that a function parameter is unused. */
171 /* Its purpose is simply to reduce compiler warnings. Note also that */
172 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
173 /* ANSI compilers (e.g. LCC). */
174#define QT_FT_UNUSED( x ) (x) = (x)
175
176 /* Disable the tracing mechanism for simplicity -- developers can */
177 /* activate it easily by redefining these two macros. */
178#ifndef QT_FT_ERROR
179#define QT_FT_ERROR( x ) do ; while ( 0 ) /* nothing */
180#endif
181
182#ifndef QT_FT_TRACE
183#define QT_FT_TRACE( x ) do ; while ( 0 ) /* nothing */
184#endif
185
186#ifndef QT_FT_MEM_SET
187#define QT_FT_MEM_SET( d, s, c ) qt_ft_memset( d, s, c )
188#endif
189
190#ifndef QT_FT_MEM_ZERO
191#define QT_FT_MEM_ZERO( dest, count ) QT_FT_MEM_SET( dest, 0, count )
192#endif
193
194 /* define this to dump debugging information */
195#define xxxDEBUG_GRAYS
196
197
198#define RAS_ARG PWorker worker
199#define RAS_ARG_ PWorker worker,
200
201#define RAS_VAR worker
202#define RAS_VAR_ worker,
203
204#define ras (*worker)
205
206
207 /* must be at least 6 bits! */
208#define PIXEL_BITS 8
209
210#define ONE_PIXEL ( 1L << PIXEL_BITS )
211#define PIXEL_MASK ( -1L << PIXEL_BITS )
212#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
213#define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS )
214#define FLOOR( x ) ( (x) & -ONE_PIXEL )
215#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
216#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
217
218#if PIXEL_BITS >= 6
219#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) )
220#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
221#else
222#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
223#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
224#endif
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 int 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 int skip_spans;
321 } TWorker, *PWorker;
322
323
324 typedef struct TRaster_
325 {
326 void* buffer;
327 long buffer_size;
328 long buffer_allocated_size;
329 int band_size;
330 void* memory;
331 PWorker worker;
332
333 } TRaster, *PRaster;
334
335 int q_gray_rendered_spans(TRaster *raster)
336 {
337 if ( raster && raster->worker )
338 return raster->worker->skip_spans > 0 ? 0 : -raster->worker->skip_spans;
339 return 0;
340 }
341
342 /*************************************************************************/
343 /* */
344 /* Initialize the cells table. */
345 /* */
346 static void
347 gray_init_cells( RAS_ARG_ void* buffer,
348 long byte_size )
349 {
350 ras.buffer = buffer;
351 ras.buffer_size = byte_size;
352
353 ras.ycells = (PCell*) buffer;
354 ras.cells = NULL;
355 ras.max_cells = 0;
356 ras.num_cells = 0;
357 ras.area = 0;
358 ras.cover = 0;
359 ras.invalid = 1;
360 }
361
362
363 /*************************************************************************/
364 /* */
365 /* Compute the outline bounding box. */
366 /* */
367 static void
368 gray_compute_cbox( RAS_ARG )
369 {
370 QT_FT_Outline* outline = &ras.outline;
371 QT_FT_Vector* vec = outline->points;
372 QT_FT_Vector* limit = vec + outline->n_points;
373
374
375 if ( outline->n_points <= 0 )
376 {
377 ras.min_ex = ras.max_ex = 0;
378 ras.min_ey = ras.max_ey = 0;
379 return;
380 }
381
382 ras.min_ex = ras.max_ex = vec->x;
383 ras.min_ey = ras.max_ey = vec->y;
384
385 vec++;
386
387 for ( ; vec < limit; vec++ )
388 {
389 TPos x = vec->x;
390 TPos y = vec->y;
391
392
393 if ( x < ras.min_ex ) ras.min_ex = x;
394 if ( x > ras.max_ex ) ras.max_ex = x;
395 if ( y < ras.min_ey ) ras.min_ey = y;
396 if ( y > ras.max_ey ) ras.max_ey = y;
397 }
398
399 /* truncate the bounding box to integer pixels */
400 ras.min_ex = ras.min_ex >> 6;
401 ras.min_ey = ras.min_ey >> 6;
402 ras.max_ex = ( ras.max_ex + 63 ) >> 6;
403 ras.max_ey = ( ras.max_ey + 63 ) >> 6;
404 }
405
406
407 /*************************************************************************/
408 /* */
409 /* Record the current cell in the table. */
410 /* */
411 static PCell
412 gray_find_cell( RAS_ARG )
413 {
414 PCell *pcell, cell;
415 int x = ras.ex;
416
417
418 if ( x > ras.max_ex )
419 x = ras.max_ex;
420
421 pcell = &ras.ycells[ras.ey];
422 for (;;)
423 {
424 cell = *pcell;
425 if ( cell == NULL || cell->x > x )
426 break;
427
428 if ( cell->x == x )
429 goto Exit;
430
431 pcell = &cell->next;
432 }
433
434 if ( ras.num_cells >= ras.max_cells )
435 qt_ft_longjmp( ras.jump_buffer, 1 );
436
437 cell = ras.cells + ras.num_cells++;
438 cell->x = x;
439 cell->area = 0;
440 cell->cover = 0;
441
442 cell->next = *pcell;
443 *pcell = cell;
444
445 Exit:
446 return cell;
447 }
448
449
450 static void
451 gray_record_cell( RAS_ARG )
452 {
453 if ( !ras.invalid && ( ras.area | ras.cover ) )
454 {
455 PCell cell = gray_find_cell( RAS_VAR );
456
457
458 cell->area += ras.area;
459 cell->cover += ras.cover;
460 }
461 }
462
463
464 /*************************************************************************/
465 /* */
466 /* Set the current cell to a new position. */
467 /* */
468 static void
469 gray_set_cell( RAS_ARG_ TCoord ex,
470 TCoord ey )
471 {
472 /* Move the cell pointer to a new position. We set the `invalid' */
473 /* flag to indicate that the cell isn't part of those we're interested */
474 /* in during the render phase. This means that: */
475 /* */
476 /* . the new vertical position must be within min_ey..max_ey-1. */
477 /* . the new horizontal position must be strictly less than max_ex */
478 /* */
479 /* Note that if a cell is to the left of the clipping region, it is */
480 /* actually set to the (min_ex-1) horizontal position. */
481
482 /* All cells that are on the left of the clipping region go to the */
483 /* min_ex - 1 horizontal position. */
484 ey -= ras.min_ey;
485
486 if ( ex > ras.max_ex )
487 ex = ras.max_ex;
488
489 ex -= ras.min_ex;
490 if ( ex < 0 )
491 ex = -1;
492
493 /* are we moving to a different cell ? */
494 if ( ex != ras.ex || ey != ras.ey )
495 {
496 /* record the current one if it is valid */
497 if ( !ras.invalid )
498 gray_record_cell( RAS_VAR );
499
500 ras.area = 0;
501 ras.cover = 0;
502 }
503
504 ras.ex = ex;
505 ras.ey = ey;
506 ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
507 ex >= ras.count_ex );
508 }
509
510
511 /*************************************************************************/
512 /* */
513 /* Start a new contour at a given cell. */
514 /* */
515 static void
516 gray_start_cell( RAS_ARG_ TCoord ex,
517 TCoord ey )
518 {
519 if ( ex > ras.max_ex )
520 ex = (TCoord)( ras.max_ex );
521
522 if ( ex < ras.min_ex )
523 ex = (TCoord)( ras.min_ex - 1 );
524
525 ras.area = 0;
526 ras.cover = 0;
527 ras.ex = ex - ras.min_ex;
528 ras.ey = ey - ras.min_ey;
529 ras.last_ey = SUBPIXELS( ey );
530 ras.invalid = 0;
531
532 gray_set_cell( RAS_VAR_ ex, ey );
533 }
534
535
536 /*************************************************************************/
537 /* */
538 /* Render a scanline as one or more cells. */
539 /* */
540 static void
541 gray_render_scanline( RAS_ARG_ TCoord ey,
542 TPos x1,
543 TCoord y1,
544 TPos x2,
545 TCoord y2 )
546 {
547 TCoord ex1, ex2, fx1, fx2, delta;
548 int p, first, dx;
549 int incr, lift, mod, rem;
550
551
552 dx = x2 - x1;
553
554 ex1 = TRUNC( x1 );
555 ex2 = TRUNC( x2 );
556 fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
557 fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
558
559 /* trivial case. Happens often */
560 if ( y1 == y2 )
561 {
562 gray_set_cell( RAS_VAR_ ex2, ey );
563 return;
564 }
565
566 /* everything is located in a single cell. That is easy! */
567 /* */
568 if ( ex1 == ex2 )
569 {
570 delta = y2 - y1;
571 ras.area += (TArea)( fx1 + fx2 ) * delta;
572 ras.cover += delta;
573 return;
574 }
575
576 /* ok, we'll have to render a run of adjacent cells on the same */
577 /* scanline... */
578 /* */
579 p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
580 first = ONE_PIXEL;
581 incr = 1;
582
583 if ( dx < 0 )
584 {
585 p = fx1 * ( y2 - y1 );
586 first = 0;
587 incr = -1;
588 dx = -dx;
589 }
590
591 delta = (TCoord)( p / dx );
592 mod = (TCoord)( p % dx );
593 if ( mod < 0 )
594 {
595 delta--;
596 mod += (TCoord)dx;
597 }
598
599 ras.area += (TArea)( fx1 + first ) * delta;
600 ras.cover += delta;
601
602 ex1 += incr;
603 gray_set_cell( RAS_VAR_ ex1, ey );
604 y1 += delta;
605
606 if ( ex1 != ex2 )
607 {
608 p = ONE_PIXEL * ( y2 - y1 + delta );
609 lift = (TCoord)( p / dx );
610 rem = (TCoord)( p % dx );
611 if ( rem < 0 )
612 {
613 lift--;
614 rem += (TCoord)dx;
615 }
616
617 mod -= (int)dx;
618
619 while ( ex1 != ex2 )
620 {
621 delta = lift;
622 mod += rem;
623 if ( mod >= 0 )
624 {
625 mod -= (TCoord)dx;
626 delta++;
627 }
628
629 ras.area += (TArea)ONE_PIXEL * delta;
630 ras.cover += delta;
631 y1 += delta;
632 ex1 += incr;
633 gray_set_cell( RAS_VAR_ ex1, ey );
634 }
635 }
636
637 delta = y2 - y1;
638 ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
639 ras.cover += delta;
640 }
641
642
643 /*************************************************************************/
644 /* */
645 /* Render a given line as a series of scanlines. */
646 /* */
647 static void
648 gray_render_line( RAS_ARG_ TPos to_x,
649 TPos to_y )
650 {
651 TCoord ey1, ey2, fy1, fy2;
652 TPos dx, dy, x, x2;
653 int p, first;
654 int delta, rem, mod, lift, incr;
655
656
657 ey1 = TRUNC( ras.last_ey );
658 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
659 fy1 = (TCoord)( ras.y - ras.last_ey );
660 fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
661
662 dx = to_x - ras.x;
663 dy = to_y - ras.y;
664
665 /* XXX: we should do something about the trivial case where dx == 0, */
666 /* as it happens very often! */
667
668 /* perform vertical clipping */
669 {
670 TCoord min, max;
671
672
673 min = ey1;
674 max = ey2;
675 if ( ey1 > ey2 )
676 {
677 min = ey2;
678 max = ey1;
679 }
680 if ( min >= ras.max_ey || max < ras.min_ey )
681 goto End;
682 }
683
684 /* everything is on a single scanline */
685 if ( ey1 == ey2 )
686 {
687 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
688 goto End;
689 }
690
691 /* vertical line - avoid calling gray_render_scanline */
692 incr = 1;
693
694 if ( dx == 0 )
695 {
696 TCoord ex = TRUNC( ras.x );
697 TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
698 TPos area;
699
700
701 first = ONE_PIXEL;
702 if ( dy < 0 )
703 {
704 first = 0;
705 incr = -1;
706 }
707
708 delta = (int)( first - fy1 );
709 ras.area += (TArea)two_fx * delta;
710 ras.cover += delta;
711 ey1 += incr;
712
713 gray_set_cell( &ras, ex, ey1 );
714
715 delta = (int)( first + first - ONE_PIXEL );
716 area = (TArea)two_fx * delta;
717 while ( ey1 != ey2 )
718 {
719 ras.area += area;
720 ras.cover += delta;
721 ey1 += incr;
722
723 gray_set_cell( &ras, ex, ey1 );
724 }
725
726 delta = (int)( fy2 - ONE_PIXEL + first );
727 ras.area += (TArea)two_fx * delta;
728 ras.cover += delta;
729
730 goto End;
731 }
732
733 /* ok, we have to render several scanlines */
734 p = ( ONE_PIXEL - fy1 ) * dx;
735 first = ONE_PIXEL;
736 incr = 1;
737
738 if ( dy < 0 )
739 {
740 p = fy1 * dx;
741 first = 0;
742 incr = -1;
743 dy = -dy;
744 }
745
746 delta = (int)( p / dy );
747 mod = (int)( p % dy );
748 if ( mod < 0 )
749 {
750 delta--;
751 mod += (TCoord)dy;
752 }
753
754 x = ras.x + delta;
755 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
756
757 ey1 += incr;
758 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
759
760 if ( ey1 != ey2 )
761 {
762 p = ONE_PIXEL * dx;
763 lift = (int)( p / dy );
764 rem = (int)( p % dy );
765 if ( rem < 0 )
766 {
767 lift--;
768 rem += (int)dy;
769 }
770 mod -= (int)dy;
771
772 while ( ey1 != ey2 )
773 {
774 delta = lift;
775 mod += rem;
776 if ( mod >= 0 )
777 {
778 mod -= (int)dy;
779 delta++;
780 }
781
782 x2 = x + delta;
783 gray_render_scanline( RAS_VAR_ ey1, x,
784 (TCoord)( ONE_PIXEL - first ), x2,
785 (TCoord)first );
786 x = x2;
787
788 ey1 += incr;
789 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
790 }
791 }
792
793 gray_render_scanline( RAS_VAR_ ey1, x,
794 (TCoord)( ONE_PIXEL - first ), to_x,
795 fy2 );
796
797 End:
798 ras.x = to_x;
799 ras.y = to_y;
800 ras.last_ey = SUBPIXELS( ey2 );
801 }
802
803
804 static void
805 gray_split_conic( QT_FT_Vector* base )
806 {
807 TPos a, b;
808
809
810 base[4].x = base[2].x;
811 b = base[1].x;
812 a = base[3].x = ( base[2].x + b ) / 2;
813 b = base[1].x = ( base[0].x + b ) / 2;
814 base[2].x = ( a + b ) / 2;
815
816 base[4].y = base[2].y;
817 b = base[1].y;
818 a = base[3].y = ( base[2].y + b ) / 2;
819 b = base[1].y = ( base[0].y + b ) / 2;
820 base[2].y = ( a + b ) / 2;
821 }
822
823
824 static void
825 gray_render_conic( RAS_ARG_ const QT_FT_Vector* control,
826 const QT_FT_Vector* to )
827 {
828 TPos dx, dy;
829 int top, level;
830 int* levels;
831 QT_FT_Vector* arc;
832
833
834 dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
835 if ( dx < 0 )
836 dx = -dx;
837 dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
838 if ( dy < 0 )
839 dy = -dy;
840 if ( dx < dy )
841 dx = dy;
842
843 level = 1;
844 dx = dx / ras.conic_level;
845 while ( dx > 0 )
846 {
847 dx >>= 2;
848 level++;
849 }
850
851 /* a shortcut to speed things up */
852 if ( level <= 1 )
853 {
854 /* we compute the mid-point directly in order to avoid */
855 /* calling gray_split_conic() */
856 TPos to_x, to_y, mid_x, mid_y;
857
858
859 to_x = UPSCALE( to->x );
860 to_y = UPSCALE( to->y );
861 mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
862 mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
863
864 gray_render_line( RAS_VAR_ mid_x, mid_y );
865 gray_render_line( RAS_VAR_ to_x, to_y );
866
867 return;
868 }
869
870 arc = ras.bez_stack;
871 levels = ras.lev_stack;
872 top = 0;
873 levels[0] = level;
874
875 arc[0].x = UPSCALE( to->x );
876 arc[0].y = UPSCALE( to->y );
877 arc[1].x = UPSCALE( control->x );
878 arc[1].y = UPSCALE( control->y );
879 arc[2].x = ras.x;
880 arc[2].y = ras.y;
881
882 while ( top >= 0 )
883 {
884 level = levels[top];
885 if ( level > 1 )
886 {
887 /* check that the arc crosses the current band */
888 TPos min, max, y;
889
890
891 min = max = arc[0].y;
892
893 y = arc[1].y;
894 if ( y < min ) min = y;
895 if ( y > max ) max = y;
896
897 y = arc[2].y;
898 if ( y < min ) min = y;
899 if ( y > max ) max = y;
900
901 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
902 goto Draw;
903
904 gray_split_conic( arc );
905 arc += 2;
906 top++;
907 levels[top] = levels[top - 1] = level - 1;
908 continue;
909 }
910
911 Draw:
912 {
913 TPos to_x, to_y, mid_x, mid_y;
914
915
916 to_x = arc[0].x;
917 to_y = arc[0].y;
918 mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
919 mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
920
921 gray_render_line( RAS_VAR_ mid_x, mid_y );
922 gray_render_line( RAS_VAR_ to_x, to_y );
923
924 top--;
925 arc -= 2;
926 }
927 }
928
929 return;
930 }
931
932
933 static void
934 gray_split_cubic( QT_FT_Vector* base )
935 {
936 TPos a, b, c, d;
937
938
939 base[6].x = base[3].x;
940 c = base[1].x;
941 d = base[2].x;
942 base[1].x = a = ( base[0].x + c ) / 2;
943 base[5].x = b = ( base[3].x + d ) / 2;
944 c = ( c + d ) / 2;
945 base[2].x = a = ( a + c ) / 2;
946 base[4].x = b = ( b + c ) / 2;
947 base[3].x = ( a + b ) / 2;
948
949 base[6].y = base[3].y;
950 c = base[1].y;
951 d = base[2].y;
952 base[1].y = a = ( base[0].y + c ) / 2;
953 base[5].y = b = ( base[3].y + d ) / 2;
954 c = ( c + d ) / 2;
955 base[2].y = a = ( a + c ) / 2;
956 base[4].y = b = ( b + c ) / 2;
957 base[3].y = ( a + b ) / 2;
958 }
959
960
961 static void
962 gray_render_cubic( RAS_ARG_ const QT_FT_Vector* control1,
963 const QT_FT_Vector* control2,
964 const QT_FT_Vector* to )
965 {
966 TPos dx, dy, da, db;
967 int top, level;
968 int* levels;
969 QT_FT_Vector* arc;
970
971
972 dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
973 if ( dx < 0 )
974 dx = -dx;
975 dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
976 if ( dy < 0 )
977 dy = -dy;
978 if ( dx < dy )
979 dx = dy;
980 da = dx;
981
982 dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
983 if ( dx < 0 )
984 dx = -dx;
985 dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->y + control2->y );
986 if ( dy < 0 )
987 dy = -dy;
988 if ( dx < dy )
989 dx = dy;
990 db = dx;
991
992 level = 1;
993 da = da / ras.cubic_level;
994 db = db / ras.conic_level;
995 while ( da > 0 || db > 0 )
996 {
997 da >>= 2;
998 db >>= 3;
999 level++;
1000 }
1001
1002 if ( level <= 1 )
1003 {
1004 TPos to_x, to_y, mid_x, mid_y;
1005
1006
1007 to_x = UPSCALE( to->x );
1008 to_y = UPSCALE( to->y );
1009 mid_x = ( ras.x + to_x +
1010 3 * UPSCALE( control1->x + control2->x ) ) / 8;
1011 mid_y = ( ras.y + to_y +
1012 3 * UPSCALE( control1->y + control2->y ) ) / 8;
1013
1014 gray_render_line( RAS_VAR_ mid_x, mid_y );
1015 gray_render_line( RAS_VAR_ to_x, to_y );
1016 return;
1017 }
1018
1019 arc = ras.bez_stack;
1020 arc[0].x = UPSCALE( to->x );
1021 arc[0].y = UPSCALE( to->y );
1022 arc[1].x = UPSCALE( control2->x );
1023 arc[1].y = UPSCALE( control2->y );
1024 arc[2].x = UPSCALE( control1->x );
1025 arc[2].y = UPSCALE( control1->y );
1026 arc[3].x = ras.x;
1027 arc[3].y = ras.y;
1028
1029 levels = ras.lev_stack;
1030 top = 0;
1031 levels[0] = level;
1032
1033 while ( top >= 0 )
1034 {
1035 level = levels[top];
1036 if ( level > 1 )
1037 {
1038 /* check that the arc crosses the current band */
1039 TPos min, max, y;
1040
1041
1042 min = max = arc[0].y;
1043 y = arc[1].y;
1044 if ( y < min ) min = y;
1045 if ( y > max ) max = y;
1046 y = arc[2].y;
1047 if ( y < min ) min = y;
1048 if ( y > max ) max = y;
1049 y = arc[3].y;
1050 if ( y < min ) min = y;
1051 if ( y > max ) max = y;
1052 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
1053 goto Draw;
1054 gray_split_cubic( arc );
1055 arc += 3;
1056 top ++;
1057 levels[top] = levels[top - 1] = level - 1;
1058 continue;
1059 }
1060
1061 Draw:
1062 {
1063 TPos to_x, to_y, mid_x, mid_y;
1064
1065
1066 to_x = arc[0].x;
1067 to_y = arc[0].y;
1068 mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
1069 mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
1070
1071 gray_render_line( RAS_VAR_ mid_x, mid_y );
1072 gray_render_line( RAS_VAR_ to_x, to_y );
1073 top --;
1074 arc -= 3;
1075 }
1076 }
1077
1078 return;
1079 }
1080
1081
1082
1083 static int
1084 gray_move_to( const QT_FT_Vector* to,
1085 PWorker worker )
1086 {
1087 TPos x, y;
1088
1089
1090 /* record current cell, if any */
1091 gray_record_cell( worker );
1092
1093 /* start to a new position */
1094 x = UPSCALE( to->x );
1095 y = UPSCALE( to->y );
1096
1097 gray_start_cell( worker, TRUNC( x ), TRUNC( y ) );
1098
1099 worker->x = x;
1100 worker->y = y;
1101 return 0;
1102 }
1103
1104
1105 static int
1106 gray_line_to( const QT_FT_Vector* to,
1107 PWorker worker )
1108 {
1109 gray_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) );
1110 return 0;
1111 }
1112
1113
1114 static int
1115 gray_conic_to( const QT_FT_Vector* control,
1116 const QT_FT_Vector* to,
1117 PWorker worker )
1118 {
1119 gray_render_conic( worker, control, to );
1120 return 0;
1121 }
1122
1123
1124 static int
1125 gray_cubic_to( const QT_FT_Vector* control1,
1126 const QT_FT_Vector* control2,
1127 const QT_FT_Vector* to,
1128 PWorker worker )
1129 {
1130 gray_render_cubic( worker, control1, control2, to );
1131 return 0;
1132 }
1133
1134
1135 static void
1136 gray_render_span( int count,
1137 const QT_FT_Span* spans,
1138 PWorker worker )
1139 {
1140 unsigned char* p;
1141 QT_FT_Bitmap* map = &worker->target;
1142
1143 for ( ; count > 0; count--, spans++ )
1144 {
1145 unsigned char coverage = spans->coverage;
1146
1147 /* first of all, compute the scanline offset */
1148 p = (unsigned char*)map->buffer - spans->y * map->pitch;
1149 if ( map->pitch >= 0 )
1150 p += ( map->rows - 1 ) * map->pitch;
1151
1152
1153 if ( coverage )
1154 {
1155 /* For small-spans it is faster to do it by ourselves than
1156 * calling `memset'. This is mainly due to the cost of the
1157 * function call.
1158 */
1159 if ( spans->len >= 8 )
1160 QT_FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
1161 else
1162 {
1163 unsigned char* q = p + spans->x;
1164
1165
1166 switch ( spans->len )
1167 {
1168 case 7: *q++ = (unsigned char)coverage;
1169 case 6: *q++ = (unsigned char)coverage;
1170 case 5: *q++ = (unsigned char)coverage;
1171 case 4: *q++ = (unsigned char)coverage;
1172 case 3: *q++ = (unsigned char)coverage;
1173 case 2: *q++ = (unsigned char)coverage;
1174 case 1: *q = (unsigned char)coverage;
1175 default:
1176 ;
1177 }
1178 }
1179 }
1180 }
1181 }
1182
1183
1184 static void
1185 gray_hline( RAS_ARG_ TCoord x,
1186 TCoord y,
1187 TPos area,
1188 int acount )
1189 {
1190 QT_FT_Span* span;
1191 int coverage;
1192 int skip;
1193
1194
1195 /* compute the coverage line's coverage, depending on the */
1196 /* outline fill rule */
1197 /* */
1198 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1199 /* */
1200 coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
1201 /* use range 0..256 */
1202 if ( coverage < 0 )
1203 coverage = -coverage;
1204
1205 if ( ras.outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL )
1206 {
1207 coverage &= 511;
1208
1209 if ( coverage > 256 )
1210 coverage = 512 - coverage;
1211 else if ( coverage == 256 )
1212 coverage = 255;
1213 }
1214 else
1215 {
1216 /* normal non-zero winding rule */
1217 if ( coverage >= 256 )
1218 coverage = 255;
1219 }
1220
1221 y += (TCoord)ras.min_ey;
1222 x += (TCoord)ras.min_ex;
1223
1224 /* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
1225 if ( x >= 32768 )
1226 x = 32767;
1227
1228 if ( coverage )
1229 {
1230 /* see whether we can add this span to the current list */
1231 span = ras.gray_spans + ras.num_gray_spans - 1;
1232 if ( ras.num_gray_spans > 0 &&
1233 span->y == y &&
1234 (int)span->x + span->len == (int)x &&
1235 span->coverage == coverage )
1236 {
1237 span->len = (unsigned short)( span->len + acount );
1238 return;
1239 }
1240
1241 if ( ras.num_gray_spans >= QT_FT_MAX_GRAY_SPANS )
1242 {
1243 if ( ras.render_span && ras.num_gray_spans > ras.skip_spans )
1244 {
1245 skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
1246 ras.render_span( ras.num_gray_spans - skip,
1247 ras.gray_spans + skip,
1248 ras.render_span_data );
1249 }
1250
1251 ras.skip_spans -= ras.num_gray_spans;
1252
1253 /* ras.render_span( span->y, ras.gray_spans, count ); */
1254
1255#ifdef DEBUG_GRAYS
1256
1257 if ( 1 )
1258 {
1259 int n;
1260
1261
1262 fprintf( stderr, "y=%3d ", y );
1263 span = ras.gray_spans;
1264 for ( n = 0; n < count; n++, span++ )
1265 fprintf( stderr, "[%d..%d]:%02x ",
1266 span->x, span->x + span->len - 1, span->coverage );
1267 fprintf( stderr, "\n" );
1268 }
1269
1270#endif /* DEBUG_GRAYS */
1271
1272 ras.num_gray_spans = 0;
1273
1274 span = ras.gray_spans;
1275 }
1276 else
1277 span++;
1278
1279 /* add a gray span to the current list */
1280 span->x = (short)x;
1281 span->len = (unsigned short)acount;
1282 span->y = (short)y;
1283 span->coverage = (unsigned char)coverage;
1284
1285 ras.num_gray_spans++;
1286 }
1287 }
1288
1289
1290#ifdef DEBUG_GRAYS
1291
1292 /* to be called while in the debugger */
1293 gray_dump_cells( RAS_ARG )
1294 {
1295 int yindex;
1296
1297
1298 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1299 {
1300 PCell cell;
1301
1302
1303 printf( "%3d:", yindex );
1304
1305 for ( cell = ras.ycells[yindex]; cell != NULL; cell = cell->next )
1306 printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area );
1307 printf( "\n" );
1308 }
1309 }
1310
1311#endif /* DEBUG_GRAYS */
1312
1313
1314 static void
1315 gray_sweep( RAS_ARG_ const QT_FT_Bitmap* target )
1316 {
1317 int yindex;
1318
1319 QT_FT_UNUSED( target );
1320
1321
1322 if ( ras.num_cells == 0 )
1323 return;
1324
1325 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1326 {
1327 PCell cell = ras.ycells[yindex];
1328 TCoord cover = 0;
1329 TCoord x = 0;
1330
1331
1332 for ( ; cell != NULL; cell = cell->next )
1333 {
1334 TArea area;
1335
1336
1337 if ( cell->x > x && cover != 0 )
1338 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1339 cell->x - x );
1340
1341 cover += cell->cover;
1342 area = cover * ( ONE_PIXEL * 2 ) - cell->area;
1343
1344 if ( area != 0 && cell->x >= 0 )
1345 gray_hline( RAS_VAR_ cell->x, yindex, area, 1 );
1346
1347 x = cell->x + 1;
1348 }
1349
1350 if ( ras.count_ex > x && cover != 0 )
1351 gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
1352 ras.count_ex - x );
1353 }
1354 }
1355
1356 /*************************************************************************/
1357 /* */
1358 /* The following function should only compile in stand_alone mode, */
1359 /* i.e., when building this component without the rest of FreeType. */
1360 /* */
1361 /*************************************************************************/
1362
1363 /*************************************************************************/
1364 /* */
1365 /* <Function> */
1366 /* QT_FT_Outline_Decompose */
1367 /* */
1368 /* <Description> */
1369 /* Walks over an outline's structure to decompose it into individual */
1370 /* segments and Bezier arcs. This function is also able to emit */
1371 /* `move to' and `close to' operations to indicate the start and end */
1372 /* of new contours in the outline. */
1373 /* */
1374 /* <Input> */
1375 /* outline :: A pointer to the source target. */
1376 /* */
1377 /* user :: A typeless pointer which is passed to each */
1378 /* emitter during the decomposition. It can be */
1379 /* used to store the state during the */
1380 /* decomposition. */
1381 /* */
1382 /* <Return> */
1383 /* Error code. 0 means success. */
1384 /* */
1385 static
1386 int QT_FT_Outline_Decompose( const QT_FT_Outline* outline,
1387 void* user )
1388 {
1389#undef SCALED
1390#define SCALED( x ) (x)
1391
1392 QT_FT_Vector v_last;
1393 QT_FT_Vector v_control;
1394 QT_FT_Vector v_start;
1395
1396 QT_FT_Vector* point;
1397 QT_FT_Vector* limit;
1398 char* tags;
1399
1400 int n; /* index of contour in outline */
1401 int first; /* index of first point in contour */
1402 int error;
1403 char tag; /* current point's state */
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 = gray_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 = gray_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 = gray_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 = gray_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 = gray_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 = gray_cubic_to( &vec1, &vec2, &vec, user );
1559 if ( error )
1560 goto Exit;
1561 continue;
1562 }
1563
1564 error = gray_cubic_to( &vec1, &vec2, &v_start, user );
1565 goto Close;
1566 }
1567 }
1568 }
1569
1570 /* close the contour with a line segment */
1571 error = gray_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 volatile int error = 0;
1600
1601 if ( qt_ft_setjmp( ras.jump_buffer ) == 0 )
1602 {
1603 error = QT_FT_Outline_Decompose( &ras.outline, &ras );
1604 gray_record_cell( RAS_VAR );
1605 }
1606 else
1607 {
1608 error = ErrRaster_Memory_Overflow;
1609 }
1610
1611 return error;
1612 }
1613
1614
1615 static int
1616 gray_convert_glyph( RAS_ARG )
1617 {
1618 TBand bands[40];
1619 TBand* volatile band;
1620 int volatile n, num_bands;
1621 TPos volatile min, max, max_y;
1622 QT_FT_BBox* clip;
1623 int skip;
1624
1625 ras.num_gray_spans = 0;
1626
1627 /* Set up state in the raster object */
1628 gray_compute_cbox( RAS_VAR );
1629
1630 /* clip to target bitmap, exit if nothing to do */
1631 clip = &ras.clip_box;
1632
1633 if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
1634 ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
1635 return 0;
1636
1637 if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
1638 if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
1639
1640 if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
1641 if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
1642
1643 ras.count_ex = ras.max_ex - ras.min_ex;
1644 ras.count_ey = ras.max_ey - ras.min_ey;
1645
1646 /* simple heuristic used to speed-up the bezier decomposition -- see */
1647 /* the code in gray_render_conic() and gray_render_cubic() for more */
1648 /* details */
1649 ras.conic_level = 32;
1650 ras.cubic_level = 16;
1651
1652 {
1653 int level = 0;
1654
1655
1656 if ( ras.count_ex > 24 || ras.count_ey > 24 )
1657 level++;
1658 if ( ras.count_ex > 120 || ras.count_ey > 120 )
1659 level++;
1660
1661 ras.conic_level <<= level;
1662 ras.cubic_level <<= level;
1663 }
1664
1665 /* setup vertical bands */
1666 num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
1667 if ( num_bands == 0 ) num_bands = 1;
1668 if ( num_bands >= 39 ) num_bands = 39;
1669
1670 ras.band_shoot = 0;
1671
1672 min = ras.min_ey;
1673 max_y = ras.max_ey;
1674
1675 for ( n = 0; n < num_bands; n++, min = max )
1676 {
1677 max = min + ras.band_size;
1678 if ( n == num_bands - 1 || max > max_y )
1679 max = max_y;
1680
1681 bands[0].min = min;
1682 bands[0].max = max;
1683 band = bands;
1684
1685 while ( band >= bands )
1686 {
1687 TPos bottom, top, middle;
1688 int error;
1689
1690 {
1691 PCell cells_max;
1692 int yindex;
1693 int cell_start, cell_end, cell_mod;
1694
1695
1696 ras.ycells = (PCell*)ras.buffer;
1697 ras.ycount = band->max - band->min;
1698
1699 cell_start = sizeof ( PCell ) * ras.ycount;
1700 cell_mod = cell_start % sizeof ( TCell );
1701 if ( cell_mod > 0 )
1702 cell_start += sizeof ( TCell ) - cell_mod;
1703
1704 cell_end = ras.buffer_size;
1705 cell_end -= cell_end % sizeof( TCell );
1706
1707 cells_max = (PCell)( (char*)ras.buffer + cell_end );
1708 ras.cells = (PCell)( (char*)ras.buffer + cell_start );
1709 if ( ras.cells >= cells_max )
1710 goto ReduceBands;
1711
1712 ras.max_cells = (int)(cells_max - ras.cells);
1713 if ( ras.max_cells < 2 )
1714 goto ReduceBands;
1715
1716 for ( yindex = 0; yindex < ras.ycount; yindex++ )
1717 ras.ycells[yindex] = NULL;
1718 }
1719
1720 ras.num_cells = 0;
1721 ras.invalid = 1;
1722 ras.min_ey = band->min;
1723 ras.max_ey = band->max;
1724 ras.count_ey = band->max - band->min;
1725
1726 error = gray_convert_glyph_inner( RAS_VAR );
1727
1728 if ( !error )
1729 {
1730 gray_sweep( RAS_VAR_ &ras.target );
1731 band--;
1732 continue;
1733 }
1734 else if ( error != ErrRaster_Memory_Overflow )
1735 return 1;
1736
1737 ReduceBands:
1738 /* render pool overflow; we will reduce the render band by half */
1739 bottom = band->min;
1740 top = band->max;
1741 middle = bottom + ( ( top - bottom ) >> 1 );
1742
1743 /* This is too complex for a single scanline; there must */
1744 /* be some problems. */
1745 if ( middle == bottom )
1746 {
1747#ifdef DEBUG_GRAYS
1748 fprintf( stderr, "Rotten glyph!\n" );
1749#endif
1750 return ErrRaster_OutOfMemory;
1751 }
1752
1753 if ( bottom-top >= ras.band_size )
1754 ras.band_shoot++;
1755
1756 band[1].min = bottom;
1757 band[1].max = middle;
1758 band[0].min = middle;
1759 band[0].max = top;
1760 band++;
1761 }
1762 }
1763
1764 if ( ras.render_span && ras.num_gray_spans > ras.skip_spans )
1765 {
1766 skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
1767 ras.render_span( ras.num_gray_spans - skip,
1768 ras.gray_spans + skip,
1769 ras.render_span_data );
1770 }
1771
1772 ras.skip_spans -= ras.num_gray_spans;
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( QT_FT_Raster 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 if ( raster->worker )
1794 raster->worker->skip_spans = params->skip_spans;
1795
1796 // If raster object and raster buffer are allocated, but
1797 // raster size isn't of the minimum size, indicate out of
1798 // memory.
1799 if (raster->buffer_allocated_size < MINIMUM_POOL_SIZE )
1800 return ErrRaster_OutOfMemory;
1801
1802 /* return immediately if the outline is empty */
1803 if ( outline->n_points == 0 || outline->n_contours <= 0 )
1804 return 0;
1805
1806 if ( !outline || !outline->contours || !outline->points )
1807 return ErrRaster_Invalid_Outline;
1808
1809 if ( outline->n_points !=
1810 outline->contours[outline->n_contours - 1] + 1 )
1811 return ErrRaster_Invalid_Outline;
1812
1813 worker = raster->worker;
1814
1815 /* if direct mode is not set, we must have a target bitmap */
1816 if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 )
1817 {
1818 if ( !target_map )
1819 return ErrRaster_Invalid_Argument;
1820
1821 /* nothing to do */
1822 if ( !target_map->width || !target_map->rows )
1823 return 0;
1824
1825 if ( !target_map->buffer )
1826 return ErrRaster_Invalid_Argument;
1827 }
1828
1829 /* this version does not support monochrome rendering */
1830 if ( !( params->flags & QT_FT_RASTER_FLAG_AA ) )
1831 return ErrRaster_Invalid_Mode;
1832
1833 /* compute clipping box */
1834 if ( ( params->flags & QT_FT_RASTER_FLAG_DIRECT ) == 0 )
1835 {
1836 /* compute clip box from target pixmap */
1837 ras.clip_box.xMin = 0;
1838 ras.clip_box.yMin = 0;
1839 ras.clip_box.xMax = target_map->width;
1840 ras.clip_box.yMax = target_map->rows;
1841 }
1842 else if ( params->flags & QT_FT_RASTER_FLAG_CLIP )
1843 {
1844 ras.clip_box = params->clip_box;
1845 }
1846 else
1847 {
1848 ras.clip_box.xMin = -32768L;
1849 ras.clip_box.yMin = -32768L;
1850 ras.clip_box.xMax = 32767L;
1851 ras.clip_box.yMax = 32767L;
1852 }
1853
1854 gray_init_cells( worker, raster->buffer, raster->buffer_size );
1855
1856 ras.outline = *outline;
1857 ras.num_cells = 0;
1858 ras.invalid = 1;
1859 ras.band_size = raster->band_size;
1860
1861 if ( target_map )
1862 ras.target = *target_map;
1863
1864 ras.render_span = (QT_FT_Raster_Span_Func)gray_render_span;
1865 ras.render_span_data = &ras;
1866
1867 if ( params->flags & QT_FT_RASTER_FLAG_DIRECT )
1868 {
1869 ras.render_span = (QT_FT_Raster_Span_Func)params->gray_spans;
1870 ras.render_span_data = params->user;
1871 }
1872
1873 return gray_convert_glyph( worker );
1874 }
1875
1876
1877 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
1878 /**** a static object. *****/
1879
1880 static int
1881 gray_raster_new( QT_FT_Raster* araster )
1882 {
1883 *araster = malloc(sizeof(TRaster));
1884 if (!*araster) {
1885 *araster = 0;
1886 return ErrRaster_Memory_Overflow;
1887 }
1888 QT_FT_MEM_ZERO(*araster, sizeof(TRaster));
1889
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 if ( raster )
1909 {
1910 if ( pool_base && ( pool_size >= MINIMUM_POOL_SIZE ) )
1911 {
1912 PWorker worker = (PWorker)pool_base;
1913
1914
1915 rast->worker = worker;
1916 rast->buffer = pool_base +
1917 ( ( sizeof ( TWorker ) + sizeof ( TCell ) - 1 ) &
1918 ~( sizeof ( TCell ) - 1 ) );
1919 rast->buffer_size = (long)( ( pool_base + pool_size ) -
1920 (char*)rast->buffer ) &
1921 ~( sizeof ( TCell ) - 1 );
1922 rast->band_size = (int)( rast->buffer_size /
1923 ( sizeof ( TCell ) * 8 ) );
1924 }
1925 else if ( pool_base)
1926 { // Case when there is a raster pool allocated, but it
1927 // doesn't have the minimum size (and so memory will be reallocated)
1928 rast->buffer = pool_base;
1929 rast->worker = NULL;
1930 rast->buffer_size = pool_size;
1931 }
1932 else
1933 {
1934 rast->buffer = NULL;
1935 rast->buffer_size = 0;
1936 rast->worker = NULL;
1937 }
1938 rast->buffer_allocated_size = pool_size;
1939 }
1940 }
1941
1942 const QT_FT_Raster_Funcs qt_ft_grays_raster =
1943 {
1944 QT_FT_GLYPH_FORMAT_OUTLINE,
1945
1946 (QT_FT_Raster_New_Func) gray_raster_new,
1947 (QT_FT_Raster_Reset_Func) gray_raster_reset,
1948 (QT_FT_Raster_Set_Mode_Func)0,
1949 (QT_FT_Raster_Render_Func) gray_raster_render,
1950 (QT_FT_Raster_Done_Func) gray_raster_done
1951 };
1952
1953/* END */
Note: See TracBrowser for help on using the repository browser.