|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 */ |