blob: 41dcb89b11dbc049ef72cad1af157bd964b6d491 [file] [log] [blame]
David Turner5ae1bad2000-06-27 23:18:39 +00001/***************************************************************************/
2/* */
3/* ftgrays.c */
4/* */
5/* A new `perfect' anti-aliasing renderer (body). */
6/* */
David Turnerc4f622c2001-10-07 10:39:03 +00007/* Copyright 2000 by */
David Turner5ae1bad2000-06-27 23:18:39 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
10/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
12/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18 /*************************************************************************/
19 /* */
20 /* This file can be compiled without the rest of the FreeType engine, */
21 /* by defining the _STANDALONE_ macro when compiling it. You also need */
22 /* to put the files `ftgrays.h' and `ftimage.h' into the current */
23 /* compilation directory. Typically, you could do something like */
24 /* */
25 /* - copy `src/base/ftgrays.c' to your current directory */
26 /* */
27 /* - copy `include/freetype/ftimage.h' and */
28 /* `include/freetype/ftgrays.h' to the same directory */
29 /* */
30 /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */
31 /* */
32 /* cc -c -D_STANDALONE_ ftgrays.c */
33 /* */
34 /* The renderer can be initialized with a call to */
David Turnerc4f622c2001-10-07 10:39:03 +000035 /* `ft_gray_raster.gray_raster_new'; an anti-aliased bitmap can be */
36 /* generated with a call to `ft_gray_raster.gray_raster_render'. */
David Turner5ae1bad2000-06-27 23:18:39 +000037 /* */
38 /* See the comments and documentation in the file `ftimage.h' for */
39 /* more details on how the raster works. */
40 /* */
41 /*************************************************************************/
42
43 /*************************************************************************/
44 /* */
45 /* This is a new anti-aliasing scan-converter for FreeType 2. The */
46 /* algorithm used here is _very_ different from the one in the standard */
47 /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */
48 /* coverage of the outline on each pixel cell. */
49 /* */
50 /* It is based on ideas that I initially found in Raph Levien's */
51 /* excellent LibArt graphics library (see http://www.levien.com/libart */
52 /* for more information, though the web pages do not tell anything */
53 /* about the renderer; you'll have to dive into the source code to */
54 /* understand how it works). */
55 /* */
56 /* Note, however, that this is a _very_ different implementation */
Werner Lembergfbeb41d2000-07-02 00:27:53 +000057 /* compared to Raph's. Coverage information is stored in a very */
58 /* different way, and I don't use sorted vector paths. Also, it */
59 /* doesn't use floating point values. */
David Turner5ae1bad2000-06-27 23:18:39 +000060 /* */
61 /* This renderer has the following advantages: */
62 /* */
63 /* - It doesn't need an intermediate bitmap. Instead, one can supply */
64 /* a callback function that will be called by the renderer to draw */
65 /* gray spans on any target surface. You can thus do direct */
66 /* composition on any kind of bitmap, provided that you give the */
67 /* renderer the right callback. */
68 /* */
69 /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */
70 /* each pixel cell */
71 /* */
72 /* - It performs a single pass on the outline (the `standard' FT2 */
73 /* renderer makes two passes). */
74 /* */
75 /* - It can easily be modified to render to _any_ number of gray levels */
76 /* cheaply. */
77 /* */
78 /* - For small (< 20) pixel sizes, it is faster than the standard */
79 /* renderer. */
80 /* */
81 /*************************************************************************/
82
83
84#include <string.h> /* for memcpy() */
David Turnerc4f622c2001-10-07 10:39:03 +000085#include <setjmp.h>
David Turner5ae1bad2000-06-27 23:18:39 +000086
87 /*************************************************************************/
88 /* */
89 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
90 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
91 /* messages during execution. */
92 /* */
93#undef FT_COMPONENT
94#define FT_COMPONENT trace_aaraster
95
96
David Turnerc4f622c2001-10-07 10:39:03 +000097#define ErrRaster_MemoryOverflow -4
98
David Turner5ae1bad2000-06-27 23:18:39 +000099#ifdef _STANDALONE_
100
Werner Lembergb48a6092000-07-09 19:15:30 +0000101
David Turner5ae1bad2000-06-27 23:18:39 +0000102#define ErrRaster_Invalid_Mode -2
Werner Lembergb48a6092000-07-09 19:15:30 +0000103#define ErrRaster_Invalid_Outline -1
David Turner5ae1bad2000-06-27 23:18:39 +0000104
105#include "ftimage.h"
106#include "ftgrays.h"
107
108 /* This macro is used to indicate that a function parameter is unused. */
109 /* Its purpose is simply to reduce compiler warnings. Note also that */
110 /* simply defining it as `(void)x' doesn't avoid warnings with certain */
111 /* ANSI compilers (e.g. LCC). */
David Turnerc6a92202000-07-04 18:12:13 +0000112#define FT_UNUSED( x ) (x) = (x)
David Turner5ae1bad2000-06-27 23:18:39 +0000113
114 /* Disable the tracing mechanism for simplicity -- developers can */
115 /* activate it easily by redefining these two macros. */
116#ifndef FT_ERROR
117#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
118#endif
119
120#ifndef FT_TRACE
121#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
122#endif
123
124
125#else /* _STANDALONE_ */
126
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000127
Werner Lemberg63408a12000-12-13 23:44:37 +0000128#include <ft2build.h>
David Turner8d3a4012001-03-20 11:14:24 +0000129#include "ftgrays.h"
Werner Lemberg63408a12000-12-13 23:44:37 +0000130#include FT_INTERNAL_OBJECTS_H
131#include FT_INTERNAL_DEBUG_H
132#include FT_OUTLINE_H
David Turner5ae1bad2000-06-27 23:18:39 +0000133
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000134#include "ftsmerrs.h"
135
136#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
137#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline
David Turner5ae1bad2000-06-27 23:18:39 +0000138
139
140#endif /* _STANDALONE_ */
141
142
143 /* define this to dump debugging information */
144#define xxxDEBUG_GRAYS
145
146 /* as usual, for the speed hungry :-) */
147
148#ifndef FT_STATIC_RASTER
149
150
151#define RAS_ARG PRaster raster
152#define RAS_ARG_ PRaster raster,
153
154#define RAS_VAR raster
155#define RAS_VAR_ raster,
156
157#define ras (*raster)
158
159
160#else /* FT_STATIC_RASTER */
161
162
163#define RAS_ARG /* empty */
164#define RAS_ARG_ /* empty */
165#define RAS_VAR /* empty */
166#define RAS_VAR_ /* empty */
167
168 static TRaster ras;
169
170
171#endif /* FT_STATIC_RASTER */
172
173
174 /* must be at least 6 bits! */
175#define PIXEL_BITS 8
176
177#define ONE_PIXEL ( 1L << PIXEL_BITS )
178#define PIXEL_MASK ( -1L << PIXEL_BITS )
179#define TRUNC( x ) ( (x) >> PIXEL_BITS )
180#define SUBPIXELS( x ) ( (x) << PIXEL_BITS )
181#define FLOOR( x ) ( (x) & -ONE_PIXEL )
182#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
183#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
184
185#if PIXEL_BITS >= 6
186#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) )
187#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
188#else
189#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
190#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
191#endif
192
193 /* Define this if you want to use a more compact storage scheme. This */
194 /* increases the number of cells available in the render pool but slows */
195 /* down the rendering a bit. It is useful if you have a really tiny */
196 /* render pool. */
197#define xxxGRAYS_COMPACT
198
199
200 /*************************************************************************/
201 /* */
202 /* TYPE DEFINITIONS */
203 /* */
David Turnerc4f622c2001-10-07 10:39:03 +0000204
205 /* don't change the following types to FT_Int or FT_Pos, since we might */
206 /* need to define them to "float" or "double" when experimenting with */
207 /* new algorithms.. */
208
David Turner5ae1bad2000-06-27 23:18:39 +0000209 typedef int TScan; /* integer scanline/pixel coordinate */
210 typedef long TPos; /* sub-pixel coordinate */
211
David Turnerc4f622c2001-10-07 10:39:03 +0000212 /* determine the type used to store cell areas. This normally takes at */
213 /* least PIXEL_BYTES*2 + 1, on 16-bit systems, we need to use 'longs' */
214 /* instead of 'ints'.. otherwise bad things happen.. */
215
216#if PIXEL_BITS <= 7
217
218 typedef int TArea;
219
220#else /* PIXEL_BITS >= 8 */
221
222 /* approximately determine the size of integers using an ANSI-C header */
223# include <limits.h>
224# if UINT_MAX == 0xFFFFU
225 typedef long TArea;
226# else
227 typedef int TArea;
228# endif
229
230#endif /* PIXEL_BITS >= 8 */
231
232
David Turner5ae1bad2000-06-27 23:18:39 +0000233 /* maximal number of gray spans in a call to the span callback */
234#define FT_MAX_GRAY_SPANS 32
235
236
237#ifdef GRAYS_COMPACT
238
239 typedef struct TCell_
240 {
241 short x : 14;
242 short y : 14;
243 int cover : PIXEL_BITS + 2;
244 int area : PIXEL_BITS * 2 + 2;
245
246 } TCell, *PCell;
247
248#else /* GRAYS_COMPACT */
249
250 typedef struct TCell_
251 {
252 TScan x;
253 TScan y;
254 int cover;
David Turnerc4f622c2001-10-07 10:39:03 +0000255 TArea area;
David Turner5ae1bad2000-06-27 23:18:39 +0000256
257 } TCell, *PCell;
258
259#endif /* GRAYS_COMPACT */
260
261
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000262 typedef struct TRaster_
David Turner5ae1bad2000-06-27 23:18:39 +0000263 {
264 PCell cells;
265 int max_cells;
266 int num_cells;
267
268 TScan min_ex, max_ex;
269 TScan min_ey, max_ey;
270
David Turnerc4f622c2001-10-07 10:39:03 +0000271 TArea area;
David Turner5ae1bad2000-06-27 23:18:39 +0000272 int cover;
273 int invalid;
274
275 TScan ex, ey;
276 TScan cx, cy;
277 TPos x, y;
278
279 TScan last_ey;
280
Werner Lemberg37802732001-04-26 13:34:36 +0000281 FT_Vector bez_stack[32 * 3 + 1];
David Turner5ae1bad2000-06-27 23:18:39 +0000282 int lev_stack[32];
283
284 FT_Outline outline;
285 FT_Bitmap target;
David Turner859a18a2000-12-14 18:50:40 +0000286 FT_BBox clip_box;
David Turner5ae1bad2000-06-27 23:18:39 +0000287
288 FT_Span gray_spans[FT_MAX_GRAY_SPANS];
289 int num_gray_spans;
290
291 FT_Raster_Span_Func render_span;
292 void* render_span_data;
293 int span_y;
294
David Turnerc4f622c2001-10-07 10:39:03 +0000295 int band_size;
296 int band_shoot;
297 int conic_level;
298 int cubic_level;
David Turner5ae1bad2000-06-27 23:18:39 +0000299
David Turnerc4f622c2001-10-07 10:39:03 +0000300 void* memory;
301 jmp_buf jump_buffer;
David Turner5ae1bad2000-06-27 23:18:39 +0000302
303 } TRaster, *PRaster;
304
305
306 /*************************************************************************/
307 /* */
308 /* Initialize the cells table. */
309 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000310 static void
David Turnerc4f622c2001-10-07 10:39:03 +0000311 gray_init_cells( RAS_ARG_ void* buffer,
312 long byte_size )
David Turner5ae1bad2000-06-27 23:18:39 +0000313 {
314 ras.cells = (PCell)buffer;
315 ras.max_cells = byte_size / sizeof ( TCell );
316 ras.num_cells = 0;
317 ras.area = 0;
318 ras.cover = 0;
319 ras.invalid = 1;
320 }
321
322
323 /*************************************************************************/
324 /* */
325 /* Compute the outline bounding box. */
326 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000327 static void
David Turnerc4f622c2001-10-07 10:39:03 +0000328 gray_compute_cbox( RAS_ARG )
David Turner5ae1bad2000-06-27 23:18:39 +0000329 {
David Turnerc4f622c2001-10-07 10:39:03 +0000330 FT_Outline* outline = &ras.outline;
331 FT_Vector* vec = outline->points;
332 FT_Vector* limit = vec + outline->n_points;
David Turner5ae1bad2000-06-27 23:18:39 +0000333
334
335 if ( outline->n_points <= 0 )
336 {
337 ras.min_ex = ras.max_ex = 0;
338 ras.min_ey = ras.max_ey = 0;
339 return;
340 }
341
342 ras.min_ex = ras.max_ex = vec->x;
343 ras.min_ey = ras.max_ey = vec->y;
344
345 vec++;
346
347 for ( ; vec < limit; vec++ )
348 {
349 TPos x = vec->x;
350 TPos y = vec->y;
351
352
353 if ( x < ras.min_ex ) ras.min_ex = x;
354 if ( x > ras.max_ex ) ras.max_ex = x;
355 if ( y < ras.min_ey ) ras.min_ey = y;
356 if ( y > ras.max_ey ) ras.max_ey = y;
357 }
358
359 /* truncate the bounding box to integer pixels */
360 ras.min_ex = ras.min_ex >> 6;
361 ras.min_ey = ras.min_ey >> 6;
362 ras.max_ex = ( ras.max_ex + 63 ) >> 6;
363 ras.max_ey = ( ras.max_ey + 63 ) >> 6;
364 }
365
366
367 /*************************************************************************/
368 /* */
369 /* Record the current cell in the table. */
370 /* */
David Turnerc4f622c2001-10-07 10:39:03 +0000371 static void
372 gray_record_cell( RAS_ARG )
David Turner5ae1bad2000-06-27 23:18:39 +0000373 {
374 PCell cell;
375
376
377 if ( !ras.invalid && ( ras.area | ras.cover ) )
378 {
379 if ( ras.num_cells >= ras.max_cells )
David Turnerc4f622c2001-10-07 10:39:03 +0000380 longjmp( ras.jump_buffer, 1 );
David Turner5ae1bad2000-06-27 23:18:39 +0000381
382 cell = ras.cells + ras.num_cells++;
383 cell->x = ras.ex - ras.min_ex;
384 cell->y = ras.ey - ras.min_ey;
385 cell->area = ras.area;
386 cell->cover = ras.cover;
387 }
David Turner5ae1bad2000-06-27 23:18:39 +0000388 }
389
390
391 /*************************************************************************/
392 /* */
393 /* Set the current cell to a new position. */
394 /* */
David Turnerc4f622c2001-10-07 10:39:03 +0000395 static void
396 gray_set_cell( RAS_ARG_ TScan ex,
397 TScan ey )
David Turner5ae1bad2000-06-27 23:18:39 +0000398 {
399 int invalid, record, clean;
400
401
402 /* Move the cell pointer to a new position. We set the `invalid' */
403 /* flag to indicate that the cell isn't part of those we're interested */
404 /* in during the render phase. This means that: */
405 /* */
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000406 /* . the new vertical position must be within min_ey..max_ey-1. */
David Turner5ae1bad2000-06-27 23:18:39 +0000407 /* . the new horizontal position must be strictly less than max_ex */
408 /* */
409 /* Note that if a cell is to the left of the clipping region, it is */
410 /* actually set to the (min_ex-1) horizontal position. */
411
412 record = 0;
413 clean = 1;
414
415 invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex );
416 if ( !invalid )
417 {
418 /* All cells that are on the left of the clipping region go to the */
419 /* min_ex - 1 horizontal position. */
420 if ( ex < ras.min_ex )
421 ex = ras.min_ex - 1;
422
423 /* if our position is new, then record the previous cell */
424 if ( ex != ras.ex || ey != ras.ey )
425 record = 1;
426 else
427 clean = ras.invalid; /* do not clean if we didn't move from */
428 /* a valid cell */
429 }
430
431 /* record the previous cell if needed (i.e., if we changed the cell */
432 /* position, of changed the `invalid' flag) */
David Turnerc4f622c2001-10-07 10:39:03 +0000433 if ( ras.invalid != invalid || record )
434 gray_record_cell( RAS_VAR );
David Turner5ae1bad2000-06-27 23:18:39 +0000435
436 if ( clean )
437 {
438 ras.area = 0;
439 ras.cover = 0;
440 }
441
442 ras.invalid = invalid;
443 ras.ex = ex;
444 ras.ey = ey;
David Turner5ae1bad2000-06-27 23:18:39 +0000445 }
446
447
448 /*************************************************************************/
449 /* */
450 /* Start a new contour at a given cell. */
451 /* */
Werner Lemberg52005c32001-06-27 23:25:46 +0000452 static void
David Turnerc4f622c2001-10-07 10:39:03 +0000453 gray_start_cell( RAS_ARG_ TScan ex,
454 TScan ey )
David Turner5ae1bad2000-06-27 23:18:39 +0000455 {
456 if ( ex < ras.min_ex )
457 ex = ras.min_ex - 1;
458
459 ras.area = 0;
460 ras.cover = 0;
461 ras.ex = ex;
462 ras.ey = ey;
463 ras.last_ey = SUBPIXELS( ey );
464 ras.invalid = 0;
465
David Turnerc4f622c2001-10-07 10:39:03 +0000466 gray_set_cell( RAS_VAR_ ex, ey );
David Turner5ae1bad2000-06-27 23:18:39 +0000467 }
468
469
470 /*************************************************************************/
471 /* */
472 /* Render a scanline as one or more cells. */
473 /* */
David Turnerc4f622c2001-10-07 10:39:03 +0000474 static void
475 gray_render_scanline( RAS_ARG_ TScan ey,
476 TPos x1,
477 TScan y1,
478 TPos x2,
479 TScan y2 )
David Turner5ae1bad2000-06-27 23:18:39 +0000480 {
481 TScan ex1, ex2, fx1, fx2, delta;
482 long p, first, dx;
483 int incr, lift, mod, rem;
484
485
486 dx = x2 - x1;
487
488 ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */
489 ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */
490 fx1 = x1 - SUBPIXELS( ex1 );
491 fx2 = x2 - SUBPIXELS( ex2 );
492
493 /* trivial case. Happens often */
494 if ( y1 == y2 )
David Turnerc4f622c2001-10-07 10:39:03 +0000495 {
496 gray_set_cell( RAS_VAR_ ex2, ey );
497 return;
498 }
David Turner5ae1bad2000-06-27 23:18:39 +0000499
500 /* everything is located in a single cell. That is easy! */
501 /* */
502 if ( ex1 == ex2 )
503 {
504 delta = y2 - y1;
David Turnerc4f622c2001-10-07 10:39:03 +0000505 ras.area += (TArea)( fx1 + fx2 ) * delta;
David Turner5ae1bad2000-06-27 23:18:39 +0000506 ras.cover += delta;
David Turnerc4f622c2001-10-07 10:39:03 +0000507 return;
David Turner5ae1bad2000-06-27 23:18:39 +0000508 }
509
510 /* ok, we'll have to render a run of adjacent cells on the same */
511 /* scanline... */
512 /* */
513 p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
514 first = ONE_PIXEL;
515 incr = 1;
516
517 if ( dx < 0 )
518 {
519 p = fx1 * ( y2 - y1 );
520 first = 0;
521 incr = -1;
522 dx = -dx;
523 }
524
525 delta = p / dx;
526 mod = p % dx;
527 if ( mod < 0 )
528 {
529 delta--;
530 mod += dx;
531 }
532
David Turnerc4f622c2001-10-07 10:39:03 +0000533 ras.area += (TArea)( fx1 + first ) * delta;
David Turner5ae1bad2000-06-27 23:18:39 +0000534 ras.cover += delta;
535
536 ex1 += incr;
David Turnerc4f622c2001-10-07 10:39:03 +0000537 gray_set_cell( RAS_VAR_ ex1, ey );
David Turner5ae1bad2000-06-27 23:18:39 +0000538 y1 += delta;
539
540 if ( ex1 != ex2 )
541 {
542 p = ONE_PIXEL * ( y2 - y1 );
543 lift = p / dx;
544 rem = p % dx;
545 if ( rem < 0 )
546 {
547 lift--;
548 rem += dx;
549 }
550
551 mod -= dx;
552
553 while ( ex1 != ex2 )
554 {
555 delta = lift;
556 mod += rem;
557 if ( mod >= 0 )
558 {
559 mod -= dx;
560 delta++;
561 }
562
David Turnerc4f622c2001-10-07 10:39:03 +0000563 ras.area += (TArea)ONE_PIXEL * delta;
David Turner5ae1bad2000-06-27 23:18:39 +0000564 ras.cover += delta;
565 y1 += delta;
566 ex1 += incr;
David Turnerc4f622c2001-10-07 10:39:03 +0000567 gray_set_cell( RAS_VAR_ ex1, ey );
David Turner5ae1bad2000-06-27 23:18:39 +0000568 }
569 }
570
571 delta = y2 - y1;
David Turnerc4f622c2001-10-07 10:39:03 +0000572 ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
David Turner5ae1bad2000-06-27 23:18:39 +0000573 ras.cover += delta;
David Turner5ae1bad2000-06-27 23:18:39 +0000574 }
575
576
577 /*************************************************************************/
578 /* */
579 /* Render a given line as a series of scanlines. */
580 /* */
David Turnerc4f622c2001-10-07 10:39:03 +0000581 static void
582 gray_render_line( RAS_ARG_ TPos to_x,
583 TPos to_y )
David Turner5ae1bad2000-06-27 23:18:39 +0000584 {
585 TScan ey1, ey2, fy1, fy2;
586 TPos dx, dy, x, x2;
587 int p, rem, mod, lift, delta, first, incr;
588
589
590 ey1 = TRUNC( ras.last_ey );
591 ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
592 fy1 = ras.y - ras.last_ey;
593 fy2 = to_y - SUBPIXELS( ey2 );
594
595 dx = to_x - ras.x;
596 dy = to_y - ras.y;
597
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000598 /* XXX: we should do something about the trivial case where dx == 0, */
599 /* as it happens very often! */
David Turner5ae1bad2000-06-27 23:18:39 +0000600
601 /* perform vertical clipping */
602 {
603 TScan min, max;
604
605
606 min = ey1;
607 max = ey2;
608 if ( ey1 > ey2 )
609 {
610 min = ey2;
611 max = ey1;
612 }
613 if ( min >= ras.max_ey || max < ras.min_ey )
614 goto End;
615 }
616
617 /* everything is on a single scanline */
618 if ( ey1 == ey2 )
619 {
David Turnerc4f622c2001-10-07 10:39:03 +0000620 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
David Turner5ae1bad2000-06-27 23:18:39 +0000621 goto End;
622 }
623
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000624 /* ok, we have to render several scanlines */
David Turner5ae1bad2000-06-27 23:18:39 +0000625 p = ( ONE_PIXEL - fy1 ) * dx;
626 first = ONE_PIXEL;
627 incr = 1;
628
629 if ( dy < 0 )
630 {
631 p = fy1 * dx;
632 first = 0;
633 incr = -1;
634 dy = -dy;
635 }
636
637 delta = p / dy;
638 mod = p % dy;
639 if ( mod < 0 )
640 {
641 delta--;
642 mod += dy;
643 }
644
645 x = ras.x + delta;
David Turnerc4f622c2001-10-07 10:39:03 +0000646 gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
David Turner5ae1bad2000-06-27 23:18:39 +0000647
648 ey1 += incr;
David Turnerc4f622c2001-10-07 10:39:03 +0000649 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
David Turner5ae1bad2000-06-27 23:18:39 +0000650
651 if ( ey1 != ey2 )
652 {
653 p = ONE_PIXEL * dx;
654 lift = p / dy;
655 rem = p % dy;
656 if ( rem < 0 )
657 {
658 lift--;
659 rem += dy;
660 }
661 mod -= dy;
662
663 while ( ey1 != ey2 )
664 {
665 delta = lift;
666 mod += rem;
667 if ( mod >= 0 )
668 {
669 mod -= dy;
670 delta++;
671 }
672
673 x2 = x + delta;
David Turnerc4f622c2001-10-07 10:39:03 +0000674 gray_render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, x2, first );
David Turner5ae1bad2000-06-27 23:18:39 +0000675 x = x2;
David Turnerc4f622c2001-10-07 10:39:03 +0000676
David Turner5ae1bad2000-06-27 23:18:39 +0000677 ey1 += incr;
David Turnerc4f622c2001-10-07 10:39:03 +0000678 gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
David Turner5ae1bad2000-06-27 23:18:39 +0000679 }
680 }
681
David Turnerc4f622c2001-10-07 10:39:03 +0000682 gray_render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, to_x, fy2 );
David Turner5ae1bad2000-06-27 23:18:39 +0000683
684 End:
685 ras.x = to_x;
686 ras.y = to_y;
687 ras.last_ey = SUBPIXELS( ey2 );
David Turner5ae1bad2000-06-27 23:18:39 +0000688 }
689
690
Werner Lemberg52005c32001-06-27 23:25:46 +0000691 static void
David Turnerc4f622c2001-10-07 10:39:03 +0000692 gray_split_conic( FT_Vector* base )
David Turner5ae1bad2000-06-27 23:18:39 +0000693 {
694 TPos a, b;
695
696
697 base[4].x = base[2].x;
698 b = base[1].x;
699 a = base[3].x = ( base[2].x + b ) / 2;
700 b = base[1].x = ( base[0].x + b ) / 2;
701 base[2].x = ( a + b ) / 2;
702
703 base[4].y = base[2].y;
704 b = base[1].y;
705 a = base[3].y = ( base[2].y + b ) / 2;
706 b = base[1].y = ( base[0].y + b ) / 2;
707 base[2].y = ( a + b ) / 2;
708 }
709
710
David Turnerc4f622c2001-10-07 10:39:03 +0000711 static void
712 gray_render_conic( RAS_ARG_ FT_Vector* control,
713 FT_Vector* to )
David Turner5ae1bad2000-06-27 23:18:39 +0000714 {
715 TPos dx, dy;
716 int top, level;
717 int* levels;
718 FT_Vector* arc;
719
720
721 dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
722 if ( dx < 0 )
723 dx = -dx;
724 dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
725 if ( dy < 0 )
726 dy = -dy;
727 if ( dx < dy )
728 dx = dy;
729
730 level = 1;
731 dx = dx / ras.conic_level;
732 while ( dx > 0 )
733 {
David Turnera8194a92000-09-02 00:20:42 +0000734 dx >>= 2;
David Turner5ae1bad2000-06-27 23:18:39 +0000735 level++;
736 }
737
738 /* a shortcut to speed things up */
739 if ( level <= 1 )
740 {
741 /* we compute the mid-point directly in order to avoid */
David Turnerc4f622c2001-10-07 10:39:03 +0000742 /* calling gray_split_conic() */
David Turner5ae1bad2000-06-27 23:18:39 +0000743 TPos to_x, to_y, mid_x, mid_y;
744
745
746 to_x = UPSCALE( to->x );
747 to_y = UPSCALE( to->y );
748 mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
749 mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
750
David Turnerc4f622c2001-10-07 10:39:03 +0000751 gray_render_line( RAS_VAR_ mid_x, mid_y );
752 gray_render_line( RAS_VAR_ to_x, to_y );
753 return;
David Turner5ae1bad2000-06-27 23:18:39 +0000754 }
755
756 arc = ras.bez_stack;
757 levels = ras.lev_stack;
758 top = 0;
759 levels[0] = level;
760
761 arc[0].x = UPSCALE( to->x );
762 arc[0].y = UPSCALE( to->y );
763 arc[1].x = UPSCALE( control->x );
764 arc[1].y = UPSCALE( control->y );
765 arc[2].x = ras.x;
766 arc[2].y = ras.y;
767
768 while ( top >= 0 )
769 {
770 level = levels[top];
771 if ( level > 1 )
772 {
773 /* check that the arc crosses the current band */
774 TPos min, max, y;
775
776
777 min = max = arc[0].y;
778
779 y = arc[1].y;
780 if ( y < min ) min = y;
781 if ( y > max ) max = y;
782
783 y = arc[2].y;
784 if ( y < min ) min = y;
785 if ( y > max ) max = y;
786
787 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
788 goto Draw;
789
David Turnerc4f622c2001-10-07 10:39:03 +0000790 gray_split_conic( arc );
David Turner5ae1bad2000-06-27 23:18:39 +0000791 arc += 2;
792 top++;
793 levels[top] = levels[top - 1] = level - 1;
794 continue;
795 }
796
797 Draw:
798 {
799 TPos to_x, to_y, mid_x, mid_y;
800
801
802 to_x = arc[0].x;
803 to_y = arc[0].y;
804 mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
805 mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
806
David Turnerc4f622c2001-10-07 10:39:03 +0000807 gray_render_line( RAS_VAR_ mid_x, mid_y );
808 gray_render_line( RAS_VAR_ to_x, to_y );
David Turner5ae1bad2000-06-27 23:18:39 +0000809
810 top--;
811 arc -= 2;
812 }
813 }
David Turnerc4f622c2001-10-07 10:39:03 +0000814 return;
David Turner5ae1bad2000-06-27 23:18:39 +0000815 }
816
817
Werner Lemberg52005c32001-06-27 23:25:46 +0000818 static void
David Turnerc4f622c2001-10-07 10:39:03 +0000819 gray_split_cubic( FT_Vector* base )
David Turner5ae1bad2000-06-27 23:18:39 +0000820 {
821 TPos a, b, c, d;
822
823
824 base[6].x = base[3].x;
825 c = base[1].x;
826 d = base[2].x;
827 base[1].x = a = ( base[0].x + c ) / 2;
828 base[5].x = b = ( base[3].x + d ) / 2;
829 c = ( c + d ) / 2;
830 base[2].x = a = ( a + c ) / 2;
831 base[4].x = b = ( b + c ) / 2;
832 base[3].x = ( a + b ) / 2;
833
834 base[6].y = base[3].y;
835 c = base[1].y;
836 d = base[2].y;
837 base[1].y = a = ( base[0].y + c ) / 2;
838 base[5].y = b = ( base[3].y + d ) / 2;
839 c = ( c + d ) / 2;
840 base[2].y = a = ( a + c ) / 2;
841 base[4].y = b = ( b + c ) / 2;
842 base[3].y = ( a + b ) / 2;
843 }
844
845
David Turnerc4f622c2001-10-07 10:39:03 +0000846 static void
847 gray_render_cubic( RAS_ARG_ FT_Vector* control1,
848 FT_Vector* control2,
849 FT_Vector* to )
David Turner5ae1bad2000-06-27 23:18:39 +0000850 {
851 TPos dx, dy, da, db;
852 int top, level;
853 int* levels;
854 FT_Vector* arc;
855
856
857 dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
858 if ( dx < 0 )
859 dx = -dx;
860 dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
861 if ( dy < 0 )
862 dy = -dy;
863 if ( dx < dy )
864 dx = dy;
865 da = dx;
866
867 dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
868 if ( dx < 0 )
869 dx = -dx;
870 dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
871 if ( dy < 0 )
872 dy = -dy;
873 if ( dx < dy )
874 dx = dy;
875 db = dx;
876
877 level = 1;
878 da = da / ras.cubic_level;
879 db = db / ras.conic_level;
880 while ( da > 0 || db > 0 )
881 {
David Turnera8194a92000-09-02 00:20:42 +0000882 da >>= 2;
883 db >>= 3;
David Turner5ae1bad2000-06-27 23:18:39 +0000884 level++;
885 }
886
887 if ( level <= 1 )
888 {
889 TPos to_x, to_y, mid_x, mid_y;
890
891
892 to_x = UPSCALE( to->x );
893 to_y = UPSCALE( to->y );
894 mid_x = ( ras.x + to_x +
895 3 * UPSCALE( control1->x + control2->x ) ) / 8;
896 mid_y = ( ras.y + to_y +
897 3 * UPSCALE( control1->y + control2->y ) ) / 8;
898
David Turnerc4f622c2001-10-07 10:39:03 +0000899 gray_render_line( RAS_VAR_ mid_x, mid_y );
900 gray_render_line( RAS_VAR_ to_x, to_y );
901 return;
David Turner5ae1bad2000-06-27 23:18:39 +0000902 }
903
904 arc = ras.bez_stack;
905 arc[0].x = UPSCALE( to->x );
906 arc[0].y = UPSCALE( to->y );
907 arc[1].x = UPSCALE( control2->x );
908 arc[1].y = UPSCALE( control2->y );
909 arc[2].x = UPSCALE( control1->x );
910 arc[2].y = UPSCALE( control1->y );
911 arc[3].x = ras.x;
912 arc[3].y = ras.y;
913
914 levels = ras.lev_stack;
915 top = 0;
916 levels[0] = level;
917
918 while ( top >= 0 )
919 {
920 level = levels[top];
921 if ( level > 1 )
922 {
923 /* check that the arc crosses the current band */
924 TPos min, max, y;
925
926
927 min = max = arc[0].y;
928 y = arc[1].y;
929 if ( y < min ) min = y;
930 if ( y > max ) max = y;
931 y = arc[2].y;
932 if ( y < min ) min = y;
933 if ( y > max ) max = y;
934 y = arc[3].y;
935 if ( y < min ) min = y;
936 if ( y > max ) max = y;
937 if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
938 goto Draw;
David Turnerc4f622c2001-10-07 10:39:03 +0000939 gray_split_cubic( arc );
David Turner5ae1bad2000-06-27 23:18:39 +0000940 arc += 3;
941 top ++;
942 levels[top] = levels[top - 1] = level - 1;
943 continue;
944 }
945
946 Draw:
947 {
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000948 TPos to_x, to_y, mid_x, mid_y;
David Turner5ae1bad2000-06-27 23:18:39 +0000949
950
951 to_x = arc[0].x;
952 to_y = arc[0].y;
953 mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
954 mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
955
David Turnerc4f622c2001-10-07 10:39:03 +0000956 gray_render_line( RAS_VAR_ mid_x, mid_y );
957 gray_render_line( RAS_VAR_ to_x, to_y );
David Turner5ae1bad2000-06-27 23:18:39 +0000958 top --;
959 arc -= 3;
960 }
961 }
David Turnerc4f622c2001-10-07 10:39:03 +0000962 return;
David Turner5ae1bad2000-06-27 23:18:39 +0000963 }
964
965
966 /* a macro comparing two cell pointers. Returns true if a <= b. */
967#if 1
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000968
David Turner5ae1bad2000-06-27 23:18:39 +0000969#define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x )
970#define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) )
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000971
David Turner5ae1bad2000-06-27 23:18:39 +0000972#else /* 1 */
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000973
David Turner5ae1bad2000-06-27 23:18:39 +0000974#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \
975 ( (a)->y == (b)->y && (a)->x < (b)->x ) )
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000976
David Turner5ae1bad2000-06-27 23:18:39 +0000977#endif /* 1 */
978
979#define SWAP_CELLS( a, b, temp ) do \
980 { \
981 temp = *(a); \
982 *(a) = *(b); \
983 *(b) = temp; \
984 } while ( 0 )
985#define DEBUG_SORT
986#define QUICK_SORT
987
988#ifdef SHELL_SORT
989
Werner Lembergfbeb41d2000-07-02 00:27:53 +0000990 /* a simple shell sort algorithm that works directly on our */
991 /* cells table */
Werner Lemberg52005c32001-06-27 23:25:46 +0000992 static void
David Turnerc4f622c2001-10-07 10:39:03 +0000993 gray_shell_sort ( PCell cells,
994 int count )
David Turner5ae1bad2000-06-27 23:18:39 +0000995 {
996 PCell i, j, limit = cells + count;
997 TCell temp;
998 int gap;
999
1000
1001 /* compute initial gap */
1002 for ( gap = 0; ++gap < count; gap *= 3 )
1003 ;
1004
1005 while ( gap /= 3 )
1006 {
1007 for ( i = cells + gap; i < limit; i++ )
1008 {
1009 for ( j = i - gap; ; j -= gap )
1010 {
1011 PCell k = j + gap;
1012
1013
1014 if ( LESS_THAN( j, k ) )
1015 break;
1016
1017 SWAP_CELLS( j, k, temp );
1018
1019 if ( j < cells + gap )
1020 break;
1021 }
1022 }
1023 }
1024 }
1025
1026#endif /* SHELL_SORT */
1027
1028
1029#ifdef QUICK_SORT
1030
1031 /* This is a non-recursive quicksort that directly process our cells */
1032 /* array. It should be faster than calling the stdlib qsort(), and we */
1033 /* can even tailor our insertion threshold... */
1034
1035#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001036 /* through a normal insertion sort */
David Turner5ae1bad2000-06-27 23:18:39 +00001037
Werner Lemberg52005c32001-06-27 23:25:46 +00001038 static void
David Turnerc4f622c2001-10-07 10:39:03 +00001039 gray_quick_sort( PCell cells,
1040 int count )
David Turner5ae1bad2000-06-27 23:18:39 +00001041 {
1042 PCell stack[40]; /* should be enough ;-) */
1043 PCell* top; /* top of stack */
1044 PCell base, limit;
1045 TCell temp;
1046
1047
1048 limit = cells + count;
1049 base = cells;
1050 top = stack;
1051
1052 for (;;)
1053 {
Werner Lemberg914b2892001-03-10 17:07:42 +00001054 int len = (int)( limit - base );
David Turner5ae1bad2000-06-27 23:18:39 +00001055 PCell i, j, pivot;
1056
1057
1058 if ( len > QSORT_THRESHOLD )
1059 {
1060 /* we use base + len/2 as the pivot */
1061 pivot = base + len / 2;
1062 SWAP_CELLS( base, pivot, temp );
1063
1064 i = base + 1;
1065 j = limit - 1;
1066
1067 /* now ensure that *i <= *base <= *j */
1068 if ( LESS_THAN( j, i ) )
1069 SWAP_CELLS( i, j, temp );
1070
1071 if ( LESS_THAN( base, i ) )
1072 SWAP_CELLS( base, i, temp );
1073
1074 if ( LESS_THAN( j, base ) )
1075 SWAP_CELLS( base, j, temp );
1076
1077 for (;;)
1078 {
1079 do i++; while ( LESS_THAN( i, base ) );
1080 do j--; while ( LESS_THAN( base, j ) );
1081
1082 if ( i > j )
1083 break;
1084
1085 SWAP_CELLS( i, j, temp );
1086 }
1087
1088 SWAP_CELLS( base, j, temp );
1089
1090 /* now, push the largest sub-array */
1091 if ( j - base > limit - i )
1092 {
1093 top[0] = base;
1094 top[1] = j;
1095 base = i;
1096 }
1097 else
1098 {
1099 top[0] = i;
1100 top[1] = limit;
1101 limit = j;
1102 }
1103 top += 2;
1104 }
1105 else
1106 {
1107 /* the sub-array is small, perform insertion sort */
1108 j = base;
1109 i = j + 1;
1110
1111 for ( ; i < limit; j = i, i++ )
1112 {
1113 for ( ; LESS_THAN( j + 1, j ); j-- )
1114 {
1115 SWAP_CELLS( j + 1, j, temp );
1116 if ( j == base )
1117 break;
1118 }
1119 }
1120 if ( top > stack )
1121 {
1122 top -= 2;
1123 base = top[0];
1124 limit = top[1];
1125 }
1126 else
1127 break;
1128 }
1129 }
1130 }
1131
1132#endif /* QUICK_SORT */
1133
1134
1135#ifdef DEBUG_GRAYS
1136#ifdef DEBUG_SORT
1137
Werner Lemberg52005c32001-06-27 23:25:46 +00001138 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001139 gray_check_sort( PCell cells,
1140 int count )
David Turner5ae1bad2000-06-27 23:18:39 +00001141 {
1142 PCell p, q;
1143
1144
1145 for ( p = cells + count - 2; p >= cells; p-- )
1146 {
1147 q = p + 1;
1148 if ( !LESS_THAN( p, q ) )
1149 return 0;
1150 }
1151 return 1;
1152 }
1153
1154#endif /* DEBUG_SORT */
1155#endif /* DEBUG_GRAYS */
1156
1157
Werner Lemberg52005c32001-06-27 23:25:46 +00001158 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001159 gray_move_to( FT_Vector* to,
1160 FT_Raster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00001161 {
1162 TPos x, y;
1163
1164
1165 /* record current cell, if any */
David Turnerc4f622c2001-10-07 10:39:03 +00001166 gray_record_cell( (PRaster)raster );
David Turner5ae1bad2000-06-27 23:18:39 +00001167
1168 /* start to a new position */
1169 x = UPSCALE( to->x );
1170 y = UPSCALE( to->y );
David Turnerc4f622c2001-10-07 10:39:03 +00001171
1172 gray_start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
1173
David Turner5ae1bad2000-06-27 23:18:39 +00001174 ((PRaster)raster)->x = x;
1175 ((PRaster)raster)->y = y;
1176 return 0;
1177 }
1178
1179
Werner Lemberg52005c32001-06-27 23:25:46 +00001180 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001181 gray_line_to( FT_Vector* to,
1182 FT_Raster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00001183 {
David Turnerc4f622c2001-10-07 10:39:03 +00001184 gray_render_line( (PRaster)raster,
1185 UPSCALE( to->x ), UPSCALE( to->y ) );
1186 return 0;
David Turner5ae1bad2000-06-27 23:18:39 +00001187 }
1188
1189
Werner Lemberg52005c32001-06-27 23:25:46 +00001190 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001191 gray_conic_to( FT_Vector* control,
1192 FT_Vector* to,
1193 FT_Raster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00001194 {
David Turnerc4f622c2001-10-07 10:39:03 +00001195 gray_render_conic( (PRaster)raster, control, to );
1196 return 0;
David Turner5ae1bad2000-06-27 23:18:39 +00001197 }
1198
1199
Werner Lemberg52005c32001-06-27 23:25:46 +00001200 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001201 gray_cubic_to( FT_Vector* control1,
1202 FT_Vector* control2,
1203 FT_Vector* to,
1204 FT_Raster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00001205 {
David Turnerc4f622c2001-10-07 10:39:03 +00001206 gray_render_cubic( (PRaster)raster, control1, control2, to );
1207 return 0;
David Turner5ae1bad2000-06-27 23:18:39 +00001208 }
1209
1210
Werner Lemberg52005c32001-06-27 23:25:46 +00001211 static void
David Turnerc4f622c2001-10-07 10:39:03 +00001212 gray_render_span( int y,
1213 int count,
1214 FT_Span* spans,
1215 PRaster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00001216 {
1217 unsigned char* p;
1218 FT_Bitmap* map = &raster->target;
1219
1220
1221 /* first of all, compute the scanline offset */
1222 p = (unsigned char*)map->buffer - y * map->pitch;
1223 if ( map->pitch >= 0 )
1224 p += ( map->rows - 1 ) * map->pitch;
1225
1226 for ( ; count > 0; count--, spans++ )
1227 {
1228 if ( spans->coverage )
1229#if 1
1230 memset( p + spans->x, (unsigned char)spans->coverage, spans->len );
1231#else /* 1 */
1232 {
1233 q = p + spans->x;
1234 limit = q + spans->len;
1235 for ( ; q < limit; q++ )
1236 q[0] = (unsigned char)spans->coverage;
1237 }
1238#endif /* 1 */
1239 }
1240 }
1241
1242
1243#ifdef DEBUG_GRAYS
1244
1245#include <stdio.h>
1246
Werner Lemberg52005c32001-06-27 23:25:46 +00001247 static void
David Turnerc4f622c2001-10-07 10:39:03 +00001248 gray_dump_cells( RAS_ARG )
David Turner5ae1bad2000-06-27 23:18:39 +00001249 {
1250 PCell cell, limit;
1251 int y = -1;
1252
1253
1254 cell = ras.cells;
1255 limit = cell + ras.num_cells;
1256
1257 for ( ; cell < limit; cell++ )
1258 {
1259 if ( cell->y != y )
1260 {
1261 fprintf( stderr, "\n%2d: ", cell->y );
1262 y = cell->y;
1263 }
1264 fprintf( stderr, "[%d %d %d]",
1265 cell->x, cell->area, cell->cover );
1266 }
1267 fprintf(stderr, "\n" );
1268 }
1269
1270#endif /* DEBUG_GRAYS */
1271
1272
Werner Lemberg52005c32001-06-27 23:25:46 +00001273 static void
David Turnerc4f622c2001-10-07 10:39:03 +00001274 gray_hline( RAS_ARG_ TScan x,
1275 TScan y,
1276 TPos area,
1277 int acount )
David Turner5ae1bad2000-06-27 23:18:39 +00001278 {
1279 FT_Span* span;
1280 int count;
1281 int coverage;
1282
1283
1284 /* compute the coverage line's coverage, depending on the */
1285 /* outline fill rule */
1286 /* */
1287 /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
1288 /* */
1289 coverage = area >> ( PIXEL_BITS * 2 + 1 - 8); /* use range 0..256 */
1290
1291 if ( ras.outline.flags & ft_outline_even_odd_fill )
1292 {
1293 if ( coverage < 0 )
1294 coverage = -coverage;
1295
1296 while ( coverage >= 512 )
1297 coverage -= 512;
1298
1299 if ( coverage > 256 )
1300 coverage = 512 - coverage;
1301 else if ( coverage == 256 )
1302 coverage = 255;
1303 }
1304 else
1305 {
1306 /* normal non-zero winding rule */
1307 if ( coverage < 0 )
1308 coverage = -coverage;
1309
1310 if ( coverage >= 256 )
1311 coverage = 255;
1312 }
1313
1314 y += ras.min_ey;
1315 x += ras.min_ex;
1316
1317 if ( coverage )
1318 {
1319 /* see if we can add this span to the current list */
1320 count = ras.num_gray_spans;
1321 span = ras.gray_spans + count - 1;
1322 if ( count > 0 &&
1323 ras.span_y == y &&
1324 (int)span->x + span->len == (int)x &&
1325 span->coverage == coverage )
1326 {
Werner Lemberg8eb03532001-06-19 23:03:41 +00001327 span->len = (unsigned short)( span->len + acount );
David Turner5ae1bad2000-06-27 23:18:39 +00001328 return;
1329 }
1330
1331 if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
1332 {
David Turnerb71c6af2000-09-17 17:17:16 +00001333 if ( ras.render_span && count > 0 )
David Turner5ae1bad2000-06-27 23:18:39 +00001334 ras.render_span( ras.span_y, count, ras.gray_spans,
1335 ras.render_span_data );
1336 /* ras.render_span( span->y, ras.gray_spans, count ); */
1337
1338#ifdef DEBUG_GRAYS
1339
1340 if ( ras.span_y >= 0 )
1341 {
1342 int n;
1343
1344
1345 fprintf( stderr, "y=%3d ", ras.span_y );
1346 span = ras.gray_spans;
1347 for ( n = 0; n < count; n++, span++ )
1348 fprintf( stderr, "[%d..%d]:%02x ",
1349 span->x, span->x + span->len - 1, span->coverage );
1350 fprintf( stderr, "\n" );
1351 }
1352
1353#endif /* DEBUG_GRAYS */
1354
1355 ras.num_gray_spans = 0;
1356 ras.span_y = y;
1357
1358 count = 0;
1359 span = ras.gray_spans;
1360 }
1361 else
1362 span++;
1363
1364 /* add a gray span to the current list */
1365 span->x = (short)x;
1366 span->len = (unsigned short)acount;
1367 span->coverage = (unsigned char)coverage;
1368 ras.num_gray_spans++;
1369 }
1370 }
1371
1372
Werner Lemberg52005c32001-06-27 23:25:46 +00001373 static void
David Turnerc4f622c2001-10-07 10:39:03 +00001374 gray_sweep( RAS_ARG_ FT_Bitmap* target )
David Turner5ae1bad2000-06-27 23:18:39 +00001375 {
David Turnerc4f622c2001-10-07 10:39:03 +00001376 TScan x, y, cover;
1377 TArea area;
David Turner5ae1bad2000-06-27 23:18:39 +00001378 PCell start, cur, limit;
1379
David Turnerc6a92202000-07-04 18:12:13 +00001380 FT_UNUSED( target );
David Turner5ae1bad2000-06-27 23:18:39 +00001381
David Turner5aeaad62001-02-23 17:47:41 +00001382 if ( ras.num_cells == 0 )
1383 return;
David Turnerc4f622c2001-10-07 10:39:03 +00001384
David Turner5ae1bad2000-06-27 23:18:39 +00001385 cur = ras.cells;
1386 limit = cur + ras.num_cells;
1387
1388 cover = 0;
1389 ras.span_y = -1;
1390 ras.num_gray_spans = 0;
1391
1392 for (;;)
1393 {
1394 start = cur;
1395 y = start->y;
1396 x = start->x;
1397
1398 area = start->area;
1399 cover += start->cover;
1400
1401 /* accumulate all start cells */
1402 for (;;)
1403 {
1404 ++cur;
1405 if ( cur >= limit || cur->y != start->y || cur->x != start->x )
1406 break;
1407
1408 area += cur->area;
1409 cover += cur->cover;
1410 }
1411
1412 /* if the start cell has a non-null area, we must draw an */
1413 /* individual gray pixel there */
1414 if ( area && x >= 0 )
1415 {
David Turnerc4f622c2001-10-07 10:39:03 +00001416 gray_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 );
David Turner5ae1bad2000-06-27 23:18:39 +00001417 x++;
1418 }
1419
1420 if ( x < 0 )
1421 x = 0;
1422
1423 if ( cur < limit && start->y == cur->y )
1424 {
1425 /* draw a gray span between the start cell and the current one */
1426 if ( cur->x > x )
David Turnerc4f622c2001-10-07 10:39:03 +00001427 gray_hline( RAS_VAR_ x, y,
David Turner5ae1bad2000-06-27 23:18:39 +00001428 cover * ( ONE_PIXEL * 2 ), cur->x - x );
1429 }
1430 else
1431 {
1432 /* draw a gray span until the end of the clipping region */
1433 if ( cover && x < ras.max_ex - ras.min_ex )
David Turnerc4f622c2001-10-07 10:39:03 +00001434 gray_hline( RAS_VAR_ x, y,
David Turner5ae1bad2000-06-27 23:18:39 +00001435 cover * ( ONE_PIXEL * 2 ),
1436 ras.max_ex - x - ras.min_ex );
1437 cover = 0;
1438 }
1439
1440 if ( cur >= limit )
1441 break;
1442 }
1443
1444 if ( ras.render_span && ras.num_gray_spans > 0 )
1445 ras.render_span( ras.span_y, ras.num_gray_spans,
1446 ras.gray_spans, ras.render_span_data );
1447
1448#ifdef DEBUG_GRAYS
1449
1450 {
1451 int n;
1452 FT_Span* span;
1453
1454
1455 fprintf( stderr, "y=%3d ", ras.span_y );
1456 span = ras.gray_spans;
1457 for ( n = 0; n < ras.num_gray_spans; n++, span++ )
1458 fprintf( stderr, "[%d..%d]:%02x ",
1459 span->x, span->x + span->len - 1, span->coverage );
1460 fprintf( stderr, "\n" );
1461 }
1462
1463#endif /* DEBUG_GRAYS */
1464
1465 }
1466
1467
1468#ifdef _STANDALONE_
1469
1470 /*************************************************************************/
1471 /* */
1472 /* The following function should only compile in stand_alone mode, */
1473 /* i.e., when building this component without the rest of FreeType. */
1474 /* */
1475 /*************************************************************************/
1476
1477 /*************************************************************************/
1478 /* */
1479 /* <Function> */
1480 /* FT_Outline_Decompose */
1481 /* */
1482 /* <Description> */
1483 /* Walks over an outline's structure to decompose it into individual */
1484 /* segments and Bezier arcs. This function is also able to emit */
1485 /* `move to' and `close to' operations to indicate the start and end */
1486 /* of new contours in the outline. */
1487 /* */
1488 /* <Input> */
1489 /* outline :: A pointer to the source target. */
1490 /* */
1491 /* interface :: A table of `emitters', i.e,. function pointers called */
1492 /* during decomposition to indicate path operations. */
1493 /* */
1494 /* user :: A typeless pointer which is passed to each emitter */
1495 /* during the decomposition. It can be used to store */
1496 /* the state during the decomposition. */
1497 /* */
1498 /* <Return> */
1499 /* Error code. 0 means sucess. */
1500 /* */
David Turnerc4f622c2001-10-07 10:39:03 +00001501 static
1502 int FT_Outline_Decompose( FT_Outline* outline,
1503 const FT_Outline_Funcs* interface,
1504 void* user )
David Turner5ae1bad2000-06-27 23:18:39 +00001505 {
1506#undef SCALED
David Turnerc4f622c2001-10-07 10:39:03 +00001507#if 0
1508# define SCALED( x ) ( ( (x) << shift ) - delta )
1509#else
1510# define SCALED( x) (x)
1511#endif
David Turner5ae1bad2000-06-27 23:18:39 +00001512
1513 FT_Vector v_last;
1514 FT_Vector v_control;
1515 FT_Vector v_start;
1516
1517 FT_Vector* point;
1518 FT_Vector* limit;
1519 char* tags;
1520
1521 int n; /* index of contour in outline */
1522 int first; /* index of first point in contour */
1523 int error;
1524 char tag; /* current point's state */
1525
David Turnerc4f622c2001-10-07 10:39:03 +00001526#if 0
David Turner5ae1bad2000-06-27 23:18:39 +00001527 int shift = interface->shift;
1528 FT_Pos delta = interface->delta;
David Turnerc4f622c2001-10-07 10:39:03 +00001529#endif
David Turner5ae1bad2000-06-27 23:18:39 +00001530
1531
1532 first = 0;
1533
1534 for ( n = 0; n < outline->n_contours; n++ )
1535 {
1536 int last; /* index of last point in contour */
1537
1538
1539 last = outline->contours[n];
1540 limit = outline->points + last;
1541
1542 v_start = outline->points[first];
1543 v_last = outline->points[last];
1544
1545 v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
1546 v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
1547
1548 v_control = v_start;
1549
1550 point = outline->points + first;
1551 tags = outline->tags + first;
1552 tag = FT_CURVE_TAG( tags[0] );
1553
1554 /* A contour cannot start with a cubic control point! */
1555 if ( tag == FT_Curve_Tag_Cubic )
1556 goto Invalid_Outline;
1557
1558 /* check first point to determine origin */
1559 if ( tag == FT_Curve_Tag_Conic )
1560 {
1561 /* first point is conic control. Yes, this happens. */
1562 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
1563 {
1564 /* start at last point if it is on the curve */
1565 v_start = v_last;
1566 limit--;
1567 }
1568 else
1569 {
1570 /* if both first and last points are conic, */
1571 /* start at their middle and record its position */
1572 /* for closure */
1573 v_start.x = ( v_start.x + v_last.x ) / 2;
1574 v_start.y = ( v_start.y + v_last.y ) / 2;
1575
1576 v_last = v_start;
1577 }
1578 point--;
1579 tags--;
1580 }
1581
1582 error = interface->move_to( &v_start, user );
1583 if ( error )
1584 goto Exit;
1585
1586 while ( point < limit )
1587 {
1588 point++;
1589 tags++;
1590
1591 tag = FT_CURVE_TAG( tags[0] );
1592 switch ( tag )
1593 {
1594 case FT_Curve_Tag_On: /* emit a single line_to */
1595 {
1596 FT_Vector vec;
1597
1598
1599 vec.x = SCALED( point->x );
1600 vec.y = SCALED( point->y );
1601
1602 error = interface->line_to( &vec, user );
1603 if ( error )
1604 goto Exit;
1605 continue;
1606 }
1607
1608 case FT_Curve_Tag_Conic: /* consume conic arcs */
1609 {
1610 v_control.x = SCALED( point->x );
1611 v_control.y = SCALED( point->y );
1612
1613 Do_Conic:
1614 if ( point < limit )
1615 {
1616 FT_Vector vec;
1617 FT_Vector v_middle;
1618
1619
1620 point++;
1621 tags++;
1622 tag = FT_CURVE_TAG( tags[0] );
1623
1624 vec.x = SCALED( point->x );
1625 vec.y = SCALED( point->y );
1626
1627 if ( tag == FT_Curve_Tag_On )
1628 {
1629 error = interface->conic_to( &v_control, &vec, user );
1630 if ( error )
1631 goto Exit;
1632 continue;
1633 }
1634
1635 if ( tag != FT_Curve_Tag_Conic )
1636 goto Invalid_Outline;
1637
1638 v_middle.x = ( v_control.x + vec.x ) / 2;
1639 v_middle.y = ( v_control.y + vec.y ) / 2;
1640
1641 error = interface->conic_to( &v_control, &v_middle, user );
1642 if ( error )
1643 goto Exit;
1644
1645 v_control = vec;
1646 goto Do_Conic;
1647 }
1648
1649 error = interface->conic_to( &v_control, &v_start, user );
1650 goto Close;
1651 }
1652
1653 default: /* FT_Curve_Tag_Cubic */
1654 {
1655 FT_Vector vec1, vec2;
1656
1657
1658 if ( point + 1 > limit ||
1659 FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
1660 goto Invalid_Outline;
1661
1662 point += 2;
1663 tags += 2;
1664
1665 vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
1666 vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
1667
1668 if ( point <= limit )
1669 {
1670 FT_Vector vec;
1671
1672
1673 vec.x = SCALED( point->x );
1674 vec.y = SCALED( point->y );
1675
1676 error = interface->cubic_to( &vec1, &vec2, &vec, user );
1677 if ( error )
1678 goto Exit;
1679 continue;
1680 }
1681
1682 error = interface->cubic_to( &vec1, &vec2, &v_start, user );
1683 goto Close;
1684 }
1685 }
1686 }
1687
1688 /* close the contour with a line segment */
1689 error = interface->line_to( &v_start, user );
1690
1691 Close:
1692 if ( error )
1693 goto Exit;
1694
1695 first = last + 1;
1696 }
1697
1698 return 0;
1699
1700 Exit:
1701 return error;
1702
1703 Invalid_Outline:
1704 return ErrRaster_Invalid_Outline;
1705 }
1706
1707#endif /* _STANDALONE_ */
1708
1709
1710 typedef struct TBand_
1711 {
1712 FT_Pos min, max;
1713
1714 } TBand;
1715
1716
Werner Lemberg52005c32001-06-27 23:25:46 +00001717 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001718 gray_convert_glyph_inner( RAS_ARG )
David Turner5ae1bad2000-06-27 23:18:39 +00001719 {
1720 static
David Turnerdc26e7b2000-10-23 22:46:56 +00001721 const FT_Outline_Funcs interface =
David Turner5ae1bad2000-06-27 23:18:39 +00001722 {
David Turnerc4f622c2001-10-07 10:39:03 +00001723 (FT_Outline_MoveTo_Func) gray_move_to,
1724 (FT_Outline_LineTo_Func) gray_line_to,
1725 (FT_Outline_ConicTo_Func) gray_conic_to,
1726 (FT_Outline_CubicTo_Func) gray_cubic_to,
David Turner5ae1bad2000-06-27 23:18:39 +00001727 0,
1728 0
1729 };
1730
David Turnerc4f622c2001-10-07 10:39:03 +00001731 volatile int error = 0;
1732
1733 if ( setjmp( ras.jump_buffer ) == 0 )
1734 {
1735 error = FT_Outline_Decompose( &ras.outline, &interface, &ras );
1736 gray_record_cell( RAS_VAR );
1737 }
1738 else
1739 {
1740 error = ErrRaster_MemoryOverflow;
1741 }
1742
1743 return error;
1744 }
1745
1746
1747 static int
1748 gray_convert_glyph( RAS_ARG )
1749 {
Werner Lemberg594f0c92000-12-20 22:09:41 +00001750 TBand bands[40], *band;
1751 int n, num_bands;
1752 TPos min, max, max_y;
1753 FT_BBox* clip;
David Turner5ae1bad2000-06-27 23:18:39 +00001754
1755
1756 /* Set up state in the raster object */
David Turnerc4f622c2001-10-07 10:39:03 +00001757 gray_compute_cbox( RAS_VAR );
David Turner5ae1bad2000-06-27 23:18:39 +00001758
1759 /* clip to target bitmap, exit if nothing to do */
David Turner859a18a2000-12-14 18:50:40 +00001760 clip = &ras.clip_box;
David Turnerc4f622c2001-10-07 10:39:03 +00001761
David Turner859a18a2000-12-14 18:50:40 +00001762 if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
1763 ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
David Turner5ae1bad2000-06-27 23:18:39 +00001764 return 0;
1765
David Turner859a18a2000-12-14 18:50:40 +00001766 if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
1767 if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
David Turner5ae1bad2000-06-27 23:18:39 +00001768
David Turner859a18a2000-12-14 18:50:40 +00001769 if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
1770 if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
David Turner5ae1bad2000-06-27 23:18:39 +00001771
Werner Lembergfbeb41d2000-07-02 00:27:53 +00001772 /* simple heuristic used to speed-up the bezier decomposition -- see */
David Turnerc4f622c2001-10-07 10:39:03 +00001773 /* the code in gray_render_conic() and gray_render_cubic() for more details */
David Turner5ae1bad2000-06-27 23:18:39 +00001774 ras.conic_level = 32;
1775 ras.cubic_level = 16;
1776
1777 {
1778 int level = 0;
1779
1780
1781 if ( ras.max_ex > 24 || ras.max_ey > 24 )
1782 level++;
1783 if ( ras.max_ex > 120 || ras.max_ey > 120 )
Werner Lembergf9b03752000-09-11 22:50:13 +00001784 level++;
David Turner5ae1bad2000-06-27 23:18:39 +00001785
1786 ras.conic_level <<= level;
1787 ras.cubic_level <<= level;
1788 }
1789
1790 /* setup vertical bands */
1791 num_bands = ( ras.max_ey - ras.min_ey ) / ras.band_size;
1792 if ( num_bands == 0 ) num_bands = 1;
1793 if ( num_bands >= 39 ) num_bands = 39;
1794
1795 ras.band_shoot = 0;
1796
1797 min = ras.min_ey;
1798 max_y = ras.max_ey;
1799
1800 for ( n = 0; n < num_bands; n++, min = max )
1801 {
1802 max = min + ras.band_size;
1803 if ( n == num_bands - 1 || max > max_y )
1804 max = max_y;
1805
1806 bands[0].min = min;
1807 bands[0].max = max;
1808 band = bands;
1809
1810 while ( band >= bands )
1811 {
1812 FT_Pos bottom, top, middle;
1813 int error;
1814
1815
1816 ras.num_cells = 0;
1817 ras.invalid = 1;
1818 ras.min_ey = band->min;
1819 ras.max_ey = band->max;
1820
David Turnerc4f622c2001-10-07 10:39:03 +00001821#if 1
1822 error = gray_convert_glyph_inner( RAS_VAR );
1823#else
David Turner5ae1bad2000-06-27 23:18:39 +00001824 error = FT_Outline_Decompose( outline, &interface, &ras ) ||
David Turnerc4f622c2001-10-07 10:39:03 +00001825 gray_record_cell( RAS_VAR );
1826#endif
David Turner5ae1bad2000-06-27 23:18:39 +00001827
1828 if ( !error )
1829 {
1830#ifdef SHELL_SORT
David Turnerc4f622c2001-10-07 10:39:03 +00001831 gray_shell_sort( ras.cells, ras.num_cells );
David Turner5ae1bad2000-06-27 23:18:39 +00001832#else
David Turnerc4f622c2001-10-07 10:39:03 +00001833 gray_quick_sort( ras.cells, ras.num_cells );
David Turner5ae1bad2000-06-27 23:18:39 +00001834#endif
1835
1836#ifdef DEBUG_GRAYS
David Turnerc4f622c2001-10-07 10:39:03 +00001837 gray_check_sort( ras.cells, ras.num_cells );
1838 gray_dump_cells( RAS_VAR );
David Turner5ae1bad2000-06-27 23:18:39 +00001839#endif
1840
David Turnerc4f622c2001-10-07 10:39:03 +00001841 gray_sweep( RAS_VAR_ &ras.target );
David Turner5ae1bad2000-06-27 23:18:39 +00001842 band--;
1843 continue;
1844 }
David Turnerc4f622c2001-10-07 10:39:03 +00001845 else if ( error != ErrRaster_MemoryOverflow )
1846 return 1;
David Turner5ae1bad2000-06-27 23:18:39 +00001847
1848 /* render pool overflow, we will reduce the render band by half */
1849 bottom = band->min;
1850 top = band->max;
1851 middle = bottom + ( ( top - bottom ) >> 1 );
1852
1853 /* waoow! This is too complex for a single scanline, something */
1854 /* must be really rotten here! */
1855 if ( middle == bottom )
1856 {
1857#ifdef DEBUG_GRAYS
1858 fprintf( stderr, "Rotten glyph!\n" );
1859#endif
1860 return 1;
1861 }
1862
1863 if ( bottom-top >= ras.band_size )
1864 ras.band_shoot++;
1865
1866 band[1].min = bottom;
1867 band[1].max = middle;
1868 band[0].min = middle;
1869 band[0].max = top;
1870 band++;
1871 }
1872 }
1873
1874 if ( ras.band_shoot > 8 && ras.band_size > 16 )
1875 ras.band_size = ras.band_size / 2;
1876
1877 return 0;
1878 }
1879
1880
Werner Lemberg52005c32001-06-27 23:25:46 +00001881 extern int
David Turnerc4f622c2001-10-07 10:39:03 +00001882 gray_raster_render( PRaster raster,
1883 FT_Raster_Params* params )
David Turner5ae1bad2000-06-27 23:18:39 +00001884 {
1885 FT_Outline* outline = (FT_Outline*)params->source;
1886 FT_Bitmap* target_map = params->target;
1887
1888
1889 if ( !raster || !raster->cells || !raster->max_cells )
1890 return -1;
1891
1892 /* return immediately if the outline is empty */
1893 if ( outline->n_points == 0 || outline->n_contours <= 0 )
1894 return 0;
1895
1896 if ( !outline || !outline->contours || !outline->points )
1897 return ErrRaster_Invalid_Outline;
1898
1899 if ( outline->n_points !=
1900 outline->contours[outline->n_contours - 1] + 1 )
1901 return ErrRaster_Invalid_Outline;
1902
David Turner78dd7102000-10-03 19:13:11 +00001903 /* if direct mode is not set, we must have a target bitmap */
Werner Lemberg6fbe4db2000-10-05 04:53:31 +00001904 if ( ( params->flags & ft_raster_flag_direct ) == 0 &&
1905 ( !target_map || !target_map->buffer ) )
David Turner5ae1bad2000-06-27 23:18:39 +00001906 return -1;
1907
David Turner78dd7102000-10-03 19:13:11 +00001908 /* this version does not support monochrome rendering */
Werner Lemberg6fbe4db2000-10-05 04:53:31 +00001909 if ( !( params->flags & ft_raster_flag_aa ) )
David Turner5ae1bad2000-06-27 23:18:39 +00001910 return ErrRaster_Invalid_Mode;
1911
David Turner859a18a2000-12-14 18:50:40 +00001912 /* compute clipping box */
Werner Lemberg594f0c92000-12-20 22:09:41 +00001913 if ( ( params->flags & ft_raster_flag_direct ) == 0 )
David Turner859a18a2000-12-14 18:50:40 +00001914 {
1915 /* compute clip box from target pixmap */
1916 ras.clip_box.xMin = 0;
1917 ras.clip_box.yMin = 0;
1918 ras.clip_box.xMax = target_map->width;
1919 ras.clip_box.yMax = target_map->rows;
1920 }
1921 else if ( params->flags & ft_raster_flag_clip )
1922 {
1923 ras.clip_box = params->clip_box;
1924 }
1925 else
1926 {
Werner Lembergcf24d512001-06-18 14:23:45 +00001927 ras.clip_box.xMin = -32768L;
1928 ras.clip_box.yMin = -32768L;
1929 ras.clip_box.xMax = 32767L;
1930 ras.clip_box.yMax = 32767L;
David Turner859a18a2000-12-14 18:50:40 +00001931 }
1932
David Turner5ae1bad2000-06-27 23:18:39 +00001933 ras.outline = *outline;
David Turner5ae1bad2000-06-27 23:18:39 +00001934 ras.num_cells = 0;
1935 ras.invalid = 1;
1936
Werner Lemberg6fbe4db2000-10-05 04:53:31 +00001937 if ( target_map )
David Turner78dd7102000-10-03 19:13:11 +00001938 ras.target = *target_map;
David Turner78dd7102000-10-03 19:13:11 +00001939
David Turnerc4f622c2001-10-07 10:39:03 +00001940 ras.render_span = (FT_Raster_Span_Func)gray_render_span;
David Turner5ae1bad2000-06-27 23:18:39 +00001941 ras.render_span_data = &ras;
1942
1943 if ( params->flags & ft_raster_flag_direct )
1944 {
1945 ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
1946 ras.render_span_data = params->user;
1947 }
1948
David Turnerc4f622c2001-10-07 10:39:03 +00001949 return gray_convert_glyph( (PRaster)raster );
David Turner5ae1bad2000-06-27 23:18:39 +00001950 }
1951
1952
1953 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
1954 /**** a static object. *****/
1955
1956#ifdef _STANDALONE_
1957
Werner Lemberg52005c32001-06-27 23:25:46 +00001958 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001959 gray_raster_new( void* memory,
1960 FT_Raster* araster )
David Turner5ae1bad2000-06-27 23:18:39 +00001961 {
1962 static TRaster the_raster;
1963
David Turnerc6a92202000-07-04 18:12:13 +00001964 FT_UNUSED( memory );
David Turner5ae1bad2000-06-27 23:18:39 +00001965
1966
1967 *araster = (FT_Raster)&the_raster;
1968 memset( &the_raster, 0, sizeof ( the_raster ) );
1969
1970 return 0;
1971 }
1972
1973
Werner Lemberg52005c32001-06-27 23:25:46 +00001974 static void
David Turnerc4f622c2001-10-07 10:39:03 +00001975 gray_raster_done( FT_Raster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00001976 {
1977 /* nothing */
David Turnerc6a92202000-07-04 18:12:13 +00001978 FT_UNUSED( raster );
David Turner5ae1bad2000-06-27 23:18:39 +00001979 }
1980
1981#else /* _STANDALONE_ */
1982
Werner Lemberg52005c32001-06-27 23:25:46 +00001983 static int
David Turnerc4f622c2001-10-07 10:39:03 +00001984 gray_raster_new( FT_Memory memory,
1985 FT_Raster* araster )
David Turner5ae1bad2000-06-27 23:18:39 +00001986 {
1987 FT_Error error;
1988 PRaster raster;
1989
1990
1991 *araster = 0;
1992 if ( !ALLOC( raster, sizeof ( TRaster ) ) )
1993 {
1994 raster->memory = memory;
1995 *araster = (FT_Raster)raster;
1996 }
1997
1998 return error;
1999 }
2000
2001
Werner Lemberg52005c32001-06-27 23:25:46 +00002002 static void
David Turnerc4f622c2001-10-07 10:39:03 +00002003 gray_raster_done( FT_Raster raster )
David Turner5ae1bad2000-06-27 23:18:39 +00002004 {
2005 FT_Memory memory = (FT_Memory)((PRaster)raster)->memory;
2006
2007
2008 FREE( raster );
2009 }
2010
2011#endif /* _STANDALONE_ */
2012
2013
Werner Lemberg52005c32001-06-27 23:25:46 +00002014 static void
David Turnerc4f622c2001-10-07 10:39:03 +00002015 gray_raster_reset( FT_Raster raster,
2016 const char* pool_base,
2017 long pool_size )
David Turner5ae1bad2000-06-27 23:18:39 +00002018 {
2019 PRaster rast = (PRaster)raster;
2020
2021
2022 if ( raster && pool_base && pool_size >= 4096 )
David Turnerc4f622c2001-10-07 10:39:03 +00002023 gray_init_cells( rast, (char*)pool_base, pool_size );
David Turner5ae1bad2000-06-27 23:18:39 +00002024
2025 rast->band_size = ( pool_size / sizeof ( TCell ) ) / 8;
2026 }
2027
2028
David Turnerdc26e7b2000-10-23 22:46:56 +00002029 const FT_Raster_Funcs ft_grays_raster =
David Turner5ae1bad2000-06-27 23:18:39 +00002030 {
2031 ft_glyph_format_outline,
2032
David Turnerc4f622c2001-10-07 10:39:03 +00002033 (FT_Raster_New_Func) gray_raster_new,
2034 (FT_Raster_Reset_Func) gray_raster_reset,
2035 (FT_Raster_Set_Mode_Func) 0,
2036 (FT_Raster_Render_Func) gray_raster_render,
2037 (FT_Raster_Done_Func) gray_raster_done
David Turner5ae1bad2000-06-27 23:18:39 +00002038 };
2039
2040
2041/* END */