1 /* Copyright (C) 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: gxshade6.c,v 1.100 2005/05/25 15:57:58 igor Exp $ */
18 /* Rendering for Coons and tensor patch shadings */
19 /*
20 A contiguous non-overlapping decomposition
21 of a tensor shading into linear color triangles.
22 */
23 #include "memory_.h"
24 #include "gx.h"
25 #include "gserrors.h"
26 #include "gsmatrix.h" /* for gscoord.h */
27 #include "gscoord.h"
28 #include "gxcspace.h"
29 #include "gxdcolor.h"
30 #include "gxistate.h"
31 #include "gxshade.h"
32 #include "gxshade4.h"
33 #include "gxdevcli.h"
34 #include "gxarith.h"
35 #include "gzpath.h"
36 #include "stdint_.h"
37 #include "math_.h"
38 #include "vdtrace.h"
39 #include <assert.h>
40
41 #define VD_TRACE_TENSOR_PATCH 1
42
43 #if NOFILL_TEST
44 static bool dbg_nofill = false;
45 #endif
46 #if SKIP_TEST
47 static int dbg_patch_cnt = 0;
48 static int dbg_quad_cnt = 0;
49 static int dbg_triangle_cnt = 0;
50 static int dbg_wedge_triangle_cnt = 0;
51 #endif
52
53 static int min_linear_grades = 255; /* The minimal number of device color grades,
54 required to apply linear color device functions. */
55
56 /* ================ Utilities ================ */
57
58 /* Get colors for patch vertices. */
59 private int
shade_next_colors(shade_coord_stream_t * cs,patch_curve_t * curves,int num_vertices)60 shade_next_colors(shade_coord_stream_t * cs, patch_curve_t * curves,
61 int num_vertices)
62 {
63 int i, code = 0;
64
65 for (i = 0; i < num_vertices && code >= 0; ++i) {
66 curves[i].vertex.cc[1] = 0; /* safety. (patch_fill may assume 2 arguments) */
67 code = shade_next_color(cs, curves[i].vertex.cc);
68 }
69 return code;
70 }
71
72 /* Get a Bezier or tensor patch element. */
73 private int
shade_next_curve(shade_coord_stream_t * cs,patch_curve_t * curve)74 shade_next_curve(shade_coord_stream_t * cs, patch_curve_t * curve)
75 {
76 int code = shade_next_coords(cs, &curve->vertex.p, 1);
77
78 if (code >= 0)
79 code = shade_next_coords(cs, curve->control,
80 countof(curve->control));
81 return code;
82 }
83
84 /*
85 * Parse the next patch out of the input stream. Return 1 if done,
86 * 0 if patch, <0 on error.
87 */
88 private int
shade_next_patch(shade_coord_stream_t * cs,int BitsPerFlag,patch_curve_t curve[4],gs_fixed_point interior[4])89 shade_next_patch(shade_coord_stream_t * cs, int BitsPerFlag,
90 patch_curve_t curve[4], gs_fixed_point interior[4] /* 0 for Coons patch */ )
91 {
92 int flag = shade_next_flag(cs, BitsPerFlag);
93 int num_colors, code;
94
95 if (flag < 0) {
96 if (!cs->is_eod(cs))
97 return_error(gs_error_rangecheck);
98 return 1; /* no more data */
99 }
100 switch (flag & 3) {
101 default:
102 return_error(gs_error_rangecheck); /* not possible */
103 case 0:
104 if ((code = shade_next_curve(cs, &curve[0])) < 0 ||
105 (code = shade_next_coords(cs, &curve[1].vertex.p, 1)) < 0
106 )
107 return code;
108 num_colors = 4;
109 goto vx;
110 case 1:
111 curve[0] = curve[1], curve[1].vertex = curve[2].vertex;
112 goto v3;
113 case 2:
114 curve[0] = curve[2], curve[1].vertex = curve[3].vertex;
115 goto v3;
116 case 3:
117 curve[1].vertex = curve[0].vertex, curve[0] = curve[3];
118 v3: num_colors = 2;
119 vx: if ((code = shade_next_coords(cs, curve[1].control, 2)) < 0 ||
120 (code = shade_next_curve(cs, &curve[2])) < 0 ||
121 (code = shade_next_curve(cs, &curve[3])) < 0 ||
122 (interior != 0 &&
123 (code = shade_next_coords(cs, interior, 4)) < 0) ||
124 (code = shade_next_colors(cs, &curve[4 - num_colors],
125 num_colors)) < 0
126 )
127 return code;
128 }
129 return 0;
130 }
131
132 int
init_patch_fill_state(patch_fill_state_t * pfs)133 init_patch_fill_state(patch_fill_state_t *pfs)
134 {
135 /* Warning : pfs->Function must be set in advance. */
136 const gs_color_space *pcs = pfs->direct_space;
137 gs_client_color fcc0, fcc1;
138 int i, code;
139
140 for (i = 0; i < pfs->num_components; i++) {
141 fcc0.paint.values[i] = -1000000;
142 fcc1.paint.values[i] = 1000000;
143 }
144 pcs->type->restrict_color(&fcc0, pcs);
145 pcs->type->restrict_color(&fcc1, pcs);
146 for (i = 0; i < pfs->num_components; i++)
147 pfs->color_domain.paint.values[i] = max(fcc1.paint.values[i] - fcc0.paint.values[i], 1);
148 pfs->vectorization = false; /* A stub for a while. Will use with pclwrite. */
149 pfs->maybe_self_intersecting = true;
150 pfs->monotonic_color = (pfs->Function == NULL);
151 pfs->linear_color = false;
152 pfs->inside = false;
153 pfs->n_color_args = 1;
154 pfs->fixed_flat = float2fixed(pfs->pis->flatness);
155 pfs->smoothness = pfs->pis->smoothness;
156 # if LAZY_WEDGES
157 code = wedge_vertex_list_elem_buffer_alloc(pfs);
158 if (code < 0)
159 return code;
160 # endif
161 pfs->max_small_coord = 1 << ((sizeof(int64_t) * 8 - 1/*sign*/) / 3);
162 return 0;
163 }
164
165 void
term_patch_fill_state(patch_fill_state_t * pfs)166 term_patch_fill_state(patch_fill_state_t *pfs)
167 {
168 # if LAZY_WEDGES
169 wedge_vertex_list_elem_buffer_free(pfs);
170 # endif
171 }
172
173 /* Resolve a patch color using the Function if necessary. */
174 inline private void
patch_resolve_color_inline(patch_color_t * ppcr,const patch_fill_state_t * pfs)175 patch_resolve_color_inline(patch_color_t * ppcr, const patch_fill_state_t *pfs)
176 {
177 if (pfs->Function) {
178 const gs_color_space *pcs = pfs->direct_space;
179
180 gs_function_evaluate(pfs->Function, ppcr->t, ppcr->cc.paint.values);
181 pcs->type->restrict_color(&ppcr->cc, pcs);
182 }
183 }
184
185 void
patch_resolve_color(patch_color_t * ppcr,const patch_fill_state_t * pfs)186 patch_resolve_color(patch_color_t * ppcr, const patch_fill_state_t *pfs)
187 {
188 patch_resolve_color_inline(ppcr, pfs);
189 }
190
191
192 /*
193 * Calculate the interpolated color at a given point.
194 * Note that we must do this twice for bilinear interpolation.
195 * We use the name ppcr rather than ppc because an Apple compiler defines
196 * ppc when compiling on PowerPC systems (!).
197 */
198 private void
patch_interpolate_color(patch_color_t * ppcr,const patch_color_t * ppc0,const patch_color_t * ppc1,const patch_fill_state_t * pfs,floatp t)199 patch_interpolate_color(patch_color_t * ppcr, const patch_color_t * ppc0,
200 const patch_color_t * ppc1, const patch_fill_state_t *pfs, floatp t)
201 {
202 /* The old code gives -IND on Intel. */
203 if (pfs->Function) {
204 ppcr->t[0] = ppc0->t[0] * (1 - t) + t * ppc1->t[0];
205 ppcr->t[1] = ppc0->t[1] * (1 - t) + t * ppc1->t[1];
206 patch_resolve_color_inline(ppcr, pfs);
207 } else {
208 int ci;
209
210 for (ci = pfs->num_components - 1; ci >= 0; --ci)
211 ppcr->cc.paint.values[ci] =
212 ppc0->cc.paint.values[ci] * (1 - t) + t * ppc1->cc.paint.values[ci];
213 }
214 }
215
216 /* ================ Specific shadings ================ */
217
218 /*
219 * The curves are stored in a clockwise or counter-clockwise order that maps
220 * to the patch definition in a non-intuitive way. The documentation
221 * (pp. 277-281 of the PostScript Language Reference Manual, Third Edition)
222 * says that the curves are in the order D1, C2, D2, C1.
223 */
224 /* The starting points of the curves: */
225 #define D1START 0
226 #define C2START 1
227 #define D2START 3
228 #define C1START 0
229 /* The control points of the curves (x means reversed order): */
230 #define D1CTRL 0
231 #define C2CTRL 1
232 #define D2XCTRL 2
233 #define C1XCTRL 3
234 /* The end points of the curves: */
235 #define D1END 1
236 #define C2END 2
237 #define D2END 2
238 #define C1END 3
239
240 /* ---------------- Common code ---------------- */
241
242 /* Evaluate a curve at a given point. */
243 private void
curve_eval(gs_fixed_point * pt,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const gs_fixed_point * p3,floatp t)244 curve_eval(gs_fixed_point * pt, const gs_fixed_point * p0,
245 const gs_fixed_point * p1, const gs_fixed_point * p2,
246 const gs_fixed_point * p3, floatp t)
247 {
248 fixed a, b, c, d;
249 fixed t01, t12;
250
251 d = p0->x;
252 curve_points_to_coefficients(d, p1->x, p2->x, p3->x,
253 a, b, c, t01, t12);
254 pt->x = (fixed) (((a * t + b) * t + c) * t + d);
255 d = p0->y;
256 curve_points_to_coefficients(d, p1->y, p2->y, p3->y,
257 a, b, c, t01, t12);
258 pt->y = (fixed) (((a * t + b) * t + c) * t + d);
259 if_debug3('2', "[2]t=%g => (%g,%g)\n", t, fixed2float(pt->x),
260 fixed2float(pt->y));
261 }
262
263 /* ---------------- Coons patch shading ---------------- */
264
265 /* Calculate the device-space coordinate corresponding to (u,v). */
266 private void
Cp_transform(gs_fixed_point * pt,const patch_curve_t curve[4],const gs_fixed_point ignore_interior[4],floatp u,floatp v)267 Cp_transform(gs_fixed_point * pt, const patch_curve_t curve[4],
268 const gs_fixed_point ignore_interior[4], floatp u, floatp v)
269 {
270 double co_u = 1.0 - u, co_v = 1.0 - v;
271 gs_fixed_point c1u, d1v, c2u, d2v;
272
273 curve_eval(&c1u, &curve[C1START].vertex.p,
274 &curve[C1XCTRL].control[1], &curve[C1XCTRL].control[0],
275 &curve[C1END].vertex.p, u);
276 curve_eval(&d1v, &curve[D1START].vertex.p,
277 &curve[D1CTRL].control[0], &curve[D1CTRL].control[1],
278 &curve[D1END].vertex.p, v);
279 curve_eval(&c2u, &curve[C2START].vertex.p,
280 &curve[C2CTRL].control[0], &curve[C2CTRL].control[1],
281 &curve[C2END].vertex.p, u);
282 curve_eval(&d2v, &curve[D2START].vertex.p,
283 &curve[D2XCTRL].control[1], &curve[D2XCTRL].control[0],
284 &curve[D2END].vertex.p, v);
285 #define COMPUTE_COORD(xy)\
286 pt->xy = (fixed)\
287 ((co_v * c1u.xy + v * c2u.xy) + (co_u * d1v.xy + u * d2v.xy) -\
288 (co_v * (co_u * curve[C1START].vertex.p.xy +\
289 u * curve[C1END].vertex.p.xy) +\
290 v * (co_u * curve[C2START].vertex.p.xy +\
291 u * curve[C2END].vertex.p.xy)))
292 COMPUTE_COORD(x);
293 COMPUTE_COORD(y);
294 #undef COMPUTE_COORD
295 if_debug4('2', "[2](u=%g,v=%g) => (%g,%g)\n",
296 u, v, fixed2float(pt->x), fixed2float(pt->y));
297 }
298
299 int
gs_shading_Cp_fill_rectangle(const gs_shading_t * psh0,const gs_rect * rect,const gs_fixed_rect * rect_clip,gx_device * dev,gs_imager_state * pis)300 gs_shading_Cp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
301 const gs_fixed_rect * rect_clip,
302 gx_device * dev, gs_imager_state * pis)
303 {
304 const gs_shading_Cp_t * const psh = (const gs_shading_Cp_t *)psh0;
305 patch_fill_state_t state;
306 shade_coord_stream_t cs;
307 patch_curve_t curve[4];
308 int code;
309
310 code = mesh_init_fill_state((mesh_fill_state_t *) &state,
311 (const gs_shading_mesh_t *)psh0, rect_clip, dev, pis);
312 if (code < 0)
313 return code;
314 state.Function = psh->params.Function;
315 code = init_patch_fill_state(&state);
316 if(code < 0)
317 return code;
318 if (VD_TRACE_TENSOR_PATCH && vd_allowed('s')) {
319 vd_get_dc('s');
320 vd_set_shift(0, 0);
321 vd_set_scale(0.01);
322 vd_set_origin(0, 0);
323 /* vd_erase(RGB(192, 192, 192)); */
324 }
325
326 curve[0].straight = curve[1].straight = curve[2].straight = curve[3].straight = false;
327 shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, pis);
328 while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
329 curve, NULL)) == 0 &&
330 (code = patch_fill(&state, curve, NULL, Cp_transform)) >= 0
331 ) {
332 DO_NOTHING;
333 }
334 if (VD_TRACE_TENSOR_PATCH && vd_allowed('s'))
335 vd_release_dc;
336 term_patch_fill_state(&state);
337 return min(code, 0);
338 }
339
340 /* ---------------- Tensor product patch shading ---------------- */
341
342 /* Calculate the device-space coordinate corresponding to (u,v). */
343 private void
Tpp_transform(gs_fixed_point * pt,const patch_curve_t curve[4],const gs_fixed_point interior[4],floatp u,floatp v)344 Tpp_transform(gs_fixed_point * pt, const patch_curve_t curve[4],
345 const gs_fixed_point interior[4], floatp u, floatp v)
346 {
347 double Bu[4], Bv[4];
348 gs_fixed_point pts[4][4];
349 int i, j;
350 double x = 0, y = 0;
351
352 /* Compute the Bernstein polynomials of u and v. */
353 {
354 double u2 = u * u, co_u = 1.0 - u, co_u2 = co_u * co_u;
355 double v2 = v * v, co_v = 1.0 - v, co_v2 = co_v * co_v;
356
357 Bu[0] = co_u * co_u2, Bu[1] = 3 * u * co_u2,
358 Bu[2] = 3 * u2 * co_u, Bu[3] = u * u2;
359 Bv[0] = co_v * co_v2, Bv[1] = 3 * v * co_v2,
360 Bv[2] = 3 * v2 * co_v, Bv[3] = v * v2;
361 }
362
363 /* Arrange the points into an indexable order. */
364 pts[0][0] = curve[0].vertex.p;
365 pts[0][1] = curve[0].control[0];
366 pts[0][2] = curve[0].control[1];
367 pts[0][3] = curve[1].vertex.p;
368 pts[1][3] = curve[1].control[0];
369 pts[2][3] = curve[1].control[1];
370 pts[3][3] = curve[2].vertex.p;
371 pts[3][2] = curve[2].control[0];
372 pts[3][1] = curve[2].control[1];
373 pts[3][0] = curve[3].vertex.p;
374 pts[2][0] = curve[3].control[0];
375 pts[1][0] = curve[3].control[1];
376 pts[1][1] = interior[0];
377 pts[2][1] = interior[1];
378 pts[2][2] = interior[2];
379 pts[1][2] = interior[3];
380
381 /* Now compute the actual point. */
382 for (i = 0; i < 4; ++i)
383 for (j = 0; j < 4; ++j) {
384 double coeff = Bu[i] * Bv[j];
385
386 x += pts[i][j].x * coeff, y += pts[i][j].y * coeff;
387 }
388 pt->x = (fixed)x, pt->y = (fixed)y;
389 }
390
391 int
gs_shading_Tpp_fill_rectangle(const gs_shading_t * psh0,const gs_rect * rect,const gs_fixed_rect * rect_clip,gx_device * dev,gs_imager_state * pis)392 gs_shading_Tpp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
393 const gs_fixed_rect * rect_clip,
394 gx_device * dev, gs_imager_state * pis)
395 {
396 const gs_shading_Tpp_t * const psh = (const gs_shading_Tpp_t *)psh0;
397 patch_fill_state_t state;
398 shade_coord_stream_t cs;
399 patch_curve_t curve[4];
400 gs_fixed_point interior[4];
401 int code;
402
403 code = mesh_init_fill_state((mesh_fill_state_t *) & state,
404 (const gs_shading_mesh_t *)psh0, rect_clip, dev, pis);
405 if (code < 0)
406 return code;
407 state.Function = psh->params.Function;
408 code = init_patch_fill_state(&state);
409 if(code < 0)
410 return code;
411 if (VD_TRACE_TENSOR_PATCH && vd_allowed('s')) {
412 vd_get_dc('s');
413 vd_set_shift(0, 0);
414 vd_set_scale(0.01);
415 vd_set_origin(0, 0);
416 /* vd_erase(RGB(192, 192, 192)); */
417 }
418 curve[0].straight = curve[1].straight = curve[2].straight = curve[3].straight = false;
419 shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, pis);
420 while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
421 curve, interior)) == 0) {
422 /*
423 * The order of points appears to be consistent with that for Coons
424 * patches, which is different from that documented in Red Book 3.
425 */
426 gs_fixed_point swapped_interior[4];
427
428 swapped_interior[0] = interior[0];
429 swapped_interior[1] = interior[3];
430 swapped_interior[2] = interior[2];
431 swapped_interior[3] = interior[1];
432 code = patch_fill(&state, curve, swapped_interior, Tpp_transform);
433 if (code < 0)
434 break;
435 }
436 term_patch_fill_state(&state);
437 if (VD_TRACE_TENSOR_PATCH && vd_allowed('s'))
438 vd_release_dc;
439 return min(code, 0);
440 }
441
442 /*
443 This algorithm performs a decomposition of the shading area
444 into a set of constant color trapezoids, some of which
445 may use the transpozed coordinate system.
446
447 The target device assumes semi-open intrvals by X to be painted
448 (See PLRM3, 7.5. Scan conversion details), i.e.
449 it doesn't paint pixels which falls exactly to the right side.
450 Note that with raster devices the algorithm doesn't paint pixels,
451 whigh are partially covered by the shading area,
452 but which's centers are outside the area.
453
454 Pixels inside a monotonic part of the shading area are painted
455 at once, but some exceptions may happen :
456
457 - While flattening boundaries of a subpatch,
458 to keep the plane coverage contiguity we insert wedges
459 between neighbor subpatches, which use a different
460 flattening factor. With non-monotonic curves
461 those wedges may overlap or be self-overlapping, and a pixel
462 is painted so many times as many wedges cover it. Fortunately
463 the area of most wedges is zero or extremily small.
464
465 - Since quazi-horizontal wedges may have a non-constant color,
466 they can't decompose into constant color trapezoids with
467 keeping the coverage contiguity. To represent them we
468 apply the XY plane transposition. But with the transposition
469 a semiopen interval can met a non-transposed one,
470 so that some lines are not covered. Therefore we emulate
471 closed intervals with expanding the transposed trapesoids in
472 fixed_epsilon, and pixels at that boundary may be painted twice.
473
474 - A boundary of a monotonic area can't compute in XY
475 preciselly due to high order polynomial equations.
476 Therefore the subdivision near the monotonity boundary
477 may paint some pixels twice within same monotonic part.
478
479 Non-monotonic areas slow down due to a tinny subdivision required.
480
481 The target device may be either raster or vector.
482 Vector devices should preciselly pass trapezoids to the output.
483 Note that ends of sides of a trapesoid are not necessary
484 the trapezoid's vertices. Converting this thing into
485 an exact quadrangle may cause an arithmetic error,
486 and the rounding must be done so that the coverage
487 contiguity is not lost.
488
489 When a device passes a trapezoid to it's output,
490 a regular rounding would keep the coverage contiguity,
491 except for the transposed trapesoids.
492 If a transposed trapezoid is being transposed back,
493 it doesn't become a canonic trapezoid, and a further
494 decomposition is neccessary. But rounding errors here
495 would break the coverage contiguity at boundaries
496 of the tansposed part of the area.
497
498 Devices, which have no transposed trapezoids and represent
499 trapezoids only with 8 coordinates of vertices of the quadrangle
500 (pclwrite is an example) may apply the backward transposition,
501 and a clipping instead the further decomposition.
502 Note that many clip regions may appear for all wedges.
503 Note that in some cases the adjustment of the right side to be
504 withdrown before the backward transposition.
505 */
506 /* We believe that a multiplication of 32-bit integers with a
507 64-bit result is performed by modern platforms performs
508 in hardware level. Therefore we widely use it here,
509 but we minimize the usage of a multiplication of longer integers.
510
511 Unfortunately we do need a multiplication of long integers
512 in intersection_of_small_bars, because solving the linear system
513 requires tripple multiples of 'fixed'. Therefore we retain
514 of it's usage in the algorithm of the main branch.
515 Configuration macro QUADRANGLES prevents it.
516 */
517
518 typedef struct {
519 gs_fixed_point pole[4][4]; /* [v][u] */
520 patch_color_t c[2][2]; /* [v][u] */
521 } tensor_patch;
522
523 typedef struct {
524 const shading_vertex_t *p[2][2]; /* [v][u] */
525 wedge_vertex_list_t *l0001, *l0111, *l1110, *l1000;
526 } quadrangle_patch;
527
528 typedef enum {
529 interpatch_padding = 1, /* A Padding between patches for poorly designed documents. */
530 inpatch_wedge = 2 /* Wedges while a patch decomposition. */
531 } wedge_type_t;
532
533 int
wedge_vertex_list_elem_buffer_alloc(patch_fill_state_t * pfs)534 wedge_vertex_list_elem_buffer_alloc(patch_fill_state_t *pfs)
535 {
536 const int max_level = LAZY_WEDGES_MAX_LEVEL;
537 gs_memory_t *memory = pfs->pis->memory;
538
539 pfs->wedge_vertex_list_elem_count_max = max_level * (1 << max_level);
540 pfs->wedge_vertex_list_elem_buffer = (wedge_vertex_list_elem_t *)gs_alloc_bytes(memory,
541 sizeof(wedge_vertex_list_elem_t) * pfs->wedge_vertex_list_elem_count_max,
542 "alloc_wedge_vertex_list_elem_buffer");
543 if (pfs->wedge_vertex_list_elem_buffer == NULL)
544 return_error(gs_error_VMerror);
545 pfs->free_wedge_vertex = NULL;
546 pfs->wedge_vertex_list_elem_count = 0;
547 return 0;
548 }
549
550 void
wedge_vertex_list_elem_buffer_free(patch_fill_state_t * pfs)551 wedge_vertex_list_elem_buffer_free(patch_fill_state_t *pfs)
552 {
553 gs_memory_t *memory = pfs->pis->memory;
554
555 gs_free_object(memory, pfs->wedge_vertex_list_elem_buffer,
556 "wedge_vertex_list_elem_buffer_free");
557 pfs->wedge_vertex_list_elem_buffer = NULL;
558 pfs->free_wedge_vertex = NULL;
559 }
560
561 private inline wedge_vertex_list_elem_t *
wedge_vertex_list_elem_reserve(patch_fill_state_t * pfs)562 wedge_vertex_list_elem_reserve(patch_fill_state_t *pfs)
563 {
564 wedge_vertex_list_elem_t *e = pfs->free_wedge_vertex;
565
566 if (e != NULL) {
567 pfs->free_wedge_vertex = e->next;
568 return e;
569 }
570 if (pfs->wedge_vertex_list_elem_count < pfs->wedge_vertex_list_elem_count_max)
571 return pfs->wedge_vertex_list_elem_buffer + pfs->wedge_vertex_list_elem_count++;
572 return NULL;
573 }
574
575 private inline void
wedge_vertex_list_elem_release(patch_fill_state_t * pfs,wedge_vertex_list_elem_t * e)576 wedge_vertex_list_elem_release(patch_fill_state_t *pfs, wedge_vertex_list_elem_t *e)
577 {
578 e->next = pfs->free_wedge_vertex;
579 pfs->free_wedge_vertex = e;
580 }
581
582 private inline void
release_triangle_wedge_vertex_list_elem(patch_fill_state_t * pfs,wedge_vertex_list_elem_t * beg,wedge_vertex_list_elem_t * end)583 release_triangle_wedge_vertex_list_elem(patch_fill_state_t *pfs,
584 wedge_vertex_list_elem_t *beg, wedge_vertex_list_elem_t *end)
585 {
586 wedge_vertex_list_elem_t *e = beg->next;
587
588 assert(beg->next->next == end);
589 beg->next = end;
590 end->prev = beg;
591 wedge_vertex_list_elem_release(pfs, e);
592 }
593
594 private inline void
release_wedge_vertex_list_interval(patch_fill_state_t * pfs,wedge_vertex_list_elem_t * beg,wedge_vertex_list_elem_t * end)595 release_wedge_vertex_list_interval(patch_fill_state_t *pfs,
596 wedge_vertex_list_elem_t *beg, wedge_vertex_list_elem_t *end)
597 {
598 wedge_vertex_list_elem_t *e = beg->next, *ee;
599
600 beg->next = end;
601 end->prev = beg;
602 for (; e != end; e = ee) {
603 ee = e->next;
604 wedge_vertex_list_elem_release(pfs, e);
605 }
606 }
607
608 private inline void
release_wedge_vertex_list(patch_fill_state_t * pfs,wedge_vertex_list_t * ll,int n)609 release_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *ll, int n)
610 {
611 int i;
612
613 for (i = 0; i < n; i++) {
614 wedge_vertex_list_t *l = ll + i;
615
616 if (l->beg != NULL) {
617 assert(l->end != NULL);
618 release_wedge_vertex_list_interval(pfs, l->beg, l->end);
619 wedge_vertex_list_elem_release(pfs, l->beg);
620 wedge_vertex_list_elem_release(pfs, l->end);
621 l->beg = l->end = NULL;
622 } else
623 assert(l->end == NULL);
624 }
625 }
626
627 private inline wedge_vertex_list_elem_t *
wedge_vertex_list_find(wedge_vertex_list_elem_t * beg,const wedge_vertex_list_elem_t * end,int level)628 wedge_vertex_list_find(wedge_vertex_list_elem_t *beg, const wedge_vertex_list_elem_t *end,
629 int level)
630 {
631 wedge_vertex_list_elem_t *e = beg;
632
633 assert(beg != NULL && end != NULL);
634 for (; e != end; e = e->next)
635 if (e->level == level)
636 return e;
637 return NULL;
638 }
639
640 private inline void
init_wedge_vertex_list(wedge_vertex_list_t * l,int n)641 init_wedge_vertex_list(wedge_vertex_list_t *l, int n)
642 {
643 memset(l, 0, sizeof(*l) * n);
644 }
645
646 private void
draw_patch(const tensor_patch * p,bool interior,ulong rgbcolor)647 draw_patch(const tensor_patch *p, bool interior, ulong rgbcolor)
648 {
649 #ifdef DEBUG
650 #if 0 /* Disabled for a better view with a specific purpose.
651 Feel free to enable fo needed. */
652 int i, step = (interior ? 1 : 3);
653
654 for (i = 0; i < 4; i += step) {
655 vd_curve(p->pole[i][0].x, p->pole[i][0].y,
656 p->pole[i][1].x, p->pole[i][1].y,
657 p->pole[i][2].x, p->pole[i][2].y,
658 p->pole[i][3].x, p->pole[i][3].y,
659 0, rgbcolor);
660 vd_curve(p->pole[0][i].x, p->pole[0][i].y,
661 p->pole[1][i].x, p->pole[1][i].y,
662 p->pole[2][i].x, p->pole[2][i].y,
663 p->pole[3][i].x, p->pole[3][i].y,
664 0, rgbcolor);
665 }
666 #endif
667 #endif
668 }
669
670 private inline void
draw_triangle(const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,ulong rgbcolor)671 draw_triangle(const gs_fixed_point *p0, const gs_fixed_point *p1,
672 const gs_fixed_point *p2, ulong rgbcolor)
673 {
674 #ifdef DEBUG
675 if (!vd_enabled)
676 return;
677 vd_quad(p0->x, p0->y, p0->x, p0->y, p1->x, p1->y, p2->x, p2->y, 0, rgbcolor);
678 #endif
679 }
680
681 private inline void
draw_quadrangle(const quadrangle_patch * p,ulong rgbcolor)682 draw_quadrangle(const quadrangle_patch *p, ulong rgbcolor)
683 {
684 #ifdef DEBUG
685 vd_quad(p->p[0][0]->p.x, p->p[0][0]->p.y,
686 p->p[0][1]->p.x, p->p[0][1]->p.y,
687 p->p[1][1]->p.x, p->p[1][1]->p.y,
688 p->p[1][0]->p.x, p->p[1][0]->p.y,
689 0, rgbcolor);
690 #endif
691 }
692
693 private inline int
curve_samples(patch_fill_state_t * pfs,const gs_fixed_point * pole,int pole_step,fixed fixed_flat)694 curve_samples(patch_fill_state_t *pfs,
695 const gs_fixed_point *pole, int pole_step, fixed fixed_flat)
696 {
697 curve_segment s;
698 int k;
699
700 s.p1.x = pole[pole_step].x;
701 s.p1.y = pole[pole_step].y;
702 s.p2.x = pole[pole_step * 2].x;
703 s.p2.y = pole[pole_step * 2].y;
704 s.pt.x = pole[pole_step * 3].x;
705 s.pt.y = pole[pole_step * 3].y;
706 k = gx_curve_log2_samples(pole[0].x, pole[0].y, &s, fixed_flat);
707 {
708 # if LAZY_WEDGES || QUADRANGLES
709 int k1;
710 fixed L = any_abs(pole[1].x - pole[0].x) + any_abs(pole[1].y - pole[0].y) +
711 any_abs(pole[2].x - pole[1].x) + any_abs(pole[2].y - pole[1].y) +
712 any_abs(pole[3].x - pole[2].x) + any_abs(pole[3].y - pole[2].y);
713 # endif
714
715 # if LAZY_WEDGES
716 /* Restrict lengths for a reasonable memory consumption : */
717 k1 = ilog2(L / fixed_1 / (1 << (LAZY_WEDGES_MAX_LEVEL - 1)));
718 k = max(k, k1);
719 # endif
720 # if QUADRANGLES
721 /* Restrict lengths for intersection_of_small_bars : */
722 k = max(k, ilog2(L) - ilog2(pfs->max_small_coord));
723 # endif
724 }
725 return 1 << k;
726 }
727
728 private bool
intersection_of_small_bars(const gs_fixed_point q[4],int i0,int i1,int i2,int i3,fixed * ry,fixed * ey)729 intersection_of_small_bars(const gs_fixed_point q[4], int i0, int i1, int i2, int i3, fixed *ry, fixed *ey)
730 {
731 /* This function is only used with QUADRANGLES. */
732 fixed dx1 = q[i1].x - q[i0].x, dy1 = q[i1].y - q[i0].y;
733 fixed dx2 = q[i2].x - q[i0].x, dy2 = q[i2].y - q[i0].y;
734 fixed dx3 = q[i3].x - q[i0].x, dy3 = q[i3].y - q[i0].y;
735 int64_t vp2a, vp2b, vp3a, vp3b;
736 int s2, s3;
737
738 if (dx1 == 0 && dy1 == 0)
739 return false; /* Zero length bars are out of interest. */
740 if (dx2 == 0 && dy2 == 0)
741 return false; /* Contacting ends are out of interest. */
742 if (dx3 == 0 && dy3 == 0)
743 return false; /* Contacting ends are out of interest. */
744 if (dx2 == dx1 && dy2 == dy1)
745 return false; /* Contacting ends are out of interest. */
746 if (dx3 == dx1 && dy3 == dy1)
747 return false; /* Contacting ends are out of interest. */
748 if (dx2 == dx3 && dy2 == dy3)
749 return false; /* Zero length bars are out of interest. */
750 vp2a = (int64_t)dx1 * dy2;
751 vp2b = (int64_t)dy1 * dx2;
752 /* vp2 = vp2a - vp2b; It can overflow int64_t, but we only need the sign. */
753 if (vp2a > vp2b)
754 s2 = 1;
755 else if (vp2a < vp2b)
756 s2 = -1;
757 else
758 s2 = 0;
759 vp3a = (int64_t)dx1 * dy3;
760 vp3b = (int64_t)dy1 * dx3;
761 /* vp3 = vp3a - vp3b; It can overflow int64_t, but we only need the sign. */
762 if (vp3a > vp3b)
763 s3 = 1;
764 else if (vp3a < vp3b)
765 s3 = -1;
766 else
767 s3 = 0;
768 if (s2 == 0) {
769 if (s3 == 0)
770 return false; /* Collinear bars - out of interest. */
771 if (0 <= dx2 && dx2 <= dx1 && 0 <= dy2 && dy2 <= dy1) {
772 /* The start of the bar 2 is in the bar 1. */
773 *ry = q[i2].y;
774 *ey = 0;
775 return true;
776 }
777 } else if (s3 == 0) {
778 if (0 <= dx3 && dx3 <= dx1 && 0 <= dy3 && dy3 <= dy1) {
779 /* The end of the bar 2 is in the bar 1. */
780 *ry = q[i3].y;
781 *ey = 0;
782 return true;
783 }
784 } else if (s2 * s3 < 0) {
785 /* The intersection definitely exists, so the determinant isn't zero. */
786 fixed d23x = dx3 - dx2, d23y = dy3 - dy2;
787 int64_t det = (int64_t)dx1 * d23y - (int64_t)dy1 * d23x;
788 int64_t mul = (int64_t)dx2 * d23y - (int64_t)dy2 * d23x;
789 # define USE_DOUBLE 0
790 # define USE_INT64_T (1 || !USE_DOUBLE)
791 # if USE_DOUBLE
792 {
793 /* Assuming big bars. Not a good thing due to 'double'. */
794 /* The determinant can't compute in double due to
795 possible loss of all significant bits when subtracting the
796 trucnated prodicts. But after we subtract in int64_t,
797 it converts to 'double' with a reasonable truncation. */
798 double dy = dy1 * (double)mul / (double)det;
799 fixed iy;
800
801 if (dy1 > 0 && dy >= dy1)
802 return false; /* Outside the bar 1. */
803 if (dy1 < 0 && dy <= dy1)
804 return false; /* Outside the bar 1. */
805 if (dy2 < dy3) {
806 if (dy <= dy2 || dy >= dy3)
807 return false; /* Outside the bar 2. */
808 } else {
809 if (dy >= dy2 || dy <= dy3)
810 return false; /* Outside the bar 2. */
811 }
812 iy = (int)floor(dy);
813 *ry = q[i0].y + iy;
814 *ey = (dy > iy ? 1 : 0);
815 }
816 # endif
817 # if USE_INT64_T
818 {
819 /* Assuming small bars : cubes of coordinates must fit into int64_t.
820 curve_samples must provide that. */
821 int64_t num = dy1 * mul, iiy;
822 fixed iy;
823 fixed pry, pey;
824
825 { /* Likely when called form wedge_trap_decompose or constant_color_quadrangle,
826 we always have det > 0 && num >= 0, but we check here for a safety reason. */
827 if (det < 0)
828 {num = -num; det = -det;}
829 if(num >= 0)
830 iiy = num / det;
831 else
832 iiy = (num - det + 1) / det;
833 iy = (fixed)iiy;
834 if (iy != iiy) {
835 /* If it is inside the bars, it must fit into fixed. */
836 return false;
837 }
838 }
839 if (dy1 > 0 && iy >= dy1)
840 return false; /* Outside the bar 1. */
841 if (dy1 < 0 && iy <= dy1)
842 return false; /* Outside the bar 1. */
843 if (dy2 < dy3) {
844 if (iy <= dy2 || iy >= dy3)
845 return false; /* Outside the bar 2. */
846 } else {
847 if (iy >= dy2 || iy <= dy3)
848 return false; /* Outside the bar 2. */
849 }
850 pry = q[i0].y + (fixed)iy;
851 pey = (iy * det < num ? 1 : 0);
852 # if USE_DOUBLE && USE_INT64_T
853 assert(*ry == pry);
854 assert(*ey == pey);
855 # endif
856 *ry = pry;
857 *ey = pey;
858 }
859 # endif
860 return true;
861 }
862 return false;
863 }
864
865 private inline void
adjust_swapped_boundary(fixed * b,bool swap_axes)866 adjust_swapped_boundary(fixed *b, bool swap_axes)
867 {
868 if (swap_axes) {
869 /* Sinse the rasterizer algorithm assumes semi-open interval
870 when computing pixel coverage, we should expand
871 the right side of the area. Otherwise a dropout can happen :
872 if the left neighbour is painted with !swap_axes,
873 the left side of this area appears to be the left side
874 of the neighbour area, and the side is not included
875 into both areas.
876 */
877 *b += fixed_epsilon;
878 }
879 }
880
881 private inline void
make_trapezoid(const gs_fixed_point q[4],int vi0,int vi1,int vi2,int vi3,fixed ybot,fixed ytop,bool swap_axes,bool orient,gs_fixed_edge * le,gs_fixed_edge * re)882 make_trapezoid(const gs_fixed_point q[4],
883 int vi0, int vi1, int vi2, int vi3, fixed ybot, fixed ytop,
884 bool swap_axes, bool orient, gs_fixed_edge *le, gs_fixed_edge *re)
885 {
886 if (!orient) {
887 le->start = q[vi0];
888 le->end = q[vi1];
889 re->start = q[vi2];
890 re->end = q[vi3];
891 } else {
892 le->start = q[vi2];
893 le->end = q[vi3];
894 re->start = q[vi0];
895 re->end = q[vi1];
896 }
897 adjust_swapped_boundary(&re->start.x, swap_axes);
898 adjust_swapped_boundary(&re->end.x, swap_axes);
899 }
900
901 private inline int
gx_shade_trapezoid(patch_fill_state_t * pfs,const gs_fixed_point q[4],int vi0,int vi1,int vi2,int vi3,fixed ybot0,fixed ytop0,bool swap_axes,const gx_device_color * pdevc,bool orient)902 gx_shade_trapezoid(patch_fill_state_t *pfs, const gs_fixed_point q[4],
903 int vi0, int vi1, int vi2, int vi3, fixed ybot0, fixed ytop0,
904 bool swap_axes, const gx_device_color *pdevc, bool orient)
905 {
906 gs_fixed_edge le, re;
907 int code;
908 fixed ybot = max(ybot0, swap_axes ? pfs->rect.p.x : pfs->rect.p.y);
909 fixed ytop = min(ytop0, swap_axes ? pfs->rect.q.x : pfs->rect.q.y);
910 vd_save;
911
912 if (ybot > ytop)
913 return 0;
914 # if NOFILL_TEST
915 if (dbg_nofill)
916 return 0;
917 # endif
918 make_trapezoid(q, vi0, vi1, vi2, vi3, ybot, ytop, swap_axes, orient, &le, &re);
919 if (!VD_TRACE_DOWN)
920 vd_disable;
921 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
922 &le, &re, ybot, ytop, swap_axes, pdevc, pfs->pis->log_op);
923 vd_restore;
924 return code;
925 }
926
927 private int
patch_color_to_device_color(const patch_fill_state_t * pfs,const patch_color_t * c,gx_device_color * pdevc)928 patch_color_to_device_color(const patch_fill_state_t *pfs, const patch_color_t *c, gx_device_color *pdevc)
929 {
930 /* A code fragment copied from mesh_fill_triangle. */
931 gs_client_color fcc;
932 const gs_color_space *pcs = pfs->direct_space;
933
934 memcpy(fcc.paint.values, c->cc.paint.values,
935 sizeof(fcc.paint.values[0]) * pfs->num_components);
936 return pcs->type->remap_color(&fcc, pcs, pdevc, pfs->pis,
937 pfs->dev, gs_color_select_texture);
938 }
939
940 private inline double
color_span(const patch_fill_state_t * pfs,const patch_color_t * c0,const patch_color_t * c1)941 color_span(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1)
942 {
943 int n = pfs->num_components, i;
944 double m;
945
946 /* Dont want to copy colors, which are big things. */
947 m = any_abs(c1->cc.paint.values[0] - c0->cc.paint.values[0]) / pfs->color_domain.paint.values[0];
948 for (i = 1; i < n; i++)
949 m = max(m, any_abs(c1->cc.paint.values[i] - c0->cc.paint.values[i]) / pfs->color_domain.paint.values[i]);
950 return m;
951 }
952
953 private inline void
color_diff(const patch_fill_state_t * pfs,const patch_color_t * c0,const patch_color_t * c1,patch_color_t * d)954 color_diff(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1, patch_color_t *d)
955 {
956 int n = pfs->num_components, i;
957
958 for (i = 0; i < n; i++)
959 d->cc.paint.values[i] = c1->cc.paint.values[i] - c0->cc.paint.values[i];
960 }
961
962 private inline double
color_norm(const patch_fill_state_t * pfs,const patch_color_t * c)963 color_norm(const patch_fill_state_t *pfs, const patch_color_t *c)
964 {
965 int n = pfs->num_components, i;
966 double m;
967
968 m = any_abs(c->cc.paint.values[0]) / pfs->color_domain.paint.values[0];
969 for (i = 1; i < n; i++)
970 m = max(m, any_abs(c->cc.paint.values[i]) / pfs->color_domain.paint.values[i]);
971 return m;
972 }
973
974 private inline int
isnt_color_monotonic(const patch_fill_state_t * pfs,const patch_color_t * c0,const patch_color_t * c1)975 isnt_color_monotonic(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1)
976 { /* checks whether the color is monotonic in the n-dimensional interval,
977 where n is the number of parameters in c0->t, c1->t.
978 returns : 0 = monotonic,
979 bit 0 = not or don't know by t0,
980 bit 1 = not or don't know by t1,
981 <0 = error. */
982 /* When pfs->Function is not set, the color is monotonic.
983 In this case do not call this function because
984 it doesn't check whether pfs->Function is set.
985 Actually pfs->monotonic_color prevents that.
986 */
987 uint mask;
988 int code = gs_function_is_monotonic(pfs->Function, c0->t, c1->t, &mask);
989
990 if (code >= 0)
991 return mask;
992 return code;
993 }
994
995 private inline bool
covers_pixel_centers(fixed ybot,fixed ytop)996 covers_pixel_centers(fixed ybot, fixed ytop)
997 {
998 return fixed_pixround(ybot) < fixed_pixround(ytop);
999 }
1000
1001 private inline int
constant_color_trapezoid(patch_fill_state_t * pfs,gs_fixed_edge * le,gs_fixed_edge * re,fixed ybot,fixed ytop,bool swap_axes,const patch_color_t * c)1002 constant_color_trapezoid(patch_fill_state_t *pfs, gs_fixed_edge *le, gs_fixed_edge *re,
1003 fixed ybot, fixed ytop, bool swap_axes, const patch_color_t *c)
1004 {
1005 patch_color_t c1 = *c;
1006 gx_device_color dc;
1007 int code;
1008 vd_save;
1009
1010 # if NOFILL_TEST
1011 /* if (dbg_nofill)
1012 return 0; */
1013 # endif
1014 code = patch_color_to_device_color(pfs, &c1, &dc);
1015 if (code < 0)
1016 return code;
1017 if (!VD_TRACE_DOWN)
1018 vd_disable;
1019 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1020 le, re, ybot, ytop, swap_axes, &dc, pfs->pis->log_op);
1021 vd_restore;
1022 return code;
1023 }
1024
1025 private inline void
dc2fc(const patch_fill_state_t * pfs,gx_color_index c,frac31 fc[GX_DEVICE_COLOR_MAX_COMPONENTS])1026 dc2fc(const patch_fill_state_t *pfs, gx_color_index c,
1027 frac31 fc[GX_DEVICE_COLOR_MAX_COMPONENTS])
1028 {
1029 int j;
1030 const gx_device_color_info *cinfo = &pfs->dev->color_info;
1031
1032 for (j = 0; j < cinfo->num_components; j++) {
1033 int shift = cinfo->comp_shift[j];
1034 int bits = cinfo->comp_bits[j];
1035
1036 fc[j] = ((c >> shift) & ((1 << bits) - 1)) << (sizeof(frac31) * 8 - 1 - bits);
1037 }
1038 }
1039
1040 private inline float
function_linearity(const patch_fill_state_t * pfs,const patch_color_t * c0,const patch_color_t * c1)1041 function_linearity(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1)
1042 {
1043 float smoothness = max(pfs->smoothness, 1.0 / min_linear_grades), s = 0;
1044 /* Restrict the smoothness with 1/min_linear_grades, because cs_is_linear
1045 can't provide a better precision due to the color
1046 representation with integers.
1047 */
1048
1049 if (pfs->Function != NULL) {
1050 patch_color_t c;
1051 const float q[2] = {(float)0.3, (float)0.7};
1052 int i, j;
1053
1054 for (j = 0; j < count_of(q); j++) {
1055 c.t[0] = c0->t[0] * (1 - q[j]) + c1->t[0] * q[j];
1056 c.t[1] = c0->t[1] * (1 - q[j]) + c1->t[1] * q[j];
1057 patch_resolve_color_inline(&c, pfs);
1058 for (i = 0; i < pfs->num_components; i++) {
1059 float v = c0->cc.paint.values[i] * (1 - q[j]) + c1->cc.paint.values[i] * q[j];
1060 float d = v - c.cc.paint.values[i];
1061 float s1 = any_abs(d) / pfs->color_domain.paint.values[i];
1062
1063 if (s1 > smoothness)
1064 return s1;
1065 if (s < s1)
1066 s = s1;
1067 }
1068 }
1069 }
1070 return s;
1071 }
1072
1073 private inline int
is_color_linear(const patch_fill_state_t * pfs,const patch_color_t * c0,const patch_color_t * c1)1074 is_color_linear(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1)
1075 { /* returns : 1 = linear, 0 = unlinear, <0 = error. */
1076 if (pfs->unlinear)
1077 return 1; /* Disable this check. */
1078 else {
1079 gs_direct_color_space *cs =
1080 (gs_direct_color_space *)pfs->direct_space; /* break 'const'. */
1081 int code;
1082 float smoothness = max(pfs->smoothness, 1.0 / min_linear_grades);
1083 /* Restrict the smoothness with 1/min_linear_grades, because cs_is_linear
1084 can't provide a better precision due to the color
1085 representation with integers.
1086 */
1087 float s = function_linearity(pfs, c0, c1);
1088
1089 if (s > smoothness)
1090 return 0;
1091 code = cs_is_linear(cs, pfs->pis, pfs->dev,
1092 &c0->cc, &c1->cc, NULL, NULL, smoothness - s);
1093 if (code <= 0)
1094 return code;
1095 return 1;
1096 }
1097 }
1098
1099 private int
decompose_linear_color(patch_fill_state_t * pfs,gs_fixed_edge * le,gs_fixed_edge * re,fixed ybot,fixed ytop,bool swap_axes,const patch_color_t * c0,const patch_color_t * c1,int level)1100 decompose_linear_color(patch_fill_state_t *pfs, gs_fixed_edge *le, gs_fixed_edge *re,
1101 fixed ybot, fixed ytop, bool swap_axes, const patch_color_t *c0,
1102 const patch_color_t *c1, int level)
1103 {
1104 /* Assuming a very narrow trapezoid - ignore the transversal color variation. */
1105 /* Assuming the XY span is restricted with curve_samples.
1106 It is important for intersection_of_small_bars to compute faster. */
1107 int code;
1108 patch_color_t c;
1109
1110 if (level > 100)
1111 return_error(gs_error_unregistered); /* Must not happen. */
1112 /* Use the recursive decomposition due to isnt_color_monotonic
1113 based on fn_is_monotonic_proc_t is_monotonic,
1114 which applies to intervals. */
1115 patch_interpolate_color(&c, c0, c1, pfs, 0.5);
1116 if (ytop - ybot < fixed_1 / 2) /* Prevent an infinite color decomposition. */
1117 return constant_color_trapezoid(pfs, le, re, ybot, ytop, swap_axes, &c);
1118 else {
1119 bool monotonic_color_save = pfs->monotonic_color;
1120 bool linear_color_save = pfs->linear_color;
1121
1122 if (!pfs->monotonic_color) {
1123 code = isnt_color_monotonic(pfs, c0, c1);
1124 if (code < 0)
1125 return code;
1126 if (!code)
1127 pfs->monotonic_color = true;
1128 }
1129 if (pfs->monotonic_color && !pfs->linear_color) {
1130 code = is_color_linear(pfs, c0, c1);
1131 if (code < 0)
1132 return code;
1133 if (code > 0)
1134 pfs->linear_color = true;
1135 }
1136 if (!pfs->unlinear && pfs->linear_color) {
1137 gx_device *pdev = pfs->dev;
1138 frac31 fc[2][GX_DEVICE_COLOR_MAX_COMPONENTS];
1139 gs_fill_attributes fa;
1140 gx_device_color dc[2];
1141 gs_fixed_rect clip;
1142 int code;
1143
1144 clip = pfs->rect;
1145 if (swap_axes) {
1146 fixed v;
1147
1148 v = clip.p.x; clip.p.x = clip.p.y; clip.p.y = v;
1149 v = clip.q.x; clip.q.x = clip.q.y; clip.q.y = v;
1150 /* Don't need adjust_swapped_boundary here. */
1151 }
1152 clip.p.y = max(clip.p.y, ybot);
1153 clip.q.y = min(clip.q.y, ytop);
1154 fa.clip = &clip;
1155 fa.ht = NULL;
1156 fa.swap_axes = swap_axes;
1157 fa.lop = 0;
1158 fa.ystart = ybot;
1159 fa.yend = ytop;
1160 code = patch_color_to_device_color(pfs, c0, &dc[0]);
1161 if (code < 0)
1162 return code;
1163 if (dc[0].type == &gx_dc_type_data_pure) {
1164 dc2fc(pfs, dc[0].colors.pure, fc[0]);
1165 code = patch_color_to_device_color(pfs, c1, &dc[1]);
1166 if (code < 0)
1167 return code;
1168 dc2fc(pfs, dc[1].colors.pure, fc[1]);
1169 code = dev_proc(pdev, fill_linear_color_trapezoid)(pdev, &fa,
1170 &le->start, &le->end, &re->start, &re->end,
1171 fc[0], fc[1], NULL, NULL);
1172 if (code == 1) {
1173 pfs->monotonic_color = monotonic_color_save;
1174 pfs->linear_color = linear_color_save;
1175 return 0; /* The area is filled. */
1176 }
1177 if (code < 0)
1178 return code;
1179 else /* code == 0, the device requested to decompose the area. */
1180 return_error(gs_error_unregistered); /* Must not happen. */
1181 }
1182 }
1183 if (!pfs->unlinear || !pfs->linear_color ||
1184 color_span(pfs, c0, c1) > pfs->smoothness) {
1185 fixed y = (ybot + ytop) / 2;
1186
1187 code = decompose_linear_color(pfs, le, re, ybot, y, swap_axes, c0, &c, level + 1);
1188 if (code >= 0)
1189 code = decompose_linear_color(pfs, le, re, y, ytop, swap_axes, &c, c1, level + 1);
1190 } else
1191 code = constant_color_trapezoid(pfs, le, re, ybot, ytop, swap_axes, &c);
1192 pfs->monotonic_color = monotonic_color_save;
1193 pfs->linear_color = linear_color_save;
1194 return code;
1195 }
1196 }
1197
1198 private inline int
linear_color_trapezoid(patch_fill_state_t * pfs,gs_fixed_point q[4],int i0,int i1,int i2,int i3,fixed ybot,fixed ytop,bool swap_axes,const patch_color_t * c0,const patch_color_t * c1,bool orient)1199 linear_color_trapezoid(patch_fill_state_t *pfs, gs_fixed_point q[4], int i0, int i1, int i2, int i3,
1200 fixed ybot, fixed ytop, bool swap_axes, const patch_color_t *c0, const patch_color_t *c1,
1201 bool orient)
1202 {
1203 /* Assuming a very narrow trapezoid - ignore the transversal color change. */
1204 gs_fixed_edge le, re;
1205
1206 make_trapezoid(q, i0, i1, i2, i3, ybot, ytop, swap_axes, orient, &le, &re);
1207 return decompose_linear_color(pfs, &le, &re, ybot, ytop, swap_axes, c0, c1, 0);
1208 }
1209
1210 private int
wedge_trap_decompose(patch_fill_state_t * pfs,gs_fixed_point q[4],fixed ybot,fixed ytop,const patch_color_t * c0,const patch_color_t * c1,bool swap_axes,bool self_intersecting)1211 wedge_trap_decompose(patch_fill_state_t *pfs, gs_fixed_point q[4],
1212 fixed ybot, fixed ytop, const patch_color_t *c0, const patch_color_t *c1,
1213 bool swap_axes, bool self_intersecting)
1214 {
1215 /* Assuming a very narrow trapezoid - ignore the transversal color change. */
1216 fixed dx1, dy1, dx2, dy2;
1217 bool orient;
1218
1219 if (!pfs->vectorization && !covers_pixel_centers(ybot, ytop))
1220 return 0;
1221 if (ybot == ytop)
1222 return 0;
1223 dx1 = q[1].x - q[0].x, dy1 = q[1].y - q[0].y;
1224 dx2 = q[2].x - q[0].x, dy2 = q[2].y - q[0].y;
1225 #if 1
1226 if (!swap_axes)
1227 vd_quad(q[0].x, q[0].y, q[1].x, q[1].y, q[3].x, q[3].y, q[2].x, q[2].y, 0, RGB(255, 0, 0));
1228 else
1229 vd_quad(q[0].y, q[0].x, q[1].y, q[1].x, q[3].y, q[3].x, q[2].y, q[2].x, 0, RGB(255, 0, 0));
1230 #endif
1231 if ((int64_t)dx1 * dy2 != (int64_t)dy1 * dx2) {
1232 orient = ((int64_t)dx1 * dy2 > (int64_t)dy1 * dx2);
1233 return linear_color_trapezoid(pfs, q, 0, 1, 2, 3, ybot, ytop, swap_axes, c0, c1, orient);
1234 } else {
1235 fixed dx3 = q[3].x - q[0].x, dy3 = q[3].y - q[0].y;
1236
1237 orient = ((int64_t)dx1 * dy3 > (int64_t)dy1 * dx3);
1238 return linear_color_trapezoid(pfs, q, 0, 1, 2, 3, ybot, ytop, swap_axes, c0, c1, orient);
1239 }
1240 }
1241
1242 private inline int
fill_wedge_trap(patch_fill_state_t * pfs,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * q0,const gs_fixed_point * q1,const patch_color_t * c0,const patch_color_t * c1,bool swap_axes,bool self_intersecting)1243 fill_wedge_trap(patch_fill_state_t *pfs, const gs_fixed_point *p0, const gs_fixed_point *p1,
1244 const gs_fixed_point *q0, const gs_fixed_point *q1, const patch_color_t *c0, const patch_color_t *c1,
1245 bool swap_axes, bool self_intersecting)
1246 {
1247 /* We assume that the width of the wedge is close to zero,
1248 so we can ignore the slope when computing transversal distances. */
1249 gs_fixed_point p[4];
1250 const patch_color_t *cc0, *cc1;
1251
1252 if (p0->y < p1->y) {
1253 p[2] = *p0;
1254 p[3] = *p1;
1255 cc0 = c0;
1256 cc1 = c1;
1257 } else {
1258 p[2] = *p1;
1259 p[3] = *p0;
1260 cc0 = c1;
1261 cc1 = c0;
1262 }
1263 p[0] = *q0;
1264 p[1] = *q1;
1265 return wedge_trap_decompose(pfs, p, p[2].y, p[3].y, cc0, cc1, swap_axes, self_intersecting);
1266 }
1267
1268 private void
split_curve_s(const gs_fixed_point * pole,gs_fixed_point * q0,gs_fixed_point * q1,int pole_step)1269 split_curve_s(const gs_fixed_point *pole, gs_fixed_point *q0, gs_fixed_point *q1, int pole_step)
1270 {
1271 /* This copies a code fragment from split_curve_midpoint,
1272 substituting another data type.
1273 */
1274 /*
1275 * We have to define midpoint carefully to avoid overflow.
1276 * (If it overflows, something really pathological is going
1277 * on, but we could get infinite recursion that way....)
1278 */
1279 #define midpoint(a,b)\
1280 (arith_rshift_1(a) + arith_rshift_1(b) + (((a) | (b)) & 1))
1281 fixed x12 = midpoint(pole[1 * pole_step].x, pole[2 * pole_step].x);
1282 fixed y12 = midpoint(pole[1 * pole_step].y, pole[2 * pole_step].y);
1283
1284 /* q[0] and q[1] must not be the same as pole. */
1285 q0[1 * pole_step].x = midpoint(pole[0 * pole_step].x, pole[1 * pole_step].x);
1286 q0[1 * pole_step].y = midpoint(pole[0 * pole_step].y, pole[1 * pole_step].y);
1287 q1[2 * pole_step].x = midpoint(pole[2 * pole_step].x, pole[3 * pole_step].x);
1288 q1[2 * pole_step].y = midpoint(pole[2 * pole_step].y, pole[3 * pole_step].y);
1289 q0[2 * pole_step].x = midpoint(q0[1 * pole_step].x, x12);
1290 q0[2 * pole_step].y = midpoint(q0[1 * pole_step].y, y12);
1291 q1[1 * pole_step].x = midpoint(x12, q1[2 * pole_step].x);
1292 q1[1 * pole_step].y = midpoint(y12, q1[2 * pole_step].y);
1293 q0[0 * pole_step].x = pole[0 * pole_step].x;
1294 q0[0 * pole_step].y = pole[0 * pole_step].y;
1295 q0[3 * pole_step].x = q1[0 * pole_step].x = midpoint(q0[2 * pole_step].x, q1[1 * pole_step].x);
1296 q0[3 * pole_step].y = q1[0 * pole_step].y = midpoint(q0[2 * pole_step].y, q1[1 * pole_step].y);
1297 q1[3 * pole_step].x = pole[3 * pole_step].x;
1298 q1[3 * pole_step].y = pole[3 * pole_step].y;
1299 #undef midpoint
1300 }
1301
1302 private void
split_curve(const gs_fixed_point pole[4],gs_fixed_point q0[4],gs_fixed_point q1[4])1303 split_curve(const gs_fixed_point pole[4], gs_fixed_point q0[4], gs_fixed_point q1[4])
1304 {
1305 split_curve_s(pole, q0, q1, 1);
1306 }
1307
1308
1309 private void
generate_inner_vertices(gs_fixed_point * p,const gs_fixed_point pole[4],int k)1310 generate_inner_vertices(gs_fixed_point *p, const gs_fixed_point pole[4], int k)
1311 {
1312 /* Recure to get exactly same points as when devided a patch. */
1313 /* An iteration can't give them preciselly. */
1314 if (k > 1) {
1315 gs_fixed_point q[2][4];
1316
1317 split_curve(pole, q[0], q[1]);
1318 p[k / 2] = q[0][3];
1319 generate_inner_vertices(p, q[0], k / 2);
1320 generate_inner_vertices(p + k / 2, q[1], k / 2);
1321 }
1322 }
1323
1324 private inline void
do_swap_axes(gs_fixed_point * p,int k)1325 do_swap_axes(gs_fixed_point *p, int k)
1326 {
1327 int i;
1328
1329 for (i = 0; i < k; i++) {
1330 p[i].x ^= p[i].y; p[i].y ^= p[i].x; p[i].x ^= p[i].y;
1331 }
1332 }
1333
1334 private inline void
y_extreme_vertice(gs_fixed_point * q,const gs_fixed_point * p,int k,int minmax)1335 y_extreme_vertice(gs_fixed_point *q, const gs_fixed_point *p, int k, int minmax)
1336 {
1337 int i;
1338 gs_fixed_point r = *p;
1339
1340 for (i = 1; i < k; i++)
1341 if ((p[i].y - r.y) * minmax > 0)
1342 r = p[i];
1343 *q = r;
1344 }
1345
1346 private inline fixed
span_x(const gs_fixed_point * p,int k)1347 span_x(const gs_fixed_point *p, int k)
1348 {
1349 int i;
1350 fixed xmin = p[0].x, xmax = p[0].x;
1351
1352 for (i = 1; i < k; i++) {
1353 xmin = min(xmin, p[i].x);
1354 xmax = max(xmax, p[i].x);
1355 }
1356 return xmax - xmin;
1357 }
1358
1359 private inline fixed
span_y(const gs_fixed_point * p,int k)1360 span_y(const gs_fixed_point *p, int k)
1361 {
1362 int i;
1363 fixed ymin = p[0].y, ymax = p[0].y;
1364
1365 for (i = 1; i < k; i++) {
1366 ymin = min(ymin, p[i].y);
1367 ymax = max(ymax, p[i].y);
1368 }
1369 return ymax - ymin;
1370 }
1371
1372 private inline void
draw_wedge(const gs_fixed_point * p,int n)1373 draw_wedge(const gs_fixed_point *p, int n)
1374 {
1375 #ifdef DEBUG
1376 int i;
1377
1378 if (!vd_enabled)
1379 return;
1380 vd_setlinewidth(4);
1381 vd_setcolor(RGB(255, 0, 0));
1382 vd_beg_path;
1383 vd_moveto(p[0].x, p[0].y);
1384 for (i = 1; i < n; i++)
1385 vd_lineto(p[i].x, p[i].y);
1386 vd_closepath;
1387 vd_end_path;
1388 vd_fill;
1389 /*vd_stroke;*/
1390 #endif
1391 }
1392
1393 private inline fixed
manhattan_dist(const gs_fixed_point * p0,const gs_fixed_point * p1)1394 manhattan_dist(const gs_fixed_point *p0, const gs_fixed_point *p1)
1395 {
1396 fixed dx = any_abs(p1->x - p0->x), dy = any_abs(p1->y - p0->y);
1397
1398 return max(dx, dy);
1399 }
1400
1401 private inline void
create_wedge_vertex_list(patch_fill_state_t * pfs,wedge_vertex_list_t * l,const gs_fixed_point * p0,const gs_fixed_point * p1)1402 create_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *l,
1403 const gs_fixed_point *p0, const gs_fixed_point *p1)
1404 {
1405 assert(l->end == NULL);
1406 l->beg = wedge_vertex_list_elem_reserve(pfs);
1407 l->end = wedge_vertex_list_elem_reserve(pfs);
1408 assert(l->beg != NULL);
1409 assert(l->end != NULL);
1410 l->beg->prev = l->end->next = NULL;
1411 l->beg->next = l->end;
1412 l->end->prev = l->beg;
1413 l->beg->p = *p0;
1414 l->end->p = *p1;
1415 l->beg->level = l->end->level = 0;
1416 }
1417
1418 private inline wedge_vertex_list_elem_t *
insert_wedge_vertex_list_elem(patch_fill_state_t * pfs,wedge_vertex_list_t * l,const gs_fixed_point * p)1419 insert_wedge_vertex_list_elem(patch_fill_state_t *pfs, wedge_vertex_list_t *l, const gs_fixed_point *p)
1420 {
1421 wedge_vertex_list_elem_t *e = wedge_vertex_list_elem_reserve(pfs);
1422
1423 /* We have got enough free elements due to the preliminary decomposition
1424 of curves to LAZY_WEDGES_MAX_LEVEL, see curve_samples. */
1425 assert(e != NULL);
1426 assert(l->beg->next == l->end);
1427 assert(l->end->prev == l->beg);
1428 e->next = l->end;
1429 e->prev = l->beg;
1430 e->p = *p;
1431 e->level = max(l->beg->level, l->end->level) + 1;
1432 e->divide_count = 0;
1433 l->beg->next = l->end->prev = e;
1434 { int sx = l->beg->p.x < l->end->p.x ? 1 : -1;
1435 int sy = l->beg->p.y < l->end->p.y ? 1 : -1;
1436
1437 assert((p->x - l->beg->p.x) * sx >= 0);
1438 assert((p->y - l->beg->p.y) * sy >= 0);
1439 assert((l->end->p.x - p->x) * sx >= 0);
1440 assert((l->end->p.y - p->y) * sy >= 0);
1441 }
1442 return e;
1443 }
1444
1445 private inline wedge_vertex_list_elem_t *
open_wedge_median(patch_fill_state_t * pfs,wedge_vertex_list_t * l,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * pm)1446 open_wedge_median(patch_fill_state_t *pfs, wedge_vertex_list_t *l,
1447 const gs_fixed_point *p0, const gs_fixed_point *p1, const gs_fixed_point *pm)
1448 {
1449 wedge_vertex_list_elem_t *e;
1450
1451 if (!l->last_side) {
1452 if (l->beg == NULL)
1453 create_wedge_vertex_list(pfs, l, p0, p1);
1454 assert(l->beg->p.x == p0->x);
1455 assert(l->beg->p.y == p0->y);
1456 assert(l->end->p.x == p1->x);
1457 assert(l->end->p.y == p1->y);
1458 e = insert_wedge_vertex_list_elem(pfs, l, pm);
1459 e->divide_count++;
1460 return e;
1461 } else {
1462 if (l->beg == NULL) {
1463 create_wedge_vertex_list(pfs, l, p1, p0);
1464 e = insert_wedge_vertex_list_elem(pfs, l, pm);
1465 e->divide_count++;
1466 return e;
1467 }
1468 assert(l->beg->p.x == p1->x);
1469 assert(l->beg->p.y == p1->y);
1470 assert(l->end->p.x == p0->x);
1471 assert(l->end->p.y == p0->y);
1472 if (l->beg->next == l->end) {
1473 e = insert_wedge_vertex_list_elem(pfs, l, pm);
1474 e->divide_count++;
1475 return e;
1476 } else {
1477 e = wedge_vertex_list_find(l->beg, l->end,
1478 max(l->beg->level, l->end->level) + 1);
1479 assert(e != NULL);
1480 assert(e->p.x == pm->x && e->p.y == pm->y);
1481 e->divide_count++;
1482 return e;
1483 }
1484 }
1485 }
1486
1487 private inline void
make_wedge_median(patch_fill_state_t * pfs,wedge_vertex_list_t * l,wedge_vertex_list_t * l0,bool forth,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * pm)1488 make_wedge_median(patch_fill_state_t *pfs, wedge_vertex_list_t *l,
1489 wedge_vertex_list_t *l0, bool forth,
1490 const gs_fixed_point *p0, const gs_fixed_point *p1, const gs_fixed_point *pm)
1491 {
1492 l->last_side = l0->last_side;
1493 if (!l->last_side ^ !forth) {
1494 l->end = open_wedge_median(pfs, l0, p0, p1, pm);
1495 l->beg = l0->beg;
1496 } else {
1497 l->beg = open_wedge_median(pfs, l0, p0, p1, pm);
1498 l->end = l0->end;
1499 }
1500 }
1501
1502 private int fill_wedge_from_list(patch_fill_state_t *pfs, const wedge_vertex_list_t *l,
1503 const patch_color_t *c0, const patch_color_t *c1);
1504
1505 private inline int
close_wedge_median(patch_fill_state_t * pfs,wedge_vertex_list_t * l,const patch_color_t * c0,const patch_color_t * c1)1506 close_wedge_median(patch_fill_state_t *pfs, wedge_vertex_list_t *l,
1507 const patch_color_t *c0, const patch_color_t *c1)
1508 {
1509 int code;
1510
1511 if (!l->last_side)
1512 return 0;
1513 code = fill_wedge_from_list(pfs, l, c1, c0);
1514 if (code < 0)
1515 return code;
1516 release_wedge_vertex_list_interval(pfs, l->beg, l->end);
1517 return 0;
1518 }
1519
1520 private inline void
move_wedge(wedge_vertex_list_t * l,const wedge_vertex_list_t * l0,bool forth)1521 move_wedge(wedge_vertex_list_t *l, const wedge_vertex_list_t *l0, bool forth)
1522 {
1523 if (!l->last_side ^ !forth) {
1524 l->beg = l->end;
1525 l->end = l0->end;
1526 } else {
1527 l->end = l->beg;
1528 l->beg = l0->beg;
1529 }
1530 }
1531
1532 private inline int
fill_triangle_wedge_aux(patch_fill_state_t * pfs,const shading_vertex_t * q0,const shading_vertex_t * q1,const shading_vertex_t * q2)1533 fill_triangle_wedge_aux(patch_fill_state_t *pfs,
1534 const shading_vertex_t *q0, const shading_vertex_t *q1, const shading_vertex_t *q2)
1535 { int code;
1536 const gs_fixed_point *p0, *p1, *p2;
1537 gs_fixed_point qq0, qq1, qq2;
1538 fixed dx = any_abs(q0->p.x - q1->p.x), dy = any_abs(q0->p.y - q1->p.y);
1539 bool swap_axes;
1540
1541 # if SKIP_TEST
1542 dbg_wedge_triangle_cnt++;
1543 # endif
1544 if (dx > dy) {
1545 swap_axes = true;
1546 qq0.x = q0->p.y;
1547 qq0.y = q0->p.x;
1548 qq1.x = q1->p.y;
1549 qq1.y = q1->p.x;
1550 qq2.x = q2->p.y;
1551 qq2.y = q2->p.x;
1552 p0 = &qq0;
1553 p1 = &qq1;
1554 p2 = &qq2;
1555 } else {
1556 swap_axes = false;
1557 p0 = &q0->p;
1558 p1 = &q1->p;
1559 p2 = &q2->p;
1560 }
1561 /* We decompose the thin triangle into 2 thin trapezoids.
1562 An optimization with decomposing into 2 triangles
1563 appears low useful, because the self_intersecting argument
1564 with inline expansion does that job perfectly. */
1565 if (p0->y < p1->y) {
1566 code = fill_wedge_trap(pfs, p0, p2, p0, p1, &q0->c, &q2->c, swap_axes, false);
1567 if (code < 0)
1568 return code;
1569 return fill_wedge_trap(pfs, p2, p1, p0, p1, &q2->c, &q1->c, swap_axes, false);
1570 } else {
1571 code = fill_wedge_trap(pfs, p0, p2, p1, p0, &q0->c, &q2->c, swap_axes, false);
1572 if (code < 0)
1573 return code;
1574 return fill_wedge_trap(pfs, p2, p1, p1, p0, &q2->c, &q1->c, swap_axes, false);
1575 }
1576 }
1577
1578 private inline int
try_device_linear_color(patch_fill_state_t * pfs,bool wedge,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2)1579 try_device_linear_color(patch_fill_state_t *pfs, bool wedge,
1580 const shading_vertex_t *p0, const shading_vertex_t *p1,
1581 const shading_vertex_t *p2)
1582 {
1583 /* Returns :
1584 <0 - error;
1585 0 - success;
1586 1 - decompose to linear color areas;
1587 2 - decompose to constant color areas;
1588 */
1589 int code;
1590
1591 if (pfs->unlinear)
1592 return 2;
1593 if (!wedge) {
1594 gs_direct_color_space *cs =
1595 (gs_direct_color_space *)pfs->direct_space; /* break 'const'. */
1596 float smoothness = max(pfs->smoothness, 1.0 / min_linear_grades);
1597 /* Restrict the smoothness with 1/min_linear_grades, because cs_is_linear
1598 can't provide a better precision due to the color
1599 representation with integers.
1600 */
1601 float s0, s1, s2, s01, s012;
1602
1603 s0 = function_linearity(pfs, &p0->c, &p1->c);
1604 if (s0 > smoothness)
1605 return 1;
1606 s1 = function_linearity(pfs, &p1->c, &p2->c);
1607 if (s1 > smoothness)
1608 return 1;
1609 s2 = function_linearity(pfs, &p2->c, &p0->c);
1610 if (s2 > smoothness)
1611 return 1;
1612 /* fixme: check an inner color ? */
1613 s01 = max(s0, s1);
1614 s012 = max(s01, s2);
1615 code = cs_is_linear(cs, pfs->pis, pfs->dev,
1616 &p0->c.cc, &p1->c.cc, &p2->c.cc, NULL, smoothness - s012);
1617 if (code < 0)
1618 return code;
1619 if (code == 0)
1620 return 1;
1621 }
1622 { gx_device *pdev = pfs->dev;
1623 frac31 fc[3][GX_DEVICE_COLOR_MAX_COMPONENTS];
1624 gs_fill_attributes fa;
1625 gx_device_color dc[3];
1626 vd_save;
1627
1628 fa.clip = &pfs->rect;
1629 fa.ht = NULL;
1630 fa.swap_axes = false;
1631 fa.lop = 0;
1632 code = patch_color_to_device_color(pfs, &p0->c, &dc[0]);
1633 if (code < 0)
1634 return code;
1635 if (dc[0].type != &gx_dc_type_data_pure)
1636 return 2;
1637 dc2fc(pfs, dc[0].colors.pure, fc[0]);
1638 if (!wedge) {
1639 code = patch_color_to_device_color(pfs, &p1->c, &dc[1]);
1640 if (code < 0)
1641 return code;
1642 dc2fc(pfs, dc[1].colors.pure, fc[1]);
1643 }
1644 code = patch_color_to_device_color(pfs, &p2->c, &dc[2]);
1645 if (code < 0)
1646 return code;
1647 dc2fc(pfs, dc[2].colors.pure, fc[2]);
1648 draw_triangle(&p0->p, &p1->p, &p2->p, RGB(255, 0, 0));
1649 if (!VD_TRACE_DOWN)
1650 vd_disable;
1651 code = dev_proc(pdev, fill_linear_color_triangle)(pdev, &fa,
1652 &p0->p, &p1->p, &p2->p,
1653 fc[0], (wedge ? NULL : fc[1]), fc[2]);
1654 vd_restore;
1655 if (code == 1)
1656 return 0; /* The area is filled. */
1657 if (code < 0)
1658 return code;
1659 else /* code == 0, the device requested to decompose the area. */
1660 return 1;
1661 }
1662 }
1663
1664 private inline int
fill_triangle_wedge(patch_fill_state_t * pfs,const shading_vertex_t * q0,const shading_vertex_t * q1,const shading_vertex_t * q2)1665 fill_triangle_wedge(patch_fill_state_t *pfs,
1666 const shading_vertex_t *q0, const shading_vertex_t *q1, const shading_vertex_t *q2)
1667 {
1668 if ((int64_t)(q1->p.x - q0->p.x) * (q2->p.y - q0->p.y) ==
1669 (int64_t)(q1->p.y - q0->p.y) * (q2->p.x - q0->p.x))
1670 return 0; /* Zero area. */
1671 draw_triangle(&q0->p, &q1->p, &q2->p, RGB(255, 255, 0));
1672 /*
1673 Can't apply try_device_linear_color here
1674 because didn't check is_color_linear.
1675 Maybe need a decomposition.
1676 Do same as for 'unlinear', and branch later.
1677 */
1678 return fill_triangle_wedge_aux(pfs, q0, q1, q2);
1679 }
1680
1681 private inline int
fill_triangle_wedge_from_list(patch_fill_state_t * pfs,const wedge_vertex_list_elem_t * beg,const wedge_vertex_list_elem_t * end,const wedge_vertex_list_elem_t * mid,const patch_color_t * c0,const patch_color_t * c1)1682 fill_triangle_wedge_from_list(patch_fill_state_t *pfs,
1683 const wedge_vertex_list_elem_t *beg, const wedge_vertex_list_elem_t *end,
1684 const wedge_vertex_list_elem_t *mid,
1685 const patch_color_t *c0, const patch_color_t *c1)
1686 {
1687 shading_vertex_t p[3];
1688
1689 p[0].p = beg->p;
1690 p[0].c = *c0; /* fixme : unhappy copying colors. */
1691 p[1].p = end->p;
1692 p[1].c = *c1;
1693 p[2].p = mid->p;
1694 patch_interpolate_color(&p[2].c, c0, c1, pfs, 0.5);
1695 return fill_triangle_wedge(pfs, &p[0], &p[1], &p[2]);
1696 }
1697
1698 private int
fill_wedge_from_list_rec(patch_fill_state_t * pfs,wedge_vertex_list_elem_t * beg,const wedge_vertex_list_elem_t * end,int level,const patch_color_t * c0,const patch_color_t * c1)1699 fill_wedge_from_list_rec(patch_fill_state_t *pfs,
1700 wedge_vertex_list_elem_t *beg, const wedge_vertex_list_elem_t *end,
1701 int level, const patch_color_t *c0, const patch_color_t *c1)
1702 {
1703 if (beg->next == end)
1704 return 0;
1705 else if (beg->next->next == end) {
1706 assert(beg->next->divide_count == 1 || beg->next->divide_count == 2);
1707 if (beg->next->divide_count != 1)
1708 return 0;
1709 return fill_triangle_wedge_from_list(pfs, beg, end, beg->next, c0, c1);
1710 } else {
1711 gs_fixed_point p;
1712 wedge_vertex_list_elem_t *e;
1713 patch_color_t c;
1714 int code;
1715
1716 p.x = (beg->p.x + end->p.x) / 2;
1717 p.y = (beg->p.y + end->p.y) / 2;
1718 e = wedge_vertex_list_find(beg, end, level + 1);
1719 assert(e != NULL);
1720 assert(e->p.x == p.x && e->p.y == p.y);
1721 patch_interpolate_color(&c, c0, c1, pfs, 0.5);
1722 code = fill_wedge_from_list_rec(pfs, beg, e, level + 1, c0, &c);
1723 if (code < 0)
1724 return code;
1725 code = fill_wedge_from_list_rec(pfs, e, end, level + 1, &c, c1);
1726 if (code < 0)
1727 return code;
1728 assert(e->divide_count == 1 || e->divide_count == 2);
1729 if (e->divide_count != 1)
1730 return 0;
1731 return fill_triangle_wedge_from_list(pfs, beg, end, e, c0, c1);
1732 }
1733 }
1734
1735 private int
fill_wedge_from_list(patch_fill_state_t * pfs,const wedge_vertex_list_t * l,const patch_color_t * c0,const patch_color_t * c1)1736 fill_wedge_from_list(patch_fill_state_t *pfs, const wedge_vertex_list_t *l,
1737 const patch_color_t *c0, const patch_color_t *c1)
1738 {
1739 return fill_wedge_from_list_rec(pfs, l->beg, l->end,
1740 max(l->beg->level, l->end->level), c0, c1);
1741 }
1742
1743 private inline int
terminate_wedge_vertex_list(patch_fill_state_t * pfs,wedge_vertex_list_t * l,const patch_color_t * c0,const patch_color_t * c1)1744 terminate_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *l,
1745 const patch_color_t *c0, const patch_color_t *c1)
1746 {
1747 if (l->beg != NULL) {
1748 int code = fill_wedge_from_list(pfs, l, c0, c1);
1749
1750 if (code < 0)
1751 return code;
1752 release_wedge_vertex_list(pfs, l, 1);
1753 }
1754 return 0;
1755 }
1756
1757 private int
wedge_by_triangles(patch_fill_state_t * pfs,int ka,const gs_fixed_point pole[4],const patch_color_t * c0,const patch_color_t * c1)1758 wedge_by_triangles(patch_fill_state_t *pfs, int ka,
1759 const gs_fixed_point pole[4], const patch_color_t *c0, const patch_color_t *c1)
1760 { /* Assuming ka >= 2, see fill_wedges. */
1761 gs_fixed_point q[2][4];
1762 shading_vertex_t p[3];
1763 int code;
1764
1765 split_curve(pole, q[0], q[1]);
1766 p[0].p = pole[0];
1767 p[0].c = *c0; /* fixme : unhappy copying colors. */
1768 p[1].p = pole[3];
1769 p[1].c = *c1;
1770 p[2].p = q[0][3];
1771 patch_interpolate_color(&p[2].c, c0, c1, pfs, 0.5);
1772 code = fill_triangle_wedge(pfs, &p[0], &p[1], &p[2]);
1773 if (code < 0)
1774 return code;
1775 if (ka == 2)
1776 return 0;
1777 code = wedge_by_triangles(pfs, ka / 2, q[0], c0, &p[2].c);
1778 if (code < 0)
1779 return code;
1780 return wedge_by_triangles(pfs, ka / 2, q[1], &p[2].c, c1);
1781 }
1782
1783 private inline bool
is_linear_color_applicable(const patch_fill_state_t * pfs)1784 is_linear_color_applicable(const patch_fill_state_t *pfs)
1785 {
1786 if (!USE_LINEAR_COLOR_PROCS)
1787 return false;
1788 if (pfs->dev->color_info.separable_and_linear != GX_CINFO_SEP_LIN)
1789 return false;
1790 if (gx_get_cmap_procs(pfs->pis, pfs->dev)->is_halftoned(pfs->pis, pfs->dev))
1791 return false;
1792 return true;
1793 }
1794
1795 int
mesh_padding(patch_fill_state_t * pfs,const gs_fixed_point * p0,const gs_fixed_point * p1,const patch_color_t * c0,const patch_color_t * c1)1796 mesh_padding(patch_fill_state_t *pfs, const gs_fixed_point *p0, const gs_fixed_point *p1,
1797 const patch_color_t *c0, const patch_color_t *c1)
1798 {
1799 gs_fixed_point q0, q1;
1800 const patch_color_t *cc0, *cc1;
1801 fixed dx = p1->x - p0->x;
1802 fixed dy = p1->y - p0->y;
1803 bool swap_axes = (any_abs(dx) > any_abs(dy));
1804 gs_fixed_edge le, re;
1805 const fixed adjust = INTERPATCH_PADDING;
1806
1807 pfs->unlinear = !is_linear_color_applicable(pfs);
1808 if (swap_axes) {
1809 if (p0->x < p1->x) {
1810 q0.x = p0->y;
1811 q0.y = p0->x;
1812 q1.x = p1->y;
1813 q1.y = p1->x;
1814 cc0 = c0;
1815 cc1 = c1;
1816 } else {
1817 q0.x = p1->y;
1818 q0.y = p1->x;
1819 q1.x = p0->y;
1820 q1.y = p0->x;
1821 cc0 = c1;
1822 cc1 = c0;
1823 }
1824 } else if (p0->y < p1->y) {
1825 q0 = *p0;
1826 q1 = *p1;
1827 cc0 = c0;
1828 cc1 = c1;
1829 } else {
1830 q0 = *p1;
1831 q1 = *p0;
1832 cc0 = c1;
1833 cc1 = c0;
1834 }
1835 le.start.x = q0.x - adjust;
1836 re.start.x = q0.x + adjust;
1837 le.start.y = re.start.y = q0.y - adjust;
1838 le.end.x = q1.x - adjust;
1839 re.end.x = q1.x + adjust;
1840 le.end.y = re.end.y = q1.y + adjust;
1841 adjust_swapped_boundary(&re.start.x, swap_axes);
1842 adjust_swapped_boundary(&re.end.x, swap_axes);
1843 return decompose_linear_color(pfs, &le, &re, le.start.y, le.end.y, swap_axes, cc0, cc1, 0);
1844 /* fixme : for a better performance and quality, we would like to
1845 consider the bar as an oriented one and to know at what side of it the spot resides.
1846 If we know that, we could expand only to outside the spot.
1847 Note that if the boundary has a self-intersection,
1848 we still need to expand to both directions.
1849 */
1850 }
1851
1852 private int
fill_wedges_aux(patch_fill_state_t * pfs,int k,int ka,const gs_fixed_point pole[4],const patch_color_t * c0,const patch_color_t * c1,int wedge_type)1853 fill_wedges_aux(patch_fill_state_t *pfs, int k, int ka,
1854 const gs_fixed_point pole[4], const patch_color_t *c0, const patch_color_t *c1,
1855 int wedge_type)
1856 {
1857 int code;
1858
1859 if (k > 1) {
1860 gs_fixed_point q[2][4];
1861 patch_color_t c;
1862
1863 patch_interpolate_color(&c, c0, c1, pfs, 0.5);
1864 split_curve(pole, q[0], q[1]);
1865 code = fill_wedges_aux(pfs, k / 2, ka, q[0], c0, &c, wedge_type);
1866 if (code < 0)
1867 return code;
1868 return fill_wedges_aux(pfs, k / 2, ka, q[1], &c, c1, wedge_type);
1869 } else {
1870 if (INTERPATCH_PADDING && (wedge_type & interpatch_padding)) {
1871 vd_bar(pole[0].x, pole[0].y, pole[3].x, pole[3].y, 0, RGB(255, 0, 0));
1872 code = mesh_padding(pfs, &pole[0], &pole[3], c0, c1);
1873 if (code < 0)
1874 return code;
1875 }
1876 if (ka >= 2 && (wedge_type & inpatch_wedge))
1877 return wedge_by_triangles(pfs, ka, pole, c0, c1);
1878 return 0;
1879 }
1880 }
1881
1882 private int
fill_wedges(patch_fill_state_t * pfs,int k0,int k1,const gs_fixed_point * pole,int pole_step,const patch_color_t * c0,const patch_color_t * c1,int wedge_type)1883 fill_wedges(patch_fill_state_t *pfs, int k0, int k1,
1884 const gs_fixed_point *pole, int pole_step,
1885 const patch_color_t *c0, const patch_color_t *c1, int wedge_type)
1886 {
1887 /* Generate wedges between 2 variants of a curve flattening. */
1888 /* k0, k1 is a power of 2. */
1889 gs_fixed_point p[4];
1890
1891 if (!(wedge_type & interpatch_padding) && k0 == k1)
1892 return 0; /* Wedges are zero area. */
1893 if (k0 > k1) {
1894 k0 ^= k1; k1 ^= k0; k0 ^= k1;
1895 }
1896 p[0] = pole[0];
1897 p[1] = pole[pole_step];
1898 p[2] = pole[pole_step * 2];
1899 p[3] = pole[pole_step * 3];
1900 return fill_wedges_aux(pfs, k0, k1 / k0, p, c0, c1, wedge_type);
1901 }
1902
1903 private inline void
make_vertices(gs_fixed_point q[4],const quadrangle_patch * p)1904 make_vertices(gs_fixed_point q[4], const quadrangle_patch *p)
1905 {
1906 q[0] = p->p[0][0]->p;
1907 q[1] = p->p[0][1]->p;
1908 q[2] = p->p[1][1]->p;
1909 q[3] = p->p[1][0]->p;
1910 }
1911
1912 private inline void
wrap_vertices_by_y(gs_fixed_point q[4],const gs_fixed_point s[4])1913 wrap_vertices_by_y(gs_fixed_point q[4], const gs_fixed_point s[4])
1914 {
1915 fixed y = s[0].y;
1916 int i = 0;
1917
1918 if (y > s[1].y)
1919 i = 1, y = s[1].y;
1920 if (y > s[2].y)
1921 i = 2, y = s[2].y;
1922 if (y > s[3].y)
1923 i = 3, y = s[3].y;
1924 q[0] = s[(i + 0) % 4];
1925 q[1] = s[(i + 1) % 4];
1926 q[2] = s[(i + 2) % 4];
1927 q[3] = s[(i + 3) % 4];
1928 }
1929
1930 private int
ordered_triangle(patch_fill_state_t * pfs,gs_fixed_edge * le,gs_fixed_edge * re,patch_color_t * c)1931 ordered_triangle(patch_fill_state_t *pfs, gs_fixed_edge *le, gs_fixed_edge *re, patch_color_t *c)
1932 {
1933 gs_fixed_edge ue;
1934 int code;
1935 gx_device_color dc;
1936 vd_save;
1937
1938 # if NOFILL_TEST
1939 if (dbg_nofill)
1940 return 0;
1941 # endif
1942 if (!VD_TRACE_DOWN)
1943 vd_disable;
1944 code = patch_color_to_device_color(pfs, c, &dc);
1945 if (code < 0)
1946 return code;
1947 if (le->end.y < re->end.y) {
1948 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1949 le, re, le->start.y, le->end.y, false, &dc, pfs->pis->log_op);
1950 if (code >= 0) {
1951 ue.start = le->end;
1952 ue.end = re->end;
1953 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1954 &ue, re, le->end.y, re->end.y, false, &dc, pfs->pis->log_op);
1955 }
1956 } else if (le->end.y > re->end.y) {
1957 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1958 le, re, le->start.y, re->end.y, false, &dc, pfs->pis->log_op);
1959 if (code >= 0) {
1960 ue.start = re->end;
1961 ue.end = le->end;
1962 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1963 le, &ue, re->end.y, le->end.y, false, &dc, pfs->pis->log_op);
1964 }
1965 } else
1966 code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1967 le, re, le->start.y, le->end.y, false, &dc, pfs->pis->log_op);
1968 vd_restore;
1969 return code;
1970 }
1971
1972 private int
constant_color_triangle(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2)1973 constant_color_triangle(patch_fill_state_t *pfs,
1974 const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2)
1975 {
1976 patch_color_t c, cc;
1977 gs_fixed_edge le, re;
1978 fixed dx0, dy0, dx1, dy1;
1979 const shading_vertex_t *pp;
1980 int i;
1981
1982 draw_triangle(&p0->p, &p1->p, &p2->p, RGB(255, 0, 0));
1983 patch_interpolate_color(&c, &p0->c, &p1->c, pfs, 0.5);
1984 patch_interpolate_color(&cc, &p2->c, &c, pfs, 0.5);
1985 for (i = 0; i < 3; i++) {
1986 /* fixme : does optimizer compiler expand this cycle ? */
1987 if (p0->p.y <= p1->p.y && p0->p.y <= p2->p.y) {
1988 le.start = re.start = p0->p;
1989 le.end = p1->p;
1990 re.end = p2->p;
1991
1992 dx0 = le.end.x - le.start.x;
1993 dy0 = le.end.y - le.start.y;
1994 dx1 = re.end.x - re.start.x;
1995 dy1 = re.end.y - re.start.y;
1996 if ((int64_t)dx0 * dy1 < (int64_t)dy0 * dx1)
1997 return ordered_triangle(pfs, &le, &re, &c);
1998 else
1999 return ordered_triangle(pfs, &re, &le, &c);
2000 }
2001 pp = p0; p0 = p1; p1 = p2; p2 = pp;
2002 }
2003 return 0;
2004 }
2005
2006
2007 private int
constant_color_quadrangle(patch_fill_state_t * pfs,const quadrangle_patch * p,bool self_intersecting)2008 constant_color_quadrangle(patch_fill_state_t *pfs, const quadrangle_patch *p, bool self_intersecting)
2009 {
2010 /* Assuming the XY span is restricted with curve_samples.
2011 It is important for intersection_of_small_bars to compute faster. */
2012 gs_fixed_point q[4];
2013 fixed ry, ey;
2014 int code;
2015 bool swap_axes = false;
2016 gx_device_color dc;
2017 patch_color_t c1, c2, c;
2018 bool orient;
2019
2020 draw_quadrangle(p, RGB(0, 255, 0));
2021 patch_interpolate_color(&c1, &p->p[0][0]->c, &p->p[0][1]->c, pfs, 0.5);
2022 patch_interpolate_color(&c2, &p->p[1][0]->c, &p->p[1][1]->c, pfs, 0.5);
2023 patch_interpolate_color(&c, &c1, &c2, pfs, 0.5);
2024 code = patch_color_to_device_color(pfs, &c, &dc);
2025 if (code < 0)
2026 return code;
2027 { gs_fixed_point qq[4];
2028
2029 make_vertices(qq, p);
2030 # if 0 /* Swapping axes may improve the precision,
2031 but slows down due to the area expantion needed
2032 in gx_shade_trapezoid. */
2033 dx = span_x(qq, 4);
2034 dy = span_y(qq, 4);
2035 if (dy < dx) {
2036 do_swap_axes(qq, 4);
2037 swap_axes = true;
2038 }
2039 # endif
2040 wrap_vertices_by_y(q, qq);
2041 }
2042 { fixed dx1 = q[1].x - q[0].x, dy1 = q[1].y - q[0].y;
2043 fixed dx3 = q[3].x - q[0].x, dy3 = q[3].y - q[0].y;
2044 int64_t g13 = (int64_t)dx1 * dy3, h13 = (int64_t)dy1 * dx3;
2045
2046 if (g13 == h13) {
2047 fixed dx2 = q[2].x - q[0].x, dy2 = q[2].y - q[0].y;
2048 int64_t g23 = (int64_t)dx2 * dy3, h23 = (int64_t)dy2 * dx3;
2049
2050 if (dx1 == 0 && dy1 == 0 && g23 == h23)
2051 return 0;
2052 if (g23 != h23) {
2053 orient = (g23 > h23);
2054 if (q[2].y <= q[3].y) {
2055 if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[2].y, swap_axes, &dc, orient)) < 0)
2056 return code;
2057 return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient);
2058 } else {
2059 if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[3].y, swap_axes, &dc, orient)) < 0)
2060 return code;
2061 return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient);
2062 }
2063 } else {
2064 int64_t g12 = (int64_t)dx1 * dy2, h12 = (int64_t)dy1 * dx2;
2065
2066 if (dx3 == 0 && dy3 == 0 && g12 == h12)
2067 return 0;
2068 orient = (g12 > h12);
2069 if (q[1].y <= q[2].y) {
2070 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0)
2071 return code;
2072 return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[1].y, q[2].y, swap_axes, &dc, orient);
2073 } else {
2074 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[0].y, q[2].y, swap_axes, &dc, orient)) < 0)
2075 return code;
2076 return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient);
2077 }
2078 }
2079 }
2080 orient = ((int64_t)dx1 * dy3 > (int64_t)dy1 * dx3);
2081 }
2082 if (q[1].y <= q[2].y && q[2].y <= q[3].y) {
2083 if (self_intersecting && intersection_of_small_bars(q, 0, 3, 1, 2, &ry, &ey)) {
2084 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0)
2085 return code;
2086 if ((code = gx_shade_trapezoid(pfs, q, 0, 3, 1, 2, q[1].y, ry + ey, swap_axes, &dc, orient)) < 0)
2087 return code;
2088 if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, ry, q[2].y, swap_axes, &dc, orient)) < 0)
2089 return code;
2090 return gx_shade_trapezoid(pfs, q, 0, 3, 2, 3, q[2].y, q[3].y, swap_axes, &dc, orient);
2091 } else {
2092 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0)
2093 return code;
2094 if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[2].y, swap_axes, &dc, orient)) < 0)
2095 return code;
2096 return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient);
2097 }
2098 } else if (q[1].y <= q[3].y && q[3].y <= q[2].y) {
2099 if (self_intersecting && intersection_of_small_bars(q, 0, 3, 1, 2, &ry, &ey)) {
2100 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0)
2101 return code;
2102 if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, ry + ey, swap_axes, &dc, orient)) < 0)
2103 return code;
2104 if ((code = gx_shade_trapezoid(pfs, q, 0, 3, 1, 2, ry, q[3].y, swap_axes, &dc, orient)) < 0)
2105 return code;
2106 return gx_shade_trapezoid(pfs, q, 3, 2, 1, 2, q[3].y, q[2].y, swap_axes, &dc, orient);
2107 } else {
2108 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0)
2109 return code;
2110 if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[3].y, swap_axes, &dc, orient)) < 0)
2111 return code;
2112 return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient);
2113 }
2114 } else if (q[2].y <= q[1].y && q[1].y <= q[3].y) {
2115 if (self_intersecting && intersection_of_small_bars(q, 0, 1, 2, 3, &ry, &ey)) {
2116 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0)
2117 return code;
2118 if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0)
2119 return code;
2120 if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 0, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0)
2121 return code;
2122 return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, ry, q[3].y, swap_axes, &dc, orient);
2123 } else if (self_intersecting && intersection_of_small_bars(q, 0, 3, 1, 2, &ry, &ey)) {
2124 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0)
2125 return code;
2126 if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0)
2127 return code;
2128 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0)
2129 return code;
2130 return gx_shade_trapezoid(pfs, q, 0, 3, 2, 3, ry, q[3].y, swap_axes, &dc, orient);
2131 } else {
2132 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0)
2133 return code;
2134 if ((code = gx_shade_trapezoid(pfs, q, 2, 3, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient)) < 0)
2135 return code;
2136 return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[1].y, q[3].y, swap_axes, &dc, orient);
2137 }
2138 } else if (q[2].y <= q[3].y && q[3].y <= q[1].y) {
2139 if (self_intersecting && intersection_of_small_bars(q, 0, 1, 2, 3, &ry, &ey)) {
2140 /* Same code as someone above. */
2141 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0)
2142 return code;
2143 if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0)
2144 return code;
2145 if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 0, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0)
2146 return code;
2147 return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, ry, q[3].y, swap_axes, &dc, orient);
2148 } else if (self_intersecting && intersection_of_small_bars(q, 0, 3, 2, 1, &ry, &ey)) {
2149 /* Same code as someone above. */
2150 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0)
2151 return code;
2152 if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0)
2153 return code;
2154 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0)
2155 return code;
2156 return gx_shade_trapezoid(pfs, q, 0, 3, 2, 3, ry, q[3].y, swap_axes, &dc, orient);
2157 } else {
2158 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[2].y, swap_axes, &dc, orient)) < 0)
2159 return code;
2160 if ((code = gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient)) < 0)
2161 return code;
2162 return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient);
2163 }
2164 } else if (q[3].y <= q[1].y && q[1].y <= q[2].y) {
2165 if (self_intersecting && intersection_of_small_bars(q, 0, 1, 3, 2, &ry, &ey)) {
2166 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0)
2167 return code;
2168 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, ry + ey, swap_axes, &dc, orient)) < 0)
2169 return code;
2170 if ((code = gx_shade_trapezoid(pfs, q, 3, 2, 0, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0)
2171 return code;
2172 return gx_shade_trapezoid(pfs, q, 3, 2, 1, 2, q[1].y, q[2].y, swap_axes, &dc, orient);
2173 } else {
2174 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0)
2175 return code;
2176 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, q[1].y, swap_axes, &dc, orient)) < 0)
2177 return code;
2178 return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[1].y, q[2].y, swap_axes, &dc, orient);
2179 }
2180 } else if (q[3].y <= q[2].y && q[2].y <= q[1].y) {
2181 if (self_intersecting && intersection_of_small_bars(q, 0, 1, 2, 3, &ry, &ey)) {
2182 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0)
2183 return code;
2184 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, ry + ey, swap_axes, &dc, orient)) < 0)
2185 return code;
2186 if ((code = gx_shade_trapezoid(pfs, q, 3, 2, 0, 1, ry, q[2].y, swap_axes, &dc, orient)) < 0)
2187 return code;
2188 return gx_shade_trapezoid(pfs, q, 2, 1, 0, 1, q[2].y, q[1].y, swap_axes, &dc, orient);
2189 } else {
2190 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0)
2191 return code;
2192 if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient)) < 0)
2193 return code;
2194 return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient);
2195 }
2196 } else {
2197 /* Impossible. */
2198 return_error(gs_error_unregistered);
2199 }
2200 }
2201
2202 private inline void
divide_quadrangle_by_v(patch_fill_state_t * pfs,quadrangle_patch * s0,quadrangle_patch * s1,shading_vertex_t q[2],const quadrangle_patch * p)2203 divide_quadrangle_by_v(patch_fill_state_t *pfs, quadrangle_patch *s0, quadrangle_patch *s1,
2204 shading_vertex_t q[2], const quadrangle_patch *p)
2205 {
2206 q[0].p.x = (p->p[0][0]->p.x + p->p[1][0]->p.x) / 2;
2207 q[1].p.x = (p->p[0][1]->p.x + p->p[1][1]->p.x) / 2;
2208 q[0].p.y = (p->p[0][0]->p.y + p->p[1][0]->p.y) / 2;
2209 q[1].p.y = (p->p[0][1]->p.y + p->p[1][1]->p.y) / 2;
2210 patch_interpolate_color(&q[0].c, &p->p[0][0]->c, &p->p[1][0]->c, pfs, 0.5);
2211 patch_interpolate_color(&q[1].c, &p->p[0][1]->c, &p->p[1][1]->c, pfs, 0.5);
2212 s0->p[0][0] = p->p[0][0];
2213 s0->p[0][1] = p->p[0][1];
2214 s0->p[1][0] = s1->p[0][0] = &q[0];
2215 s0->p[1][1] = s1->p[0][1] = &q[1];
2216 s1->p[1][0] = p->p[1][0];
2217 s1->p[1][1] = p->p[1][1];
2218 }
2219
2220 private inline void
divide_quadrangle_by_u(patch_fill_state_t * pfs,quadrangle_patch * s0,quadrangle_patch * s1,shading_vertex_t q[2],const quadrangle_patch * p)2221 divide_quadrangle_by_u(patch_fill_state_t *pfs, quadrangle_patch *s0, quadrangle_patch *s1,
2222 shading_vertex_t q[2], const quadrangle_patch *p)
2223 {
2224 q[0].p.x = (p->p[0][0]->p.x + p->p[0][1]->p.x) / 2;
2225 q[1].p.x = (p->p[1][0]->p.x + p->p[1][1]->p.x) / 2;
2226 q[0].p.y = (p->p[0][0]->p.y + p->p[0][1]->p.y) / 2;
2227 q[1].p.y = (p->p[1][0]->p.y + p->p[1][1]->p.y) / 2;
2228 patch_interpolate_color(&q[0].c, &p->p[0][0]->c, &p->p[0][1]->c, pfs, 0.5);
2229 patch_interpolate_color(&q[1].c, &p->p[1][0]->c, &p->p[1][1]->c, pfs, 0.5);
2230 s0->p[0][0] = p->p[0][0];
2231 s0->p[1][0] = p->p[1][0];
2232 s0->p[0][1] = s1->p[0][0] = &q[0];
2233 s0->p[1][1] = s1->p[1][0] = &q[1];
2234 s1->p[0][1] = p->p[0][1];
2235 s1->p[1][1] = p->p[1][1];
2236 }
2237
2238 private inline int
is_quadrangle_color_monotonic(const patch_fill_state_t * pfs,const quadrangle_patch * p,bool * not_monotonic_by_u,bool * not_monotonic_by_v)2239 is_quadrangle_color_monotonic(const patch_fill_state_t *pfs, const quadrangle_patch *p,
2240 bool *not_monotonic_by_u, bool *not_monotonic_by_v)
2241 { /* returns : 1 = monotonic, 0 = don't know, <0 = error. */
2242 int code;
2243
2244 code = isnt_color_monotonic(pfs, &p->p[0][0]->c, &p->p[1][1]->c);
2245 if (code <= 0)
2246 return code;
2247 if (code & 1)
2248 *not_monotonic_by_v = true;
2249 if (code & 2)
2250 *not_monotonic_by_u = true;
2251 return !code;
2252 }
2253
2254 private inline bool
quadrangle_bbox_covers_pixel_centers(const quadrangle_patch * p)2255 quadrangle_bbox_covers_pixel_centers(const quadrangle_patch *p)
2256 {
2257 fixed xbot, xtop, ybot, ytop;
2258
2259 xbot = min(min(p->p[0][0]->p.x, p->p[0][1]->p.x),
2260 min(p->p[1][0]->p.x, p->p[1][1]->p.x));
2261 xtop = max(max(p->p[0][0]->p.x, p->p[0][1]->p.x),
2262 max(p->p[1][0]->p.x, p->p[1][1]->p.x));
2263 if (covers_pixel_centers(xbot, xtop))
2264 return true;
2265 ybot = min(min(p->p[0][0]->p.y, p->p[0][1]->p.y),
2266 min(p->p[1][0]->p.y, p->p[1][1]->p.y));
2267 ytop = max(max(p->p[0][0]->p.y, p->p[0][1]->p.y),
2268 max(p->p[1][0]->p.y, p->p[1][1]->p.y));
2269 if (covers_pixel_centers(ybot, ytop))
2270 return true;
2271 return false;
2272 }
2273
2274 private inline void
divide_bar(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,int radix,shading_vertex_t * p)2275 divide_bar(patch_fill_state_t *pfs,
2276 const shading_vertex_t *p0, const shading_vertex_t *p1, int radix, shading_vertex_t *p)
2277 {
2278 p->p.x = (fixed)((int64_t)p0->p.x * (radix - 1) + p1->p.x) / radix;
2279 p->p.y = (fixed)((int64_t)p0->p.y * (radix - 1) + p1->p.y) / radix;
2280 patch_interpolate_color(&p->c, &p0->c, &p1->c, pfs, (double)(radix - 1) / radix);
2281 }
2282
2283 private inline void
bbox_of_points(gs_fixed_rect * r,const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2,const gs_fixed_point * p3)2284 bbox_of_points(gs_fixed_rect *r,
2285 const gs_fixed_point *p0, const gs_fixed_point *p1,
2286 const gs_fixed_point *p2, const gs_fixed_point *p3)
2287 {
2288 r->p.x = r->q.x = p0->x;
2289 r->p.y = r->q.y = p0->y;
2290
2291 if (r->p.x > p1->x)
2292 r->p.x = p1->x;
2293 if (r->q.x < p1->x)
2294 r->q.x = p1->x;
2295 if (r->p.y > p1->y)
2296 r->p.y = p1->y;
2297 if (r->q.y < p1->y)
2298 r->q.y = p1->y;
2299
2300 if (r->p.x > p2->x)
2301 r->p.x = p2->x;
2302 if (r->q.x < p2->x)
2303 r->q.x = p2->x;
2304 if (r->p.y > p2->y)
2305 r->p.y = p2->y;
2306 if (r->q.y < p2->y)
2307 r->q.y = p2->y;
2308
2309 if (p3 == NULL)
2310 return;
2311
2312 if (r->p.x > p3->x)
2313 r->p.x = p3->x;
2314 if (r->q.x < p3->x)
2315 r->q.x = p3->x;
2316 if (r->p.y > p3->y)
2317 r->p.y = p3->y;
2318 if (r->q.y < p3->y)
2319 r->q.y = p3->y;
2320 }
2321
2322 private int
triangle_by_4(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2,wedge_vertex_list_t * l01,wedge_vertex_list_t * l12,wedge_vertex_list_t * l20,double cd,fixed sd)2323 triangle_by_4(patch_fill_state_t *pfs,
2324 const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2,
2325 wedge_vertex_list_t *l01, wedge_vertex_list_t *l12, wedge_vertex_list_t *l20,
2326 double cd, fixed sd)
2327 {
2328 shading_vertex_t p01, p12, p20;
2329 wedge_vertex_list_t L01, L12, L20, L[3];
2330 bool inside_save = pfs->inside;
2331 gs_fixed_rect r, r1;
2332 int code;
2333
2334 if (!pfs->inside) {
2335 bbox_of_points(&r, &p0->p, &p1->p, &p2->p, NULL);
2336 r1 = r;
2337 rect_intersect(r, pfs->rect);
2338 if (r.q.x <= r.p.x || r.q.y <= r.p.y)
2339 return 0; /* Outside. */
2340 }
2341 code = try_device_linear_color(pfs, false, p0, p1, p2);
2342 switch(code) {
2343 case 0: /* The area is filled. */
2344 return 0;
2345 case 2: /* decompose to constant color areas */
2346 if (sd < fixed_1 * 4)
2347 return constant_color_triangle(pfs, p2, p0, p1);
2348 if (pfs->Function != NULL) {
2349 double d01 = color_span(pfs, &p1->c, &p0->c);
2350 double d12 = color_span(pfs, &p2->c, &p1->c);
2351 double d20 = color_span(pfs, &p0->c, &p2->c);
2352
2353 if (d01 <= pfs->smoothness / COLOR_CONTIGUITY &&
2354 d12 <= pfs->smoothness / COLOR_CONTIGUITY &&
2355 d20 <= pfs->smoothness / COLOR_CONTIGUITY)
2356 return constant_color_triangle(pfs, p2, p0, p1);
2357 } else if (cd <= pfs->smoothness / COLOR_CONTIGUITY)
2358 return constant_color_triangle(pfs, p2, p0, p1);
2359 break;
2360 case 1: /* decompose to linear color areas */
2361 if (sd < fixed_1)
2362 return constant_color_triangle(pfs, p2, p0, p1);
2363 break;
2364 default: /* Error. */
2365 return code;
2366 }
2367 if (!pfs->inside) {
2368 if (r.p.x == r1.p.x && r.p.y == r1.p.y &&
2369 r.q.x == r1.q.x && r.q.y == r1.q.y)
2370 pfs->inside = true;
2371 }
2372 divide_bar(pfs, p0, p1, 2, &p01);
2373 divide_bar(pfs, p1, p2, 2, &p12);
2374 divide_bar(pfs, p2, p0, 2, &p20);
2375 if (LAZY_WEDGES) {
2376 init_wedge_vertex_list(L, count_of(L));
2377 make_wedge_median(pfs, &L01, l01, true, &p0->p, &p1->p, &p01.p);
2378 make_wedge_median(pfs, &L12, l12, true, &p1->p, &p2->p, &p12.p);
2379 make_wedge_median(pfs, &L20, l20, false, &p2->p, &p0->p, &p20.p);
2380 } else {
2381 code = fill_triangle_wedge(pfs, p0, p1, &p01);
2382 if (code < 0)
2383 return code;
2384 code = fill_triangle_wedge(pfs, p1, p2, &p12);
2385 if (code < 0)
2386 return code;
2387 code = fill_triangle_wedge(pfs, p2, p0, &p20);
2388 if (code < 0)
2389 return code;
2390 }
2391 code = triangle_by_4(pfs, p0, &p01, &p20, &L01, &L[0], &L20, cd / 2, sd / 2);
2392 if (code < 0)
2393 return code;
2394 if (LAZY_WEDGES) {
2395 move_wedge(&L01, l01, true);
2396 move_wedge(&L20, l20, false);
2397 }
2398 code = triangle_by_4(pfs, p1, &p12, &p01, &L12, &L[1], &L01, cd / 2, sd / 2);
2399 if (code < 0)
2400 return code;
2401 if (LAZY_WEDGES)
2402 move_wedge(&L12, l12, true);
2403 code = triangle_by_4(pfs, p2, &p20, &p12, &L20, &L[2], &L12, cd / 2, sd / 2);
2404 if (code < 0)
2405 return code;
2406 L[0].last_side = L[1].last_side = L[2].last_side = true;
2407 code = triangle_by_4(pfs, &p01, &p12, &p20, &L[1], &L[2], &L[0], cd / 2, sd / 2);
2408 if (code < 0)
2409 return code;
2410 if (LAZY_WEDGES) {
2411 code = close_wedge_median(pfs, l01, &p0->c, &p1->c);
2412 if (code < 0)
2413 return code;
2414 code = close_wedge_median(pfs, l12, &p1->c, &p2->c);
2415 if (code < 0)
2416 return code;
2417 code = close_wedge_median(pfs, l20, &p2->c, &p0->c);
2418 if (code < 0)
2419 return code;
2420 code = terminate_wedge_vertex_list(pfs, &L[0], &p01.c, &p20.c);
2421 if (code < 0)
2422 return code;
2423 code = terminate_wedge_vertex_list(pfs, &L[1], &p12.c, &p01.c);
2424 if (code < 0)
2425 return code;
2426 code = terminate_wedge_vertex_list(pfs, &L[2], &p20.c, &p12.c);
2427 if (code < 0)
2428 return code;
2429 }
2430 pfs->inside = inside_save;
2431 return 0;
2432 }
2433
2434 private inline int
fill_triangle(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2,wedge_vertex_list_t * l01,wedge_vertex_list_t * l12,wedge_vertex_list_t * l20)2435 fill_triangle(patch_fill_state_t *pfs,
2436 const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2,
2437 wedge_vertex_list_t *l01, wedge_vertex_list_t *l12, wedge_vertex_list_t *l20)
2438 {
2439 fixed sd01 = max(any_abs(p1->p.x - p0->p.x), any_abs(p1->p.y - p0->p.y));
2440 fixed sd12 = max(any_abs(p2->p.x - p1->p.x), any_abs(p2->p.y - p1->p.y));
2441 fixed sd20 = max(any_abs(p0->p.x - p2->p.x), any_abs(p0->p.y - p2->p.y));
2442 fixed sd1 = max(sd01, sd12);
2443 fixed sd = max(sd1, sd20);
2444 double cd = 0;
2445
2446 # if SKIP_TEST
2447 dbg_triangle_cnt++;
2448 # endif
2449 if (pfs->Function == NULL) {
2450 double d01 = color_span(pfs, &p1->c, &p0->c);
2451 double d12 = color_span(pfs, &p2->c, &p1->c);
2452 double d20 = color_span(pfs, &p0->c, &p2->c);
2453 double cd1 = max(d01, d12);
2454
2455 cd = max(cd1, d20);
2456 }
2457 return triangle_by_4(pfs, p0, p1, p2, l01, l12, l20, cd, sd);
2458 }
2459
2460 private int
small_mesh_triangle(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2)2461 small_mesh_triangle(patch_fill_state_t *pfs,
2462 const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2)
2463 {
2464 int code;
2465 wedge_vertex_list_t l[3];
2466
2467 init_wedge_vertex_list(l, count_of(l));
2468 code = fill_triangle(pfs, p0, p1, p2, &l[0], &l[1], &l[2]);
2469 if (code < 0)
2470 return code;
2471 code = terminate_wedge_vertex_list(pfs, &l[0], &p0->c, &p1->c);
2472 if (code < 0)
2473 return code;
2474 code = terminate_wedge_vertex_list(pfs, &l[1], &p1->c, &p2->c);
2475 if (code < 0)
2476 return code;
2477 return terminate_wedge_vertex_list(pfs, &l[2], &p2->c, &p0->c);
2478 }
2479
2480 private int
mesh_triangle_rec(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2)2481 mesh_triangle_rec(patch_fill_state_t *pfs,
2482 const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2)
2483 {
2484 pfs->unlinear = !is_linear_color_applicable(pfs);
2485 if (manhattan_dist(&p0->p, &p1->p) < pfs->max_small_coord &&
2486 manhattan_dist(&p1->p, &p2->p) < pfs->max_small_coord &&
2487 manhattan_dist(&p2->p, &p0->p) < pfs->max_small_coord)
2488 return small_mesh_triangle(pfs, p0, p1, p2);
2489 else {
2490 /* Subdivide into 4 triangles with 3 triangle non-lazy wedges.
2491 Doing so against the wedge_vertex_list_elem_buffer overflow.
2492 We could apply a smarter method, dividing long sides
2493 with no wedges and short sides with lazy wedges.
2494 This needs to start wedges dynamically when
2495 a side becomes short. We don't do so because the
2496 number of checks per call significantly increases
2497 and the logics is complicated, but the performance
2498 advantage appears small due to big meshes are rare.
2499 */
2500 shading_vertex_t p01, p12, p20;
2501 int code;
2502
2503 divide_bar(pfs, p0, p1, 2, &p01);
2504 divide_bar(pfs, p1, p2, 2, &p12);
2505 divide_bar(pfs, p2, p0, 2, &p20);
2506 code = fill_triangle_wedge(pfs, p0, p1, &p01);
2507 if (code < 0)
2508 return code;
2509 code = fill_triangle_wedge(pfs, p1, p2, &p12);
2510 if (code < 0)
2511 return code;
2512 code = fill_triangle_wedge(pfs, p2, p0, &p20);
2513 if (code < 0)
2514 return code;
2515 code = mesh_triangle_rec(pfs, p0, &p01, &p20);
2516 if (code < 0)
2517 return code;
2518 code = mesh_triangle_rec(pfs, p1, &p12, &p01);
2519 if (code < 0)
2520 return code;
2521 code = mesh_triangle_rec(pfs, p2, &p20, &p12);
2522 if (code < 0)
2523 return code;
2524 return mesh_triangle_rec(pfs, &p01, &p12, &p20);
2525 }
2526 }
2527
2528 int
mesh_triangle(patch_fill_state_t * pfs,const shading_vertex_t * p0,const shading_vertex_t * p1,const shading_vertex_t * p2)2529 mesh_triangle(patch_fill_state_t *pfs,
2530 const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2)
2531 {
2532 if ((*dev_proc(pfs->dev, pattern_manage))(pfs->dev,
2533 gs_no_id, NULL, pattern_manage__shading_area) > 0) {
2534 /* Inform the device with the shading coverage area.
2535 First compute the sign of the area, because
2536 all areas to be clipped in same direction. */
2537 gx_device *pdev = pfs->dev;
2538 gx_path path;
2539 int code;
2540 fixed d01x = p1->p.x - p0->p.x, d01y = p1->p.y - p0->p.y;
2541 fixed d12x = p2->p.x - p1->p.x, d12y = p2->p.y - p1->p.y;
2542 int64_t s1 = (int64_t)d01x * d12y - (int64_t)d01y * d12x;
2543
2544 gx_path_init_local(&path, pdev->memory);
2545 code = gx_path_add_point(&path, p0->p.x, p0->p.y);
2546 if (code >= 0 && s1 >= 0)
2547 code = gx_path_add_line(&path, p1->p.x, p1->p.y);
2548 if (code >= 0)
2549 code = gx_path_add_line(&path, p2->p.x, p2->p.y);
2550 if (code >= 0 && s1 < 0)
2551 code = gx_path_add_line(&path, p1->p.x, p1->p.y);
2552 if (code >= 0)
2553 code = gx_path_close_subpath(&path);
2554 if (code >= 0)
2555 code = (*dev_proc(pfs->dev, fill_path))(pdev, NULL, &path, NULL, NULL, NULL);
2556 gx_path_free(&path, "mesh_triangle");
2557 if (code < 0)
2558 return code;
2559 }
2560 return mesh_triangle_rec(pfs, p0, p1, p2);
2561 }
2562
2563 private inline int
triangles4(patch_fill_state_t * pfs,const quadrangle_patch * p,bool dummy_argument)2564 triangles4(patch_fill_state_t *pfs, const quadrangle_patch *p, bool dummy_argument)
2565 {
2566 shading_vertex_t p0001, p1011, q;
2567 wedge_vertex_list_t l[4];
2568 int code;
2569
2570 init_wedge_vertex_list(l, count_of(l));
2571 divide_bar(pfs, p->p[0][0], p->p[0][1], 2, &p0001);
2572 divide_bar(pfs, p->p[1][0], p->p[1][1], 2, &p1011);
2573 divide_bar(pfs, &p0001, &p1011, 2, &q);
2574 code = fill_triangle(pfs, p->p[0][0], p->p[0][1], &q, p->l0001, &l[0], &l[3]);
2575 if (code < 0)
2576 return code;
2577 l[0].last_side = true;
2578 l[3].last_side = true;
2579 code = fill_triangle(pfs, p->p[0][1], p->p[1][1], &q, p->l0111, &l[1], &l[0]);
2580 if (code < 0)
2581 return code;
2582 l[1].last_side = true;
2583 code = fill_triangle(pfs, p->p[1][1], p->p[1][0], &q, p->l1110, &l[2], &l[1]);
2584 if (code < 0)
2585 return code;
2586 l[2].last_side = true;
2587 code = fill_triangle(pfs, p->p[1][0], p->p[0][0], &q, p->l1000, &l[3], &l[2]);
2588 if (code < 0)
2589 return code;
2590 code = terminate_wedge_vertex_list(pfs, &l[0], &p->p[0][1]->c, &q.c);
2591 if (code < 0)
2592 return code;
2593 code = terminate_wedge_vertex_list(pfs, &l[1], &p->p[1][1]->c, &q.c);
2594 if (code < 0)
2595 return code;
2596 code = terminate_wedge_vertex_list(pfs, &l[2], &p->p[1][0]->c, &q.c);
2597 if (code < 0)
2598 return code;
2599 code = terminate_wedge_vertex_list(pfs, &l[3], &q.c, &p->p[0][0]->c);
2600 if (code < 0)
2601 return code;
2602 return 0;
2603 }
2604
2605 private inline int
triangles2(patch_fill_state_t * pfs,const quadrangle_patch * p,bool dummy_argument)2606 triangles2(patch_fill_state_t *pfs, const quadrangle_patch *p, bool dummy_argument)
2607 {
2608 wedge_vertex_list_t l;
2609 int code;
2610
2611 init_wedge_vertex_list(&l, 1);
2612 code = fill_triangle(pfs, p->p[0][0], p->p[0][1], p->p[1][1], p->l0001, p->l0111, &l);
2613 if (code < 0)
2614 return code;
2615 l.last_side = true;
2616 code = fill_triangle(pfs, p->p[1][1], p->p[1][0], p->p[0][0], p->l1110, p->l1000, &l);
2617 if (code < 0)
2618 return code;
2619 code = terminate_wedge_vertex_list(pfs, &l, &p->p[1][1]->c, &p->p[0][0]->c);
2620 if (code < 0)
2621 return code;
2622 return 0;
2623 }
2624
2625 private inline void
make_quadrangle(const tensor_patch * p,shading_vertex_t qq[2][2],wedge_vertex_list_t l[4],quadrangle_patch * q)2626 make_quadrangle(const tensor_patch *p, shading_vertex_t qq[2][2],
2627 wedge_vertex_list_t l[4], quadrangle_patch *q)
2628 {
2629 qq[0][0].p = p->pole[0][0];
2630 qq[0][1].p = p->pole[0][3];
2631 qq[1][0].p = p->pole[3][0];
2632 qq[1][1].p = p->pole[3][3];
2633 qq[0][0].c = p->c[0][0];
2634 qq[0][1].c = p->c[0][1];
2635 qq[1][0].c = p->c[1][0];
2636 qq[1][1].c = p->c[1][1];
2637 q->p[0][0] = &qq[0][0];
2638 q->p[0][1] = &qq[0][1];
2639 q->p[1][0] = &qq[1][0];
2640 q->p[1][1] = &qq[1][1];
2641 q->l0001 = &l[0];
2642 q->l0111 = &l[1];
2643 q->l1110 = &l[2];
2644 q->l1000 = &l[3];
2645 }
2646
2647 private inline int
is_quadrangle_color_linear_by_u(const patch_fill_state_t * pfs,const quadrangle_patch * p)2648 is_quadrangle_color_linear_by_u(const patch_fill_state_t *pfs, const quadrangle_patch *p)
2649 { /* returns : 1 = linear, 0 = unlinear, <0 = error. */
2650 int code;
2651
2652 code = is_color_linear(pfs, &p->p[0][0]->c, &p->p[0][1]->c);
2653 if (code <= 0)
2654 return code;
2655 return is_color_linear(pfs, &p->p[1][0]->c, &p->p[1][1]->c);
2656 }
2657
2658 private inline int
is_quadrangle_color_linear_by_v(const patch_fill_state_t * pfs,const quadrangle_patch * p)2659 is_quadrangle_color_linear_by_v(const patch_fill_state_t *pfs, const quadrangle_patch *p)
2660 { /* returns : 1 = linear, 0 = unlinear, <0 = error. */
2661 int code;
2662
2663 code = is_color_linear(pfs, &p->p[0][0]->c, &p->p[1][0]->c);
2664 if (code <= 0)
2665 return code;
2666 return is_color_linear(pfs, &p->p[0][1]->c, &p->p[1][1]->c);
2667 }
2668
2669 private inline int
is_quadrangle_color_linear_by_diagonals(const patch_fill_state_t * pfs,const quadrangle_patch * p)2670 is_quadrangle_color_linear_by_diagonals(const patch_fill_state_t *pfs, const quadrangle_patch *p)
2671 { /* returns : 1 = linear, 0 = unlinear, <0 = error. */
2672 int code;
2673
2674 code = is_color_linear(pfs, &p->p[0][0]->c, &p->p[1][1]->c);
2675 if (code <= 0)
2676 return code;
2677 return is_color_linear(pfs, &p->p[0][1]->c, &p->p[1][0]->c);
2678 }
2679
2680 typedef enum {
2681 color_change_small,
2682 color_change_gradient,
2683 color_change_linear,
2684 color_change_bilinear,
2685 color_change_general
2686 } color_change_type_t;
2687
2688 private inline color_change_type_t
quadrangle_color_change(const patch_fill_state_t * pfs,const quadrangle_patch * p,bool is_big_u,bool is_big_v,bool * divide_u,bool * divide_v)2689 quadrangle_color_change(const patch_fill_state_t *pfs, const quadrangle_patch *p,
2690 bool is_big_u, bool is_big_v, bool *divide_u, bool *divide_v)
2691 {
2692 patch_color_t d0001, d1011, d;
2693 double D, D0001, D1011, D0010, D0111, D0011, D0110;
2694 double Du, Dv;
2695
2696 color_diff(pfs, &p->p[0][0]->c, &p->p[0][1]->c, &d0001);
2697 color_diff(pfs, &p->p[1][0]->c, &p->p[1][1]->c, &d1011);
2698 D0001 = color_norm(pfs, &d0001);
2699 D1011 = color_norm(pfs, &d1011);
2700 D0010 = color_span(pfs, &p->p[0][0]->c, &p->p[1][0]->c);
2701 D0111 = color_span(pfs, &p->p[0][1]->c, &p->p[1][1]->c);
2702 D0011 = color_span(pfs, &p->p[0][0]->c, &p->p[1][1]->c);
2703 D0110 = color_span(pfs, &p->p[0][1]->c, &p->p[1][0]->c);
2704 if (pfs->unlinear) {
2705 if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness &&
2706 D0010 <= pfs->smoothness && D0111 <= pfs->smoothness &&
2707 D0011 <= pfs->smoothness && D0110 <= pfs->smoothness)
2708 return color_change_small;
2709 if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness) {
2710 if (!is_big_v) {
2711 /* The color function looks uncontiguous. */
2712 return color_change_small;
2713 }
2714 *divide_v = true;
2715 return color_change_gradient;
2716 }
2717 if (D0010 <= pfs->smoothness && D0111 <= pfs->smoothness) {
2718 if (!is_big_u) {
2719 /* The color function looks uncontiguous. */
2720 return color_change_small;
2721 }
2722 *divide_u = true;
2723 return color_change_gradient;
2724 }
2725 }
2726 color_diff(pfs, &d0001, &d1011, &d);
2727 Du = max(D0001, D1011);
2728 Dv = max(D0010, D0111);
2729 if (Du <= pfs->smoothness / 8 && Dv <= pfs->smoothness / 8)
2730 return color_change_small;
2731 if (Du <= pfs->smoothness / 8)
2732 return color_change_linear;
2733 if (Dv <= pfs->smoothness / 8)
2734 return color_change_linear;
2735 D = color_norm(pfs, &d);
2736 if (D <= pfs->smoothness)
2737 return color_change_bilinear;
2738 #if 0 /* Disabled due to a 0.5% slowdown with the test file of the Bug 687948. */
2739 if (Du > Dv && is_big_u)
2740 *divide_u = true;
2741 else if (Du < Dv && is_big_v)
2742 *divide_v = true;
2743 else if (is_big_u)
2744 *divide_u = true;
2745 else if (is_big_v)
2746 *divide_v = true;
2747 else {
2748 /* The color function looks uncontiguous. */
2749 return color_change_small;
2750 }
2751 #else
2752 if (Du > Dv)
2753 *divide_u = true;
2754 else
2755 *divide_v = true;
2756 #endif
2757 return color_change_general;
2758 }
2759
2760 private int
fill_quadrangle(patch_fill_state_t * pfs,const quadrangle_patch * p,bool big,int level)2761 fill_quadrangle(patch_fill_state_t *pfs, const quadrangle_patch *p, bool big, int level)
2762 {
2763 /* The quadrangle is flattened enough by V and U, so ignore inner poles. */
2764 /* Assuming the XY span is restricted with curve_samples.
2765 It is important for intersection_of_small_bars to compute faster. */
2766 quadrangle_patch s0, s1;
2767 wedge_vertex_list_t l0, l1, l2;
2768 int code;
2769 bool divide_u = false, divide_v = false, big1 = big;
2770 shading_vertex_t q[2];
2771 bool monotonic_color_save = pfs->monotonic_color;
2772 bool linear_color_save = pfs->linear_color;
2773 bool inside_save = pfs->inside;
2774 gs_fixed_rect r, r1;
2775 /* Warning : pfs->monotonic_color is not restored on error. */
2776
2777 if (level > 100)
2778 return_error(gs_error_unregistered); /* Safety. */
2779 if (!pfs->inside) {
2780 bbox_of_points(&r, &p->p[0][0]->p, &p->p[0][1]->p, &p->p[1][0]->p, &p->p[1][1]->p);
2781 r1 = r;
2782 rect_intersect(r, pfs->rect);
2783 if (r.q.x <= r.p.x || r.q.y <= r.p.y)
2784 return 0; /* Outside. */
2785 }
2786 if (big) {
2787 /* Likely 'big' is an unuseful rudiment due to curve_samples
2788 restricts lengthes. We keep it for a while because its implementation
2789 isn't obvious and its time consumption is invisibly small.
2790 */
2791 fixed size_u = max(max(any_abs(p->p[0][0]->p.x - p->p[0][1]->p.x),
2792 any_abs(p->p[1][0]->p.x - p->p[1][1]->p.x)),
2793 max(any_abs(p->p[0][0]->p.y - p->p[0][1]->p.y),
2794 any_abs(p->p[1][0]->p.y - p->p[1][1]->p.y)));
2795 fixed size_v = max(max(any_abs(p->p[0][0]->p.x - p->p[1][0]->p.x),
2796 any_abs(p->p[0][1]->p.x - p->p[1][1]->p.x)),
2797 max(any_abs(p->p[0][0]->p.y - p->p[1][0]->p.y),
2798 any_abs(p->p[0][1]->p.y - p->p[1][1]->p.y)));
2799
2800 if (QUADRANGLES && pfs->maybe_self_intersecting) {
2801 if (size_v > pfs->max_small_coord) {
2802 /* constant_color_quadrangle can't handle big self-intersecting areas
2803 because we don't want int64_t in it. */
2804 divide_v = true;
2805 } else if (size_u > pfs->max_small_coord) {
2806 /* constant_color_quadrangle can't handle big self-intersecting areas,
2807 because we don't want int64_t in it. */
2808 divide_u = true;
2809 } else
2810 big1 = false;
2811 } else
2812 big1 = false;
2813 }
2814 if (!big1) {
2815 bool is_big_u = false, is_big_v = false;
2816 double d0001x = any_abs(p->p[0][0]->p.x - p->p[0][1]->p.x);
2817 double d1011x = any_abs(p->p[1][0]->p.x - p->p[1][1]->p.x);
2818 double d0001y = any_abs(p->p[0][0]->p.y - p->p[0][1]->p.y);
2819 double d1011y = any_abs(p->p[1][0]->p.y - p->p[1][1]->p.y);
2820 double d0010x = any_abs(p->p[0][0]->p.x - p->p[1][0]->p.x);
2821 double d0111x = any_abs(p->p[0][1]->p.x - p->p[1][1]->p.x);
2822 double d0010y = any_abs(p->p[0][0]->p.y - p->p[1][0]->p.y);
2823 double d0111y = any_abs(p->p[0][1]->p.y - p->p[1][1]->p.y);
2824
2825 if (d0001x > fixed_1 || d1011x > fixed_1 || d0001y > fixed_1 || d1011y > fixed_1)
2826 is_big_u = true;
2827 if (d0010x > fixed_1 || d0111x > fixed_1 || d0010y > fixed_1 || d0111y > fixed_1)
2828 is_big_v = true;
2829 else if (!is_big_u)
2830 return (QUADRANGLES || !pfs->maybe_self_intersecting ?
2831 constant_color_quadrangle : triangles4)(pfs, p,
2832 pfs->maybe_self_intersecting);
2833 if (!pfs->monotonic_color) {
2834 bool not_monotonic_by_u = false, not_monotonic_by_v = false;
2835
2836 code = is_quadrangle_color_monotonic(pfs, p, ¬_monotonic_by_u, ¬_monotonic_by_v);
2837 if (code < 0)
2838 return code;
2839 if (is_big_u)
2840 divide_u = not_monotonic_by_u;
2841 if (is_big_v)
2842 divide_v = not_monotonic_by_v;
2843 if (!divide_u && !divide_v)
2844 pfs->monotonic_color = true;
2845 }
2846 if (pfs->monotonic_color && !pfs->linear_color) {
2847 if (divide_v && divide_u) {
2848 if (d0001x + d1011x + d0001y + d1011y > d0010x + d0111x + d0010y + d0111y)
2849 divide_v = false;
2850 else
2851 divide_u = false;
2852 } else if (!divide_u && !divide_v && !pfs->unlinear) {
2853 if (is_big_u) {
2854 code = is_quadrangle_color_linear_by_u(pfs, p);
2855 if (code < 0)
2856 return code;
2857 divide_u = !code;
2858 }
2859 if (is_big_v) {
2860 code = is_quadrangle_color_linear_by_v(pfs, p);
2861 if (code < 0)
2862 return code;
2863 divide_v = !code;
2864 }
2865 if (is_big_u && is_big_v) {
2866 code = is_quadrangle_color_linear_by_diagonals(pfs, p);
2867 if (code < 0)
2868 return code;
2869 if (!code) {
2870 if (d0001x + d1011x + d0001y + d1011y > d0010x + d0111x + d0010y + d0111y) {
2871 divide_u = true;
2872 divide_v = false;
2873 } else {
2874 divide_v = true;
2875 divide_u = false;
2876 }
2877 }
2878 }
2879 }
2880 if (!divide_u && !divide_v)
2881 pfs->linear_color = true;
2882 }
2883 if (!pfs->linear_color) {
2884 /* go to divide. */
2885 } else switch(quadrangle_color_change(pfs, p, is_big_u, is_big_v, ÷_u, ÷_v)) {
2886 case color_change_small:
2887 code = (QUADRANGLES || !pfs->maybe_self_intersecting ?
2888 constant_color_quadrangle : triangles4)(pfs, p,
2889 pfs->maybe_self_intersecting);
2890 pfs->monotonic_color = monotonic_color_save;
2891 pfs->linear_color = linear_color_save;
2892 return code;
2893 case color_change_bilinear:
2894 if (!QUADRANGLES) {
2895 code = triangles4(pfs, p, true);
2896 pfs->monotonic_color = monotonic_color_save;
2897 pfs->linear_color = linear_color_save;
2898 return code;
2899 }
2900 case color_change_linear:
2901 if (!QUADRANGLES) {
2902 code = triangles2(pfs, p, true);
2903 pfs->monotonic_color = monotonic_color_save;
2904 pfs->linear_color = linear_color_save;
2905 return code;
2906 }
2907 case color_change_gradient:
2908 case color_change_general:
2909 ; /* goto divide. */
2910 }
2911 }
2912 if (!pfs->inside) {
2913 if (r.p.x == r1.p.x && r.p.y == r1.p.y &&
2914 r.q.x == r1.q.x && r.q.y == r1.q.y)
2915 pfs->inside = true;
2916 }
2917 if (LAZY_WEDGES)
2918 init_wedge_vertex_list(&l0, 1);
2919 if (divide_v) {
2920 divide_quadrangle_by_v(pfs, &s0, &s1, q, p);
2921 if (LAZY_WEDGES) {
2922 make_wedge_median(pfs, &l1, p->l0111, true, &p->p[0][1]->p, &p->p[1][1]->p, &s0.p[1][1]->p);
2923 make_wedge_median(pfs, &l2, p->l1000, false, &p->p[1][0]->p, &p->p[0][0]->p, &s0.p[1][0]->p);
2924 s0.l1110 = s1.l0001 = &l0;
2925 s0.l0111 = s1.l0111 = &l1;
2926 s0.l1000 = s1.l1000 = &l2;
2927 s0.l0001 = p->l0001;
2928 s1.l1110 = p->l1110;
2929 } else {
2930 code = fill_triangle_wedge(pfs, s0.p[0][0], s1.p[1][0], s0.p[1][0]);
2931 if (code < 0)
2932 return code;
2933 code = fill_triangle_wedge(pfs, s0.p[0][1], s1.p[1][1], s0.p[1][1]);
2934 if (code < 0)
2935 return code;
2936 }
2937 code = fill_quadrangle(pfs, &s0, big, level + 1);
2938 if (code < 0)
2939 return code;
2940 if (LAZY_WEDGES) {
2941 l0.last_side = true;
2942 move_wedge(&l1, p->l0111, true);
2943 move_wedge(&l2, p->l1000, false);
2944 }
2945 code = fill_quadrangle(pfs, &s1, big1, level + 1);
2946 if (LAZY_WEDGES) {
2947 if (code < 0)
2948 return code;
2949 code = close_wedge_median(pfs, p->l0111, &p->p[0][1]->c, &p->p[1][1]->c);
2950 if (code < 0)
2951 return code;
2952 code = close_wedge_median(pfs, p->l1000, &p->p[1][0]->c, &p->p[0][0]->c);
2953 if (code < 0)
2954 return code;
2955 code = terminate_wedge_vertex_list(pfs, &l0, &s0.p[1][0]->c, &s0.p[1][1]->c);
2956 }
2957 } else if (divide_u) {
2958 divide_quadrangle_by_u(pfs, &s0, &s1, q, p);
2959 if (LAZY_WEDGES) {
2960 make_wedge_median(pfs, &l1, p->l0001, true, &p->p[0][0]->p, &p->p[0][1]->p, &s0.p[0][1]->p);
2961 make_wedge_median(pfs, &l2, p->l1110, false, &p->p[1][1]->p, &p->p[1][0]->p, &s0.p[1][1]->p);
2962 s0.l0111 = s1.l1000 = &l0;
2963 s0.l0001 = s1.l0001 = &l1;
2964 s0.l1110 = s1.l1110 = &l2;
2965 s0.l1000 = p->l1000;
2966 s1.l0111 = p->l0111;
2967 } else {
2968 code = fill_triangle_wedge(pfs, s0.p[0][0], s1.p[0][1], s0.p[0][1]);
2969 if (code < 0)
2970 return code;
2971 code = fill_triangle_wedge(pfs, s0.p[1][0], s1.p[1][1], s0.p[1][1]);
2972 if (code < 0)
2973 return code;
2974 }
2975 code = fill_quadrangle(pfs, &s0, big1, level + 1);
2976 if (code < 0)
2977 return code;
2978 if (LAZY_WEDGES) {
2979 l0.last_side = true;
2980 move_wedge(&l1, p->l0001, true);
2981 move_wedge(&l2, p->l1110, false);
2982 }
2983 code = fill_quadrangle(pfs, &s1, big1, level + 1);
2984 if (LAZY_WEDGES) {
2985 if (code < 0)
2986 return code;
2987 code = close_wedge_median(pfs, p->l0001, &p->p[0][0]->c, &p->p[0][1]->c);
2988 if (code < 0)
2989 return code;
2990 code = close_wedge_median(pfs, p->l1110, &p->p[1][1]->c, &p->p[1][0]->c);
2991 if (code < 0)
2992 return code;
2993 code = terminate_wedge_vertex_list(pfs, &l0, &s0.p[0][1]->c, &s0.p[1][1]->c);
2994 }
2995 } else
2996 code = (QUADRANGLES || !pfs->maybe_self_intersecting ?
2997 constant_color_quadrangle : triangles4)(pfs, p,
2998 pfs->maybe_self_intersecting);
2999 pfs->monotonic_color = monotonic_color_save;
3000 pfs->linear_color = linear_color_save;
3001 pfs->inside = inside_save;
3002 return code;
3003 }
3004
3005
3006
3007 private inline void
split_stripe(patch_fill_state_t * pfs,tensor_patch * s0,tensor_patch * s1,const tensor_patch * p)3008 split_stripe(patch_fill_state_t *pfs, tensor_patch *s0, tensor_patch *s1, const tensor_patch *p)
3009 {
3010 split_curve_s(p->pole[0], s0->pole[0], s1->pole[0], 1);
3011 split_curve_s(p->pole[1], s0->pole[1], s1->pole[1], 1);
3012 split_curve_s(p->pole[2], s0->pole[2], s1->pole[2], 1);
3013 split_curve_s(p->pole[3], s0->pole[3], s1->pole[3], 1);
3014 s0->c[0][0] = p->c[0][0];
3015 s0->c[1][0] = p->c[1][0];
3016 patch_interpolate_color(&s0->c[0][1], &p->c[0][0], &p->c[0][1], pfs, 0.5);
3017 patch_interpolate_color(&s0->c[1][1], &p->c[1][0], &p->c[1][1], pfs, 0.5);
3018 s1->c[0][0] = s0->c[0][1];
3019 s1->c[1][0] = s0->c[1][1];
3020 s1->c[0][1] = p->c[0][1];
3021 s1->c[1][1] = p->c[1][1];
3022 }
3023
3024 private inline void
split_patch(patch_fill_state_t * pfs,tensor_patch * s0,tensor_patch * s1,const tensor_patch * p)3025 split_patch(patch_fill_state_t *pfs, tensor_patch *s0, tensor_patch *s1, const tensor_patch *p)
3026 {
3027 split_curve_s(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4);
3028 split_curve_s(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4);
3029 split_curve_s(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4);
3030 split_curve_s(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4);
3031 s0->c[0][0] = p->c[0][0];
3032 s0->c[0][1] = p->c[0][1];
3033 patch_interpolate_color(&s0->c[1][0], &p->c[0][0], &p->c[1][0], pfs, 0.5);
3034 patch_interpolate_color(&s0->c[1][1], &p->c[0][1], &p->c[1][1], pfs, 0.5);
3035 s1->c[0][0] = s0->c[1][0];
3036 s1->c[0][1] = s0->c[1][1];
3037 s1->c[1][0] = p->c[1][0];
3038 s1->c[1][1] = p->c[1][1];
3039 }
3040
3041 private int
decompose_stripe(patch_fill_state_t * pfs,const tensor_patch * p,int ku)3042 decompose_stripe(patch_fill_state_t *pfs, const tensor_patch *p, int ku)
3043 {
3044 if (ku > 1) {
3045 tensor_patch s0, s1;
3046 int code;
3047
3048 split_stripe(pfs, &s0, &s1, p);
3049 if (0) { /* Debug purpose only. */
3050 draw_patch(&s0, true, RGB(0, 128, 128));
3051 draw_patch(&s1, true, RGB(0, 128, 128));
3052 }
3053 code = decompose_stripe(pfs, &s0, ku / 2);
3054 if (code < 0)
3055 return code;
3056 return decompose_stripe(pfs, &s1, ku / 2);
3057 } else {
3058 quadrangle_patch q;
3059 shading_vertex_t qq[2][2];
3060 wedge_vertex_list_t l[4];
3061 int code;
3062
3063 init_wedge_vertex_list(l, count_of(l));
3064 make_quadrangle(p, qq, l, &q);
3065 # if SKIP_TEST
3066 dbg_quad_cnt++;
3067 # endif
3068 code = fill_quadrangle(pfs, &q, true, 0);
3069 if (LAZY_WEDGES) {
3070 code = terminate_wedge_vertex_list(pfs, &l[0], &q.p[0][0]->c, &q.p[0][1]->c);
3071 if (code < 0)
3072 return code;
3073 code = terminate_wedge_vertex_list(pfs, &l[1], &q.p[0][1]->c, &q.p[1][1]->c);
3074 if (code < 0)
3075 return code;
3076 code = terminate_wedge_vertex_list(pfs, &l[2], &q.p[1][1]->c, &q.p[1][0]->c);
3077 if (code < 0)
3078 return code;
3079 code = terminate_wedge_vertex_list(pfs, &l[3], &q.p[1][0]->c, &q.p[0][1]->c);
3080 if (code < 0)
3081 return code;
3082 }
3083 return code;
3084 }
3085 }
3086
3087 private int
fill_stripe(patch_fill_state_t * pfs,const tensor_patch * p)3088 fill_stripe(patch_fill_state_t *pfs, const tensor_patch *p)
3089 {
3090 /* The stripe is flattened enough by V, so ignore inner poles. */
3091 int ku[4], kum, code;
3092
3093 /* We would like to apply iterations for enumerating the kum curve parts,
3094 but the roundinmg errors would be too complicated due to
3095 the dependence on the direction. Note that neigbour
3096 patches may use the opposite direction for same bounding curve.
3097 We apply the recursive dichotomy, in which
3098 the rounding errors do not depend on the direction. */
3099 ku[0] = curve_samples(pfs, p->pole[0], 1, pfs->fixed_flat);
3100 ku[3] = curve_samples(pfs, p->pole[3], 1, pfs->fixed_flat);
3101 kum = max(ku[0], ku[3]);
3102 code = fill_wedges(pfs, ku[0], kum, p->pole[0], 1, &p->c[0][0], &p->c[0][1], inpatch_wedge);
3103 if (code < 0)
3104 return code;
3105 if (INTERPATCH_PADDING) {
3106 vd_bar(p->pole[0][0].x, p->pole[0][0].y, p->pole[3][0].x, p->pole[3][0].y, 0, RGB(255, 0, 0));
3107 code = mesh_padding(pfs, &p->pole[0][0], &p->pole[3][0], &p->c[0][0], &p->c[1][0]);
3108 if (code < 0)
3109 return code;
3110 vd_bar(p->pole[0][3].x, p->pole[0][3].y, p->pole[3][3].x, p->pole[3][3].y, 0, RGB(255, 0, 0));
3111 code = mesh_padding(pfs, &p->pole[0][3], &p->pole[3][3], &p->c[0][1], &p->c[1][1]);
3112 if (code < 0)
3113 return code;
3114 }
3115 code = decompose_stripe(pfs, p, kum);
3116 if (code < 0)
3117 return code;
3118 return fill_wedges(pfs, ku[3], kum, p->pole[3], 1, &p->c[1][0], &p->c[1][1], inpatch_wedge);
3119 }
3120
3121 private inline bool
is_curve_x_monotonic(const gs_fixed_point * pole,int pole_step)3122 is_curve_x_monotonic(const gs_fixed_point *pole, int pole_step)
3123 { /* true = monotonic, false = don't know. */
3124 return (pole[0 * pole_step].x <= pole[1 * pole_step].x &&
3125 pole[1 * pole_step].x <= pole[2 * pole_step].x &&
3126 pole[2 * pole_step].x <= pole[3 * pole_step].x) ||
3127 (pole[0 * pole_step].x >= pole[1 * pole_step].x &&
3128 pole[1 * pole_step].x >= pole[2 * pole_step].x &&
3129 pole[2 * pole_step].x >= pole[3 * pole_step].x);
3130 }
3131
3132 private inline bool
is_curve_y_monotonic(const gs_fixed_point * pole,int pole_step)3133 is_curve_y_monotonic(const gs_fixed_point *pole, int pole_step)
3134 { /* true = monotonic, false = don't know. */
3135 return (pole[0 * pole_step].y <= pole[1 * pole_step].y &&
3136 pole[1 * pole_step].y <= pole[2 * pole_step].y &&
3137 pole[2 * pole_step].y <= pole[3 * pole_step].y) ||
3138 (pole[0 * pole_step].y >= pole[1 * pole_step].y &&
3139 pole[1 * pole_step].y >= pole[2 * pole_step].y &&
3140 pole[2 * pole_step].y >= pole[3 * pole_step].y);
3141 }
3142
neqs(int * a,int b)3143 private inline bool neqs(int *a, int b)
3144 { /* Unequal signs. Assuming -1, 0, 1 only. */
3145 if (*a * b < 0)
3146 return true;
3147 if (!*a)
3148 *a = b;
3149 return false;
3150 }
3151
3152 private inline int
vector_pair_orientation(const gs_fixed_point * p0,const gs_fixed_point * p1,const gs_fixed_point * p2)3153 vector_pair_orientation(const gs_fixed_point *p0, const gs_fixed_point *p1, const gs_fixed_point *p2)
3154 { fixed dx1 = p1->x - p0->x, dy1 = p1->y - p0->y;
3155 fixed dx2 = p2->x - p0->x, dy2 = p2->y - p0->y;
3156 int64_t vp = (int64_t)dx1 * dy2 - (int64_t)dy1 * dx2;
3157
3158 return (vp > 0 ? 1 : vp < 0 ? -1 : 0);
3159 }
3160
3161 private inline bool
is_x_bended(const tensor_patch * p)3162 is_x_bended(const tensor_patch *p)
3163 {
3164 int sign = vector_pair_orientation(&p->pole[0][0], &p->pole[0][1], &p->pole[1][0]);
3165
3166 if (neqs(&sign, vector_pair_orientation(&p->pole[0][1], &p->pole[0][2], &p->pole[1][1])))
3167 return true;
3168 if (neqs(&sign, vector_pair_orientation(&p->pole[0][2], &p->pole[0][3], &p->pole[1][2])))
3169 return true;
3170 if (neqs(&sign, -vector_pair_orientation(&p->pole[0][3], &p->pole[0][2], &p->pole[1][3])))
3171 return true;
3172
3173 if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[1][2], &p->pole[2][1])))
3174 return true;
3175 if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[1][2], &p->pole[2][1])))
3176 return true;
3177 if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[1][3], &p->pole[2][2])))
3178 return true;
3179 if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[1][2], &p->pole[2][3])))
3180 return true;
3181
3182 if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[2][2], &p->pole[3][1])))
3183 return true;
3184 if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[2][2], &p->pole[3][1])))
3185 return true;
3186 if (neqs(&sign, vector_pair_orientation(&p->pole[2][2], &p->pole[2][3], &p->pole[3][2])))
3187 return true;
3188 if (neqs(&sign, -vector_pair_orientation(&p->pole[2][3], &p->pole[2][2], &p->pole[3][3])))
3189 return true;
3190
3191 if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[3][2], &p->pole[2][1])))
3192 return true;
3193 if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[3][2], &p->pole[2][1])))
3194 return true;
3195 if (neqs(&sign, -vector_pair_orientation(&p->pole[3][2], &p->pole[3][3], &p->pole[2][2])))
3196 return true;
3197 if (neqs(&sign, vector_pair_orientation(&p->pole[3][3], &p->pole[3][2], &p->pole[2][3])))
3198 return true;
3199 return false;
3200 }
3201
3202 private inline bool
is_y_bended(const tensor_patch * p)3203 is_y_bended(const tensor_patch *p)
3204 {
3205 int sign = vector_pair_orientation(&p->pole[0][0], &p->pole[1][0], &p->pole[0][1]);
3206
3207 if (neqs(&sign, vector_pair_orientation(&p->pole[1][0], &p->pole[2][0], &p->pole[1][1])))
3208 return true;
3209 if (neqs(&sign, vector_pair_orientation(&p->pole[2][0], &p->pole[3][0], &p->pole[2][1])))
3210 return true;
3211 if (neqs(&sign, -vector_pair_orientation(&p->pole[3][0], &p->pole[2][0], &p->pole[3][1])))
3212 return true;
3213
3214 if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[2][1], &p->pole[1][2])))
3215 return true;
3216 if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[2][1], &p->pole[1][2])))
3217 return true;
3218 if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[3][1], &p->pole[2][2])))
3219 return true;
3220 if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[2][1], &p->pole[3][2])))
3221 return true;
3222
3223 if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[2][2], &p->pole[1][3])))
3224 return true;
3225 if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[2][2], &p->pole[1][3])))
3226 return true;
3227 if (neqs(&sign, vector_pair_orientation(&p->pole[2][2], &p->pole[3][2], &p->pole[2][3])))
3228 return true;
3229 if (neqs(&sign, -vector_pair_orientation(&p->pole[3][2], &p->pole[2][2], &p->pole[3][3])))
3230 return true;
3231
3232 if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[2][3], &p->pole[1][2])))
3233 return true;
3234 if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[2][3], &p->pole[1][2])))
3235 return true;
3236 if (neqs(&sign, -vector_pair_orientation(&p->pole[2][3], &p->pole[3][3], &p->pole[2][2])))
3237 return true;
3238 if (neqs(&sign, vector_pair_orientation(&p->pole[3][3], &p->pole[2][3], &p->pole[3][2])))
3239 return true;
3240 return false;
3241 }
3242
3243 private inline bool
is_curve_x_small(const gs_fixed_point * pole,int pole_step,fixed fixed_flat)3244 is_curve_x_small(const gs_fixed_point *pole, int pole_step, fixed fixed_flat)
3245 { /* Is curve within a single pixel, or smaller than half pixel ? */
3246 fixed xmin0 = min(pole[0 * pole_step].x, pole[1 * pole_step].x);
3247 fixed xmin1 = min(pole[2 * pole_step].x, pole[3 * pole_step].x);
3248 fixed xmin = min(xmin0, xmin1);
3249 fixed xmax0 = max(pole[0 * pole_step].x, pole[1 * pole_step].x);
3250 fixed xmax1 = max(pole[2 * pole_step].x, pole[3 * pole_step].x);
3251 fixed xmax = max(xmax0, xmax1);
3252
3253 if(xmax - xmin <= fixed_1)
3254 return true;
3255 return false;
3256 }
3257
3258 private inline bool
is_curve_y_small(const gs_fixed_point * pole,int pole_step,fixed fixed_flat)3259 is_curve_y_small(const gs_fixed_point *pole, int pole_step, fixed fixed_flat)
3260 { /* Is curve within a single pixel, or smaller than half pixel ? */
3261 fixed ymin0 = min(pole[0 * pole_step].y, pole[1 * pole_step].y);
3262 fixed ymin1 = min(pole[2 * pole_step].y, pole[3 * pole_step].y);
3263 fixed ymin = min(ymin0, ymin1);
3264 fixed ymax0 = max(pole[0 * pole_step].y, pole[1 * pole_step].y);
3265 fixed ymax1 = max(pole[2 * pole_step].y, pole[3 * pole_step].y);
3266 fixed ymax = max(ymax0, ymax1);
3267
3268 if (ymax - ymin <= fixed_1)
3269 return true;
3270 return false;
3271 }
3272
3273 private inline bool
is_patch_narrow(const patch_fill_state_t * pfs,const tensor_patch * p)3274 is_patch_narrow(const patch_fill_state_t *pfs, const tensor_patch *p)
3275 {
3276 if (!is_curve_x_small(&p->pole[0][0], 4, pfs->fixed_flat))
3277 return false;
3278 if (!is_curve_x_small(&p->pole[0][1], 4, pfs->fixed_flat))
3279 return false;
3280 if (!is_curve_x_small(&p->pole[0][2], 4, pfs->fixed_flat))
3281 return false;
3282 if (!is_curve_x_small(&p->pole[0][3], 4, pfs->fixed_flat))
3283 return false;
3284 if (!is_curve_y_small(&p->pole[0][0], 4, pfs->fixed_flat))
3285 return false;
3286 if (!is_curve_y_small(&p->pole[0][1], 4, pfs->fixed_flat))
3287 return false;
3288 if (!is_curve_y_small(&p->pole[0][2], 4, pfs->fixed_flat))
3289 return false;
3290 if (!is_curve_y_small(&p->pole[0][3], 4, pfs->fixed_flat))
3291 return false;
3292 return true;
3293 }
3294
3295 private int
fill_patch(patch_fill_state_t * pfs,const tensor_patch * p,int kv,int kv0,int kv1)3296 fill_patch(patch_fill_state_t *pfs, const tensor_patch *p, int kv, int kv0, int kv1)
3297 {
3298 if (kv <= 1) {
3299 if (is_patch_narrow(pfs, p))
3300 return fill_stripe(pfs, p);
3301 if (!is_x_bended(p))
3302 return fill_stripe(pfs, p);
3303 }
3304 { tensor_patch s0, s1;
3305 shading_vertex_t q0, q1, q2;
3306 int code;
3307
3308 split_patch(pfs, &s0, &s1, p);
3309 if (kv0 <= 1) {
3310 q0.p = s0.pole[0][0];
3311 q0.c = s0.c[0][0];
3312 q1.p = s1.pole[3][0];
3313 q1.c = s1.c[1][0];
3314 q2.p = s0.pole[3][0];
3315 q2.c = s0.c[1][0];
3316 code = fill_triangle_wedge(pfs, &q0, &q1, &q2);
3317 if (code < 0)
3318 return code;
3319 }
3320 if (kv1 <= 1) {
3321 q0.p = s0.pole[0][3];
3322 q0.c = s0.c[0][1];
3323 q1.p = s1.pole[3][3];
3324 q1.c = s1.c[1][1];
3325 q2.p = s0.pole[3][3];
3326 q2.c = s0.c[1][1];
3327 code = fill_triangle_wedge(pfs, &q0, &q1, &q2);
3328 if (code < 0)
3329 return code;
3330 }
3331 code = fill_patch(pfs, &s0, kv / 2, kv0 / 2, kv1 / 2);
3332 if (code < 0)
3333 return code;
3334 return fill_patch(pfs, &s1, kv / 2, kv0 / 2, kv1 / 2);
3335 /* fixme : To privide the precise filling order, we must
3336 decompose left and right wedges into pieces by intersections
3337 with stripes, and fill each piece with its stripe.
3338 A lazy wedge list would be fine for storing
3339 the necessary information.
3340
3341 If the patch is created from a radial shading,
3342 the wedge color appears a constant, so the filling order
3343 isn't important. The order is important for other
3344 self-overlapping patches, but the visible effect is
3345 just a slight norrowing the patch (as its lower layer appears
3346 visible through the upper layer near the side).
3347 This kind of dropout isn't harmful, because
3348 contacring self-overlapping patches are painted
3349 one after one by definition, so that a side coverage break
3350 appears unavoidable by definition.
3351
3352 Delaying this improvement because it is low important.
3353 */
3354 }
3355 }
3356
3357 private inline fixed
lcp1(fixed p0,fixed p3)3358 lcp1(fixed p0, fixed p3)
3359 { /* Computing the 1st pole of a 3d order besier, which applears a line. */
3360 return (p0 + p0 + p3) / 3;
3361 }
3362 private inline fixed
lcp2(fixed p0,fixed p3)3363 lcp2(fixed p0, fixed p3)
3364 { /* Computing the 2nd pole of a 3d order besier, which applears a line. */
3365 return (p0 + p3 + p3) / 3;
3366 }
3367
3368 private void
patch_set_color(const patch_fill_state_t * pfs,patch_color_t * c,const float * cc)3369 patch_set_color(const patch_fill_state_t *pfs, patch_color_t *c, const float *cc)
3370 {
3371 if (pfs->Function) {
3372 c->t[0] = cc[0];
3373 c->t[1] = cc[1];
3374 } else
3375 memcpy(c->cc.paint.values, cc, sizeof(c->cc.paint.values[0]) * pfs->num_components);
3376 }
3377
3378 private void
make_tensor_patch(const patch_fill_state_t * pfs,tensor_patch * p,const patch_curve_t curve[4],const gs_fixed_point interior[4])3379 make_tensor_patch(const patch_fill_state_t *pfs, tensor_patch *p, const patch_curve_t curve[4],
3380 const gs_fixed_point interior[4])
3381 {
3382 const gs_color_space *pcs = pfs->direct_space;
3383
3384 p->pole[0][0] = curve[0].vertex.p;
3385 p->pole[1][0] = curve[0].control[0];
3386 p->pole[2][0] = curve[0].control[1];
3387 p->pole[3][0] = curve[1].vertex.p;
3388 p->pole[3][1] = curve[1].control[0];
3389 p->pole[3][2] = curve[1].control[1];
3390 p->pole[3][3] = curve[2].vertex.p;
3391 p->pole[2][3] = curve[2].control[0];
3392 p->pole[1][3] = curve[2].control[1];
3393 p->pole[0][3] = curve[3].vertex.p;
3394 p->pole[0][2] = curve[3].control[0];
3395 p->pole[0][1] = curve[3].control[1];
3396 if (interior != NULL) {
3397 p->pole[1][1] = interior[0];
3398 p->pole[1][2] = interior[1];
3399 p->pole[2][2] = interior[2];
3400 p->pole[2][1] = interior[3];
3401 } else {
3402 p->pole[1][1].x = lcp1(p->pole[0][1].x, p->pole[3][1].x) +
3403 lcp1(p->pole[1][0].x, p->pole[1][3].x) -
3404 lcp1(lcp1(p->pole[0][0].x, p->pole[0][3].x),
3405 lcp1(p->pole[3][0].x, p->pole[3][3].x));
3406 p->pole[1][2].x = lcp1(p->pole[0][2].x, p->pole[3][2].x) +
3407 lcp2(p->pole[1][0].x, p->pole[1][3].x) -
3408 lcp1(lcp2(p->pole[0][0].x, p->pole[0][3].x),
3409 lcp2(p->pole[3][0].x, p->pole[3][3].x));
3410 p->pole[2][1].x = lcp2(p->pole[0][1].x, p->pole[3][1].x) +
3411 lcp1(p->pole[2][0].x, p->pole[2][3].x) -
3412 lcp2(lcp1(p->pole[0][0].x, p->pole[0][3].x),
3413 lcp1(p->pole[3][0].x, p->pole[3][3].x));
3414 p->pole[2][2].x = lcp2(p->pole[0][2].x, p->pole[3][2].x) +
3415 lcp2(p->pole[2][0].x, p->pole[2][3].x) -
3416 lcp2(lcp2(p->pole[0][0].x, p->pole[0][3].x),
3417 lcp2(p->pole[3][0].x, p->pole[3][3].x));
3418
3419 p->pole[1][1].y = lcp1(p->pole[0][1].y, p->pole[3][1].y) +
3420 lcp1(p->pole[1][0].y, p->pole[1][3].y) -
3421 lcp1(lcp1(p->pole[0][0].y, p->pole[0][3].y),
3422 lcp1(p->pole[3][0].y, p->pole[3][3].y));
3423 p->pole[1][2].y = lcp1(p->pole[0][2].y, p->pole[3][2].y) +
3424 lcp2(p->pole[1][0].y, p->pole[1][3].y) -
3425 lcp1(lcp2(p->pole[0][0].y, p->pole[0][3].y),
3426 lcp2(p->pole[3][0].y, p->pole[3][3].y));
3427 p->pole[2][1].y = lcp2(p->pole[0][1].y, p->pole[3][1].y) +
3428 lcp1(p->pole[2][0].y, p->pole[2][3].y) -
3429 lcp2(lcp1(p->pole[0][0].y, p->pole[0][3].y),
3430 lcp1(p->pole[3][0].y, p->pole[3][3].y));
3431 p->pole[2][2].y = lcp2(p->pole[0][2].y, p->pole[3][2].y) +
3432 lcp2(p->pole[2][0].y, p->pole[2][3].y) -
3433 lcp2(lcp2(p->pole[0][0].y, p->pole[0][3].y),
3434 lcp2(p->pole[3][0].y, p->pole[3][3].y));
3435 }
3436 patch_set_color(pfs, &p->c[0][0], curve[0].vertex.cc);
3437 patch_set_color(pfs, &p->c[1][0], curve[1].vertex.cc);
3438 patch_set_color(pfs, &p->c[1][1], curve[2].vertex.cc);
3439 patch_set_color(pfs, &p->c[0][1], curve[3].vertex.cc);
3440 patch_resolve_color_inline(&p->c[0][0], pfs);
3441 patch_resolve_color_inline(&p->c[0][1], pfs);
3442 patch_resolve_color_inline(&p->c[1][0], pfs);
3443 patch_resolve_color_inline(&p->c[1][1], pfs);
3444 if (!pfs->Function) {
3445 pcs->type->restrict_color(&p->c[0][0].cc, pcs);
3446 pcs->type->restrict_color(&p->c[0][1].cc, pcs);
3447 pcs->type->restrict_color(&p->c[1][0].cc, pcs);
3448 pcs->type->restrict_color(&p->c[1][1].cc, pcs);
3449 }
3450 }
3451
3452 int
gx_shade_background(gx_device * pdev,const gs_fixed_rect * rect,const gx_device_color * pdevc,gs_logical_operation_t log_op)3453 gx_shade_background(gx_device *pdev, const gs_fixed_rect *rect,
3454 const gx_device_color *pdevc, gs_logical_operation_t log_op)
3455 {
3456 gs_fixed_edge le, re;
3457
3458 le.start.x = rect->p.x - INTERPATCH_PADDING;
3459 le.start.y = rect->p.y - INTERPATCH_PADDING;
3460 le.end.x = rect->p.x - INTERPATCH_PADDING;
3461 le.end.y = rect->q.y + INTERPATCH_PADDING;
3462 re.start.x = rect->q.x + INTERPATCH_PADDING;
3463 re.start.y = rect->p.y - INTERPATCH_PADDING;
3464 re.end.x = rect->q.x + INTERPATCH_PADDING;
3465 re.end.y = rect->q.y + INTERPATCH_PADDING;
3466 return dev_proc(pdev, fill_trapezoid)(pdev,
3467 &le, &re, le.start.y, le.end.y, false, pdevc, log_op);
3468 }
3469
3470
3471 int
patch_fill(patch_fill_state_t * pfs,const patch_curve_t curve[4],const gs_fixed_point interior[4],void (* transform)(gs_fixed_point *,const patch_curve_t[4],const gs_fixed_point[4],floatp,floatp))3472 patch_fill(patch_fill_state_t *pfs, const patch_curve_t curve[4],
3473 const gs_fixed_point interior[4],
3474 void (*transform) (gs_fixed_point *, const patch_curve_t[4],
3475 const gs_fixed_point[4], floatp, floatp))
3476 {
3477 tensor_patch p;
3478 int kv[4], kvm, ku[4], kum, km;
3479 int code = 0;
3480
3481 #if SKIP_TEST
3482 dbg_patch_cnt++;
3483 /*if (dbg_patch_cnt != 67 && dbg_patch_cnt != 78)
3484 return 0;*/
3485 #endif
3486 /* We decompose the patch into tiny quadrangles,
3487 possibly inserting wedges between them against a dropout. */
3488 make_tensor_patch(pfs, &p, curve, interior);
3489 pfs->unlinear = !is_linear_color_applicable(pfs);
3490 pfs->linear_color = false;
3491 if ((*dev_proc(pfs->dev, pattern_manage))(pfs->dev,
3492 gs_no_id, NULL, pattern_manage__shading_area) > 0) {
3493 /* Inform the device with the shading coverage area.
3494 First compute the sign of the area, because
3495 all areas to be clipped in same direction. */
3496 gx_device *pdev = pfs->dev;
3497 gx_path path;
3498 fixed d01x = (curve[1].vertex.p.x - curve[0].vertex.p.x) >> 1;
3499 fixed d01y = (curve[1].vertex.p.y - curve[0].vertex.p.y) >> 1;
3500 fixed d12x = (curve[2].vertex.p.x - curve[1].vertex.p.x) >> 1;
3501 fixed d12y = (curve[2].vertex.p.y - curve[1].vertex.p.y) >> 1;
3502 fixed d23x = (curve[3].vertex.p.x - curve[2].vertex.p.x) >> 1;
3503 fixed d23y = (curve[3].vertex.p.y - curve[2].vertex.p.y) >> 1;
3504 fixed d30x = (curve[0].vertex.p.x - curve[3].vertex.p.x) >> 1;
3505 fixed d30y = (curve[0].vertex.p.y - curve[3].vertex.p.y) >> 1;
3506 int64_t s1 = (int64_t)d01x * d12y - (int64_t)d01y * d12x;
3507 int64_t s2 = (int64_t)d23x * d30y - (int64_t)d23y * d30x;
3508 int s = (s1 + s2 > 0 ? 1 : 3), i, j, k, jj, l = (s == 1 ? 0 : 1);
3509
3510 gx_path_init_local(&path, pdev->memory);
3511 if (is_x_bended(&p) || is_y_bended(&p)) {
3512 /* The patch possibly is self-overlapping,
3513 so the patch coverage may fall outside the patch outline.
3514 In this case we pass an empty path,
3515 and the device must use a bitmap mask instead clipping. */
3516 } else {
3517 code = gx_path_add_point(&path, curve[0].vertex.p.x, curve[0].vertex.p.y);
3518 for (i = k = 0; k < 4 && code >= 0; i = j, k++) {
3519 j = (i + s) % 4, jj = (s == 1 ? i : j);
3520 if (curve[jj].straight)
3521 code = gx_path_add_line(&path, curve[j].vertex.p.x,
3522 curve[j].vertex.p.y);
3523 else
3524 code = gx_path_add_curve(&path, curve[jj].control[l].x, curve[jj].control[l].y,
3525 curve[jj].control[(l + 1) & 1].x, curve[jj].control[(l + 1) & 1].y,
3526 curve[j].vertex.p.x,
3527 curve[j].vertex.p.y);
3528 }
3529 if (code >= 0)
3530 code = gx_path_close_subpath(&path);
3531 }
3532 if (code >= 0)
3533 code = (*dev_proc(pfs->dev, fill_path))(pdev, NULL, &path, NULL, NULL, NULL);
3534 gx_path_free(&path, "patch_fill");
3535 if (code < 0)
3536 return code;
3537 }
3538 /* draw_patch(&p, true, RGB(0, 0, 0)); */
3539 kv[0] = curve_samples(pfs, &p.pole[0][0], 4, pfs->fixed_flat);
3540 kv[1] = curve_samples(pfs, &p.pole[0][1], 4, pfs->fixed_flat);
3541 kv[2] = curve_samples(pfs, &p.pole[0][2], 4, pfs->fixed_flat);
3542 kv[3] = curve_samples(pfs, &p.pole[0][3], 4, pfs->fixed_flat);
3543 kvm = max(max(kv[0], kv[1]), max(kv[2], kv[3]));
3544 ku[0] = curve_samples(pfs, p.pole[0], 1, pfs->fixed_flat);
3545 ku[3] = curve_samples(pfs, p.pole[3], 1, pfs->fixed_flat);
3546 kum = max(ku[0], ku[3]);
3547 km = max(kvm, kum);
3548 # if NOFILL_TEST
3549 dbg_nofill = false;
3550 # endif
3551 code = fill_wedges(pfs, ku[0], kum, p.pole[0], 1, &p.c[0][0], &p.c[0][1],
3552 interpatch_padding | inpatch_wedge);
3553 if (code >= 0) {
3554 /* We would like to apply iterations for enumerating the kvm curve parts,
3555 but the roundinmg errors would be too complicated due to
3556 the dependence on the direction. Note that neigbour
3557 patches may use the opposite direction for same bounding curve.
3558 We apply the recursive dichotomy, in which
3559 the rounding errors do not depend on the direction. */
3560 # if NOFILL_TEST
3561 dbg_nofill = false;
3562 code = fill_patch(pfs, &p, kvm, kv[0], kv[3]);
3563 dbg_nofill = true;
3564 # endif
3565 code = fill_patch(pfs, &p, kvm, kv[0], kv[3]);
3566 }
3567 if (code >= 0)
3568 code = fill_wedges(pfs, ku[3], kum, p.pole[3], 1, &p.c[1][0], &p.c[1][1],
3569 interpatch_padding | inpatch_wedge);
3570 return code;
3571 }
3572