1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevddrw.c,v 1.27 2004/12/08 21:35:13 stefan Exp $ */
18 /* Default polygon and image drawing device procedures */
19 #include <assert.h>
20 #include "math_.h"
21 #include "memory_.h"
22 #include "stdint_.h"
23 #include "gx.h"
24 #include "gpcheck.h"
25 #include "gserrors.h"
26 #include "gsrect.h"
27 #include "gxfixed.h"
28 #include "gxmatrix.h"
29 #include "gxdcolor.h"
30 #include "gxdevice.h"
31 #include "gxiparam.h"
32 #include "gxistate.h"
33 #include "gdevddrw.h"
34 #include "vdtrace.h"
35 /*
36 #include "gxdtfill.h" - Do not remove this comment.
37 "gxdtfill.h" is included below.
38 */
39
40 #define VD_RECT_COLOR RGB(0, 0, 255)
41
42 #define SWAP(a, b, t)\
43 (t = a, a = b, b = t)
44
45 /* ---------------- Polygon and line drawing ---------------- */
46
47 /* Define the 'remainder' analogue of fixed_mult_quo. */
48 private fixed
fixed_mult_rem(fixed a,fixed b,fixed c)49 fixed_mult_rem(fixed a, fixed b, fixed c)
50 {
51 /* All kinds of truncation may happen here, but it's OK. */
52 return a * b - fixed_mult_quo(a, b, c) * c;
53 }
54
55 /*
56 * The trapezoid fill algorithm uses trap_line structures to keep track of
57 * the left and right edges during the Bresenham loop.
58 */
59 typedef struct trap_line_s {
60 /*
61 * h is the y extent of the line (edge.end.y - edge.start.y).
62 * We know h > 0.
63 */
64 fixed h;
65 /*
66 * The dx/dy ratio for the line is di + df/h.
67 * (The quotient refers to the l.s.b. of di, not fixed_1.)
68 * We know 0 <= df < h.
69 */
70 int di;
71 fixed df;
72 /*
73 * The intersection of the line with a scan line is x + xf/h + 1.
74 * (The 1 refers to the least significant bit of x, not fixed_1;
75 * similarly, the quotient refers to the l.s.b. of x.)
76 * We know -h <= xf < 0.
77 *
78 * This rational value preciselly represents the mathematical line
79 * (with no machine arithmetic error).
80 *
81 * Note that the fractional part is negative to simplify
82 * some conditions in the Bresenham algorithm.
83 * Due to that some expressions are inobvious.
84 * We believe that it's a kind of archaic
85 * for the modern hyperthreading architecture,
86 * we still keep it because the code passed a huge testing
87 * on various platforms.
88 */
89 fixed x, xf;
90 /*
91 * We increment (x,xf) by (ldi,ldf) after each scan line.
92 * (ldi,ldf) is just (di,df) converted to fixed point.
93 * We know 0 <= ldf < h.
94 */
95 fixed ldi, ldf;
96 } trap_line;
97
98
99 /*
100 * The linear color trapezoid fill algorithm uses trap_color structures to keep track of
101 * the color change during the Bresenham loop.
102 */
103 typedef struct trap_gradient_s {
104 frac31 *c; /* integer part of the color in frac32 units. */
105 int32_t *f; /* the fraction part numerator */
106 int32_t *num; /* the gradient numerator */
107 int32_t den; /* color gradient denominator */
108 } trap_gradient;
109
110
111 /*
112 * Compute the di and df members of a trap_line structure. The x extent
113 * (edge.end.x - edge.start.x) is a parameter; the y extent (h member)
114 * has already been set. Also adjust x for the initial y.
115 */
116 inline private void
compute_dx(trap_line * tl,fixed xd,fixed ys)117 compute_dx(trap_line *tl, fixed xd, fixed ys)
118 {
119 fixed h = tl->h;
120 int di;
121
122 if (xd >= 0) {
123 if (xd < h)
124 tl->di = 0, tl->df = xd;
125 else {
126 tl->di = di = (int)(xd / h);
127 tl->df = xd - di * h;
128 tl->x += ys * di;
129 }
130 } else {
131 if ((tl->df = xd + h) >= 0 /* xd >= -h */)
132 tl->di = -1, tl->x -= ys;
133 else {
134 tl->di = di = (int)-((h - 1 - xd) / h);
135 tl->df = xd - di * h;
136 tl->x += ys * di;
137 }
138 }
139 }
140
141 #define YMULT_LIMIT (max_fixed / fixed_1)
142
143 /* Compute ldi, ldf, and xf similarly. */
144 inline private void
compute_ldx(trap_line * tl,fixed ys)145 compute_ldx(trap_line *tl, fixed ys)
146 {
147 int di = tl->di;
148 fixed df = tl->df;
149 fixed h = tl->h;
150
151 if ( df < YMULT_LIMIT ) {
152 if ( df == 0 ) /* vertical edge, worth checking for */
153 tl->ldi = int2fixed(di), tl->ldf = 0, tl->xf = -h;
154 else {
155 tl->ldi = int2fixed(di) + int2fixed(df) / h;
156 tl->ldf = int2fixed(df) % h;
157 tl->xf =
158 (ys < fixed_1 ? ys * df % h : fixed_mult_rem(ys, df, h)) - h;
159 }
160 }
161 else {
162 tl->ldi = int2fixed(di) + fixed_mult_quo(fixed_1, df, h);
163 tl->ldf = fixed_mult_rem(fixed_1, df, h);
164 tl->xf = fixed_mult_rem(ys, df, h) - h;
165 }
166 }
167
168 private inline void
init_gradient(trap_gradient * g,const gs_fill_attributes * fa,const gs_linear_color_edge * e,const gs_linear_color_edge * e1,const trap_line * l,fixed ybot,int num_components)169 init_gradient(trap_gradient *g, const gs_fill_attributes *fa,
170 const gs_linear_color_edge *e, const gs_linear_color_edge *e1,
171 const trap_line *l, fixed ybot, int num_components)
172 {
173 int i;
174 int64_t c;
175 int32_t d;
176
177 if (e->c1 == NULL || e->c0 == NULL)
178 g->den = 0; /* A wedge - the color is axial along another edge. */
179 else {
180 bool ends_from_fa = (e1->c1 == NULL || e1->c0 == NULL);
181
182 if (ends_from_fa)
183 g->den = fa->yend - fa->ystart;
184 else {
185 g->den = e->end.y - e->start.y;
186 assert(g->den == l->h);
187 }
188 for (i = 0; i < num_components; i++) {
189 g->num[i] = e->c1[i] - e->c0[i];
190 c = (int64_t)g->num[i] * (uint32_t)(ybot -
191 (ends_from_fa ? fa->ystart : e->start.y));
192 d = (int32_t)(c / g->den);
193 g->c[i] = e->c0[i] + d;
194 c -= (int64_t)d * g->den;
195 if (c < 0) {
196 g->c[i]--;
197 c += g->den;
198 }
199 g->f[i] = (int32_t)c;
200 }
201 }
202 }
203
204 private inline void
step_gradient(trap_gradient * g,int num_components)205 step_gradient(trap_gradient *g, int num_components)
206 {
207 int i;
208
209 if (g->den == 0)
210 return;
211 for (i = 0; i < num_components; i++) {
212 int64_t fc = g->f[i] + (int64_t)g->num[i] * fixed_1;
213 int32_t fc32;
214
215 g->c[i] += (int32_t)(fc / g->den);
216 fc32 = (int32_t)(fc - fc / g->den * g->den);
217 if (fc32 < 0) {
218 fc32 += g->den;
219 g->c[i]--;
220 }
221 g->f[i] = fc32;
222 }
223 }
224
225 private inline bool
check_gradient_overflow(const gs_linear_color_edge * le,const gs_linear_color_edge * re,int num_components)226 check_gradient_overflow(const gs_linear_color_edge *le, const gs_linear_color_edge *re,
227 int num_components)
228 {
229 if (le->c1 == NULL || re->c1 == NULL) {
230 /* A wedge doesn't use a gradient by X. */
231 return false;
232 } else {
233 /* Check whether set_x_gradient, fill_linear_color_scanline can overflow.
234
235 dev_proc(dev, fill_linear_color_scanline) can perform its computation in 32-bit fractions,
236 so we assume it never overflows. Devices which implement it with no this
237 assumption must implement the check in gx_default_fill_linear_color_trapezoid,
238 gx_default_fill_linear_color_triangle with a function other than this one.
239
240 Since set_x_gradient perform computations in int64_t, which provides 63 bits
241 while multiplying a 32-bits color value to a coordinate,
242 we must restrict the X span with 63 - 32 = 31 bits.
243 */
244 int32_t xl = min(le->start.x, le->end.x);
245 int32_t xr = min(re->start.x, re->end.x);
246 /* The pixel span boundaries : */
247 return arith_rshift_1(xr) - arith_rshift_1(xl) >= 0x3FFFFFFE;
248 }
249 }
250
251
252 private inline int
set_x_gradient_nowedge(trap_gradient * xg,const trap_gradient * lg,const trap_gradient * rg,const trap_line * l,const trap_line * r,int il,int ir,int num_components)253 set_x_gradient_nowedge(trap_gradient *xg, const trap_gradient *lg, const trap_gradient *rg,
254 const trap_line *l, const trap_line *r, int il, int ir, int num_components)
255 {
256 /* Ignoring the ending coordinats fractions,
257 so the gridient is slightly shifted to the left (in <1 'fixed' unit). */
258 int32_t xl = l->x - (l->xf == -l->h ? 1 : 0) - fixed_half; /* Revert the GX_FILL_TRAPEZOID shift. */
259 int32_t xr = r->x - (r->xf == -r->h ? 1 : 0) - fixed_half; /* Revert the GX_FILL_TRAPEZOID shift. */
260 /* The pixel span boundaries : */
261 int32_t x0 = int2fixed(il) + fixed_half; /* Shift to the pixel center. */
262 int32_t x1 = int2fixed(ir) + fixed_half; /* Shift to the pixel center. */
263 int i;
264
265 # ifdef DEBUG
266 if (arith_rshift_1(xr) - arith_rshift_1(xl) >= 0x3FFFFFFE) /* Can overflow ? */
267 return_error(gs_error_unregistered); /* Must not happen. */
268 # endif
269 xg->den = fixed2int(x1 - x0);
270 for (i = 0; i < num_components; i++) {
271 /* Ignoring the ending colors fractions,
272 so the color gets a slightly smaller value
273 (in <1 'frac31' unit), but it's not important due to
274 the further conversion to [0, 1 << cinfo->comp_bits[j]],
275 which drops the fraction anyway. */
276 int32_t cl = lg->c[i];
277 int32_t cr = rg->c[i];
278 int32_t c0 = (int32_t)(cl + ((int64_t)cr - cl) * (x0 - xl) / (xr - xl));
279 int32_t c1 = (int32_t)(cl + ((int64_t)cr - cl) * (x1 - xl) / (xr - xl));
280
281 xg->c[i] = c0;
282 xg->f[i] = 0; /* Insufficient bits to compute it better.
283 The color so the color gets a slightly smaller value
284 (in <1 'frac31' unit), but it's not important due to
285 the further conversion to [0, 1 << cinfo->comp_bits[j]],
286 which drops the fraction anyway.
287 So setting 0 appears pretty good and fast. */
288 xg->num[i] = c1 - c0;
289 }
290 return 0;
291 }
292
293 private inline int
set_x_gradient(trap_gradient * xg,const trap_gradient * lg,const trap_gradient * rg,const trap_line * l,const trap_line * r,int il,int ir,int num_components)294 set_x_gradient(trap_gradient *xg, const trap_gradient *lg, const trap_gradient *rg,
295 const trap_line *l, const trap_line *r, int il, int ir, int num_components)
296 {
297 if (lg->den == 0 || rg->den == 0) {
298 /* A wedge doesn't use a gradient by X. */
299 int i;
300
301 xg->den = 1;
302 for (i = 0; i < num_components; i++) {
303 xg->c[i] = (lg->den == 0 ? rg->c[i] : lg->c[i]);
304 xg->f[i] = 0; /* Compatible to set_x_gradient_nowedge. */
305 xg->num[i] = 0;
306 }
307 return 0;
308 } else
309 return set_x_gradient_nowedge(xg, lg, rg, l, r, il, ir, num_components);
310 }
311
312 /*
313 * Fill a trapezoid.
314 * Since we need several statically defined variants of this algorithm,
315 * we stored it in gxdtfill.h and include it configuring with
316 * macros defined here.
317 */
318 #define LINEAR_COLOR 0 /* Common for shading variants. */
319 #define EDGE_TYPE gs_fixed_edge /* Common for non-shading variants. */
320 #define FILL_ATTRS gs_logical_operation_t /* Common for non-shading variants. */
321
322 #define GX_FILL_TRAPEZOID private int gx_fill_trapezoid_as_fd
323 #define CONTIGUOUS_FILL 0
324 #define SWAP_AXES 1
325 #define FILL_DIRECT 1
326 #include "gxdtfill.h"
327 #undef GX_FILL_TRAPEZOID
328 #undef CONTIGUOUS_FILL
329 #undef SWAP_AXES
330 #undef FILL_DIRECT
331
332 #define GX_FILL_TRAPEZOID private int gx_fill_trapezoid_as_nd
333 #define CONTIGUOUS_FILL 0
334 #define SWAP_AXES 1
335 #define FILL_DIRECT 0
336 #include "gxdtfill.h"
337 #undef GX_FILL_TRAPEZOID
338 #undef CONTIGUOUS_FILL
339 #undef SWAP_AXES
340 #undef FILL_DIRECT
341
342 #define GX_FILL_TRAPEZOID private int gx_fill_trapezoid_ns_fd
343 #define CONTIGUOUS_FILL 0
344 #define SWAP_AXES 0
345 #define FILL_DIRECT 1
346 #include "gxdtfill.h"
347 #undef GX_FILL_TRAPEZOID
348 #undef CONTIGUOUS_FILL
349 #undef SWAP_AXES
350 #undef FILL_DIRECT
351
352 #define GX_FILL_TRAPEZOID private int gx_fill_trapezoid_ns_nd
353 #define CONTIGUOUS_FILL 0
354 #define SWAP_AXES 0
355 #define FILL_DIRECT 0
356 #include "gxdtfill.h"
357 #undef GX_FILL_TRAPEZOID
358 #undef CONTIGUOUS_FILL
359 #undef SWAP_AXES
360 #undef FILL_DIRECT
361
362 #define GX_FILL_TRAPEZOID int gx_fill_trapezoid_cf_fd
363 #define CONTIGUOUS_FILL 1
364 #define SWAP_AXES 0
365 #define FILL_DIRECT 1
366 #include "gxdtfill.h"
367 #undef GX_FILL_TRAPEZOID
368 #undef CONTIGUOUS_FILL
369 #undef SWAP_AXES
370 #undef FILL_DIRECT
371
372 #define GX_FILL_TRAPEZOID int gx_fill_trapezoid_cf_nd
373 #define CONTIGUOUS_FILL 1
374 #define SWAP_AXES 0
375 #define FILL_DIRECT 0
376 #include "gxdtfill.h"
377 #undef GX_FILL_TRAPEZOID
378 #undef CONTIGUOUS_FILL
379 #undef SWAP_AXES
380 #undef FILL_DIRECT
381
382 #undef EDGE_TYPE
383 #undef LINEAR_COLOR
384 #undef FILL_ATTRS
385
386 #define LINEAR_COLOR 1 /* Common for shading variants. */
387 #define EDGE_TYPE gs_linear_color_edge /* Common for shading variants. */
388 #define FILL_ATTRS const gs_fill_attributes * /* Common for non-shading variants. */
389
390 #define GX_FILL_TRAPEZOID private int gx_fill_trapezoid_ns_lc
391 #define CONTIGUOUS_FILL 0
392 #define SWAP_AXES 0
393 #define FILL_DIRECT 1
394 #include "gxdtfill.h"
395 #undef GX_FILL_TRAPEZOID
396 #undef CONTIGUOUS_FILL
397 #undef SWAP_AXES
398 #undef FILL_DIRECT
399
400 #define GX_FILL_TRAPEZOID private int gx_fill_trapezoid_as_lc
401 #define CONTIGUOUS_FILL 0
402 #define SWAP_AXES 1
403 #define FILL_DIRECT 1
404 #include "gxdtfill.h"
405 #undef GX_FILL_TRAPEZOID
406 #undef CONTIGUOUS_FILL
407 #undef SWAP_AXES
408 #undef FILL_DIRECT
409
410 #undef EDGE_TYPE
411 #undef LINEAR_COLOR
412 #undef FILL_ATTRS
413
414
415 int
gx_default_fill_trapezoid(gx_device * dev,const gs_fixed_edge * left,const gs_fixed_edge * right,fixed ybot,fixed ytop,bool swap_axes,const gx_device_color * pdevc,gs_logical_operation_t lop)416 gx_default_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left,
417 const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes,
418 const gx_device_color * pdevc, gs_logical_operation_t lop)
419 {
420 bool fill_direct = color_writes_pure(pdevc, lop);
421
422 if (swap_axes) {
423 if (fill_direct)
424 return gx_fill_trapezoid_as_fd(dev, left, right, ybot, ytop, 0, pdevc, lop);
425 else
426 return gx_fill_trapezoid_as_nd(dev, left, right, ybot, ytop, 0, pdevc, lop);
427 } else {
428 if (fill_direct)
429 return gx_fill_trapezoid_ns_fd(dev, left, right, ybot, ytop, 0, pdevc, lop);
430 else
431 return gx_fill_trapezoid_ns_nd(dev, left, right, ybot, ytop, 0, pdevc, lop);
432 }
433 }
434
435 private inline void
middle_frac31_color(frac31 * c,const frac31 * c0,const frac31 * c2,int num_components)436 middle_frac31_color(frac31 *c, const frac31 *c0, const frac31 *c2, int num_components)
437 {
438 /* Assuming non-negative values. */
439 int i;
440
441 for (i = 0; i < num_components; i++)
442 c[i] = (int32_t)(((uint32_t)c0[i] + (uint32_t)c2[i]) >> 1);
443 }
444
445 private inline int
fill_linear_color_trapezoid_nocheck(gx_device * dev,const gs_fill_attributes * fa,const gs_linear_color_edge * le,const gs_linear_color_edge * re)446 fill_linear_color_trapezoid_nocheck(gx_device *dev, const gs_fill_attributes *fa,
447 const gs_linear_color_edge *le, const gs_linear_color_edge *re)
448 {
449 fixed y02 = max(le->start.y, re->start.y), ymin = max(y02, fa->clip->p.y);
450 fixed y13 = min(le->end.y, re->end.y), ymax = min(y13, fa->clip->q.y);
451 int code;
452
453 code = (fa->swap_axes ? gx_fill_trapezoid_as_lc : gx_fill_trapezoid_ns_lc)(dev,
454 le, re, ymin, ymax, 0, NULL, fa);
455 if (code < 0)
456 return code;
457 return !code;
458 }
459
460
461 /* Fill a trapezoid with a linear color.
462 [p0 : p1] - left edge, from bottom to top.
463 [p2 : p3] - right edge, from bottom to top.
464 The filled area is within Y-spans of both edges.
465
466 This implemetation actually handles a bilinear color,
467 in which the generatrix keeps a parallelizm to the X axis.
468 In general a bilinear function doesn't keep the generatrix parallelizm,
469 so the caller must decompose/approximate such functions.
470
471 Return values :
472 1 - success;
473 0 - Too big. The area isn't filled. The client must decompose the area.
474 <0 - error.
475 */
476 int
gx_default_fill_linear_color_trapezoid(gx_device * dev,const gs_fill_attributes * fa,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const gs_fixed_point * p3,const frac31 * c0,const frac31 * c1,const frac31 * c2,const frac31 * c3)477 gx_default_fill_linear_color_trapezoid(gx_device *dev, const gs_fill_attributes *fa,
478 const gs_fixed_point *p0, const gs_fixed_point *p1,
479 const gs_fixed_point *p2, const gs_fixed_point *p3,
480 const frac31 *c0, const frac31 *c1,
481 const frac31 *c2, const frac31 *c3)
482 {
483 gs_linear_color_edge le, re;
484 int num_components = dev->color_info.num_components;
485
486 le.start = *p0;
487 le.end = *p1;
488 le.c0 = c0;
489 le.c1 = c1;
490 le.clip_x = fa->clip->p.x;
491 re.start = *p2;
492 re.end = *p3;
493 re.c0 = c2;
494 re.c1 = c3;
495 re.clip_x = fa->clip->q.x;
496 if (check_gradient_overflow(&le, &re, num_components))
497 return 0;
498 return fill_linear_color_trapezoid_nocheck(dev, fa, &le, &re);
499 }
500
501 private inline int
fill_linear_color_triangle(gx_device * dev,const gs_fill_attributes * fa,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const frac31 * c0,const frac31 * c1,const frac31 * c2)502 fill_linear_color_triangle(gx_device *dev, const gs_fill_attributes *fa,
503 const gs_fixed_point *p0, const gs_fixed_point *p1,
504 const gs_fixed_point *p2,
505 const frac31 *c0, const frac31 *c1, const frac31 *c2)
506 { /* p0 must be the lowest vertex. */
507 int code;
508 gs_linear_color_edge e0, e1, e2;
509 int num_components = dev->color_info.num_components;
510
511 if (p0->y == p1->y)
512 return gx_default_fill_linear_color_trapezoid(dev, fa, p0, p2, p1, p2, c0, c2, c1, c2);
513 if (p1->y == p2->y)
514 return gx_default_fill_linear_color_trapezoid(dev, fa, p0, p2, p0, p1, c0, c2, c0, c1);
515 e0.start = *p0;
516 e0.end = *p2;
517 e0.c0 = c0;
518 e0.c1 = c2;
519 e0.clip_x = fa->clip->p.x;
520 e1.start = *p0;
521 e1.end = *p1;
522 e1.c0 = c0;
523 e1.c1 = c1;
524 e1.clip_x = fa->clip->q.x;
525 if (p0->y < p1->y && p1->y < p2->y) {
526 e2.start = *p1;
527 e2.end = *p2;
528 e2.c0 = c1;
529 e2.c1 = c2;
530 e2.clip_x = fa->clip->q.x;
531 if (check_gradient_overflow(&e0, &e1, num_components))
532 return 0;
533 if (check_gradient_overflow(&e0, &e2, num_components))
534 return 0;
535 code = fill_linear_color_trapezoid_nocheck(dev, fa, &e0, &e1);
536 if (code <= 0) /* Sic! */
537 return code;
538 return fill_linear_color_trapezoid_nocheck(dev, fa, &e0, &e2);
539 } else { /* p0->y < p2->y && p2->y < p1->y */
540 e2.start = *p2;
541 e2.end = *p1;
542 e2.c0 = c2;
543 e2.c1 = c1;
544 e2.clip_x = fa->clip->q.x;
545 if (check_gradient_overflow(&e0, &e1, num_components))
546 return 0;
547 if (check_gradient_overflow(&e2, &e1, num_components))
548 return 0;
549 code = fill_linear_color_trapezoid_nocheck(dev, fa, &e0, &e1);
550 if (code <= 0) /* Sic! */
551 return code;
552 return fill_linear_color_trapezoid_nocheck(dev, fa, &e2, &e1);
553 }
554 }
555
556 /* Fill a triangle with a linear color. */
557 int
gx_default_fill_linear_color_triangle(gx_device * dev,const gs_fill_attributes * fa,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const frac31 * c0,const frac31 * c1,const frac31 * c2)558 gx_default_fill_linear_color_triangle(gx_device *dev, const gs_fill_attributes *fa,
559 const gs_fixed_point *p0, const gs_fixed_point *p1,
560 const gs_fixed_point *p2,
561 const frac31 *c0, const frac31 *c1, const frac31 *c2)
562 {
563 fixed dx1 = p1->x - p0->x, dy1 = p1->y - p0->y;
564 fixed dx2 = p2->x - p0->x, dy2 = p2->y - p0->y;
565
566 if ((int64_t)dx1 * dy2 < (int64_t)dx2 * dy1) {
567 const gs_fixed_point *p = p1;
568 const frac31 *c = c1;
569
570 p1 = p2;
571 p2 = p;
572 c1 = c2;
573 c2 = c;
574 }
575 if (p0->y <= p1->y && p0->y <= p2->y)
576 return fill_linear_color_triangle(dev, fa, p0, p1, p2, c0, c1, c2);
577 if (p1->y <= p0->y && p1->y <= p2->y)
578 return fill_linear_color_triangle(dev, fa, p1, p2, p0, c1, c2, c0);
579 else
580 return fill_linear_color_triangle(dev, fa, p2, p0, p1, c2, c0, c1);
581 }
582
583 /* Fill a parallelogram whose points are p, p+a, p+b, and p+a+b. */
584 /* We should swap axes to get best accuracy, but we don't. */
585 /* We must be very careful to follow the center-of-pixel rule in all cases. */
586 int
gx_default_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_device_color * pdevc,gs_logical_operation_t lop)587 gx_default_fill_parallelogram(gx_device * dev,
588 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
589 const gx_device_color * pdevc, gs_logical_operation_t lop)
590 {
591 fixed t;
592 fixed qx, qy, ym;
593 dev_proc_fill_trapezoid((*fill_trapezoid));
594 gs_fixed_edge left, right;
595 int code;
596
597 /* Make a special fast check for rectangles. */
598 if (PARALLELOGRAM_IS_RECT(ax, ay, bx, by)) {
599 gs_int_rect r;
600
601 INT_RECT_FROM_PARALLELOGRAM(&r, px, py, ax, ay, bx, by);
602 return gx_fill_rectangle_device_rop(r.p.x, r.p.y, r.q.x - r.p.x,
603 r.q.y - r.p.y, pdevc, dev, lop);
604 }
605 /*
606 * Not a rectangle. Ensure that the 'a' line is to the left of
607 * the 'b' line. Testing ax <= bx is neither sufficient nor
608 * necessary: in general, we need to compare the slopes.
609 */
610 /* Ensure ay >= 0, by >= 0. */
611 if (ay < 0)
612 px += ax, py += ay, ax = -ax, ay = -ay;
613 if (by < 0)
614 px += bx, py += by, bx = -bx, by = -by;
615 qx = px + ax + bx;
616 if ((ax ^ bx) < 0) { /* In this case, the test ax <= bx is sufficient. */
617 if (ax > bx)
618 SWAP(ax, bx, t), SWAP(ay, by, t);
619 } else { /*
620 * Compare the slopes. We know that ay >= 0, by >= 0,
621 * and ax and bx have the same sign; the lines are in the
622 * correct order iff
623 * ay/ax >= by/bx, or
624 * ay*bx >= by*ax
625 * Eventually we can probably find a better way to test this,
626 * without using floating point.
627 */
628 if ((double)ay * bx < (double)by * ax)
629 SWAP(ax, bx, t), SWAP(ay, by, t);
630 }
631 fill_trapezoid = dev_proc(dev, fill_trapezoid);
632 qy = py + ay + by;
633 left.start.x = right.start.x = px;
634 left.start.y = right.start.y = py;
635 left.end.x = px + ax;
636 left.end.y = py + ay;
637 right.end.x = px + bx;
638 right.end.y = py + by;
639 #define ROUNDED_SAME(p1, p2)\
640 (fixed_pixround(p1) == fixed_pixround(p2))
641 if (ay < by) {
642 if (!ROUNDED_SAME(py, left.end.y)) {
643 code = (*fill_trapezoid) (dev, &left, &right, py, left.end.y,
644 false, pdevc, lop);
645 if (code < 0)
646 return code;
647 }
648 left.start = left.end;
649 left.end.x = qx, left.end.y = qy;
650 ym = right.end.y;
651 if (!ROUNDED_SAME(left.start.y, ym)) {
652 code = (*fill_trapezoid) (dev, &left, &right, left.start.y, ym,
653 false, pdevc, lop);
654 if (code < 0)
655 return code;
656 }
657 right.start = right.end;
658 right.end.x = qx, right.end.y = qy;
659 } else {
660 if (!ROUNDED_SAME(py, right.end.y)) {
661 code = (*fill_trapezoid) (dev, &left, &right, py, right.end.y,
662 false, pdevc, lop);
663 if (code < 0)
664 return code;
665 }
666 right.start = right.end;
667 right.end.x = qx, right.end.y = qy;
668 ym = left.end.y;
669 if (!ROUNDED_SAME(right.start.y, ym)) {
670 code = (*fill_trapezoid) (dev, &left, &right, right.start.y, ym,
671 false, pdevc, lop);
672 if (code < 0)
673 return code;
674 }
675 left.start = left.end;
676 left.end.x = qx, left.end.y = qy;
677 }
678 if (!ROUNDED_SAME(ym, qy))
679 return (*fill_trapezoid) (dev, &left, &right, ym, qy,
680 false, pdevc, lop);
681 else
682 return 0;
683 #undef ROUNDED_SAME
684 }
685
686 /* Fill a triangle whose points are p, p+a, and p+b. */
687 /* We should swap axes to get best accuracy, but we don't. */
688 int
gx_default_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_device_color * pdevc,gs_logical_operation_t lop)689 gx_default_fill_triangle(gx_device * dev,
690 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
691 const gx_device_color * pdevc, gs_logical_operation_t lop)
692 {
693 fixed t;
694 fixed ym;
695
696 dev_proc_fill_trapezoid((*fill_trapezoid)) =
697 dev_proc(dev, fill_trapezoid);
698 gs_fixed_edge left, right;
699 int code;
700
701 /* Ensure ay >= 0, by >= 0. */
702 if (ay < 0)
703 px += ax, py += ay, bx -= ax, by -= ay, ax = -ax, ay = -ay;
704 if (by < 0)
705 px += bx, py += by, ax -= bx, ay -= by, bx = -bx, by = -by;
706 /* Ensure ay <= by. */
707 if (ay > by)
708 SWAP(ax, bx, t), SWAP(ay, by, t);
709 /*
710 * Make a special check for a flat bottom or top,
711 * which we can handle with a single call on fill_trapezoid.
712 */
713 left.start.x = right.start.x = px;
714 left.start.y = right.start.y = py;
715 if (ay == 0) {
716 /* Flat top */
717 if (ax < 0)
718 left.start.x = px + ax;
719 else
720 right.start.x = px + ax;
721 left.end.x = right.end.x = px + bx;
722 left.end.y = right.end.y = py + by;
723 ym = py;
724 } else if (ay == by) {
725 /* Flat bottom */
726 if (ax < bx)
727 left.end.x = px + ax, right.end.x = px + bx;
728 else
729 left.end.x = px + bx, right.end.x = px + ax;
730 left.end.y = right.end.y = py + by;
731 ym = py;
732 } else {
733 ym = py + ay;
734 if (fixed_mult_quo(bx, ay, by) < ax) {
735 /* The 'b' line is to the left of the 'a' line. */
736 left.end.x = px + bx, left.end.y = py + by;
737 right.end.x = px + ax, right.end.y = py + ay;
738 code = (*fill_trapezoid) (dev, &left, &right, py, ym,
739 false, pdevc, lop);
740 right.start = right.end;
741 right.end = left.end;
742 } else {
743 /* The 'a' line is to the left of the 'b' line. */
744 left.end.x = px + ax, left.end.y = py + ay;
745 right.end.x = px + bx, right.end.y = py + by;
746 code = (*fill_trapezoid) (dev, &left, &right, py, ym,
747 false, pdevc, lop);
748 left.start = left.end;
749 left.end = right.end;
750 }
751 if (code < 0)
752 return code;
753 }
754 return (*fill_trapezoid) (dev, &left, &right, ym, right.end.y,
755 false, pdevc, lop);
756 }
757
758 /* Draw a one-pixel-wide line. */
759 int
gx_default_draw_thin_line(gx_device * dev,fixed fx0,fixed fy0,fixed fx1,fixed fy1,const gx_device_color * pdevc,gs_logical_operation_t lop)760 gx_default_draw_thin_line(gx_device * dev,
761 fixed fx0, fixed fy0, fixed fx1, fixed fy1,
762 const gx_device_color * pdevc, gs_logical_operation_t lop)
763 {
764 int ix = fixed2int_var(fx0);
765 int iy = fixed2int_var(fy0);
766 int itox = fixed2int_var(fx1);
767 int itoy = fixed2int_var(fy1);
768
769 return_if_interrupt(dev->memory);
770 if (itoy == iy) { /* horizontal line */
771 return (ix <= itox ?
772 gx_fill_rectangle_device_rop(ix, iy, itox - ix + 1, 1,
773 pdevc, dev, lop) :
774 gx_fill_rectangle_device_rop(itox, iy, ix - itox + 1, 1,
775 pdevc, dev, lop)
776 );
777 }
778 if (itox == ix) { /* vertical line */
779 return (iy <= itoy ?
780 gx_fill_rectangle_device_rop(ix, iy, 1, itoy - iy + 1,
781 pdevc, dev, lop) :
782 gx_fill_rectangle_device_rop(ix, itoy, 1, iy - itoy + 1,
783 pdevc, dev, lop)
784 );
785 } {
786 fixed h = fy1 - fy0;
787 fixed w = fx1 - fx0;
788 fixed tf;
789 bool swap_axes;
790 gs_fixed_edge left, right;
791
792 if ((w < 0 ? -w : w) <= (h < 0 ? -h : h)) {
793 if (h < 0)
794 SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf),
795 h = -h;
796 right.start.x = (left.start.x = fx0 - fixed_half) + fixed_1;
797 right.end.x = (left.end.x = fx1 - fixed_half) + fixed_1;
798 left.start.y = right.start.y = fy0;
799 left.end.y = right.end.y = fy1;
800 swap_axes = false;
801 } else {
802 if (w < 0)
803 SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf),
804 w = -w;
805 right.start.x = (left.start.x = fy0 - fixed_half) + fixed_1;
806 right.end.x = (left.end.x = fy1 - fixed_half) + fixed_1;
807 left.start.y = right.start.y = fx0;
808 left.end.y = right.end.y = fx1;
809 swap_axes = true;
810 }
811 return (*dev_proc(dev, fill_trapezoid)) (dev, &left, &right,
812 left.start.y, left.end.y,
813 swap_axes, pdevc, lop);
814 }
815 }
816
817 /* Stub out the obsolete procedure. */
818 int
gx_default_draw_line(gx_device * dev,int x0,int y0,int x1,int y1,gx_color_index color)819 gx_default_draw_line(gx_device * dev,
820 int x0, int y0, int x1, int y1, gx_color_index color)
821 {
822 return -1;
823 }
824
825 /* ---------------- Image drawing ---------------- */
826
827 /* GC structures for image enumerator */
828 public_st_gx_image_enum_common();
829
830 private
831 ENUM_PTRS_WITH(image_enum_common_enum_ptrs, gx_image_enum_common_t *eptr)
832 return 0;
833 case 0: return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
834 ENUM_PTRS_END
835
RELOC_PTRS_WITH(image_enum_common_reloc_ptrs,gx_image_enum_common_t * eptr)836 private RELOC_PTRS_WITH(image_enum_common_reloc_ptrs, gx_image_enum_common_t *eptr)
837 {
838 eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst);
839 }
840 RELOC_PTRS_END
841
842 /*
843 * gx_default_begin_image is only invoked for ImageType 1 images. However,
844 * the argument types are different, and if the device provides a
845 * begin_typed_image procedure, we should use it. See gxdevice.h.
846 */
847 private int
gx_no_begin_image(gx_device * dev,const gs_imager_state * pis,const gs_image_t * pim,gs_image_format_t format,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)848 gx_no_begin_image(gx_device * dev,
849 const gs_imager_state * pis, const gs_image_t * pim,
850 gs_image_format_t format, const gs_int_rect * prect,
851 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
852 gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
853 {
854 return -1;
855 }
856 int
gx_default_begin_image(gx_device * dev,const gs_imager_state * pis,const gs_image_t * pim,gs_image_format_t format,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)857 gx_default_begin_image(gx_device * dev,
858 const gs_imager_state * pis, const gs_image_t * pim,
859 gs_image_format_t format, const gs_int_rect * prect,
860 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
861 gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
862 {
863 /*
864 * Hand off to begin_typed_image, being careful to avoid a
865 * possible recursion loop.
866 */
867 dev_proc_begin_image((*save_begin_image)) = dev_proc(dev, begin_image);
868 gs_image_t image;
869 const gs_image_t *ptim;
870 int code;
871
872 set_dev_proc(dev, begin_image, gx_no_begin_image);
873 if (pim->format == format)
874 ptim = pim;
875 else {
876 image = *pim;
877 image.format = format;
878 ptim = ℑ
879 }
880 code = (*dev_proc(dev, begin_typed_image))
881 (dev, pis, NULL, (const gs_image_common_t *)ptim, prect, pdcolor,
882 pcpath, memory, pinfo);
883 set_dev_proc(dev, begin_image, save_begin_image);
884 return code;
885 }
886
887 int
gx_default_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)888 gx_default_begin_typed_image(gx_device * dev,
889 const gs_imager_state * pis, const gs_matrix * pmat,
890 const gs_image_common_t * pic, const gs_int_rect * prect,
891 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
892 gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
893 { /*
894 * If this is an ImageType 1 image using the imager's CTM,
895 * defer to begin_image.
896 */
897 if (pic->type->begin_typed_image == gx_begin_image1) {
898 const gs_image_t *pim = (const gs_image_t *)pic;
899
900 if (pmat == 0 ||
901 (pis != 0 && !memcmp(pmat, &ctm_only(pis), sizeof(*pmat)))
902 ) {
903 int code = (*dev_proc(dev, begin_image))
904 (dev, pis, pim, pim->format, prect, pdcolor,
905 pcpath, memory, pinfo);
906
907 if (code >= 0)
908 return code;
909 }
910 }
911 return (*pic->type->begin_typed_image)
912 (dev, pis, pmat, pic, prect, pdcolor, pcpath, memory, pinfo);
913 }
914
915 /* Backward compatibility for obsolete driver procedures. */
916
917 int
gx_default_image_data(gx_device * dev,gx_image_enum_common_t * info,const byte ** plane_data,int data_x,uint raster,int height)918 gx_default_image_data(gx_device *dev, gx_image_enum_common_t * info,
919 const byte ** plane_data,
920 int data_x, uint raster, int height)
921 {
922 return gx_image_data(info, plane_data, data_x, raster, height);
923 }
924
925 int
gx_default_end_image(gx_device * dev,gx_image_enum_common_t * info,bool draw_last)926 gx_default_end_image(gx_device *dev, gx_image_enum_common_t * info,
927 bool draw_last)
928 {
929 return gx_image_end(info, draw_last);
930 }
931