/src/ghostpdl/base/gxshade6.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Rendering for Coons and tensor patch shadings */ |
18 | | /* |
19 | | A contiguous non-overlapping decomposition |
20 | | of a tensor shading into linear color triangles. |
21 | | */ |
22 | | #include "memory_.h" |
23 | | #include "gx.h" |
24 | | #include "gserrors.h" |
25 | | #include "gsmatrix.h" /* for gscoord.h */ |
26 | | #include "gscoord.h" |
27 | | #include "gscicach.h" |
28 | | #include "gxcspace.h" |
29 | | #include "gxdcolor.h" |
30 | | #include "gxgstate.h" |
31 | | #include "gxshade.h" |
32 | | #include "gxdevcli.h" |
33 | | #include "gxshade4.h" |
34 | | #include "gxarith.h" |
35 | | #include "gzpath.h" |
36 | | #include "stdint_.h" |
37 | | #include "math_.h" |
38 | | #include "gsicc_cache.h" |
39 | | #include "gxdevsop.h" |
40 | | |
41 | | /* The original version of the shading code 'decompose's shadings into |
42 | | * smaller and smaller regions until they are smaller than 1 pixel, and then |
43 | | * fills them. (Either with a constant colour, or with a linear filled trap). |
44 | | * |
45 | | * Previous versions of the code (from svn revision 7936 until June 2011 |
46 | | * (shortly after the switch to git)) changed this limit to be 1 point or 1 |
47 | | * pixel (whichever is larger) (on the grounds that as resolution increases, |
48 | | * we are unlikely to be able to notice increasingly small inaccuracies in |
49 | | * the shading). Given how people abuse the resolution at which things are |
50 | | * rendered (especially when rendering to images that can subsequently be |
51 | | * zoomed), this seems a poor trade off. See bug 691152. |
52 | | * |
53 | | * The code has now been changed back to operate with the proper 1 pixel |
54 | | * decomposition, which will cost us performance in some cases. Should |
55 | | * people want to restore the previous operation, they should build with |
56 | | * MAX_SHADING_RESOLUTION predefined to 72. In general, this symbol can be |
57 | | * set to the maximum dpi that shading should ever be performed at. Leaving |
58 | | * it undefined will leave the default (1 pixel limit) in place. |
59 | | * |
60 | | * A possible future optimisation here may be to use different max shading |
61 | | * resolutions for linear and non-linear shadings; linear shadings appear to |
62 | | * result in calls to "fill linear traps", and non linear ones appear to |
63 | | * result in calls to "fill constant color". As such linear shadings are much |
64 | | * more forgiving of a higher decomposition threshold. |
65 | | */ |
66 | | |
67 | | #if NOFILL_TEST |
68 | | static bool dbg_nofill = false; |
69 | | #endif |
70 | | #if SKIP_TEST |
71 | | static int dbg_patch_cnt = 0; |
72 | | static int dbg_quad_cnt = 0; |
73 | | static int dbg_triangle_cnt = 0; |
74 | | static int dbg_wedge_triangle_cnt = 0; |
75 | | #endif |
76 | | |
77 | | enum { |
78 | | min_linear_grades = 255 /* The minimal number of device color grades, |
79 | | required to apply linear color device functions. */ |
80 | | }; |
81 | | |
82 | | /* ================ Utilities ================ */ |
83 | | |
84 | | static int |
85 | | allocate_color_stack(patch_fill_state_t *pfs, gs_memory_t *memory) |
86 | 267k | { |
87 | 267k | if (pfs->color_stack != NULL) |
88 | 0 | return 0; |
89 | 267k | pfs->color_stack_step = offset_of(patch_color_t, cc.paint.values[pfs->num_components]); |
90 | 267k | pfs->color_stack_step = (pfs->color_stack_step + sizeof(void *) - 1) / sizeof(void *) * sizeof(void *); /* Alignment */ |
91 | | |
92 | 267k | pfs->color_stack_size = pfs->color_stack_step * SHADING_COLOR_STACK_SIZE; |
93 | 267k | pfs->color_stack = gs_alloc_bytes(memory, pfs->color_stack_size, "allocate_color_stack"); |
94 | 267k | if (pfs->color_stack == NULL) |
95 | 0 | return_error(gs_error_VMerror); |
96 | 267k | pfs->color_stack_limit = pfs->color_stack + pfs->color_stack_size; |
97 | 267k | pfs->color_stack_ptr = pfs->color_stack; |
98 | 267k | pfs->memory = memory; |
99 | 267k | return 0; |
100 | 267k | } |
101 | | |
102 | | static inline byte * |
103 | | reserve_colors_inline(patch_fill_state_t *pfs, patch_color_t *c[], int n) |
104 | 263M | { |
105 | 263M | int i; |
106 | 263M | byte *ptr0 = pfs->color_stack_ptr, *ptr = ptr0; |
107 | | |
108 | 844M | for (i = 0; i < n; i++, ptr += pfs->color_stack_step) |
109 | 580M | c[i] = (patch_color_t *)ptr; |
110 | 263M | if (ptr > pfs->color_stack_limit) { |
111 | 0 | c[0] = NULL; /* safety. */ |
112 | 0 | return NULL; |
113 | 0 | } |
114 | 263M | pfs->color_stack_ptr = ptr; |
115 | 263M | return ptr0; |
116 | 263M | } |
117 | | |
118 | | byte * |
119 | | reserve_colors(patch_fill_state_t *pfs, patch_color_t *c[], int n) |
120 | 778 | { |
121 | 778 | return reserve_colors_inline(pfs, c, n); |
122 | 778 | } |
123 | | |
124 | | static inline void |
125 | | release_colors_inline(patch_fill_state_t *pfs, byte *ptr, int n) |
126 | 263M | { |
127 | | #if 0 /* Saving the invariant for records. */ |
128 | | pfs->color_stack_ptr = pfs->color_stack_step * n; |
129 | | assert((byte *)pfs->color_stack_ptr == ptr); |
130 | | #else |
131 | 263M | pfs->color_stack_ptr = ptr; |
132 | 263M | #endif |
133 | 263M | } |
134 | | void |
135 | | release_colors(patch_fill_state_t *pfs, byte *ptr, int n) |
136 | 778 | { |
137 | 778 | release_colors_inline(pfs, ptr, n); |
138 | 778 | } |
139 | | |
140 | | /* Get colors for patch vertices. */ |
141 | | static int |
142 | | shade_next_colors(shade_coord_stream_t * cs, patch_curve_t * curves, |
143 | | int num_vertices) |
144 | 767k | { |
145 | 767k | int i, code = 0; |
146 | | |
147 | 3.21M | for (i = 0; i < num_vertices && code >= 0; ++i) { |
148 | 2.44M | curves[i].vertex.cc[1] = 0; /* safety. (patch_fill may assume 2 arguments) */ |
149 | 2.44M | code = shade_next_color(cs, curves[i].vertex.cc); |
150 | 2.44M | } |
151 | 767k | return code; |
152 | 767k | } |
153 | | |
154 | | /* Get a Bezier or tensor patch element. */ |
155 | | static int |
156 | | shade_next_curve(shade_coord_stream_t * cs, patch_curve_t * curve) |
157 | 1.99M | { |
158 | 1.99M | int code = shade_next_coords(cs, &curve->vertex.p, 1); |
159 | | |
160 | 1.99M | if (code >= 0) |
161 | 1.99M | code = shade_next_coords(cs, curve->control, |
162 | 1.99M | countof(curve->control)); |
163 | 1.99M | return code; |
164 | 1.99M | } |
165 | | |
166 | | /* |
167 | | * Parse the next patch out of the input stream. Return 1 if done, |
168 | | * 0 if patch, <0 on error. |
169 | | */ |
170 | | static int |
171 | | shade_next_patch(shade_coord_stream_t * cs, int BitsPerFlag, |
172 | | patch_curve_t curve[4], gs_fixed_point interior[4] /* 0 for Coons patch */) |
173 | 768k | { |
174 | 768k | int flag = shade_next_flag(cs, BitsPerFlag); |
175 | 768k | int num_colors, code; |
176 | | |
177 | 768k | if (flag < 0) { |
178 | 1.20k | if (!cs->is_eod(cs)) |
179 | 0 | return_error(gs_error_rangecheck); |
180 | 1.20k | return 1; /* no more data */ |
181 | 1.20k | } |
182 | 767k | if (cs->first_patch && (flag & 3) != 0) { |
183 | 0 | return_error(gs_error_rangecheck); |
184 | 0 | } |
185 | 767k | cs->first_patch = 0; |
186 | 767k | switch (flag & 3) { |
187 | 0 | default: |
188 | 0 | return_error(gs_error_rangecheck); /* not possible */ |
189 | 456k | case 0: |
190 | 456k | if ((code = shade_next_curve(cs, &curve[0])) < 0 || |
191 | 456k | (code = shade_next_coords(cs, &curve[1].vertex.p, 1)) < 0 |
192 | 456k | ) |
193 | 62 | return code; |
194 | 456k | num_colors = 4; |
195 | 456k | goto vx; |
196 | 85.6k | case 1: |
197 | 85.6k | curve[0] = curve[1], curve[1].vertex = curve[2].vertex; |
198 | 85.6k | goto v3; |
199 | 91.6k | case 2: |
200 | 91.6k | curve[0] = curve[2], curve[1].vertex = curve[3].vertex; |
201 | 91.6k | goto v3; |
202 | 134k | case 3: |
203 | 134k | curve[1].vertex = curve[0].vertex, curve[0] = curve[3]; |
204 | 311k | v3: num_colors = 2; |
205 | 767k | vx: if ((code = shade_next_coords(cs, curve[1].control, 2)) < 0 || |
206 | 767k | (code = shade_next_curve(cs, &curve[2])) < 0 || |
207 | 767k | (code = shade_next_curve(cs, &curve[3])) < 0 || |
208 | 767k | (interior != 0 && |
209 | 767k | (code = shade_next_coords(cs, interior, 4)) < 0) || |
210 | 767k | (code = shade_next_colors(cs, &curve[4 - num_colors], |
211 | 767k | num_colors)) < 0 |
212 | 767k | ) |
213 | 740 | return code; |
214 | 766k | cs->align(cs, 8); /* See shade_next_vertex. */ |
215 | 767k | } |
216 | 766k | return 0; |
217 | 767k | } |
218 | | |
219 | | static inline bool |
220 | | is_linear_color_applicable(const patch_fill_state_t *pfs) |
221 | 10.4M | { |
222 | 10.4M | if (!USE_LINEAR_COLOR_PROCS) |
223 | 0 | return false; |
224 | 10.4M | if (!colors_are_separable_and_linear(&pfs->dev->color_info)) |
225 | 5.54M | return false; |
226 | 4.85M | if (gx_get_cmap_procs(pfs->pgs, pfs->dev)->is_halftoned(pfs->pgs, pfs->dev)) |
227 | 395k | return false; |
228 | 4.46M | return true; |
229 | 4.85M | } |
230 | | |
231 | | static int |
232 | | alloc_patch_fill_memory(patch_fill_state_t *pfs, gs_memory_t *memory, const gs_color_space *pcs) |
233 | 267k | { |
234 | 267k | int code; |
235 | | |
236 | 267k | pfs->memory = memory; |
237 | 267k | # if LAZY_WEDGES |
238 | 267k | code = wedge_vertex_list_elem_buffer_alloc(pfs); |
239 | 267k | if (code < 0) |
240 | 0 | return code; |
241 | 267k | # endif |
242 | 267k | pfs->max_small_coord = 1 << ((sizeof(int64_t) * 8 - 1/*sign*/) / 3); |
243 | 267k | code = allocate_color_stack(pfs, memory); |
244 | 267k | if (code < 0) |
245 | 0 | return code; |
246 | 267k | if (pfs->unlinear || pcs == NULL) |
247 | 14.6k | pfs->pcic = NULL; |
248 | 252k | else { |
249 | 252k | pfs->pcic = gs_color_index_cache_create(memory, pcs, pfs->dev, pfs->pgs, true, pfs->trans_device); |
250 | 252k | if (pfs->pcic == NULL) |
251 | 0 | return_error(gs_error_VMerror); |
252 | 252k | } |
253 | 267k | return 0; |
254 | 267k | } |
255 | | |
256 | | int |
257 | | init_patch_fill_state(patch_fill_state_t *pfs) |
258 | 267k | { |
259 | | /* Warning : pfs->Function must be set in advance. */ |
260 | 267k | const gs_color_space *pcs = pfs->direct_space; |
261 | 267k | gs_client_color fcc0, fcc1; |
262 | 267k | int i; |
263 | | |
264 | 1.04M | for (i = 0; i < pfs->num_components; i++) { |
265 | 779k | fcc0.paint.values[i] = -1000000; |
266 | 779k | fcc1.paint.values[i] = 1000000; |
267 | 779k | } |
268 | 267k | pcs->type->restrict_color(&fcc0, pcs); |
269 | 267k | pcs->type->restrict_color(&fcc1, pcs); |
270 | 1.04M | for (i = 0; i < pfs->num_components; i++) |
271 | 779k | pfs->color_domain.paint.values[i] = max(fcc1.paint.values[i] - fcc0.paint.values[i], 1); |
272 | 267k | pfs->vectorization = false; /* A stub for a while. Will use with pclwrite. */ |
273 | 267k | pfs->maybe_self_intersecting = true; |
274 | 267k | pfs->monotonic_color = (pfs->Function == NULL); |
275 | 267k | pfs->function_arg_shift = 0; |
276 | 267k | pfs->linear_color = false; |
277 | 267k | pfs->inside = false; |
278 | 267k | pfs->n_color_args = 1; |
279 | | #ifdef MAX_SHADING_RESOLUTION |
280 | | pfs->decomposition_limit = float2fixed(min(pfs->dev->HWResolution[0], |
281 | | pfs->dev->HWResolution[1]) / MAX_SHADING_RESOLUTION); |
282 | | pfs->decomposition_limit = max(pfs->decomposition_limit, fixed_1); |
283 | | #else |
284 | 267k | pfs->decomposition_limit = fixed_1; |
285 | 267k | #endif |
286 | 267k | pfs->fixed_flat = float2fixed(pfs->pgs->flatness); |
287 | | /* Restrict the pfs->smoothness with 1/min_linear_grades, because cs_is_linear |
288 | | can't provide a better precision due to the color |
289 | | representation with integers. |
290 | | */ |
291 | 267k | pfs->smoothness = max(pfs->pgs->smoothness, 1.0 / min_linear_grades); |
292 | 267k | pfs->color_stack_size = 0; |
293 | 267k | pfs->color_stack_step = 0; |
294 | 267k | pfs->color_stack_ptr = NULL; |
295 | 267k | pfs->color_stack = NULL; |
296 | 267k | pfs->color_stack_limit = NULL; |
297 | 267k | pfs->unlinear = !is_linear_color_applicable(pfs); |
298 | 267k | pfs->pcic = NULL; |
299 | 267k | return alloc_patch_fill_memory(pfs, pfs->pgs->memory, pcs); |
300 | 267k | } |
301 | | |
302 | | bool |
303 | | term_patch_fill_state(patch_fill_state_t *pfs) |
304 | 267k | { |
305 | 267k | bool b = (pfs->color_stack_ptr != pfs->color_stack); |
306 | 267k | # if LAZY_WEDGES |
307 | 267k | wedge_vertex_list_elem_buffer_free(pfs); |
308 | 267k | # endif |
309 | 267k | if (pfs->color_stack) |
310 | 267k | gs_free_object(pfs->memory, pfs->color_stack, "term_patch_fill_state"); |
311 | 267k | if (pfs->pcic != NULL) |
312 | 252k | gs_color_index_cache_destroy(pfs->pcic); |
313 | 267k | return b; |
314 | 267k | } |
315 | | |
316 | | /* Resolve a patch color using the Function if necessary. */ |
317 | | static inline void |
318 | | patch_resolve_color_inline(patch_color_t * ppcr, const patch_fill_state_t *pfs) |
319 | 106M | { |
320 | 106M | if (pfs->Function) { |
321 | 103M | const gs_color_space *pcs = pfs->direct_space; |
322 | | |
323 | 103M | gs_function_evaluate(pfs->Function, ppcr->t, ppcr->cc.paint.values); |
324 | 103M | pcs->type->restrict_color(&ppcr->cc, pcs); |
325 | 103M | } |
326 | 106M | } |
327 | | |
328 | | void |
329 | | patch_resolve_color(patch_color_t * ppcr, const patch_fill_state_t *pfs) |
330 | 0 | { |
331 | 0 | patch_resolve_color_inline(ppcr, pfs); |
332 | 0 | } |
333 | | |
334 | | /* |
335 | | * Calculate the interpolated color at a given point. |
336 | | * Note that we must do this twice for bilinear interpolation. |
337 | | * We use the name ppcr rather than ppc because an Apple compiler defines |
338 | | * ppc when compiling on PowerPC systems (!). |
339 | | */ |
340 | | static void |
341 | | patch_interpolate_color(patch_color_t * ppcr, const patch_color_t * ppc0, |
342 | | const patch_color_t * ppc1, const patch_fill_state_t *pfs, double t) |
343 | 318M | { |
344 | | /* The old code gives -IND on Intel. */ |
345 | 318M | if (pfs->Function) { |
346 | 64.7M | ppcr->t[0] = ppc0->t[0] * (1 - t) + t * ppc1->t[0]; |
347 | 64.7M | ppcr->t[1] = ppc0->t[1] * (1 - t) + t * ppc1->t[1]; |
348 | 64.7M | patch_resolve_color_inline(ppcr, pfs); |
349 | 253M | } else { |
350 | 253M | int ci; |
351 | | |
352 | 1.20G | for (ci = pfs->num_components - 1; ci >= 0; --ci) |
353 | 950M | ppcr->cc.paint.values[ci] = |
354 | 950M | ppc0->cc.paint.values[ci] * (1 - t) + t * ppc1->cc.paint.values[ci]; |
355 | 253M | } |
356 | 318M | } |
357 | | |
358 | | /* ================ Specific shadings ================ */ |
359 | | |
360 | | /* |
361 | | * The curves are stored in a clockwise or counter-clockwise order that maps |
362 | | * to the patch definition in a non-intuitive way. The documentation |
363 | | * (pp. 277-281 of the PostScript Language Reference Manual, Third Edition) |
364 | | * says that the curves are in the order D1, C2, D2, C1. |
365 | | */ |
366 | | /* The starting points of the curves: */ |
367 | 0 | #define D1START 0 |
368 | 0 | #define C2START 1 |
369 | 0 | #define D2START 3 |
370 | 0 | #define C1START 0 |
371 | | /* The control points of the curves (x means reversed order): */ |
372 | 0 | #define D1CTRL 0 |
373 | 0 | #define C2CTRL 1 |
374 | 0 | #define D2XCTRL 2 |
375 | 0 | #define C1XCTRL 3 |
376 | | /* The end points of the curves: */ |
377 | 0 | #define D1END 1 |
378 | 0 | #define C2END 2 |
379 | 0 | #define D2END 2 |
380 | 0 | #define C1END 3 |
381 | | |
382 | | /* ---------------- Common code ---------------- */ |
383 | | |
384 | | /* Evaluate a curve at a given point. */ |
385 | | static void |
386 | | curve_eval(gs_fixed_point * pt, const gs_fixed_point * p0, |
387 | | const gs_fixed_point * p1, const gs_fixed_point * p2, |
388 | | const gs_fixed_point * p3, double t) |
389 | 0 | { |
390 | 0 | fixed a, b, c, d; |
391 | 0 | fixed t01, t12; |
392 | |
|
393 | 0 | d = p0->x; |
394 | 0 | curve_points_to_coefficients(d, p1->x, p2->x, p3->x, |
395 | 0 | a, b, c, t01, t12); |
396 | 0 | pt->x = (fixed) (((a * t + b) * t + c) * t + d); |
397 | 0 | d = p0->y; |
398 | 0 | curve_points_to_coefficients(d, p1->y, p2->y, p3->y, |
399 | 0 | a, b, c, t01, t12); |
400 | 0 | pt->y = (fixed) (((a * t + b) * t + c) * t + d); |
401 | 0 | if_debug3('2', "[2]t=%g => (%g,%g)\n", t, fixed2float(pt->x), |
402 | 0 | fixed2float(pt->y)); |
403 | 0 | } |
404 | | |
405 | | /* ---------------- Coons patch shading ---------------- */ |
406 | | |
407 | | /* Calculate the device-space coordinate corresponding to (u,v). */ |
408 | | static void |
409 | | Cp_transform(gs_fixed_point * pt, const patch_curve_t curve[4], |
410 | | const gs_fixed_point ignore_interior[4], double u, double v) |
411 | 0 | { |
412 | 0 | double co_u = 1.0 - u, co_v = 1.0 - v; |
413 | 0 | gs_fixed_point c1u, d1v, c2u, d2v; |
414 | |
|
415 | 0 | curve_eval(&c1u, &curve[C1START].vertex.p, |
416 | 0 | &curve[C1XCTRL].control[1], &curve[C1XCTRL].control[0], |
417 | 0 | &curve[C1END].vertex.p, u); |
418 | 0 | curve_eval(&d1v, &curve[D1START].vertex.p, |
419 | 0 | &curve[D1CTRL].control[0], &curve[D1CTRL].control[1], |
420 | 0 | &curve[D1END].vertex.p, v); |
421 | 0 | curve_eval(&c2u, &curve[C2START].vertex.p, |
422 | 0 | &curve[C2CTRL].control[0], &curve[C2CTRL].control[1], |
423 | 0 | &curve[C2END].vertex.p, u); |
424 | 0 | curve_eval(&d2v, &curve[D2START].vertex.p, |
425 | 0 | &curve[D2XCTRL].control[1], &curve[D2XCTRL].control[0], |
426 | 0 | &curve[D2END].vertex.p, v); |
427 | 0 | #define COMPUTE_COORD(xy)\ |
428 | 0 | pt->xy = (fixed)\ |
429 | 0 | ((co_v * c1u.xy + v * c2u.xy) + (co_u * d1v.xy + u * d2v.xy) -\ |
430 | 0 | (co_v * (co_u * curve[C1START].vertex.p.xy +\ |
431 | 0 | u * curve[C1END].vertex.p.xy) +\ |
432 | 0 | v * (co_u * curve[C2START].vertex.p.xy +\ |
433 | 0 | u * curve[C2END].vertex.p.xy))) |
434 | 0 | COMPUTE_COORD(x); |
435 | 0 | COMPUTE_COORD(y); |
436 | 0 | #undef COMPUTE_COORD |
437 | 0 | if_debug4('2', "[2](u=%g,v=%g) => (%g,%g)\n", |
438 | 0 | u, v, fixed2float(pt->x), fixed2float(pt->y)); |
439 | 0 | } |
440 | | |
441 | | int |
442 | | gs_shading_Cp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect, |
443 | | const gs_fixed_rect * rect_clip, |
444 | | gx_device * dev, gs_gstate * pgs) |
445 | 58 | { |
446 | 58 | const gs_shading_Cp_t * const psh = (const gs_shading_Cp_t *)psh0; |
447 | 58 | patch_fill_state_t state; |
448 | 58 | shade_coord_stream_t cs; |
449 | 58 | patch_curve_t curve[4]; |
450 | 58 | int code; |
451 | | |
452 | 58 | code = mesh_init_fill_state((mesh_fill_state_t *) &state, |
453 | 58 | (const gs_shading_mesh_t *)psh0, rect_clip, dev, pgs); |
454 | 58 | if (code < 0) { |
455 | 0 | if (state.icclink != NULL) gsicc_release_link(state.icclink); |
456 | 0 | return code; |
457 | 0 | } |
458 | 58 | state.Function = psh->params.Function; |
459 | 58 | code = init_patch_fill_state(&state); |
460 | 58 | if(code < 0) { |
461 | 0 | if (state.icclink != NULL) gsicc_release_link(state.icclink); |
462 | 0 | return code; |
463 | 0 | } |
464 | | |
465 | 58 | curve[0].straight = curve[1].straight = curve[2].straight = curve[3].straight = false; |
466 | 58 | shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, pgs); |
467 | 300 | while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag, |
468 | 300 | curve, NULL)) == 0 && |
469 | 300 | (code = patch_fill(&state, curve, NULL, Cp_transform)) >= 0 |
470 | 242 | ) { |
471 | 242 | DO_NOTHING; |
472 | 242 | } |
473 | 58 | if (term_patch_fill_state(&state)) |
474 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
475 | 58 | if (state.icclink != NULL) gsicc_release_link(state.icclink); |
476 | 58 | return min(code, 0); |
477 | 58 | } |
478 | | |
479 | | /* ---------------- Tensor product patch shading ---------------- */ |
480 | | |
481 | | /* Calculate the device-space coordinate corresponding to (u,v). */ |
482 | | static void |
483 | | Tpp_transform(gs_fixed_point * pt, const patch_curve_t curve[4], |
484 | | const gs_fixed_point interior[4], double u, double v) |
485 | 0 | { |
486 | 0 | double Bu[4], Bv[4]; |
487 | 0 | gs_fixed_point pts[4][4]; |
488 | 0 | int i, j; |
489 | 0 | double x = 0, y = 0; |
490 | | |
491 | | /* Compute the Bernstein polynomials of u and v. */ |
492 | 0 | { |
493 | 0 | double u2 = u * u, co_u = 1.0 - u, co_u2 = co_u * co_u; |
494 | 0 | double v2 = v * v, co_v = 1.0 - v, co_v2 = co_v * co_v; |
495 | |
|
496 | 0 | Bu[0] = co_u * co_u2, Bu[1] = 3 * u * co_u2, |
497 | 0 | Bu[2] = 3 * u2 * co_u, Bu[3] = u * u2; |
498 | 0 | Bv[0] = co_v * co_v2, Bv[1] = 3 * v * co_v2, |
499 | 0 | Bv[2] = 3 * v2 * co_v, Bv[3] = v * v2; |
500 | 0 | } |
501 | | |
502 | | /* Arrange the points into an indexable order. */ |
503 | 0 | pts[0][0] = curve[0].vertex.p; |
504 | 0 | pts[0][1] = curve[0].control[0]; |
505 | 0 | pts[0][2] = curve[0].control[1]; |
506 | 0 | pts[0][3] = curve[1].vertex.p; |
507 | 0 | pts[1][3] = curve[1].control[0]; |
508 | 0 | pts[2][3] = curve[1].control[1]; |
509 | 0 | pts[3][3] = curve[2].vertex.p; |
510 | 0 | pts[3][2] = curve[2].control[0]; |
511 | 0 | pts[3][1] = curve[2].control[1]; |
512 | 0 | pts[3][0] = curve[3].vertex.p; |
513 | 0 | pts[2][0] = curve[3].control[0]; |
514 | 0 | pts[1][0] = curve[3].control[1]; |
515 | 0 | pts[1][1] = interior[0]; |
516 | 0 | pts[2][1] = interior[1]; |
517 | 0 | pts[2][2] = interior[2]; |
518 | 0 | pts[1][2] = interior[3]; |
519 | | |
520 | | /* Now compute the actual point. */ |
521 | 0 | for (i = 0; i < 4; ++i) |
522 | 0 | for (j = 0; j < 4; ++j) { |
523 | 0 | double coeff = Bu[i] * Bv[j]; |
524 | |
|
525 | 0 | x += pts[i][j].x * coeff, y += pts[i][j].y * coeff; |
526 | 0 | } |
527 | 0 | pt->x = (fixed)x, pt->y = (fixed)y; |
528 | 0 | } |
529 | | |
530 | | int |
531 | | gs_shading_Tpp_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect, |
532 | | const gs_fixed_rect * rect_clip, |
533 | | gx_device * dev, gs_gstate * pgs) |
534 | 1.95k | { |
535 | 1.95k | const gs_shading_Tpp_t * const psh = (const gs_shading_Tpp_t *)psh0; |
536 | 1.95k | patch_fill_state_t state; |
537 | 1.95k | shade_coord_stream_t cs; |
538 | 1.95k | patch_curve_t curve[4]; |
539 | 1.95k | gs_fixed_point interior[4]; |
540 | 1.95k | int code; |
541 | | |
542 | 1.95k | code = mesh_init_fill_state((mesh_fill_state_t *) & state, |
543 | 1.95k | (const gs_shading_mesh_t *)psh0, rect_clip, dev, pgs); |
544 | 1.95k | if (code < 0) { |
545 | 0 | if (state.icclink != NULL) gsicc_release_link(state.icclink); |
546 | 0 | return code; |
547 | 0 | } |
548 | 1.95k | state.Function = psh->params.Function; |
549 | 1.95k | code = init_patch_fill_state(&state); |
550 | 1.95k | if(code < 0) |
551 | 0 | return code; |
552 | 1.95k | curve[0].straight = curve[1].straight = curve[2].straight = curve[3].straight = false; |
553 | 1.95k | shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, pgs); |
554 | 768k | while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag, |
555 | 768k | curve, interior)) == 0) { |
556 | | /* |
557 | | * The order of points appears to be consistent with that for Coons |
558 | | * patches, which is different from that documented in Red Book 3. |
559 | | */ |
560 | 766k | gs_fixed_point swapped_interior[4]; |
561 | | |
562 | 766k | swapped_interior[0] = interior[0]; |
563 | 766k | swapped_interior[1] = interior[3]; |
564 | 766k | swapped_interior[2] = interior[2]; |
565 | 766k | swapped_interior[3] = interior[1]; |
566 | 766k | code = patch_fill(&state, curve, swapped_interior, Tpp_transform); |
567 | 766k | if (code < 0) |
568 | 0 | break; |
569 | 766k | } |
570 | 1.95k | if (term_patch_fill_state(&state)) |
571 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
572 | 1.95k | if (state.icclink != NULL) gsicc_release_link(state.icclink); |
573 | 1.95k | return min(code, 0); |
574 | 1.95k | } |
575 | | |
576 | | /* |
577 | | This algorithm performs a decomposition of the shading area |
578 | | into a set of constant color trapezoids, some of which |
579 | | may use the transpozed coordinate system. |
580 | | |
581 | | The target device assumes semi-open intrvals by X to be painted |
582 | | (See PLRM3, 7.5. Scan conversion details), i.e. |
583 | | it doesn't paint pixels which falls exactly to the right side. |
584 | | Note that with raster devices the algorithm doesn't paint pixels, |
585 | | whigh are partially covered by the shading area, |
586 | | but which's centers are outside the area. |
587 | | |
588 | | Pixels inside a monotonic part of the shading area are painted |
589 | | at once, but some exceptions may happen : |
590 | | |
591 | | - While flattening boundaries of a subpatch, |
592 | | to keep the plane coverage contiguity we insert wedges |
593 | | between neighbor subpatches, which use a different |
594 | | flattening factor. With non-monotonic curves |
595 | | those wedges may overlap or be self-overlapping, and a pixel |
596 | | is painted so many times as many wedges cover it. Fortunately |
597 | | the area of most wedges is zero or extremily small. |
598 | | |
599 | | - Since quazi-horizontal wedges may have a non-constant color, |
600 | | they can't decompose into constant color trapezoids with |
601 | | keeping the coverage contiguity. To represent them we |
602 | | apply the XY plane transposition. But with the transposition |
603 | | a semiopen interval can met a non-transposed one, |
604 | | so that some lines are not covered. Therefore we emulate |
605 | | closed intervals with expanding the transposed trapesoids in |
606 | | fixed_epsilon, and pixels at that boundary may be painted twice. |
607 | | |
608 | | - A boundary of a monotonic area can't compute in XY |
609 | | preciselly due to high order polynomial equations. |
610 | | Therefore the subdivision near the monotonity boundary |
611 | | may paint some pixels twice within same monotonic part. |
612 | | |
613 | | Non-monotonic areas slow down due to a tinny subdivision required. |
614 | | |
615 | | The target device may be either raster or vector. |
616 | | Vector devices should preciselly pass trapezoids to the output. |
617 | | Note that ends of sides of a trapesoid are not necessary |
618 | | the trapezoid's vertices. Converting this thing into |
619 | | an exact quadrangle may cause an arithmetic error, |
620 | | and the rounding must be done so that the coverage |
621 | | contiguity is not lost. |
622 | | |
623 | | When a device passes a trapezoid to it's output, |
624 | | a regular rounding would keep the coverage contiguity, |
625 | | except for the transposed trapesoids. |
626 | | If a transposed trapezoid is being transposed back, |
627 | | it doesn't become a canonic trapezoid, and a further |
628 | | decomposition is neccessary. But rounding errors here |
629 | | would break the coverage contiguity at boundaries |
630 | | of the tansposed part of the area. |
631 | | |
632 | | Devices, which have no transposed trapezoids and represent |
633 | | trapezoids only with 8 coordinates of vertices of the quadrangle |
634 | | (pclwrite is an example) may apply the backward transposition, |
635 | | and a clipping instead the further decomposition. |
636 | | Note that many clip regions may appear for all wedges. |
637 | | Note that in some cases the adjustment of the right side to be |
638 | | withdrown before the backward transposition. |
639 | | */ |
640 | | /* We believe that a multiplication of 32-bit integers with a |
641 | | 64-bit result is performed by modern platforms performs |
642 | | in hardware level. Therefore we widely use it here, |
643 | | but we minimize the usage of a multiplication of longer integers. |
644 | | |
645 | | Unfortunately we do need a multiplication of long integers |
646 | | in intersection_of_small_bars, because solving the linear system |
647 | | requires tripple multiples of 'fixed'. Therefore we retain |
648 | | of it's usage in the algorithm of the main branch. |
649 | | Configuration macro QUADRANGLES prevents it. |
650 | | */ |
651 | | |
652 | | typedef struct { |
653 | | gs_fixed_point pole[4][4]; /* [v][u] */ |
654 | | patch_color_t *c[2][2]; /* [v][u] */ |
655 | | } tensor_patch; |
656 | | |
657 | | typedef enum { |
658 | | interpatch_padding = 1, /* A Padding between patches for poorly designed documents. */ |
659 | | inpatch_wedge = 2 /* Wedges while a patch decomposition. */ |
660 | | } wedge_type_t; |
661 | | |
662 | | int |
663 | | wedge_vertex_list_elem_buffer_alloc(patch_fill_state_t *pfs) |
664 | 267k | { |
665 | 267k | const int max_level = LAZY_WEDGES_MAX_LEVEL; |
666 | 267k | gs_memory_t *memory = pfs->memory; |
667 | | |
668 | | /* We have 'max_level' levels, each of which divides 1 or 3 sides. |
669 | | LAZY_WEDGES stores all 2^level divisions until |
670 | | the other area of same bnoundary is processed. |
671 | | Thus the upper estimation of the buffer size is : |
672 | | max_level * (1 << max_level) * 3. |
673 | | Likely this estimation to be decreased to |
674 | | max_level * (1 << max_level) * 2. |
675 | | because 1 side of a triangle is always outside the division path. |
676 | | For now we set the smaller estimation for obtaining an experimental data |
677 | | from the wild. */ |
678 | 267k | pfs->wedge_vertex_list_elem_count_max = max_level * (1 << max_level) * 2; |
679 | 267k | pfs->wedge_vertex_list_elem_buffer = (wedge_vertex_list_elem_t *)gs_alloc_bytes(memory, |
680 | 267k | sizeof(wedge_vertex_list_elem_t) * pfs->wedge_vertex_list_elem_count_max, |
681 | 267k | "alloc_wedge_vertex_list_elem_buffer"); |
682 | 267k | if (pfs->wedge_vertex_list_elem_buffer == NULL) |
683 | 0 | return_error(gs_error_VMerror); |
684 | 267k | pfs->free_wedge_vertex = NULL; |
685 | 267k | pfs->wedge_vertex_list_elem_count = 0; |
686 | 267k | return 0; |
687 | 267k | } |
688 | | |
689 | | void |
690 | | wedge_vertex_list_elem_buffer_free(patch_fill_state_t *pfs) |
691 | 267k | { |
692 | 267k | gs_memory_t *memory = pfs->memory; |
693 | | |
694 | 267k | gs_free_object(memory, pfs->wedge_vertex_list_elem_buffer, |
695 | 267k | "wedge_vertex_list_elem_buffer_free"); |
696 | 267k | pfs->wedge_vertex_list_elem_buffer = NULL; |
697 | 267k | pfs->free_wedge_vertex = NULL; |
698 | 267k | } |
699 | | |
700 | | static inline wedge_vertex_list_elem_t * |
701 | | wedge_vertex_list_elem_reserve(patch_fill_state_t *pfs) |
702 | 30.5M | { |
703 | 30.5M | wedge_vertex_list_elem_t *e = pfs->free_wedge_vertex; |
704 | | |
705 | 30.5M | if (e != NULL) { |
706 | 29.5M | pfs->free_wedge_vertex = e->next; |
707 | 29.5M | return e; |
708 | 29.5M | } |
709 | 950k | if (pfs->wedge_vertex_list_elem_count < pfs->wedge_vertex_list_elem_count_max) |
710 | 950k | return pfs->wedge_vertex_list_elem_buffer + pfs->wedge_vertex_list_elem_count++; |
711 | 0 | return NULL; |
712 | 950k | } |
713 | | |
714 | | static inline void |
715 | | wedge_vertex_list_elem_release(patch_fill_state_t *pfs, wedge_vertex_list_elem_t *e) |
716 | 30.5M | { |
717 | 30.5M | e->next = pfs->free_wedge_vertex; |
718 | 30.5M | pfs->free_wedge_vertex = e; |
719 | 30.5M | } |
720 | | |
721 | | static inline void |
722 | | release_wedge_vertex_list_interval(patch_fill_state_t *pfs, |
723 | | wedge_vertex_list_elem_t *beg, wedge_vertex_list_elem_t *end) |
724 | 15.9M | { |
725 | 15.9M | wedge_vertex_list_elem_t *e = beg->next, *ee; |
726 | | |
727 | 15.9M | beg->next = end; |
728 | 15.9M | end->prev = beg; |
729 | 30.8M | for (; e != end; e = ee) { |
730 | 14.9M | ee = e->next; |
731 | 14.9M | wedge_vertex_list_elem_release(pfs, e); |
732 | 14.9M | } |
733 | 15.9M | } |
734 | | |
735 | | static inline int |
736 | | release_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *ll, int n) |
737 | 7.78M | { |
738 | 7.78M | int i; |
739 | | |
740 | 15.5M | for (i = 0; i < n; i++) { |
741 | 7.78M | wedge_vertex_list_t *l = ll + i; |
742 | | |
743 | 7.78M | if (l->beg != NULL) { |
744 | 7.78M | if (l->end == NULL) |
745 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
746 | 7.78M | release_wedge_vertex_list_interval(pfs, l->beg, l->end); |
747 | 7.78M | wedge_vertex_list_elem_release(pfs, l->beg); |
748 | 7.78M | wedge_vertex_list_elem_release(pfs, l->end); |
749 | 7.78M | l->beg = l->end = NULL; |
750 | 7.78M | } else if (l->end != NULL) |
751 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
752 | 7.78M | } |
753 | 7.78M | return 0; |
754 | 7.78M | } |
755 | | |
756 | | static inline wedge_vertex_list_elem_t * |
757 | | wedge_vertex_list_find(wedge_vertex_list_elem_t *beg, const wedge_vertex_list_elem_t *end, |
758 | | int level) |
759 | 9.80M | { |
760 | 9.80M | wedge_vertex_list_elem_t *e = beg; |
761 | | |
762 | 9.80M | if (beg == NULL || end == NULL) |
763 | 0 | return NULL; /* Must not happen. */ |
764 | 26.7M | for (; e != end; e = e->next) |
765 | 26.7M | if (e->level == level) |
766 | 9.80M | return e; |
767 | 0 | return NULL; |
768 | 9.80M | } |
769 | | |
770 | | static inline void |
771 | | init_wedge_vertex_list(wedge_vertex_list_t *l, int n) |
772 | 65.1M | { |
773 | 65.1M | memset(l, 0, sizeof(*l) * n); |
774 | 65.1M | } |
775 | | |
776 | | /* For a given set of poles in the tensor patch (for instance |
777 | | * [0][0], [0][1], [0][2], [0][3] or [0][2], [1][2], [2][2], [3][2]) |
778 | | * return the number of subdivisions required to flatten the bezier |
779 | | * given by those poles to the required flatness. |
780 | | */ |
781 | | static inline int |
782 | | curve_samples(patch_fill_state_t *pfs, |
783 | | const gs_fixed_point *pole, int pole_step, fixed fixed_flat) |
784 | 30.8M | { |
785 | 30.8M | curve_segment s; |
786 | 30.8M | int k; |
787 | | |
788 | 30.8M | s.p1.x = pole[pole_step].x; |
789 | 30.8M | s.p1.y = pole[pole_step].y; |
790 | 30.8M | s.p2.x = pole[pole_step * 2].x; |
791 | 30.8M | s.p2.y = pole[pole_step * 2].y; |
792 | 30.8M | s.pt.x = pole[pole_step * 3].x; |
793 | 30.8M | s.pt.y = pole[pole_step * 3].y; |
794 | 30.8M | k = gx_curve_log2_samples(pole[0].x, pole[0].y, &s, fixed_flat); |
795 | 30.8M | { |
796 | 30.8M | # if LAZY_WEDGES || QUADRANGLES |
797 | 30.8M | int k1; |
798 | 30.8M | fixed L = any_abs(pole[pole_step * 1].x - pole[pole_step * 0].x) + any_abs(pole[pole_step * 1].y - pole[pole_step * 0].y) + |
799 | 30.8M | any_abs(pole[pole_step * 2].x - pole[pole_step * 1].x) + any_abs(pole[pole_step * 2].y - pole[pole_step * 1].y) + |
800 | 30.8M | any_abs(pole[pole_step * 3].x - pole[pole_step * 2].x) + any_abs(pole[pole_step * 3].y - pole[pole_step * 2].y); |
801 | 30.8M | # endif |
802 | | |
803 | 30.8M | # if LAZY_WEDGES |
804 | | /* Restrict lengths for a reasonable memory consumption : */ |
805 | 30.8M | k1 = ilog2(L / fixed_1 / (1 << (LAZY_WEDGES_MAX_LEVEL - 1))); |
806 | 30.8M | k = max(k, k1); |
807 | 30.8M | # endif |
808 | | # if QUADRANGLES |
809 | | /* Restrict lengths for intersection_of_small_bars : */ |
810 | | k = max(k, ilog2(L) - ilog2(pfs->max_small_coord)); |
811 | | # endif |
812 | 30.8M | } |
813 | 30.8M | return 1 << k; |
814 | 30.8M | } |
815 | | |
816 | | static inline bool |
817 | | intersection_of_small_bars(const gs_fixed_point q[4], int i0, int i1, int i2, int i3, fixed *ry, fixed *ey) |
818 | 0 | { |
819 | | /* This function is only used with QUADRANGLES. */ |
820 | 0 | return gx_intersect_small_bars(q[i0].x, q[i0].y, q[i1].x, q[i1].y, q[i2].x, q[i2].y, q[i3].x, q[i3].y, ry, ey); |
821 | 0 | } |
822 | | |
823 | | static inline void |
824 | | adjust_swapped_boundary(fixed *b, bool swap_axes) |
825 | 129M | { |
826 | 129M | if (swap_axes) { |
827 | | /* Sinse the rasterizer algorithm assumes semi-open interval |
828 | | when computing pixel coverage, we should expand |
829 | | the right side of the area. Otherwise a dropout can happen : |
830 | | if the left neighbour is painted with !swap_axes, |
831 | | the left side of this area appears to be the left side |
832 | | of the neighbour area, and the side is not included |
833 | | into both areas. |
834 | | */ |
835 | 56.6M | *b += fixed_epsilon; |
836 | 56.6M | } |
837 | 129M | } |
838 | | |
839 | | static inline void |
840 | | make_trapezoid(const gs_fixed_point q[4], |
841 | | int vi0, int vi1, int vi2, int vi3, fixed ybot, fixed ytop, |
842 | | bool swap_axes, bool orient, gs_fixed_edge *le, gs_fixed_edge *re) |
843 | 29.3M | { |
844 | 29.3M | if (!orient) { |
845 | 16.3M | le->start = q[vi0]; |
846 | 16.3M | le->end = q[vi1]; |
847 | 16.3M | re->start = q[vi2]; |
848 | 16.3M | re->end = q[vi3]; |
849 | 16.3M | } else { |
850 | 12.9M | le->start = q[vi2]; |
851 | 12.9M | le->end = q[vi3]; |
852 | 12.9M | re->start = q[vi0]; |
853 | 12.9M | re->end = q[vi1]; |
854 | 12.9M | } |
855 | 29.3M | adjust_swapped_boundary(&re->start.x, swap_axes); |
856 | 29.3M | adjust_swapped_boundary(&re->end.x, swap_axes); |
857 | 29.3M | } |
858 | | |
859 | | static inline int |
860 | | gx_shade_trapezoid(patch_fill_state_t *pfs, const gs_fixed_point q[4], |
861 | | int vi0, int vi1, int vi2, int vi3, fixed ybot0, fixed ytop0, |
862 | | bool swap_axes, const gx_device_color *pdevc, bool orient) |
863 | 2.06M | { |
864 | 2.06M | gs_fixed_edge le, re; |
865 | 2.06M | int code; |
866 | 2.06M | fixed ybot = max(ybot0, swap_axes ? pfs->rect.p.x : pfs->rect.p.y); |
867 | 2.06M | fixed ytop = min(ytop0, swap_axes ? pfs->rect.q.x : pfs->rect.q.y); |
868 | 2.06M | fixed xleft = (swap_axes ? pfs->rect.p.y : pfs->rect.p.x); |
869 | 2.06M | fixed xright = (swap_axes ? pfs->rect.q.y : pfs->rect.q.x); |
870 | | |
871 | 2.06M | if (ybot >= ytop) |
872 | 682k | return 0; |
873 | | # if NOFILL_TEST |
874 | | if (dbg_nofill) |
875 | | return 0; |
876 | | # endif |
877 | 1.38M | make_trapezoid(q, vi0, vi1, vi2, vi3, ybot, ytop, swap_axes, orient, &le, &re); |
878 | 1.38M | if (!pfs->inside) { |
879 | 684k | bool clip = false; |
880 | | |
881 | | /* We are asked to clip a trapezoid to a rectangle. If the rectangle |
882 | | * is entirely contained within the rectangle, then no clipping is |
883 | | * actually required. If the left edge is entirely to the right of |
884 | | * the rectangle, or the right edge is entirely to the left, we |
885 | | * clip away to nothing. If the left edge is entirely to the left of |
886 | | * the rectangle, then we can simplify it to a vertical edge along |
887 | | * the edge of the rectangle. Likewise with the right edge if it's |
888 | | * entirely to the right of the rectangle.*/ |
889 | 684k | if (le.start.x > xright) { |
890 | 56.8k | if (le.end.x > xright) { |
891 | 126 | return 0; |
892 | 126 | } |
893 | 56.6k | clip = true; |
894 | 627k | } else if (le.end.x > xright) { |
895 | 36.6k | clip = true; |
896 | 36.6k | } |
897 | 684k | if (le.start.x < xleft) { |
898 | 281k | if (le.end.x < xleft) { |
899 | 64.4k | le.start.x = xleft; |
900 | 64.4k | le.end.x = xleft; |
901 | 64.4k | le.start.y = ybot; |
902 | 64.4k | le.end.y = ytop; |
903 | 216k | } else { |
904 | 216k | clip = true; |
905 | 216k | } |
906 | 403k | } else if (le.end.x < xleft) { |
907 | 145k | clip = true; |
908 | 145k | } |
909 | 684k | if (re.start.x < xleft) { |
910 | 41.6k | if (re.end.x < xleft) { |
911 | 39 | return 0; |
912 | 39 | } |
913 | 41.6k | clip = true; |
914 | 642k | } else if (re.end.x < xleft) { |
915 | 56.5k | clip = true; |
916 | 56.5k | } |
917 | 684k | if (re.start.x > xright) { |
918 | 199k | if (re.end.x > xright) { |
919 | 53.0k | re.start.x = xright; |
920 | 53.0k | re.end.x = xright; |
921 | 53.0k | re.start.y = ybot; |
922 | 53.0k | re.end.y = ytop; |
923 | 146k | } else { |
924 | 146k | clip = true; |
925 | 146k | } |
926 | 485k | } else if (re.end.x > xright) { |
927 | 214k | clip = true; |
928 | 214k | } |
929 | 684k | if (clip) |
930 | 481k | { |
931 | | /* Some form of clipping seems to be required. A certain amount |
932 | | * of horridness goes on here to ensure that we round 'outwards' |
933 | | * in all cases. */ |
934 | 481k | gs_fixed_edge lenew, renew; |
935 | 481k | fixed ybl, ybr, ytl, ytr, ymid; |
936 | | |
937 | | /* Reduce the clipping region horizontally if possible. */ |
938 | 481k | if (re.start.x > re.end.x) { |
939 | 177k | if (re.start.x < xright) |
940 | 31.2k | xright = re.start.x; |
941 | 304k | } else if (re.end.x < xright) |
942 | 39.6k | xright = re.end.x; |
943 | 481k | if (le.start.x > le.end.x) { |
944 | 177k | if (le.end.x > xleft) |
945 | 31.9k | xleft = le.end.x; |
946 | 304k | } else if (le.start.x > xleft) |
947 | 35.1k | xleft = le.start.x; |
948 | | |
949 | 481k | ybot = max(ybot, min(le.start.y, re.start.y)); |
950 | 481k | ytop = min(ytop, max(le.end.y, re.end.y)); |
951 | | #if 0 |
952 | | /* RJW: I've disabled this code a) because it doesn't make any |
953 | | * difference in the cluster tests, and b) because I think it's wrong. |
954 | | * Taking the first case as an example; just because the le.start.x |
955 | | * is > xright, does not mean that we can simply truncate the edge at |
956 | | * xright, as this may throw away part of the trap between ybot and |
957 | | * the new le.start.y. */ |
958 | | /* Reduce the edges to the left/right of the clipping region. */ |
959 | | /* Only in the 4 cases which can bring ytop/ybot closer */ |
960 | | if (le.start.x > xright) { |
961 | | le.start.y += (fixed)((int64_t)(le.end.y-le.start.y)* |
962 | | (int64_t)(le.start.x-xright)/ |
963 | | (int64_t)(le.start.x-le.end.x)); |
964 | | le.start.x = xright; |
965 | | } |
966 | | if (re.start.x < xleft) { |
967 | | re.start.y += (fixed)((int64_t)(re.end.y-re.start.y)* |
968 | | (int64_t)(xleft-re.start.x)/ |
969 | | (int64_t)(re.end.x-re.start.x)); |
970 | | re.start.x = xleft; |
971 | | } |
972 | | if (le.end.x > xright) { |
973 | | le.end.y -= (fixed)((int64_t)(le.end.y-le.start.y)* |
974 | | (int64_t)(le.end.x-xright)/ |
975 | | (int64_t)(le.end.x-le.start.x)); |
976 | | le.end.x = xright; |
977 | | } |
978 | | if (re.end.x < xleft) { |
979 | | re.end.y -= (fixed)((int64_t)(re.end.y-re.start.y)* |
980 | | (int64_t)(xleft-re.end.x)/ |
981 | | (int64_t)(re.start.x-re.end.x)); |
982 | | re.end.x = xleft; |
983 | | } |
984 | | #endif |
985 | | |
986 | 481k | if (ybot >= ytop) |
987 | 0 | return 0; |
988 | | /* Follow the edges in, so that le.start.y == ybot etc. */ |
989 | 481k | if (le.start.y < ybot) { |
990 | 265k | int round = ((le.end.x < le.start.x) ? |
991 | 138k | (le.end.y-le.start.y-1) : 0); |
992 | 265k | le.start.x += (fixed)(((int64_t)(ybot-le.start.y)* |
993 | 265k | (int64_t)(le.end.x-le.start.x)-round)/ |
994 | 265k | (int64_t)(le.end.y-le.start.y)); |
995 | 265k | le.start.y = ybot; |
996 | 265k | } |
997 | 481k | if (le.end.y > ytop) { |
998 | 267k | int round = ((le.end.x > le.start.x) ? |
999 | 224k | (le.end.y-le.start.y-1) : 0); |
1000 | 267k | le.end.x += (fixed)(((int64_t)(le.end.y-ytop)* |
1001 | 267k | (int64_t)(le.start.x-le.end.x)-round)/ |
1002 | 267k | (int64_t)(le.end.y-le.start.y)); |
1003 | 267k | le.end.y = ytop; |
1004 | 267k | } |
1005 | 481k | if ((le.start.x < xleft) && (le.end.x < xleft)) { |
1006 | 266k | le.start.x = xleft; |
1007 | 266k | le.end.x = xleft; |
1008 | 266k | le.start.y = ybot; |
1009 | 266k | le.end.y = ytop; |
1010 | 266k | } |
1011 | 481k | if (re.start.y < ybot) { |
1012 | 268k | int round = ((re.end.x > re.start.x) ? |
1013 | 224k | (re.end.y-re.start.y-1) : 0); |
1014 | 268k | re.start.x += (fixed)(((int64_t)(ybot-re.start.y)* |
1015 | 268k | (int64_t)(re.end.x-re.start.x)+round)/ |
1016 | 268k | (int64_t)(re.end.y-re.start.y)); |
1017 | 268k | re.start.y = ybot; |
1018 | 268k | } |
1019 | 481k | if (re.end.y > ytop) { |
1020 | 270k | int round = ((re.end.x < re.start.x) ? |
1021 | 138k | (re.end.y-re.start.y-1) : 0); |
1022 | 270k | re.end.x += (fixed)(((int64_t)(re.end.y-ytop)* |
1023 | 270k | (int64_t)(re.start.x-re.end.x)+round)/ |
1024 | 270k | (int64_t)(re.end.y-re.start.y)); |
1025 | 270k | re.end.y = ytop; |
1026 | 270k | } |
1027 | 481k | if ((re.start.x > xright) && (re.end.x > xright)) { |
1028 | 95.1k | re.start.x = xright; |
1029 | 95.1k | re.end.x = xright; |
1030 | 95.1k | re.start.y = ybot; |
1031 | 95.1k | re.end.y = ytop; |
1032 | 95.1k | } |
1033 | | /* Now, check whether the left and right edges cross. Previously |
1034 | | * this comment said: "This can only happen (for well formed |
1035 | | * input) in the case where one of the edges was completely out |
1036 | | * of range and has now been pulled in to the edge of the clip |
1037 | | * region." I now do not believe this to be true. */ |
1038 | 481k | if (le.start.x > re.start.x) { |
1039 | 76.4k | if (le.start.x == le.end.x) { |
1040 | 36.9k | if (re.start.x == re.end.x) |
1041 | 0 | return 0; |
1042 | 36.9k | ybot += (fixed)((int64_t)(re.end.y-re.start.y)* |
1043 | 36.9k | (int64_t)(le.start.x-re.start.x)/ |
1044 | 36.9k | (int64_t)(re.end.x-re.start.x)); |
1045 | 36.9k | re.start.x = le.start.x; |
1046 | 39.4k | } else { |
1047 | 39.4k | ybot += (fixed)((int64_t)(le.end.y-le.start.y)* |
1048 | 39.4k | (int64_t)(le.start.x-re.start.x)/ |
1049 | 39.4k | (int64_t)(le.start.x-le.end.x)); |
1050 | 39.4k | le.start.x = re.start.x; |
1051 | 39.4k | } |
1052 | 76.4k | if (ybot >= ytop) |
1053 | 26.1k | return 0; |
1054 | 50.3k | le.start.y = ybot; |
1055 | 50.3k | re.start.y = ybot; |
1056 | 50.3k | } |
1057 | 455k | if (le.end.x > re.end.x) { |
1058 | 49.7k | if (le.start.x == le.end.x) { |
1059 | 30.4k | if (re.start.x == re.end.x) |
1060 | 0 | return 0; |
1061 | 30.4k | ytop -= (fixed)((int64_t)(re.end.y-re.start.y)* |
1062 | 30.4k | (int64_t)(le.end.x-re.end.x)/ |
1063 | 30.4k | (int64_t)(re.start.x-re.end.x)); |
1064 | 30.4k | re.end.x = le.end.x; |
1065 | 30.4k | } else { |
1066 | 19.2k | ytop -= (fixed)((int64_t)(le.end.y-le.start.y)* |
1067 | 19.2k | (int64_t)(le.end.x-re.end.x)/ |
1068 | 19.2k | (int64_t)(le.end.x-le.start.x)); |
1069 | 19.2k | le.end.x = re.end.x; |
1070 | 19.2k | } |
1071 | 49.7k | if (ybot >= ytop) |
1072 | 24.2k | return 0; |
1073 | 25.4k | le.end.y = ytop; |
1074 | 25.4k | re.end.y = ytop; |
1075 | 25.4k | } |
1076 | | /* At this point we are guaranteed that le and re are constrained |
1077 | | * as tightly as possible to the ybot/ytop range, and that the |
1078 | | * entire ybot/ytop range will be marked at least somewhere. All |
1079 | | * we need to do now is to actually fill the region. |
1080 | | */ |
1081 | 431k | lenew.start.x = xleft; |
1082 | 431k | lenew.start.y = ybot; |
1083 | 431k | lenew.end.x = xleft; |
1084 | 431k | lenew.end.y = ytop; |
1085 | 431k | renew.start.x = xright; |
1086 | 431k | renew.start.y = ybot; |
1087 | 431k | renew.end.x = xright; |
1088 | 431k | renew.end.y = ytop; |
1089 | | /* Figure out where the left edge intersects with the left at |
1090 | | * the bottom */ |
1091 | 431k | ybl = ybot; |
1092 | 431k | if (le.start.x > le.end.x) { |
1093 | 65.9k | ybl += (fixed)((int64_t)(le.start.x-xleft) * |
1094 | 65.9k | (int64_t)(le.end.y-le.start.y) / |
1095 | 65.9k | (int64_t)(le.start.x-le.end.x)); |
1096 | 65.9k | if (ybl > ytop) |
1097 | 26.2k | ybl = ytop; |
1098 | 65.9k | } |
1099 | | /* Figure out where the right edge intersects with the right at |
1100 | | * the bottom */ |
1101 | 431k | ybr = ybot; |
1102 | 431k | if (re.start.x < re.end.x) { |
1103 | 149k | ybr += (fixed)((int64_t)(xright-re.start.x) * |
1104 | 149k | (int64_t)(re.end.y-re.start.y) / |
1105 | 149k | (int64_t)(re.end.x-re.start.x)); |
1106 | 149k | if (ybr > ytop) |
1107 | 28.3k | ybr = ytop; |
1108 | 149k | } |
1109 | | /* Figure out where the left edge intersects with the left at |
1110 | | * the top */ |
1111 | 431k | ytl = ytop; |
1112 | 431k | if (le.end.x > le.start.x) { |
1113 | 72.6k | ytl -= (fixed)((int64_t)(le.end.x-xleft) * |
1114 | 72.6k | (int64_t)(le.end.y-le.start.y) / |
1115 | 72.6k | (int64_t)(le.end.x-le.start.x)); |
1116 | 72.6k | if (ytl < ybot) |
1117 | 26.4k | ytl = ybot; |
1118 | 72.6k | } |
1119 | | /* Figure out where the right edge intersects with the right at |
1120 | | * the bottom */ |
1121 | 431k | ytr = ytop; |
1122 | 431k | if (re.end.x < re.start.x) { |
1123 | 160k | ytr -= (fixed)((int64_t)(xright-re.end.x) * |
1124 | 160k | (int64_t)(re.end.y-re.start.y) / |
1125 | 160k | (int64_t)(re.start.x-re.end.x)); |
1126 | 160k | if (ytr < ybot) |
1127 | 25.8k | ytr = ybot; |
1128 | 160k | } |
1129 | | /* Check for the 2 cases where top and bottom diagonal extents |
1130 | | * overlap, and deal with them explicitly. */ |
1131 | 431k | if (ytl < ybr) { |
1132 | | /* | | |
1133 | | * ---+-----+--- |
1134 | | * | /222| |
1135 | | * |/111/| |
1136 | | * |000/ | |
1137 | | * ---+-----+--- |
1138 | | * | | |
1139 | | */ |
1140 | 28.8k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1141 | 28.8k | &lenew, &re, ybot, ytl, |
1142 | 28.8k | swap_axes, pdevc, pfs->pgs->log_op); |
1143 | 28.8k | if (code < 0) |
1144 | 0 | return code; |
1145 | 28.8k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1146 | 28.8k | &le, &re, ytl, ybr, |
1147 | 28.8k | swap_axes, pdevc, pfs->pgs->log_op); |
1148 | 28.8k | if (code < 0) |
1149 | 0 | return code; |
1150 | 28.8k | ybot = ybr; |
1151 | 28.8k | return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1152 | 28.8k | &le, &renew, ybr, ytop, |
1153 | 28.8k | swap_axes, pdevc, pfs->pgs->log_op); |
1154 | 402k | } else if (ytr < ybl) { |
1155 | | /* | | |
1156 | | * ---+-----+---- |
1157 | | * |555\ | |
1158 | | * |\444\| |
1159 | | * | \333| |
1160 | | * ---+-----+--- |
1161 | | * | | |
1162 | | */ |
1163 | 33.6k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1164 | 33.6k | &le, &renew, ybot, ytr, |
1165 | 33.6k | swap_axes, pdevc, pfs->pgs->log_op); |
1166 | 33.6k | if (code < 0) |
1167 | 0 | return code; |
1168 | 33.6k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1169 | 33.6k | &le, &re, ytr, ybl, |
1170 | 33.6k | swap_axes, pdevc, pfs->pgs->log_op); |
1171 | 33.6k | if (code < 0) |
1172 | 0 | return code; |
1173 | 33.6k | return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1174 | 33.6k | &le, &re, ybl, ytop, |
1175 | 33.6k | swap_axes, pdevc, pfs->pgs->log_op); |
1176 | 33.6k | } |
1177 | | /* Fill in any section where both left and right edges are |
1178 | | * diagonal at the bottom */ |
1179 | 369k | ymid = ybl; |
1180 | 369k | if (ymid > ybr) |
1181 | 22.3k | ymid = ybr; |
1182 | 369k | if (ymid > ybot) { |
1183 | | /* |\ | | /| |
1184 | | * | \6/| or |\6/ | |
1185 | | * ---+----+--- ---+----+--- |
1186 | | * | | | | |
1187 | | */ |
1188 | 8.78k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1189 | 8.78k | &le, &re, ybot, ymid, |
1190 | 8.78k | swap_axes, pdevc, pfs->pgs->log_op); |
1191 | 8.78k | if (code < 0) |
1192 | 0 | return code; |
1193 | 8.78k | ybot = ymid; |
1194 | 8.78k | } |
1195 | | /* Fill in any section where both left and right edges are |
1196 | | * diagonal at the top */ |
1197 | 369k | ymid = ytl; |
1198 | 369k | if (ymid < ytr) |
1199 | 18.2k | ymid = ytr; |
1200 | 369k | if (ymid < ytop) { |
1201 | | /* | | | | |
1202 | | * ---+----+--- ---+----+--- |
1203 | | * |/7\ | or | /7\| |
1204 | | * | \| |/ | |
1205 | | */ |
1206 | 10.3k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1207 | 10.3k | &le, &re, ymid, ytop, |
1208 | 10.3k | swap_axes, pdevc, pfs->pgs->log_op); |
1209 | 10.3k | if (code < 0) |
1210 | 0 | return code; |
1211 | 10.3k | ytop = ymid; |
1212 | 10.3k | } |
1213 | | /* Now do the single diagonal cases at the bottom */ |
1214 | 369k | if (ybl > ybot) { |
1215 | | /* | | |
1216 | | * |\666| |
1217 | | * ---+----+--- |
1218 | | * | | |
1219 | | */ |
1220 | 22.3k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1221 | 22.3k | &le, &renew, ybot, ybl, |
1222 | 22.3k | swap_axes, pdevc, pfs->pgs->log_op); |
1223 | 22.3k | if (code < 0) |
1224 | 0 | return code; |
1225 | 22.3k | ybot = ybl; |
1226 | 346k | } else if (ybr > ybot) { |
1227 | | /* | | |
1228 | | * |777/| |
1229 | | * ---+----+--- |
1230 | | * | | |
1231 | | */ |
1232 | 19.3k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1233 | 19.3k | &lenew, &re, ybot, ybr, |
1234 | 19.3k | swap_axes, pdevc, pfs->pgs->log_op); |
1235 | 19.3k | if (code < 0) |
1236 | 0 | return code; |
1237 | 19.3k | ybot = ybr; |
1238 | 19.3k | } |
1239 | | /* Now do the single diagonal cases at the top */ |
1240 | 369k | if (ytl < ytop) { |
1241 | | /* | | |
1242 | | * ---+----+--- |
1243 | | * |/888| |
1244 | | * | | |
1245 | | */ |
1246 | 18.2k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1247 | 18.2k | &le, &renew, ytl, ytop, |
1248 | 18.2k | swap_axes, pdevc, pfs->pgs->log_op); |
1249 | 18.2k | if (code < 0) |
1250 | 0 | return code; |
1251 | 18.2k | ytop = ytl; |
1252 | 350k | } else if (ytr < ytop) { |
1253 | | /* | | |
1254 | | * ---+----+--- |
1255 | | * |999\| |
1256 | | * | | |
1257 | | */ |
1258 | 24.0k | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1259 | 24.0k | &lenew, &re, ytr, ytop, |
1260 | 24.0k | swap_axes, pdevc, pfs->pgs->log_op); |
1261 | 24.0k | if (code < 0) |
1262 | 0 | return code; |
1263 | 24.0k | ytop = ytr; |
1264 | 24.0k | } |
1265 | | /* And finally just whatever rectangular section is left over in |
1266 | | * the middle */ |
1267 | 369k | if (ybot > ytop) |
1268 | 0 | return 0; |
1269 | 369k | return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1270 | 369k | &lenew, &renew, ybot, ytop, |
1271 | 369k | swap_axes, pdevc, pfs->pgs->log_op); |
1272 | 369k | } |
1273 | 684k | } |
1274 | 905k | return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1275 | 905k | &le, &re, ybot, ytop, swap_axes, pdevc, pfs->pgs->log_op); |
1276 | 1.38M | } |
1277 | | |
1278 | | static inline void |
1279 | | dc2fc31(const patch_fill_state_t *pfs, gx_device_color *pdevc, |
1280 | | frac31 fc[GX_DEVICE_COLOR_MAX_COMPONENTS]) |
1281 | 0 | { |
1282 | 0 | int j; |
1283 | 0 | const gx_device_color_info *cinfo = &pfs->trans_device->color_info; |
1284 | | /* Note trans device is actually either the transparency parent |
1285 | | device if transparency is present or the target device. Basically |
1286 | | the device from which we want to get the color information from |
1287 | | for this */ |
1288 | |
|
1289 | 0 | if (pdevc->type == &gx_dc_type_data_pure) { |
1290 | 0 | for (j = 0; j < cinfo->num_components; j++) { |
1291 | 0 | int shift = cinfo->comp_shift[j]; |
1292 | 0 | int bits = cinfo->comp_bits[j]; |
1293 | |
|
1294 | 0 | fc[j] = ((pdevc->colors.pure >> shift) & ((1 << bits) - 1)) << |
1295 | 0 | (sizeof(frac31) * 8 - 1 - bits); |
1296 | 0 | } |
1297 | 0 | } else { |
1298 | 0 | for (j = 0; j < cinfo->num_components; j++) { |
1299 | 0 | fc[j] = cv2frac31(pdevc->colors.devn.values[j]); |
1300 | 0 | } |
1301 | 0 | } |
1302 | 0 | } |
1303 | | |
1304 | 853M | #define DEBUG_COLOR_INDEX_CACHE 0 |
1305 | | |
1306 | | static inline int |
1307 | | patch_color_to_device_color_inline(const patch_fill_state_t *pfs, |
1308 | | const patch_color_t *c, gx_device_color *pdevc, |
1309 | | frac31 *frac_values) |
1310 | 213M | { |
1311 | | /* Must return 2 if the color is not pure. |
1312 | | See try_device_linear_color. |
1313 | | */ |
1314 | 213M | int code; |
1315 | 213M | gx_device_color devc; |
1316 | | |
1317 | 213M | #ifdef PACIFY_VALGRIND |
1318 | | /* This is a hack to get us around some valgrind warnings seen |
1319 | | * when transparency is in use with the clist. We run through |
1320 | | * the shading code dealing with pfs->num_components components. |
1321 | | * I believe this is intended to match the source space of the |
1322 | | * shading, as we have to perform all shadings in the source |
1323 | | * space initially, and only convert after decomposition. |
1324 | | * When this reaches down to the clist writing phase, the |
1325 | | * clist writes pfs->dev->color_info.num_components color |
1326 | | * components to the clist. In the example I am using |
1327 | | * pfs->num_components = 1 |
1328 | | * pfs->dev->color_info.num_components=3 |
1329 | | * So valgrind complains that 2 of the 3 color components |
1330 | | * it is writing are uninitialised. Magically, it appears |
1331 | | * not to actually use them when read back though, so |
1332 | | * it suffices to blank them to kill the warnings now. |
1333 | | * If pfs->num_components > pfs->dev->color_info.num_components |
1334 | | * then we'll not be writing enough information to the clist |
1335 | | * and so hopefully we'll see bad rendering! |
1336 | | * |
1337 | | * An example that shows why this is required: |
1338 | | * make gsdebugvg |
1339 | | * valgrind --track-origins=yes debugbin/gs -sOutputFile=test.ps |
1340 | | * -dMaxBitmap=1000 -sDEVICE=ps2write -r300 -Z: -dNOPAUSE |
1341 | | * -dBATCH -K2000000 -dClusterJob Bug693480.pdf |
1342 | | * (though ps2write is not implicated here). |
1343 | | */ |
1344 | 213M | if (frac_values) { |
1345 | 141M | int i; |
1346 | 141M | int n = pfs->dev->color_info.num_components; |
1347 | 168M | for (i = pfs->num_components; i < n; i++) { |
1348 | 27.0M | frac_values[i] = 0; |
1349 | 27.0M | } |
1350 | 141M | } |
1351 | 213M | #endif |
1352 | | |
1353 | 213M | if (DEBUG_COLOR_INDEX_CACHE && pdevc == NULL) |
1354 | 0 | pdevc = &devc; |
1355 | 213M | if (pfs->pcic) { |
1356 | 143M | code = gs_cached_color_index(pfs->pcic, c->cc.paint.values, pdevc, frac_values); |
1357 | 143M | if (code < 0) |
1358 | 0 | return code; |
1359 | 143M | } |
1360 | 213M | if (DEBUG_COLOR_INDEX_CACHE || pfs->pcic == NULL) { |
1361 | | # if DEBUG_COLOR_INDEX_CACHE |
1362 | | gx_color_index cindex = pdevc->colors.pure; |
1363 | | # endif |
1364 | 70.1M | gs_client_color fcc; |
1365 | 70.1M | const gs_color_space *pcs = pfs->direct_space; |
1366 | | |
1367 | 70.1M | if (pcs != NULL) { |
1368 | | |
1369 | 70.1M | if (pdevc == NULL) |
1370 | 0 | pdevc = &devc; |
1371 | 70.1M | memcpy(fcc.paint.values, c->cc.paint.values, |
1372 | 70.1M | sizeof(fcc.paint.values[0]) * pfs->num_components); |
1373 | 70.1M | code = pcs->type->remap_color(&fcc, pcs, pdevc, pfs->pgs, |
1374 | 70.1M | pfs->trans_device, gs_color_select_texture); |
1375 | 70.1M | if (code < 0) |
1376 | 0 | return code; |
1377 | 70.1M | if (frac_values != NULL) { |
1378 | 0 | if (!(pdevc->type == &gx_dc_type_data_devn || |
1379 | 0 | pdevc->type == &gx_dc_type_data_pure)) |
1380 | 0 | return 2; |
1381 | 0 | dc2fc31(pfs, pdevc, frac_values); |
1382 | 0 | } |
1383 | | # if DEBUG_COLOR_INDEX_CACHE |
1384 | | if (cindex != pdevc->colors.pure) |
1385 | | return_error(gs_error_unregistered); |
1386 | | # endif |
1387 | 70.1M | } else { |
1388 | | /* This is reserved for future extension, |
1389 | | when a linear color triangle with frac31 colors is being decomposed |
1390 | | during a clist rasterization. In this case frac31 colors are written into |
1391 | | the patch color, and pcs==NULL means an identity color mapping. |
1392 | | For a while we assume here pfs->pcic is also NULL. */ |
1393 | 0 | int j; |
1394 | 0 | const gx_device_color_info *cinfo = &pfs->dev->color_info; |
1395 | |
|
1396 | 0 | for (j = 0; j < cinfo->num_components; j++) |
1397 | 0 | frac_values[j] = (frac31)c->cc.paint.values[j]; |
1398 | 0 | pdevc->type = &gx_dc_type_data_pure; |
1399 | 0 | } |
1400 | 70.1M | } |
1401 | 213M | return 0; |
1402 | 213M | } |
1403 | | |
1404 | | int |
1405 | | patch_color_to_device_color(const patch_fill_state_t *pfs, const patch_color_t *c, gx_device_color *pdevc) |
1406 | 0 | { |
1407 | 0 | return patch_color_to_device_color_inline(pfs, c, pdevc, NULL); |
1408 | 0 | } |
1409 | | |
1410 | | static inline double |
1411 | | color_span(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1) |
1412 | 337M | { |
1413 | 337M | int n = pfs->num_components, i; |
1414 | 337M | double m; |
1415 | | |
1416 | | /* Dont want to copy colors, which are big things. */ |
1417 | 337M | m = any_abs(c1->cc.paint.values[0] - c0->cc.paint.values[0]) / pfs->color_domain.paint.values[0]; |
1418 | 1.25G | for (i = 1; i < n; i++) |
1419 | 922M | m = max(m, any_abs(c1->cc.paint.values[i] - c0->cc.paint.values[i]) / pfs->color_domain.paint.values[i]); |
1420 | 337M | return m; |
1421 | 337M | } |
1422 | | |
1423 | | static inline void |
1424 | | color_diff(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1, patch_color_t *d) |
1425 | 67.2M | { |
1426 | 67.2M | int n = pfs->num_components, i; |
1427 | | |
1428 | 320M | for (i = 0; i < n; i++) |
1429 | 252M | d->cc.paint.values[i] = c1->cc.paint.values[i] - c0->cc.paint.values[i]; |
1430 | 67.2M | } |
1431 | | |
1432 | | static inline double |
1433 | | color_norm(const patch_fill_state_t *pfs, const patch_color_t *c) |
1434 | 51.6M | { |
1435 | 51.6M | int n = pfs->num_components, i; |
1436 | 51.6M | double m; |
1437 | | |
1438 | 51.6M | m = any_abs(c->cc.paint.values[0]) / pfs->color_domain.paint.values[0]; |
1439 | 194M | for (i = 1; i < n; i++) |
1440 | 142M | m = max(m, any_abs(c->cc.paint.values[i]) / pfs->color_domain.paint.values[i]); |
1441 | 51.6M | return m; |
1442 | 51.6M | } |
1443 | | |
1444 | | static inline int |
1445 | | isnt_color_monotonic(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1) |
1446 | 14.2M | { /* checks whether the color is monotonic in the n-dimensional interval, |
1447 | | where n is the number of parameters in c0->t, c1->t. |
1448 | | returns : 0 = monotonic, |
1449 | | bit 0 = not or don't know by t0, |
1450 | | bit 1 = not or don't know by t1, |
1451 | | <0 = error. */ |
1452 | | /* When pfs->Function is not set, the color is monotonic. |
1453 | | In this case do not call this function because |
1454 | | it doesn't check whether pfs->Function is set. |
1455 | | Actually pfs->monotonic_color prevents that. |
1456 | | */ |
1457 | | /* This assumes that the color space is always monotonic. |
1458 | | Non-monotonic color spaces are not recommended by PLRM, |
1459 | | and the result with them may be imprecise. |
1460 | | */ |
1461 | 14.2M | uint mask; |
1462 | 14.2M | int code = gs_function_is_monotonic(pfs->Function, c0->t, c1->t, &mask); |
1463 | | |
1464 | 14.2M | if (code >= 0) |
1465 | 14.2M | return mask; |
1466 | 21 | return code; |
1467 | 14.2M | } |
1468 | | |
1469 | | static inline bool |
1470 | | covers_pixel_centers(fixed ybot, fixed ytop) |
1471 | 38.0M | { |
1472 | 38.0M | return fixed_pixround(ybot) < fixed_pixround(ytop); |
1473 | 38.0M | } |
1474 | | |
1475 | | static inline int |
1476 | | constant_color_trapezoid(patch_fill_state_t *pfs, gs_fixed_edge *le, gs_fixed_edge *re, |
1477 | | fixed ybot, fixed ytop, bool swap_axes, const patch_color_t *c) |
1478 | 19.8M | { |
1479 | 19.8M | gx_device_color dc; |
1480 | 19.8M | int code; |
1481 | | |
1482 | | # if NOFILL_TEST |
1483 | | /* if (dbg_nofill) |
1484 | | return 0; */ |
1485 | | # endif |
1486 | | |
1487 | 19.8M | code = patch_color_to_device_color_inline(pfs, c, &dc, NULL); |
1488 | 19.8M | if (code < 0) |
1489 | 0 | return code; |
1490 | | |
1491 | 19.8M | dc.tag = device_current_tag(pfs->dev); |
1492 | | |
1493 | 19.8M | return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
1494 | 19.8M | le, re, ybot, ytop, swap_axes, &dc, pfs->pgs->log_op); |
1495 | 19.8M | } |
1496 | | |
1497 | | static inline float |
1498 | | function_linearity(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1) |
1499 | 168M | { |
1500 | 168M | float s = 0; |
1501 | | |
1502 | 168M | if (pfs->Function != NULL) { |
1503 | 19.0M | patch_color_t c; |
1504 | | /* Solaris 9 (Sun C 5.5) compiler cannot initialize a 'const' */ |
1505 | | /* unless it is 'static const' */ |
1506 | 19.0M | static const float q[2] = {(float)0.3, (float)0.7}; |
1507 | 19.0M | int i, j; |
1508 | | |
1509 | 55.6M | for (j = 0; j < count_of(q); j++) { |
1510 | 37.3M | c.t[0] = c0->t[0] * (1 - q[j]) + c1->t[0] * q[j]; |
1511 | 37.3M | c.t[1] = c0->t[1] * (1 - q[j]) + c1->t[1] * q[j]; |
1512 | 37.3M | patch_resolve_color_inline(&c, pfs); |
1513 | 142M | for (i = 0; i < pfs->num_components; i++) { |
1514 | 105M | float v = c0->cc.paint.values[i] * (1 - q[j]) + c1->cc.paint.values[i] * q[j]; |
1515 | 105M | float d = v - c.cc.paint.values[i]; |
1516 | 105M | float s1 = any_abs(d) / pfs->color_domain.paint.values[i]; |
1517 | | |
1518 | 105M | if (s1 > pfs->smoothness) |
1519 | 778k | return s1; |
1520 | 105M | if (s < s1) |
1521 | 9.59M | s = s1; |
1522 | 105M | } |
1523 | 37.3M | } |
1524 | 19.0M | } |
1525 | 167M | return s; |
1526 | 168M | } |
1527 | | |
1528 | | static inline int |
1529 | | is_color_linear(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1) |
1530 | 55.4M | { /* returns : 1 = linear, 0 = unlinear, <0 = error. */ |
1531 | 55.4M | if (pfs->unlinear) |
1532 | 10.0M | return 1; /* Disable this check. */ |
1533 | 45.3M | else { |
1534 | 45.3M | const gs_color_space *cs = pfs->direct_space; |
1535 | 45.3M | int code; |
1536 | 45.3M | float s = function_linearity(pfs, c0, c1); |
1537 | | |
1538 | 45.3M | if (s > pfs->smoothness) |
1539 | 450k | return 0; |
1540 | 44.9M | if (pfs->cs_always_linear) |
1541 | 18.7M | return 1; |
1542 | 26.1M | code = cs_is_linear(cs, pfs->pgs, pfs->trans_device, |
1543 | 26.1M | &c0->cc, &c1->cc, NULL, NULL, pfs->smoothness - s, pfs->icclink); |
1544 | 26.1M | if (code <= 0) |
1545 | 159k | return code; |
1546 | 25.9M | return 1; |
1547 | 26.1M | } |
1548 | 55.4M | } |
1549 | | |
1550 | | static int |
1551 | | decompose_linear_color(patch_fill_state_t *pfs, gs_fixed_edge *le, gs_fixed_edge *re, |
1552 | | fixed ybot, fixed ytop, bool swap_axes, const patch_color_t *c0, |
1553 | | const patch_color_t *c1) |
1554 | 83.5M | { |
1555 | | /* Assuming a very narrow trapezoid - ignore the transversal color variation. */ |
1556 | | /* Assuming the XY span is restricted with curve_samples. |
1557 | | It is important for intersection_of_small_bars to compute faster. */ |
1558 | 83.5M | int code; |
1559 | 83.5M | patch_color_t *c; |
1560 | 83.5M | byte *color_stack_ptr; |
1561 | 83.5M | bool save_inside = pfs->inside; |
1562 | | |
1563 | 83.5M | if (!pfs->inside) { |
1564 | 71.9M | gs_fixed_rect r, r1; |
1565 | | |
1566 | 71.9M | if(swap_axes) { |
1567 | 31.2M | r.p.y = min(le->start.x, le->end.x); |
1568 | 31.2M | r.p.x = min(le->start.y, le->end.y); |
1569 | 31.2M | r.q.y = max(re->start.x, re->end.x); |
1570 | 31.2M | r.q.x = max(re->start.y, re->end.y); |
1571 | 40.7M | } else { |
1572 | 40.7M | r.p.x = min(le->start.x, le->end.x); |
1573 | 40.7M | r.p.y = min(le->start.y, le->end.y); |
1574 | 40.7M | r.q.x = max(re->start.x, re->end.x); |
1575 | 40.7M | r.q.y = max(re->start.y, re->end.y); |
1576 | 40.7M | } |
1577 | 71.9M | r1 = r; |
1578 | 71.9M | rect_intersect(r, pfs->rect); |
1579 | 71.9M | if (r.q.x <= r.p.x || r.q.y <= r.p.y) |
1580 | 43.9M | return 0; |
1581 | 27.9M | if (r1.p.x == r.p.x && r1.p.y == r.p.y && |
1582 | 27.9M | r1.q.x == r.q.x && r1.q.y == r.q.y) |
1583 | 10.5M | pfs->inside = true; |
1584 | 27.9M | } |
1585 | 39.5M | color_stack_ptr = reserve_colors_inline(pfs, &c, 1); |
1586 | 39.5M | if (color_stack_ptr == NULL) |
1587 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1588 | | /* Use the recursive decomposition due to isnt_color_monotonic |
1589 | | based on fn_is_monotonic_proc_t is_monotonic, |
1590 | | which applies to intervals. */ |
1591 | 39.5M | patch_interpolate_color(c, c0, c1, pfs, 0.5); |
1592 | 39.5M | if (ytop - ybot < pfs->decomposition_limit) /* Prevent an infinite color decomposition. */ |
1593 | 3.20M | code = constant_color_trapezoid(pfs, le, re, ybot, ytop, swap_axes, c); |
1594 | 36.3M | else { |
1595 | 36.3M | bool monotonic_color_save = pfs->monotonic_color; |
1596 | 36.3M | bool linear_color_save = pfs->linear_color; |
1597 | | |
1598 | 36.3M | if (!pfs->monotonic_color) { |
1599 | 11.9M | code = isnt_color_monotonic(pfs, c0, c1); |
1600 | 11.9M | if (code < 0) |
1601 | 21 | goto out; |
1602 | 11.9M | if (!code) |
1603 | 9.35M | pfs->monotonic_color = true; |
1604 | 11.9M | } |
1605 | 36.3M | if (pfs->monotonic_color && !pfs->linear_color) { |
1606 | 19.8M | code = is_color_linear(pfs, c0, c1); |
1607 | 19.8M | if (code < 0) |
1608 | 0 | goto out; |
1609 | 19.8M | if (code > 0) |
1610 | 19.6M | pfs->linear_color = true; |
1611 | 19.8M | } |
1612 | 36.3M | if (!pfs->unlinear && pfs->linear_color) { |
1613 | 9.56M | gx_device *pdev = pfs->dev; |
1614 | 9.56M | frac31 fc[2][GX_DEVICE_COLOR_MAX_COMPONENTS]; |
1615 | 9.56M | gs_fill_attributes fa; |
1616 | 9.56M | gs_fixed_rect clip; |
1617 | | |
1618 | 9.56M | memset(fc, 0x99, sizeof(fc)); |
1619 | | |
1620 | 9.56M | clip = pfs->rect; |
1621 | 9.56M | if (swap_axes) { |
1622 | 3.23M | fixed v; |
1623 | | |
1624 | 3.23M | v = clip.p.x; clip.p.x = clip.p.y; clip.p.y = v; |
1625 | 3.23M | v = clip.q.x; clip.q.x = clip.q.y; clip.q.y = v; |
1626 | | /* Don't need adjust_swapped_boundary here. */ |
1627 | 3.23M | } |
1628 | 9.56M | clip.p.y = max(clip.p.y, ybot); |
1629 | 9.56M | clip.q.y = min(clip.q.y, ytop); |
1630 | 9.56M | fa.clip = &clip; |
1631 | 9.56M | fa.ht = NULL; |
1632 | 9.56M | fa.swap_axes = swap_axes; |
1633 | 9.56M | fa.lop = 0; |
1634 | 9.56M | fa.ystart = ybot; |
1635 | 9.56M | fa.yend = ytop; |
1636 | 9.56M | code = patch_color_to_device_color_inline(pfs, c0, NULL, fc[0]); |
1637 | 9.56M | if (code < 0) |
1638 | 0 | goto out; |
1639 | 9.56M | if (code == 2) { |
1640 | | /* Must not happen. */ |
1641 | 0 | code=gs_note_error(gs_error_unregistered); |
1642 | 0 | goto out; |
1643 | 0 | } |
1644 | 9.56M | code = patch_color_to_device_color_inline(pfs, c1, NULL, fc[1]); |
1645 | 9.56M | if (code < 0) |
1646 | 0 | goto out; |
1647 | 9.56M | code = dev_proc(pdev, fill_linear_color_trapezoid)(pdev, &fa, |
1648 | 9.56M | &le->start, &le->end, &re->start, &re->end, |
1649 | 9.56M | fc[0], fc[1], NULL, NULL); |
1650 | 9.56M | if (code == 1) { |
1651 | 9.56M | pfs->monotonic_color = monotonic_color_save; |
1652 | 9.56M | pfs->linear_color = linear_color_save; |
1653 | 9.56M | code = 0; /* The area is filled. */ |
1654 | 9.56M | goto out; |
1655 | 9.56M | } |
1656 | 17 | if (code < 0) |
1657 | 17 | goto out; |
1658 | 0 | else { /* code == 0, the device requested to decompose the area. */ |
1659 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
1660 | 0 | goto out; |
1661 | 0 | } |
1662 | 17 | } |
1663 | 26.7M | if (!pfs->unlinear || !pfs->linear_color || |
1664 | 26.7M | color_span(pfs, c0, c1) > pfs->smoothness) { |
1665 | 10.1M | fixed y = (ybot + ytop) / 2; |
1666 | | |
1667 | 10.1M | code = decompose_linear_color(pfs, le, re, ybot, y, swap_axes, c0, c); |
1668 | 10.1M | if (code >= 0) |
1669 | 10.1M | code = decompose_linear_color(pfs, le, re, y, ytop, swap_axes, c, c1); |
1670 | 10.1M | } else |
1671 | 16.6M | code = constant_color_trapezoid(pfs, le, re, ybot, ytop, swap_axes, c); |
1672 | 26.7M | pfs->monotonic_color = monotonic_color_save; |
1673 | 26.7M | pfs->linear_color = linear_color_save; |
1674 | 26.7M | } |
1675 | 39.5M | out: |
1676 | 39.5M | pfs->inside = save_inside; |
1677 | 39.5M | release_colors_inline(pfs, color_stack_ptr, 1); |
1678 | 39.5M | return code; |
1679 | 39.5M | } |
1680 | | |
1681 | | static inline int |
1682 | | linear_color_trapezoid(patch_fill_state_t *pfs, gs_fixed_point q[4], int i0, int i1, int i2, int i3, |
1683 | | fixed ybot, fixed ytop, bool swap_axes, const patch_color_t *c0, const patch_color_t *c1, |
1684 | | bool orient) |
1685 | 27.9M | { |
1686 | | /* Assuming a very narrow trapezoid - ignore the transversal color change. */ |
1687 | 27.9M | gs_fixed_edge le, re; |
1688 | | |
1689 | 27.9M | make_trapezoid(q, i0, i1, i2, i3, ybot, ytop, swap_axes, orient, &le, &re); |
1690 | 27.9M | return decompose_linear_color(pfs, &le, &re, ybot, ytop, swap_axes, c0, c1); |
1691 | 27.9M | } |
1692 | | |
1693 | | static int |
1694 | | wedge_trap_decompose(patch_fill_state_t *pfs, gs_fixed_point q[4], |
1695 | | fixed ybot, fixed ytop, const patch_color_t *c0, const patch_color_t *c1, |
1696 | | bool swap_axes, bool self_intersecting) |
1697 | 38.0M | { |
1698 | | /* Assuming a very narrow trapezoid - ignore the transversal color change. */ |
1699 | 38.0M | fixed dx1, dy1, dx2, dy2; |
1700 | 38.0M | bool orient; |
1701 | | |
1702 | 38.0M | if (!pfs->vectorization && !covers_pixel_centers(ybot, ytop)) |
1703 | 10.1M | return 0; |
1704 | 27.9M | if (ybot == ytop) |
1705 | 0 | return 0; |
1706 | 27.9M | dx1 = q[1].x - q[0].x, dy1 = q[1].y - q[0].y; |
1707 | 27.9M | dx2 = q[2].x - q[0].x, dy2 = q[2].y - q[0].y; |
1708 | 27.9M | if ((int64_t)dx1 * dy2 != (int64_t)dy1 * dx2) { |
1709 | 13.9M | orient = ((int64_t)dx1 * dy2 > (int64_t)dy1 * dx2); |
1710 | 13.9M | return linear_color_trapezoid(pfs, q, 0, 1, 2, 3, ybot, ytop, swap_axes, c0, c1, orient); |
1711 | 14.0M | } else { |
1712 | 14.0M | fixed dx3 = q[3].x - q[0].x, dy3 = q[3].y - q[0].y; |
1713 | | |
1714 | 14.0M | orient = ((int64_t)dx1 * dy3 > (int64_t)dy1 * dx3); |
1715 | 14.0M | return linear_color_trapezoid(pfs, q, 0, 1, 2, 3, ybot, ytop, swap_axes, c0, c1, orient); |
1716 | 14.0M | } |
1717 | 27.9M | } |
1718 | | |
1719 | | static inline int |
1720 | | fill_wedge_trap(patch_fill_state_t *pfs, const gs_fixed_point *p0, const gs_fixed_point *p1, |
1721 | | const gs_fixed_point *q0, const gs_fixed_point *q1, const patch_color_t *c0, const patch_color_t *c1, |
1722 | | bool swap_axes, bool self_intersecting) |
1723 | 38.0M | { |
1724 | | /* We assume that the width of the wedge is close to zero, |
1725 | | so we can ignore the slope when computing transversal distances. */ |
1726 | 38.0M | gs_fixed_point p[4]; |
1727 | 38.0M | const patch_color_t *cc0, *cc1; |
1728 | | |
1729 | 38.0M | if (p0->y < p1->y) { |
1730 | 18.5M | p[2] = *p0; |
1731 | 18.5M | p[3] = *p1; |
1732 | 18.5M | cc0 = c0; |
1733 | 18.5M | cc1 = c1; |
1734 | 19.5M | } else { |
1735 | 19.5M | p[2] = *p1; |
1736 | 19.5M | p[3] = *p0; |
1737 | 19.5M | cc0 = c1; |
1738 | 19.5M | cc1 = c0; |
1739 | 19.5M | } |
1740 | 38.0M | p[0] = *q0; |
1741 | 38.0M | p[1] = *q1; |
1742 | 38.0M | return wedge_trap_decompose(pfs, p, p[2].y, p[3].y, cc0, cc1, swap_axes, self_intersecting); |
1743 | 38.0M | } |
1744 | | |
1745 | | static void |
1746 | | split_curve_s(const gs_fixed_point *pole, gs_fixed_point *q0, gs_fixed_point *q1, int pole_step) |
1747 | 229M | { |
1748 | | /* This copies a code fragment from split_curve_midpoint, |
1749 | | substituting another data type. |
1750 | | */ |
1751 | | /* |
1752 | | * We have to define midpoint carefully to avoid overflow. |
1753 | | * (If it overflows, something really pathological is going |
1754 | | * on, but we could get infinite recursion that way....) |
1755 | | */ |
1756 | 229M | #define midpoint(a,b)\ |
1757 | 2.74G | (arith_rshift_1(a) + arith_rshift_1(b) + (((a) | (b)) & 1)) |
1758 | 229M | fixed x12 = midpoint(pole[1 * pole_step].x, pole[2 * pole_step].x); |
1759 | 229M | fixed y12 = midpoint(pole[1 * pole_step].y, pole[2 * pole_step].y); |
1760 | | |
1761 | | /* q[0] and q[1] must not be the same as pole. */ |
1762 | 229M | q0[1 * pole_step].x = midpoint(pole[0 * pole_step].x, pole[1 * pole_step].x); |
1763 | 229M | q0[1 * pole_step].y = midpoint(pole[0 * pole_step].y, pole[1 * pole_step].y); |
1764 | 229M | q1[2 * pole_step].x = midpoint(pole[2 * pole_step].x, pole[3 * pole_step].x); |
1765 | 229M | q1[2 * pole_step].y = midpoint(pole[2 * pole_step].y, pole[3 * pole_step].y); |
1766 | 229M | q0[2 * pole_step].x = midpoint(q0[1 * pole_step].x, x12); |
1767 | 229M | q0[2 * pole_step].y = midpoint(q0[1 * pole_step].y, y12); |
1768 | 229M | q1[1 * pole_step].x = midpoint(x12, q1[2 * pole_step].x); |
1769 | 229M | q1[1 * pole_step].y = midpoint(y12, q1[2 * pole_step].y); |
1770 | 229M | q0[0 * pole_step].x = pole[0 * pole_step].x; |
1771 | 229M | q0[0 * pole_step].y = pole[0 * pole_step].y; |
1772 | 229M | q0[3 * pole_step].x = q1[0 * pole_step].x = midpoint(q0[2 * pole_step].x, q1[1 * pole_step].x); |
1773 | 229M | q0[3 * pole_step].y = q1[0 * pole_step].y = midpoint(q0[2 * pole_step].y, q1[1 * pole_step].y); |
1774 | 229M | q1[3 * pole_step].x = pole[3 * pole_step].x; |
1775 | 229M | q1[3 * pole_step].y = pole[3 * pole_step].y; |
1776 | 229M | #undef midpoint |
1777 | 229M | } |
1778 | | |
1779 | | static void |
1780 | | split_curve(const gs_fixed_point pole[4], gs_fixed_point q0[4], gs_fixed_point q1[4]) |
1781 | 5.81M | { |
1782 | 5.81M | split_curve_s(pole, q0, q1, 1); |
1783 | 5.81M | } |
1784 | | |
1785 | | #ifdef SHADING_SWAP_AXES_FOR_PRECISION |
1786 | | static inline void |
1787 | | do_swap_axes(gs_fixed_point *p, int k) |
1788 | | { |
1789 | | int i; |
1790 | | |
1791 | | for (i = 0; i < k; i++) { |
1792 | | p[i].x ^= p[i].y; p[i].y ^= p[i].x; p[i].x ^= p[i].y; |
1793 | | } |
1794 | | } |
1795 | | |
1796 | | static inline fixed |
1797 | | span_x(const gs_fixed_point *p, int k) |
1798 | | { |
1799 | | int i; |
1800 | | fixed xmin = p[0].x, xmax = p[0].x; |
1801 | | |
1802 | | for (i = 1; i < k; i++) { |
1803 | | xmin = min(xmin, p[i].x); |
1804 | | xmax = max(xmax, p[i].x); |
1805 | | } |
1806 | | return xmax - xmin; |
1807 | | } |
1808 | | |
1809 | | static inline fixed |
1810 | | span_y(const gs_fixed_point *p, int k) |
1811 | | { |
1812 | | int i; |
1813 | | fixed ymin = p[0].y, ymax = p[0].y; |
1814 | | |
1815 | | for (i = 1; i < k; i++) { |
1816 | | ymin = min(ymin, p[i].y); |
1817 | | ymax = max(ymax, p[i].y); |
1818 | | } |
1819 | | return ymax - ymin; |
1820 | | } |
1821 | | #endif |
1822 | | |
1823 | | static inline fixed |
1824 | | manhattan_dist(const gs_fixed_point *p0, const gs_fixed_point *p1) |
1825 | 25.0M | { |
1826 | 25.0M | fixed dx = any_abs(p1->x - p0->x), dy = any_abs(p1->y - p0->y); |
1827 | | |
1828 | 25.0M | return max(dx, dy); |
1829 | 25.0M | } |
1830 | | |
1831 | | static inline int |
1832 | | create_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *l, |
1833 | | const gs_fixed_point *p0, const gs_fixed_point *p1) |
1834 | 7.78M | { |
1835 | 7.78M | if (l->end != NULL) |
1836 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1837 | 7.78M | l->beg = wedge_vertex_list_elem_reserve(pfs); |
1838 | 7.78M | l->end = wedge_vertex_list_elem_reserve(pfs); |
1839 | 7.78M | if (l->beg == NULL) |
1840 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1841 | 7.78M | if (l->end == NULL) |
1842 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1843 | 7.78M | l->beg->prev = l->end->next = NULL; |
1844 | 7.78M | l->beg->next = l->end; |
1845 | 7.78M | l->end->prev = l->beg; |
1846 | 7.78M | l->beg->p = *p0; |
1847 | 7.78M | l->end->p = *p1; |
1848 | 7.78M | l->beg->level = l->end->level = 0; |
1849 | 7.78M | return 0; |
1850 | 7.78M | } |
1851 | | |
1852 | | static inline int |
1853 | | insert_wedge_vertex_list_elem(patch_fill_state_t *pfs, wedge_vertex_list_t *l, |
1854 | | const gs_fixed_point *p, wedge_vertex_list_elem_t **r) |
1855 | 14.9M | { |
1856 | 14.9M | wedge_vertex_list_elem_t *e = wedge_vertex_list_elem_reserve(pfs); |
1857 | | |
1858 | | /* We have got enough free elements due to the preliminary decomposition |
1859 | | of curves to LAZY_WEDGES_MAX_LEVEL, see curve_samples. */ |
1860 | 14.9M | if (e == NULL) |
1861 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1862 | 14.9M | if (l->beg->next != l->end) |
1863 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1864 | 14.9M | if (l->end->prev != l->beg) |
1865 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1866 | 14.9M | e->next = l->end; |
1867 | 14.9M | e->prev = l->beg; |
1868 | 14.9M | e->p = *p; |
1869 | 14.9M | e->level = max(l->beg->level, l->end->level) + 1; |
1870 | 14.9M | e->divide_count = 0; |
1871 | 14.9M | l->beg->next = l->end->prev = e; |
1872 | 14.9M | { int sx = l->beg->p.x < l->end->p.x ? 1 : -1; |
1873 | 14.9M | int sy = l->beg->p.y < l->end->p.y ? 1 : -1; |
1874 | | |
1875 | 14.9M | if ((p->x - l->beg->p.x) * sx < 0) |
1876 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1877 | 14.9M | if ((p->y - l->beg->p.y) * sy < 0) |
1878 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1879 | 14.9M | if ((l->end->p.x - p->x) * sx < 0) |
1880 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1881 | 14.9M | if ((l->end->p.y - p->y) * sy < 0) |
1882 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1883 | 14.9M | } |
1884 | 14.9M | *r = e; |
1885 | 14.9M | return 0; |
1886 | 14.9M | } |
1887 | | |
1888 | | static inline int |
1889 | | open_wedge_median(patch_fill_state_t *pfs, wedge_vertex_list_t *l, |
1890 | | const gs_fixed_point *p0, const gs_fixed_point *p1, const gs_fixed_point *pm, |
1891 | | wedge_vertex_list_elem_t **r) |
1892 | 22.6M | { |
1893 | 22.6M | wedge_vertex_list_elem_t *e; |
1894 | 22.6M | int code; |
1895 | | |
1896 | 22.6M | if (!l->last_side) { |
1897 | 14.5M | if (l->beg == NULL) { |
1898 | 7.55M | code = create_wedge_vertex_list(pfs, l, p0, p1); |
1899 | 7.55M | if (code < 0) |
1900 | 0 | return code; |
1901 | 7.55M | } |
1902 | 14.5M | if (l->beg->p.x != p0->x) |
1903 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1904 | 14.5M | if (l->beg->p.y != p0->y) |
1905 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1906 | 14.5M | if (l->end->p.x != p1->x) |
1907 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1908 | 14.5M | if (l->end->p.y != p1->y) |
1909 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1910 | 14.5M | code = insert_wedge_vertex_list_elem(pfs, l, pm, &e); |
1911 | 14.5M | if (code < 0) |
1912 | 0 | return code; |
1913 | 14.5M | e->divide_count++; |
1914 | 14.5M | } else if (l->beg == NULL) { |
1915 | 230k | code = create_wedge_vertex_list(pfs, l, p1, p0); |
1916 | 230k | if (code < 0) |
1917 | 0 | return code; |
1918 | 230k | code = insert_wedge_vertex_list_elem(pfs, l, pm, &e); |
1919 | 230k | if (code < 0) |
1920 | 0 | return code; |
1921 | 230k | e->divide_count++; |
1922 | 7.92M | } else { |
1923 | 7.92M | if (l->beg->p.x != p1->x) |
1924 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1925 | 7.92M | if (l->beg->p.y != p1->y) |
1926 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1927 | 7.92M | if (l->end->p.x != p0->x) |
1928 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1929 | 7.92M | if (l->end->p.y != p0->y) |
1930 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1931 | 7.92M | if (l->beg->next == l->end) { |
1932 | 180k | code = insert_wedge_vertex_list_elem(pfs, l, pm, &e); |
1933 | 180k | if (code < 0) |
1934 | 0 | return code; |
1935 | 180k | e->divide_count++; |
1936 | 7.74M | } else { |
1937 | 7.74M | e = wedge_vertex_list_find(l->beg, l->end, |
1938 | 7.74M | max(l->beg->level, l->end->level) + 1); |
1939 | 7.74M | if (e == NULL) |
1940 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1941 | 7.74M | if (e->p.x != pm->x || e->p.y != pm->y) |
1942 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1943 | 7.74M | e->divide_count++; |
1944 | 7.74M | } |
1945 | 7.92M | } |
1946 | 22.6M | *r = e; |
1947 | 22.6M | return 0; |
1948 | 22.6M | } |
1949 | | |
1950 | | static inline int |
1951 | | make_wedge_median(patch_fill_state_t *pfs, wedge_vertex_list_t *l, |
1952 | | wedge_vertex_list_t *l0, bool forth, |
1953 | | const gs_fixed_point *p0, const gs_fixed_point *p1, const gs_fixed_point *pm) |
1954 | 22.6M | { |
1955 | 22.6M | int code; |
1956 | | |
1957 | 22.6M | l->last_side = l0->last_side; |
1958 | 22.6M | if (!l->last_side ^ !forth) { |
1959 | 13.1M | code = open_wedge_median(pfs, l0, p0, p1, pm, &l->end); |
1960 | 13.1M | l->beg = l0->beg; |
1961 | 13.1M | } else { |
1962 | 9.50M | code = open_wedge_median(pfs, l0, p0, p1, pm, &l->beg); |
1963 | 9.50M | l->end = l0->end; |
1964 | 9.50M | } |
1965 | 22.6M | return code; |
1966 | 22.6M | } |
1967 | | |
1968 | | static int fill_wedge_from_list(patch_fill_state_t *pfs, const wedge_vertex_list_t *l, |
1969 | | const patch_color_t *c0, const patch_color_t *c1); |
1970 | | |
1971 | | static inline int |
1972 | | close_wedge_median(patch_fill_state_t *pfs, wedge_vertex_list_t *l, |
1973 | | const patch_color_t *c0, const patch_color_t *c1) |
1974 | 22.6M | { |
1975 | 22.6M | int code; |
1976 | | |
1977 | 22.6M | if (!l->last_side) |
1978 | 14.5M | return 0; |
1979 | 8.15M | code = fill_wedge_from_list(pfs, l, c1, c0); |
1980 | 8.15M | if (code < 0) |
1981 | 0 | return code; |
1982 | 8.15M | release_wedge_vertex_list_interval(pfs, l->beg, l->end); |
1983 | 8.15M | return 0; |
1984 | 8.15M | } |
1985 | | |
1986 | | static inline void |
1987 | | move_wedge(wedge_vertex_list_t *l, const wedge_vertex_list_t *l0, bool forth) |
1988 | 22.6M | { |
1989 | 22.6M | if (!l->last_side ^ !forth) { |
1990 | 13.1M | l->beg = l->end; |
1991 | 13.1M | l->end = l0->end; |
1992 | 13.1M | } else { |
1993 | 9.50M | l->end = l->beg; |
1994 | 9.50M | l->beg = l0->beg; |
1995 | 9.50M | } |
1996 | 22.6M | } |
1997 | | |
1998 | | static inline int |
1999 | | fill_triangle_wedge_aux(patch_fill_state_t *pfs, |
2000 | | const shading_vertex_t *q0, const shading_vertex_t *q1, const shading_vertex_t *q2) |
2001 | 19.0M | { int code; |
2002 | 19.0M | const gs_fixed_point *p0, *p1, *p2; |
2003 | 19.0M | gs_fixed_point qq0, qq1, qq2; |
2004 | 19.0M | fixed dx = any_abs(q0->p.x - q1->p.x), dy = any_abs(q0->p.y - q1->p.y); |
2005 | 19.0M | bool swap_axes; |
2006 | | |
2007 | | # if SKIP_TEST |
2008 | | dbg_wedge_triangle_cnt++; |
2009 | | # endif |
2010 | 19.0M | if (dx > dy) { |
2011 | 10.7M | swap_axes = true; |
2012 | 10.7M | qq0.x = q0->p.y; |
2013 | 10.7M | qq0.y = q0->p.x; |
2014 | 10.7M | qq1.x = q1->p.y; |
2015 | 10.7M | qq1.y = q1->p.x; |
2016 | 10.7M | qq2.x = q2->p.y; |
2017 | 10.7M | qq2.y = q2->p.x; |
2018 | 10.7M | p0 = &qq0; |
2019 | 10.7M | p1 = &qq1; |
2020 | 10.7M | p2 = &qq2; |
2021 | 10.7M | } else { |
2022 | 8.26M | swap_axes = false; |
2023 | 8.26M | p0 = &q0->p; |
2024 | 8.26M | p1 = &q1->p; |
2025 | 8.26M | p2 = &q2->p; |
2026 | 8.26M | } |
2027 | | /* We decompose the thin triangle into 2 thin trapezoids. |
2028 | | An optimization with decomposing into 2 triangles |
2029 | | appears low useful, because the self_intersecting argument |
2030 | | with inline expansion does that job perfectly. */ |
2031 | 19.0M | if (p0->y < p1->y) { |
2032 | 9.30M | code = fill_wedge_trap(pfs, p0, p2, p0, p1, q0->c, q2->c, swap_axes, false); |
2033 | 9.30M | if (code < 0) |
2034 | 2 | return code; |
2035 | 9.30M | return fill_wedge_trap(pfs, p2, p1, p0, p1, q2->c, q1->c, swap_axes, false); |
2036 | 9.74M | } else { |
2037 | 9.74M | code = fill_wedge_trap(pfs, p0, p2, p1, p0, q0->c, q2->c, swap_axes, false); |
2038 | 9.74M | if (code < 0) |
2039 | 6 | return code; |
2040 | 9.74M | return fill_wedge_trap(pfs, p2, p1, p1, p0, q2->c, q1->c, swap_axes, false); |
2041 | 9.74M | } |
2042 | 19.0M | } |
2043 | | |
2044 | | static inline int |
2045 | | try_device_linear_color(patch_fill_state_t *pfs, bool wedge, |
2046 | | const shading_vertex_t *p0, const shading_vertex_t *p1, |
2047 | | const shading_vertex_t *p2) |
2048 | 91.7M | { |
2049 | | /* Returns : |
2050 | | <0 - error; |
2051 | | 0 - success; |
2052 | | 1 - decompose to linear color areas; |
2053 | | 2 - decompose to constant color areas; |
2054 | | */ |
2055 | 91.7M | int code; |
2056 | | |
2057 | 91.7M | if (pfs->unlinear) |
2058 | 50.5M | return 2; |
2059 | 41.2M | if (!wedge) { |
2060 | 41.2M | const gs_color_space *cs = pfs->direct_space; |
2061 | | |
2062 | 41.2M | if (cs != NULL) { |
2063 | 41.2M | float s0, s1, s2, s01, s012; |
2064 | | |
2065 | 41.2M | s0 = function_linearity(pfs, p0->c, p1->c); |
2066 | 41.2M | if (s0 > pfs->smoothness) |
2067 | 198k | return 1; |
2068 | 41.0M | s1 = function_linearity(pfs, p1->c, p2->c); |
2069 | 41.0M | if (s1 > pfs->smoothness) |
2070 | 127k | return 1; |
2071 | 40.9M | s2 = function_linearity(pfs, p2->c, p0->c); |
2072 | 40.9M | if (s2 > pfs->smoothness) |
2073 | 1.80k | return 1; |
2074 | | /* fixme: check an inner color ? */ |
2075 | 40.9M | s01 = max(s0, s1); |
2076 | 40.9M | s012 = max(s01, s2); |
2077 | 40.9M | if (pfs->cs_always_linear) |
2078 | 13.8M | code = 1; |
2079 | 27.0M | else |
2080 | 27.0M | code = cs_is_linear(cs, pfs->pgs, pfs->trans_device, |
2081 | 40.9M | &p0->c->cc, &p1->c->cc, &p2->c->cc, NULL, |
2082 | 40.9M | pfs->smoothness - s012, pfs->icclink); |
2083 | 40.9M | if (code < 0) |
2084 | 0 | return code; |
2085 | 40.9M | if (code == 0) |
2086 | 127k | return 1; |
2087 | 40.9M | } |
2088 | 41.2M | } |
2089 | 40.7M | { gx_device *pdev = pfs->dev; |
2090 | 40.7M | frac31 fc[3][GX_DEVICE_COLOR_MAX_COMPONENTS]; |
2091 | 40.7M | gs_fill_attributes fa; |
2092 | 40.7M | gx_device_color dc[3]; |
2093 | | |
2094 | 40.7M | fa.clip = &pfs->rect; |
2095 | 40.7M | fa.ht = NULL; |
2096 | 40.7M | fa.swap_axes = false; |
2097 | 40.7M | fa.lop = 0; |
2098 | 40.7M | code = patch_color_to_device_color_inline(pfs, p0->c, &dc[0], fc[0]); |
2099 | 40.7M | if (code != 0) |
2100 | 0 | return code; |
2101 | 40.7M | if (!(dc[0].type == &gx_dc_type_data_pure || |
2102 | 40.7M | dc[0].type == &gx_dc_type_data_devn)) |
2103 | 0 | return 2; |
2104 | 40.7M | if (!wedge) { |
2105 | 40.7M | code = patch_color_to_device_color_inline(pfs, p1->c, &dc[1], fc[1]); |
2106 | 40.7M | if (code != 0) |
2107 | 0 | return code; |
2108 | 40.7M | } |
2109 | 40.7M | code = patch_color_to_device_color_inline(pfs, p2->c, &dc[2], fc[2]); |
2110 | 40.7M | if (code != 0) |
2111 | 0 | return code; |
2112 | 40.7M | code = dev_proc(pdev, fill_linear_color_triangle)(pdev, &fa, |
2113 | 40.7M | &p0->p, &p1->p, &p2->p, |
2114 | 40.7M | fc[0], (wedge ? NULL : fc[1]), fc[2]); |
2115 | 40.7M | if (code == 1) |
2116 | 40.7M | return 0; /* The area is filled. */ |
2117 | 0 | if (code < 0) |
2118 | 0 | return code; |
2119 | 0 | else /* code == 0, the device requested to decompose the area. */ |
2120 | 0 | return 1; |
2121 | 0 | } |
2122 | 0 | } |
2123 | | |
2124 | | static inline int |
2125 | | fill_triangle_wedge(patch_fill_state_t *pfs, |
2126 | | const shading_vertex_t *q0, const shading_vertex_t *q1, const shading_vertex_t *q2) |
2127 | 36.4M | { |
2128 | 36.4M | if ((int64_t)(q1->p.x - q0->p.x) * (q2->p.y - q0->p.y) == |
2129 | 36.4M | (int64_t)(q1->p.y - q0->p.y) * (q2->p.x - q0->p.x)) |
2130 | 17.4M | return 0; /* Zero area. */ |
2131 | | /* |
2132 | | Can't apply try_device_linear_color here |
2133 | | because didn't check is_color_linear. |
2134 | | Maybe need a decomposition. |
2135 | | Do same as for 'unlinear', and branch later. |
2136 | | */ |
2137 | 19.0M | return fill_triangle_wedge_aux(pfs, q0, q1, q2); |
2138 | 36.4M | } |
2139 | | |
2140 | | static inline int |
2141 | | fill_triangle_wedge_from_list(patch_fill_state_t *pfs, |
2142 | | const wedge_vertex_list_elem_t *beg, const wedge_vertex_list_elem_t *end, |
2143 | | const wedge_vertex_list_elem_t *mid, |
2144 | | const patch_color_t *c0, const patch_color_t *c1) |
2145 | 7.19M | { |
2146 | 7.19M | shading_vertex_t p[3]; |
2147 | 7.19M | patch_color_t *c; |
2148 | 7.19M | byte *color_stack_ptr = reserve_colors_inline(pfs, &c, 1); |
2149 | 7.19M | int code; |
2150 | | |
2151 | 7.19M | if (color_stack_ptr == NULL) |
2152 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2153 | 7.19M | p[2].c = c; |
2154 | 7.19M | p[0].p = beg->p; |
2155 | 7.19M | p[0].c = c0; |
2156 | 7.19M | p[1].p = end->p; |
2157 | 7.19M | p[1].c = c1; |
2158 | 7.19M | p[2].p = mid->p; |
2159 | 7.19M | patch_interpolate_color(c, c0, c1, pfs, 0.5); |
2160 | 7.19M | code = fill_triangle_wedge(pfs, &p[0], &p[1], &p[2]); |
2161 | 7.19M | release_colors_inline(pfs, color_stack_ptr, 1); |
2162 | 7.19M | return code; |
2163 | 7.19M | } |
2164 | | |
2165 | | static int |
2166 | | fill_wedge_from_list_rec(patch_fill_state_t *pfs, |
2167 | | wedge_vertex_list_elem_t *beg, const wedge_vertex_list_elem_t *end, |
2168 | | int level, const patch_color_t *c0, const patch_color_t *c1) |
2169 | 20.0M | { |
2170 | 20.0M | if (beg->next == end) |
2171 | 5.11M | return 0; |
2172 | 14.9M | else if (beg->next->next == end) { |
2173 | 12.8M | if (beg->next->divide_count != 1 && beg->next->divide_count != 2) |
2174 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2175 | 12.8M | if (beg->next->divide_count != 1) |
2176 | 7.69M | return 0; |
2177 | 5.18M | return fill_triangle_wedge_from_list(pfs, beg, end, beg->next, c0, c1); |
2178 | 12.8M | } else { |
2179 | 2.05M | gs_fixed_point p; |
2180 | 2.05M | wedge_vertex_list_elem_t *e; |
2181 | 2.05M | patch_color_t *c; |
2182 | 2.05M | int code; |
2183 | 2.05M | byte *color_stack_ptr = reserve_colors_inline(pfs, &c, 1); |
2184 | | |
2185 | 2.05M | if (color_stack_ptr == NULL) |
2186 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2187 | 2.05M | p.x = (beg->p.x + end->p.x) / 2; |
2188 | 2.05M | p.y = (beg->p.y + end->p.y) / 2; |
2189 | 2.05M | e = wedge_vertex_list_find(beg, end, level + 1); |
2190 | 2.05M | if (e == NULL) |
2191 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2192 | 2.05M | if (e->p.x != p.x || e->p.y != p.y) |
2193 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2194 | 2.05M | patch_interpolate_color(c, c0, c1, pfs, 0.5); |
2195 | 2.05M | code = fill_wedge_from_list_rec(pfs, beg, e, level + 1, c0, c); |
2196 | 2.05M | if (code >= 0) |
2197 | 2.05M | code = fill_wedge_from_list_rec(pfs, e, end, level + 1, c, c1); |
2198 | 2.05M | if (code >= 0) { |
2199 | 2.05M | if (e->divide_count != 1 && e->divide_count != 2) |
2200 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2201 | 2.05M | if (e->divide_count == 1) |
2202 | 2.00M | code = fill_triangle_wedge_from_list(pfs, beg, end, e, c0, c1); |
2203 | 2.05M | } |
2204 | 2.05M | release_colors_inline(pfs, color_stack_ptr, 1); |
2205 | 2.05M | return code; |
2206 | 2.05M | } |
2207 | 20.0M | } |
2208 | | |
2209 | | static int |
2210 | | fill_wedge_from_list(patch_fill_state_t *pfs, const wedge_vertex_list_t *l, |
2211 | | const patch_color_t *c0, const patch_color_t *c1) |
2212 | 15.9M | { |
2213 | 15.9M | return fill_wedge_from_list_rec(pfs, l->beg, l->end, |
2214 | 15.9M | max(l->beg->level, l->end->level), c0, c1); |
2215 | 15.9M | } |
2216 | | |
2217 | | static inline int |
2218 | | terminate_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *l, |
2219 | | const patch_color_t *c0, const patch_color_t *c1) |
2220 | 200M | { |
2221 | 200M | if (l->beg != NULL) { |
2222 | 7.78M | int code = fill_wedge_from_list(pfs, l, c0, c1); |
2223 | | |
2224 | 7.78M | if (code < 0) |
2225 | 0 | return code; |
2226 | 7.78M | return release_wedge_vertex_list(pfs, l, 1); |
2227 | 7.78M | } |
2228 | 193M | return 0; |
2229 | 200M | } |
2230 | | |
2231 | | static int |
2232 | | wedge_by_triangles(patch_fill_state_t *pfs, int ka, |
2233 | | const gs_fixed_point pole[4], const patch_color_t *c0, const patch_color_t *c1) |
2234 | 5.55M | { /* Assuming ka >= 2, see fill_wedges. */ |
2235 | 5.55M | gs_fixed_point q[2][4]; |
2236 | 5.55M | patch_color_t *c; |
2237 | 5.55M | shading_vertex_t p[3]; |
2238 | 5.55M | int code; |
2239 | 5.55M | byte *color_stack_ptr = reserve_colors_inline(pfs, &c, 1); |
2240 | | |
2241 | 5.55M | if (color_stack_ptr == NULL) |
2242 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2243 | 5.55M | p[2].c = c; |
2244 | 5.55M | split_curve(pole, q[0], q[1]); |
2245 | 5.55M | p[0].p = pole[0]; |
2246 | 5.55M | p[0].c = c0; |
2247 | 5.55M | p[1].p = pole[3]; |
2248 | 5.55M | p[1].c = c1; |
2249 | 5.55M | p[2].p = q[0][3]; |
2250 | 5.55M | patch_interpolate_color(c, c0, c1, pfs, 0.5); |
2251 | 5.55M | code = fill_triangle_wedge(pfs, &p[0], &p[1], &p[2]); |
2252 | 5.55M | if (code >= 0) { |
2253 | 5.55M | if (ka == 2) |
2254 | 2.83M | goto out; |
2255 | 2.71M | code = wedge_by_triangles(pfs, ka / 2, q[0], c0, p[2].c); |
2256 | 2.71M | } |
2257 | 2.71M | if (code >= 0) |
2258 | 2.71M | code = wedge_by_triangles(pfs, ka / 2, q[1], p[2].c, c1); |
2259 | 5.55M | out: |
2260 | 5.55M | release_colors_inline(pfs, color_stack_ptr, 1); |
2261 | 5.55M | return code; |
2262 | 2.71M | } |
2263 | | |
2264 | | int |
2265 | | mesh_padding(patch_fill_state_t *pfs, const gs_fixed_point *p0, const gs_fixed_point *p1, |
2266 | | const patch_color_t *c0, const patch_color_t *c1) |
2267 | 35.3M | { |
2268 | 35.3M | gs_fixed_point q0, q1; |
2269 | 35.3M | const patch_color_t *cc0, *cc1; |
2270 | 35.3M | fixed dx = p1->x - p0->x; |
2271 | 35.3M | fixed dy = p1->y - p0->y; |
2272 | 35.3M | bool swap_axes = (any_abs(dx) > any_abs(dy)); |
2273 | 35.3M | gs_fixed_edge le, re; |
2274 | 35.3M | const fixed adjust = INTERPATCH_PADDING; |
2275 | | |
2276 | 35.3M | if (swap_axes) { |
2277 | 12.8M | if (p0->x < p1->x) { |
2278 | 6.29M | q0.x = p0->y; |
2279 | 6.29M | q0.y = p0->x; |
2280 | 6.29M | q1.x = p1->y; |
2281 | 6.29M | q1.y = p1->x; |
2282 | 6.29M | cc0 = c0; |
2283 | 6.29M | cc1 = c1; |
2284 | 6.55M | } else { |
2285 | 6.55M | q0.x = p1->y; |
2286 | 6.55M | q0.y = p1->x; |
2287 | 6.55M | q1.x = p0->y; |
2288 | 6.55M | q1.y = p0->x; |
2289 | 6.55M | cc0 = c1; |
2290 | 6.55M | cc1 = c0; |
2291 | 6.55M | } |
2292 | 22.4M | } else if (p0->y < p1->y) { |
2293 | 3.80M | q0 = *p0; |
2294 | 3.80M | q1 = *p1; |
2295 | 3.80M | cc0 = c0; |
2296 | 3.80M | cc1 = c1; |
2297 | 18.6M | } else { |
2298 | 18.6M | q0 = *p1; |
2299 | 18.6M | q1 = *p0; |
2300 | 18.6M | cc0 = c1; |
2301 | 18.6M | cc1 = c0; |
2302 | 18.6M | } |
2303 | 35.3M | le.start.x = q0.x - adjust; |
2304 | 35.3M | re.start.x = q0.x + adjust; |
2305 | 35.3M | le.start.y = re.start.y = q0.y - adjust; |
2306 | 35.3M | le.end.x = q1.x - adjust; |
2307 | 35.3M | re.end.x = q1.x + adjust; |
2308 | 35.3M | le.end.y = re.end.y = q1.y + adjust; |
2309 | 35.3M | adjust_swapped_boundary(&re.start.x, swap_axes); |
2310 | 35.3M | adjust_swapped_boundary(&re.end.x, swap_axes); |
2311 | 35.3M | return decompose_linear_color(pfs, &le, &re, le.start.y, le.end.y, swap_axes, cc0, cc1); |
2312 | | /* fixme : for a better performance and quality, we would like to |
2313 | | consider the bar as an oriented one and to know at what side of it the spot resides. |
2314 | | If we know that, we could expand only to outside the spot. |
2315 | | Note that if the boundary has a self-intersection, |
2316 | | we still need to expand to both directions. |
2317 | | */ |
2318 | 35.3M | } |
2319 | | |
2320 | | static inline void |
2321 | | bbox_of_points(gs_fixed_rect *r, |
2322 | | const gs_fixed_point *p0, const gs_fixed_point *p1, |
2323 | | const gs_fixed_point *p2, const gs_fixed_point *p3) |
2324 | 38.1M | { |
2325 | 38.1M | r->p.x = r->q.x = p0->x; |
2326 | 38.1M | r->p.y = r->q.y = p0->y; |
2327 | | |
2328 | 38.1M | if (r->p.x > p1->x) |
2329 | 15.6M | r->p.x = p1->x; |
2330 | 38.1M | if (r->q.x < p1->x) |
2331 | 15.8M | r->q.x = p1->x; |
2332 | 38.1M | if (r->p.y > p1->y) |
2333 | 16.0M | r->p.y = p1->y; |
2334 | 38.1M | if (r->q.y < p1->y) |
2335 | 15.3M | r->q.y = p1->y; |
2336 | | |
2337 | 38.1M | if (r->p.x > p2->x) |
2338 | 8.25M | r->p.x = p2->x; |
2339 | 38.1M | if (r->q.x < p2->x) |
2340 | 8.32M | r->q.x = p2->x; |
2341 | 38.1M | if (r->p.y > p2->y) |
2342 | 7.87M | r->p.y = p2->y; |
2343 | 38.1M | if (r->q.y < p2->y) |
2344 | 8.56M | r->q.y = p2->y; |
2345 | | |
2346 | 38.1M | if (p3 == NULL) |
2347 | 27.8M | return; |
2348 | | |
2349 | 10.3M | if (r->p.x > p3->x) |
2350 | 2.13M | r->p.x = p3->x; |
2351 | 10.3M | if (r->q.x < p3->x) |
2352 | 2.58M | r->q.x = p3->x; |
2353 | 10.3M | if (r->p.y > p3->y) |
2354 | 2.10M | r->p.y = p3->y; |
2355 | 10.3M | if (r->q.y < p3->y) |
2356 | 2.26M | r->q.y = p3->y; |
2357 | 10.3M | } |
2358 | | |
2359 | | static int |
2360 | | fill_wedges_aux(patch_fill_state_t *pfs, int k, int ka, |
2361 | | const gs_fixed_point pole[4], const patch_color_t *c0, const patch_color_t *c1, |
2362 | | int wedge_type) |
2363 | 2.79M | { |
2364 | 2.79M | int code; |
2365 | | |
2366 | 2.79M | if (k > 1) { |
2367 | 1.02M | gs_fixed_point q[2][4]; |
2368 | 1.02M | patch_color_t *c; |
2369 | 1.02M | bool save_inside = pfs->inside; |
2370 | 1.02M | byte *color_stack_ptr; |
2371 | | |
2372 | 1.02M | if (!pfs->inside) { |
2373 | 949k | gs_fixed_rect r, r1; |
2374 | | |
2375 | 949k | bbox_of_points(&r, &pole[0], &pole[1], &pole[2], &pole[3]); |
2376 | 949k | r.p.x -= INTERPATCH_PADDING; |
2377 | 949k | r.p.y -= INTERPATCH_PADDING; |
2378 | 949k | r.q.x += INTERPATCH_PADDING; |
2379 | 949k | r.q.y += INTERPATCH_PADDING; |
2380 | 949k | r1 = r; |
2381 | 949k | rect_intersect(r, pfs->rect); |
2382 | 949k | if (r.q.x <= r.p.x || r.q.y <= r.p.y) |
2383 | 766k | return 0; |
2384 | 182k | if (r1.p.x == r.p.x && r1.p.y == r.p.y && |
2385 | 182k | r1.q.x == r.q.x && r1.q.y == r.q.y) |
2386 | 58.9k | pfs->inside = true; |
2387 | 182k | } |
2388 | 259k | color_stack_ptr = reserve_colors_inline(pfs, &c, 1); |
2389 | 259k | if (color_stack_ptr == NULL) |
2390 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2391 | 259k | patch_interpolate_color(c, c0, c1, pfs, 0.5); |
2392 | 259k | split_curve(pole, q[0], q[1]); |
2393 | 259k | code = fill_wedges_aux(pfs, k / 2, ka, q[0], c0, c, wedge_type); |
2394 | 259k | if (code >= 0) |
2395 | 259k | code = fill_wedges_aux(pfs, k / 2, ka, q[1], c, c1, wedge_type); |
2396 | 259k | release_colors_inline(pfs, color_stack_ptr, 1); |
2397 | 259k | pfs->inside = save_inside; |
2398 | 259k | return code; |
2399 | 1.76M | } else { |
2400 | 1.76M | if ((INTERPATCH_PADDING != 0) && (wedge_type & interpatch_padding)) { |
2401 | 1.71M | code = mesh_padding(pfs, &pole[0], &pole[3], c0, c1); |
2402 | 1.71M | if (code < 0) |
2403 | 0 | return code; |
2404 | 1.71M | } |
2405 | 1.76M | if (ka >= 2 && (wedge_type & inpatch_wedge)) |
2406 | 114k | return wedge_by_triangles(pfs, ka, pole, c0, c1); |
2407 | 1.65M | return 0; |
2408 | 1.76M | } |
2409 | 2.79M | } |
2410 | | |
2411 | | static int |
2412 | | fill_wedges(patch_fill_state_t *pfs, int k0, int k1, |
2413 | | const gs_fixed_point *pole, int pole_step, |
2414 | | const patch_color_t *c0, const patch_color_t *c1, |
2415 | | int wedge_type) |
2416 | 24.0M | { |
2417 | | /* Generate wedges between 2 variants of a curve flattening. */ |
2418 | | /* k0, k1 is a power of 2. */ |
2419 | 24.0M | gs_fixed_point p[4]; |
2420 | | |
2421 | 24.0M | if (!(wedge_type & interpatch_padding) && k0 == k1) |
2422 | 21.7M | return 0; /* Wedges are zero area. */ |
2423 | 2.27M | if (k0 > k1) { /* Swap if required, so that k0 <= k1 */ |
2424 | 0 | k0 ^= k1; k1 ^= k0; k0 ^= k1; |
2425 | 0 | } |
2426 | 2.27M | p[0] = pole[0]; |
2427 | 2.27M | p[1] = pole[pole_step]; |
2428 | 2.27M | p[2] = pole[pole_step * 2]; |
2429 | 2.27M | p[3] = pole[pole_step * 3]; |
2430 | 2.27M | return fill_wedges_aux(pfs, k0, k1 / k0, p, c0, c1, wedge_type); |
2431 | 24.0M | } |
2432 | | |
2433 | | static inline void |
2434 | | make_vertices(gs_fixed_point q[4], const quadrangle_patch *p) |
2435 | 690k | { |
2436 | 690k | q[0] = p->p[0][0]->p; |
2437 | 690k | q[1] = p->p[0][1]->p; |
2438 | 690k | q[2] = p->p[1][1]->p; |
2439 | 690k | q[3] = p->p[1][0]->p; |
2440 | 690k | } |
2441 | | |
2442 | | static inline void |
2443 | | wrap_vertices_by_y(gs_fixed_point q[4], const gs_fixed_point s[4]) |
2444 | 690k | { |
2445 | 690k | fixed y = s[0].y; |
2446 | 690k | int i = 0; |
2447 | | |
2448 | 690k | if (y > s[1].y) |
2449 | 291k | i = 1, y = s[1].y; |
2450 | 690k | if (y > s[2].y) |
2451 | 121k | i = 2, y = s[2].y; |
2452 | 690k | if (y > s[3].y) |
2453 | 57.1k | i = 3, y = s[3].y; |
2454 | 690k | q[0] = s[(i + 0) % 4]; |
2455 | 690k | q[1] = s[(i + 1) % 4]; |
2456 | 690k | q[2] = s[(i + 2) % 4]; |
2457 | 690k | q[3] = s[(i + 3) % 4]; |
2458 | 690k | } |
2459 | | |
2460 | | static int |
2461 | | ordered_triangle(patch_fill_state_t *pfs, gs_fixed_edge *le, gs_fixed_edge *re, patch_color_t *c) |
2462 | 51.3M | { |
2463 | 51.3M | gs_fixed_edge ue; |
2464 | 51.3M | int code; |
2465 | 51.3M | gx_device_color dc; |
2466 | | |
2467 | | # if NOFILL_TEST |
2468 | | if (dbg_nofill) |
2469 | | return 0; |
2470 | | # endif |
2471 | 51.3M | code = patch_color_to_device_color_inline(pfs, c, &dc, NULL); |
2472 | 51.3M | if (code < 0) |
2473 | 0 | return code; |
2474 | 51.3M | if (le->end.y < re->end.y) { |
2475 | 23.2M | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
2476 | 23.2M | le, re, le->start.y, le->end.y, false, &dc, pfs->pgs->log_op); |
2477 | 23.2M | if (code >= 0) { |
2478 | 23.2M | ue.start = le->end; |
2479 | 23.2M | ue.end = re->end; |
2480 | 23.2M | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
2481 | 23.2M | &ue, re, le->end.y, re->end.y, false, &dc, pfs->pgs->log_op); |
2482 | 23.2M | } |
2483 | 28.0M | } else if (le->end.y > re->end.y) { |
2484 | 21.6M | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
2485 | 21.6M | le, re, le->start.y, re->end.y, false, &dc, pfs->pgs->log_op); |
2486 | 21.6M | if (code >= 0) { |
2487 | 21.6M | ue.start = re->end; |
2488 | 21.6M | ue.end = le->end; |
2489 | 21.6M | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
2490 | 21.6M | le, &ue, re->end.y, le->end.y, false, &dc, pfs->pgs->log_op); |
2491 | 21.6M | } |
2492 | 21.6M | } else |
2493 | 6.41M | code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev, |
2494 | 6.41M | le, re, le->start.y, le->end.y, false, &dc, pfs->pgs->log_op); |
2495 | 51.3M | return code; |
2496 | 51.3M | } |
2497 | | |
2498 | | static int |
2499 | | constant_color_triangle(patch_fill_state_t *pfs, |
2500 | | const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2) |
2501 | 45.0M | { |
2502 | 45.0M | patch_color_t *c[2]; |
2503 | 45.0M | gs_fixed_edge le, re; |
2504 | 45.0M | fixed dx0, dy0, dx1, dy1; |
2505 | 45.0M | const shading_vertex_t *pp; |
2506 | 45.0M | int i, code = 0; |
2507 | 45.0M | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 2); |
2508 | | |
2509 | 45.0M | if (color_stack_ptr == NULL) |
2510 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2511 | 45.0M | patch_interpolate_color(c[0], p0->c, p1->c, pfs, 0.5); |
2512 | 45.0M | patch_interpolate_color(c[1], p2->c, c[0], pfs, 0.5); |
2513 | 180M | for (i = 0; i < 3; i++) { |
2514 | | /* fixme : does optimizer compiler expand this cycle ? */ |
2515 | 135M | if (p0->p.y <= p1->p.y && p0->p.y <= p2->p.y) { |
2516 | 51.3M | le.start = re.start = p0->p; |
2517 | 51.3M | le.end = p1->p; |
2518 | 51.3M | re.end = p2->p; |
2519 | | |
2520 | 51.3M | dx0 = le.end.x - le.start.x; |
2521 | 51.3M | dy0 = le.end.y - le.start.y; |
2522 | 51.3M | dx1 = re.end.x - re.start.x; |
2523 | 51.3M | dy1 = re.end.y - re.start.y; |
2524 | 51.3M | if ((int64_t)dx0 * dy1 < (int64_t)dy0 * dx1) |
2525 | 24.3M | code = ordered_triangle(pfs, &le, &re, c[1]); |
2526 | 26.9M | else |
2527 | 26.9M | code = ordered_triangle(pfs, &re, &le, c[1]); |
2528 | 51.3M | if (code < 0) |
2529 | 0 | break; |
2530 | 51.3M | } |
2531 | 135M | pp = p0; p0 = p1; p1 = p2; p2 = pp; |
2532 | 135M | } |
2533 | 45.0M | release_colors_inline(pfs, color_stack_ptr, 2); |
2534 | 45.0M | return code; |
2535 | 45.0M | } |
2536 | | |
2537 | | static inline int |
2538 | | constant_color_quadrangle_aux(patch_fill_state_t *pfs, const quadrangle_patch *p, bool self_intersecting, |
2539 | | patch_color_t *c[3]) |
2540 | 690k | { |
2541 | | /* Assuming the XY span is restricted with curve_samples. |
2542 | | It is important for intersection_of_small_bars to compute faster. */ |
2543 | 690k | gs_fixed_point q[4]; |
2544 | 690k | fixed ry, ey; |
2545 | 690k | int code; |
2546 | 690k | bool swap_axes = false; |
2547 | 690k | gx_device_color dc; |
2548 | 690k | bool orient; |
2549 | | |
2550 | 690k | dc.tag = device_current_tag(pfs->dev); |
2551 | | |
2552 | 690k | patch_interpolate_color(c[1], p->p[0][0]->c, p->p[0][1]->c, pfs, 0.5); |
2553 | 690k | patch_interpolate_color(c[2], p->p[1][0]->c, p->p[1][1]->c, pfs, 0.5); |
2554 | 690k | patch_interpolate_color(c[0], c[1], c[2], pfs, 0.5); |
2555 | 690k | code = patch_color_to_device_color_inline(pfs, c[0], &dc, NULL); |
2556 | 690k | if (code < 0) |
2557 | 0 | return code; |
2558 | 690k | { gs_fixed_point qq[4]; |
2559 | | |
2560 | 690k | make_vertices(qq, p); |
2561 | | #ifdef SHADING_SWAP_AXES_FOR_PRECISION |
2562 | | /* Swapping axes may improve the precision, |
2563 | | but slows down due to the area expansion needed |
2564 | | in gx_shade_trapezoid. */ |
2565 | | dx = span_x(qq, 4); |
2566 | | dy = span_y(qq, 4); |
2567 | | if (dy < dx) { |
2568 | | do_swap_axes(qq, 4); |
2569 | | swap_axes = true; |
2570 | | } |
2571 | | #endif |
2572 | 690k | wrap_vertices_by_y(q, qq); |
2573 | 690k | } |
2574 | 690k | { fixed dx1 = q[1].x - q[0].x, dy1 = q[1].y - q[0].y; |
2575 | 690k | fixed dx3 = q[3].x - q[0].x, dy3 = q[3].y - q[0].y; |
2576 | 690k | int64_t g13 = (int64_t)dx1 * dy3, h13 = (int64_t)dy1 * dx3; |
2577 | | |
2578 | 690k | if (g13 == h13) { |
2579 | 1.37k | fixed dx2 = q[2].x - q[0].x, dy2 = q[2].y - q[0].y; |
2580 | 1.37k | int64_t g23 = (int64_t)dx2 * dy3, h23 = (int64_t)dy2 * dx3; |
2581 | | |
2582 | 1.37k | if (dx1 == 0 && dy1 == 0 && g23 == h23) |
2583 | 0 | return 0; |
2584 | 1.37k | if (g23 != h23) { |
2585 | 1.37k | orient = (g23 > h23); |
2586 | 1.37k | if (q[2].y <= q[3].y) { |
2587 | 1.11k | if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[2].y, swap_axes, &dc, orient)) < 0) |
2588 | 0 | return code; |
2589 | 1.11k | return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient); |
2590 | 1.11k | } else { |
2591 | 260 | if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2592 | 0 | return code; |
2593 | 260 | return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient); |
2594 | 260 | } |
2595 | 1.37k | } else { |
2596 | 0 | int64_t g12 = (int64_t)dx1 * dy2, h12 = (int64_t)dy1 * dx2; |
2597 | |
|
2598 | 0 | if (dx3 == 0 && dy3 == 0 && g12 == h12) |
2599 | 0 | return 0; |
2600 | 0 | orient = (g12 > h12); |
2601 | 0 | if (q[1].y <= q[2].y) { |
2602 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2603 | 0 | return code; |
2604 | 0 | return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[1].y, q[2].y, swap_axes, &dc, orient); |
2605 | 0 | } else { |
2606 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[0].y, q[2].y, swap_axes, &dc, orient)) < 0) |
2607 | 0 | return code; |
2608 | 0 | return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient); |
2609 | 0 | } |
2610 | 0 | } |
2611 | 1.37k | } |
2612 | 688k | orient = ((int64_t)dx1 * dy3 > (int64_t)dy1 * dx3); |
2613 | 688k | } |
2614 | 688k | if (q[1].y <= q[2].y && q[2].y <= q[3].y) { |
2615 | 238k | if (self_intersecting && intersection_of_small_bars(q, 0, 3, 1, 2, &ry, &ey)) { |
2616 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2617 | 0 | return code; |
2618 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 3, 1, 2, q[1].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2619 | 0 | return code; |
2620 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, ry, q[2].y, swap_axes, &dc, orient)) < 0) |
2621 | 0 | return code; |
2622 | 0 | return gx_shade_trapezoid(pfs, q, 0, 3, 2, 3, q[2].y, q[3].y, swap_axes, &dc, orient); |
2623 | 238k | } else { |
2624 | 238k | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2625 | 0 | return code; |
2626 | 238k | if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[2].y, swap_axes, &dc, orient)) < 0) |
2627 | 0 | return code; |
2628 | 238k | return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient); |
2629 | 238k | } |
2630 | 450k | } else if (q[1].y <= q[3].y && q[3].y <= q[2].y) { |
2631 | 184k | if (self_intersecting && intersection_of_small_bars(q, 0, 3, 1, 2, &ry, &ey)) { |
2632 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2633 | 0 | return code; |
2634 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2635 | 0 | return code; |
2636 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 3, 1, 2, ry, q[3].y, swap_axes, &dc, orient)) < 0) |
2637 | 0 | return code; |
2638 | 0 | return gx_shade_trapezoid(pfs, q, 3, 2, 1, 2, q[3].y, q[2].y, swap_axes, &dc, orient); |
2639 | 184k | } else { |
2640 | 184k | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2641 | 0 | return code; |
2642 | 184k | if ((code = gx_shade_trapezoid(pfs, q, 1, 2, 0, 3, q[1].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2643 | 0 | return code; |
2644 | 184k | return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient); |
2645 | 184k | } |
2646 | 266k | } else if (q[2].y <= q[1].y && q[1].y <= q[3].y) { |
2647 | 0 | if (self_intersecting && intersection_of_small_bars(q, 0, 1, 2, 3, &ry, &ey)) { |
2648 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2649 | 0 | return code; |
2650 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2651 | 0 | return code; |
2652 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 0, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0) |
2653 | 0 | return code; |
2654 | 0 | return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, ry, q[3].y, swap_axes, &dc, orient); |
2655 | 0 | } else if (self_intersecting && intersection_of_small_bars(q, 0, 3, 1, 2, &ry, &ey)) { |
2656 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2657 | 0 | return code; |
2658 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2659 | 0 | return code; |
2660 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0) |
2661 | 0 | return code; |
2662 | 0 | return gx_shade_trapezoid(pfs, q, 0, 3, 2, 3, ry, q[3].y, swap_axes, &dc, orient); |
2663 | 0 | } else { |
2664 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2665 | 0 | return code; |
2666 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 3, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2667 | 0 | return code; |
2668 | 0 | return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[1].y, q[3].y, swap_axes, &dc, orient); |
2669 | 0 | } |
2670 | 266k | } else if (q[2].y <= q[3].y && q[3].y <= q[1].y) { |
2671 | 78 | if (self_intersecting && intersection_of_small_bars(q, 0, 1, 2, 3, &ry, &ey)) { |
2672 | | /* Same code as someone above. */ |
2673 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2674 | 0 | return code; |
2675 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2676 | 0 | return code; |
2677 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 0, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0) |
2678 | 0 | return code; |
2679 | 0 | return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, ry, q[3].y, swap_axes, &dc, orient); |
2680 | 78 | } else if (self_intersecting && intersection_of_small_bars(q, 0, 3, 2, 1, &ry, &ey)) { |
2681 | | /* Same code as someone above. */ |
2682 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2683 | 0 | return code; |
2684 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 2, 1, 2, 3, q[2].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2685 | 0 | return code; |
2686 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0) |
2687 | 0 | return code; |
2688 | 0 | return gx_shade_trapezoid(pfs, q, 0, 3, 2, 3, ry, q[3].y, swap_axes, &dc, orient); |
2689 | 78 | } else { |
2690 | 78 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[2].y, swap_axes, &dc, orient)) < 0) |
2691 | 0 | return code; |
2692 | 78 | if ((code = gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2693 | 0 | return code; |
2694 | 78 | return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient); |
2695 | 78 | } |
2696 | 266k | } else if (q[3].y <= q[1].y && q[1].y <= q[2].y) { |
2697 | 263k | if (self_intersecting && intersection_of_small_bars(q, 0, 1, 3, 2, &ry, &ey)) { |
2698 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2699 | 0 | return code; |
2700 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2701 | 0 | return code; |
2702 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 3, 2, 0, 1, ry, q[1].y, swap_axes, &dc, orient)) < 0) |
2703 | 0 | return code; |
2704 | 0 | return gx_shade_trapezoid(pfs, q, 3, 2, 1, 2, q[1].y, q[2].y, swap_axes, &dc, orient); |
2705 | 263k | } else { |
2706 | 263k | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2707 | 0 | return code; |
2708 | 263k | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, q[1].y, swap_axes, &dc, orient)) < 0) |
2709 | 0 | return code; |
2710 | 263k | return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[1].y, q[2].y, swap_axes, &dc, orient); |
2711 | 263k | } |
2712 | 263k | } else if (q[3].y <= q[2].y && q[2].y <= q[1].y) { |
2713 | 3.09k | if (self_intersecting && intersection_of_small_bars(q, 0, 1, 2, 3, &ry, &ey)) { |
2714 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2715 | 0 | return code; |
2716 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, ry + ey, swap_axes, &dc, orient)) < 0) |
2717 | 0 | return code; |
2718 | 0 | if ((code = gx_shade_trapezoid(pfs, q, 3, 2, 0, 1, ry, q[2].y, swap_axes, &dc, orient)) < 0) |
2719 | 0 | return code; |
2720 | 0 | return gx_shade_trapezoid(pfs, q, 2, 1, 0, 1, q[2].y, q[1].y, swap_axes, &dc, orient); |
2721 | 3.09k | } else { |
2722 | 3.09k | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 0, 3, q[0].y, q[3].y, swap_axes, &dc, orient)) < 0) |
2723 | 0 | return code; |
2724 | 3.09k | if ((code = gx_shade_trapezoid(pfs, q, 0, 1, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient)) < 0) |
2725 | 0 | return code; |
2726 | 3.09k | return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient); |
2727 | 3.09k | } |
2728 | 3.09k | } else { |
2729 | | /* Impossible. */ |
2730 | 0 | return_error(gs_error_unregistered); |
2731 | 0 | } |
2732 | 688k | } |
2733 | | |
2734 | | int |
2735 | | constant_color_quadrangle(patch_fill_state_t *pfs, const quadrangle_patch *p, bool self_intersecting) |
2736 | 690k | { |
2737 | 690k | patch_color_t *c[3]; |
2738 | 690k | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 3); |
2739 | 690k | int code; |
2740 | | |
2741 | 690k | if (color_stack_ptr == NULL) |
2742 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
2743 | 690k | code = constant_color_quadrangle_aux(pfs, p, self_intersecting, c); |
2744 | 690k | release_colors_inline(pfs, color_stack_ptr, 3); |
2745 | 690k | return code; |
2746 | 690k | } |
2747 | | |
2748 | | static inline void |
2749 | | divide_quadrangle_by_v(patch_fill_state_t *pfs, quadrangle_patch *s0, quadrangle_patch *s1, |
2750 | | shading_vertex_t q[2], const quadrangle_patch *p, patch_color_t *c[2]) |
2751 | 805k | { |
2752 | 805k | q[0].c = c[0]; |
2753 | 805k | q[1].c = c[1]; |
2754 | 805k | q[0].p.x = (p->p[0][0]->p.x + p->p[1][0]->p.x) / 2; |
2755 | 805k | q[1].p.x = (p->p[0][1]->p.x + p->p[1][1]->p.x) / 2; |
2756 | 805k | q[0].p.y = (p->p[0][0]->p.y + p->p[1][0]->p.y) / 2; |
2757 | 805k | q[1].p.y = (p->p[0][1]->p.y + p->p[1][1]->p.y) / 2; |
2758 | 805k | patch_interpolate_color(c[0], p->p[0][0]->c, p->p[1][0]->c, pfs, 0.5); |
2759 | 805k | patch_interpolate_color(c[1], p->p[0][1]->c, p->p[1][1]->c, pfs, 0.5); |
2760 | 805k | s0->p[0][0] = p->p[0][0]; |
2761 | 805k | s0->p[0][1] = p->p[0][1]; |
2762 | 805k | s0->p[1][0] = s1->p[0][0] = &q[0]; |
2763 | 805k | s0->p[1][1] = s1->p[0][1] = &q[1]; |
2764 | 805k | s1->p[1][0] = p->p[1][0]; |
2765 | 805k | s1->p[1][1] = p->p[1][1]; |
2766 | 805k | } |
2767 | | |
2768 | | static inline void |
2769 | | divide_quadrangle_by_u(patch_fill_state_t *pfs, quadrangle_patch *s0, quadrangle_patch *s1, |
2770 | | shading_vertex_t q[2], const quadrangle_patch *p, patch_color_t *c[2]) |
2771 | 1.64M | { |
2772 | 1.64M | q[0].c = c[0]; |
2773 | 1.64M | q[1].c = c[1]; |
2774 | 1.64M | q[0].p.x = (p->p[0][0]->p.x + p->p[0][1]->p.x) / 2; |
2775 | 1.64M | q[1].p.x = (p->p[1][0]->p.x + p->p[1][1]->p.x) / 2; |
2776 | 1.64M | q[0].p.y = (p->p[0][0]->p.y + p->p[0][1]->p.y) / 2; |
2777 | 1.64M | q[1].p.y = (p->p[1][0]->p.y + p->p[1][1]->p.y) / 2; |
2778 | 1.64M | patch_interpolate_color(c[0], p->p[0][0]->c, p->p[0][1]->c, pfs, 0.5); |
2779 | 1.64M | patch_interpolate_color(c[1], p->p[1][0]->c, p->p[1][1]->c, pfs, 0.5); |
2780 | 1.64M | s0->p[0][0] = p->p[0][0]; |
2781 | 1.64M | s0->p[1][0] = p->p[1][0]; |
2782 | 1.64M | s0->p[0][1] = s1->p[0][0] = &q[0]; |
2783 | 1.64M | s0->p[1][1] = s1->p[1][0] = &q[1]; |
2784 | 1.64M | s1->p[0][1] = p->p[0][1]; |
2785 | 1.64M | s1->p[1][1] = p->p[1][1]; |
2786 | 1.64M | } |
2787 | | |
2788 | | static inline int |
2789 | | is_quadrangle_color_monotonic(const patch_fill_state_t *pfs, const quadrangle_patch *p, |
2790 | | bool *not_monotonic_by_u, bool *not_monotonic_by_v) |
2791 | 2.32M | { /* returns : 1 = monotonic, 0 = don't know, <0 = error. */ |
2792 | 2.32M | int code, r; |
2793 | | |
2794 | 2.32M | code = isnt_color_monotonic(pfs, p->p[0][0]->c, p->p[1][1]->c); |
2795 | 2.32M | if (code <= 0) |
2796 | 2.14M | return code; |
2797 | 175k | r = code << pfs->function_arg_shift; |
2798 | 175k | if (r & 1) |
2799 | 0 | *not_monotonic_by_u = true; |
2800 | 175k | if (r & 2) |
2801 | 175k | *not_monotonic_by_v = true; |
2802 | 175k | return !code; |
2803 | 2.32M | } |
2804 | | |
2805 | | static inline void |
2806 | | divide_bar(patch_fill_state_t *pfs, |
2807 | | const shading_vertex_t *p0, const shading_vertex_t *p1, int radix, shading_vertex_t *p, |
2808 | | patch_color_t *c) |
2809 | 54.8M | { |
2810 | | /* Assuming p.c == c for providing a non-const access. */ |
2811 | 54.8M | p->p.x = (fixed)((int64_t)p0->p.x * (radix - 1) + p1->p.x) / radix; |
2812 | 54.8M | p->p.y = (fixed)((int64_t)p0->p.y * (radix - 1) + p1->p.y) / radix; |
2813 | 54.8M | patch_interpolate_color(c, p0->c, p1->c, pfs, (double)(radix - 1) / radix); |
2814 | 54.8M | } |
2815 | | |
2816 | | static int |
2817 | | triangle_by_4(patch_fill_state_t *pfs, |
2818 | | const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2, |
2819 | | wedge_vertex_list_t *l01, wedge_vertex_list_t *l12, wedge_vertex_list_t *l20, |
2820 | | double cd, fixed sd) |
2821 | 101M | { |
2822 | 101M | shading_vertex_t p01, p12, p20; |
2823 | 101M | patch_color_t *c[3]; |
2824 | 101M | wedge_vertex_list_t L01, L12, L20, L[3]; |
2825 | 101M | bool inside_save = pfs->inside; |
2826 | 101M | gs_fixed_rect r = {{0,0},{0,0}}, r1 = {{0,0},{0,0}}; |
2827 | 101M | int code = 0; |
2828 | 101M | byte *color_stack_ptr; |
2829 | 101M | const bool inside = pfs->inside; /* 'const' should help compiler to analyze initializations. */ |
2830 | | |
2831 | 101M | if (!inside) { |
2832 | 27.8M | bbox_of_points(&r, &p0->p, &p1->p, &p2->p, NULL); |
2833 | 27.8M | r1 = r; |
2834 | 27.8M | rect_intersect(r, pfs->rect); |
2835 | 27.8M | if (r.q.x <= r.p.x || r.q.y <= r.p.y) |
2836 | 9.72M | return 0; |
2837 | 27.8M | } |
2838 | 91.7M | color_stack_ptr = reserve_colors_inline(pfs, c, 3); |
2839 | 91.7M | if(color_stack_ptr == NULL) |
2840 | 0 | return_error(gs_error_unregistered); |
2841 | 91.7M | p01.c = c[0]; |
2842 | 91.7M | p12.c = c[1]; |
2843 | 91.7M | p20.c = c[2]; |
2844 | 91.7M | code = try_device_linear_color(pfs, false, p0, p1, p2); |
2845 | 91.7M | switch(code) { |
2846 | 40.7M | case 0: /* The area is filled. */ |
2847 | 40.7M | goto out; |
2848 | 50.5M | case 2: /* decompose to constant color areas */ |
2849 | | /* Halftoned devices may do with some bigger areas |
2850 | | due to imprecise representation of a contone color. |
2851 | | So we multiply the decomposition limit by 4 for a faster rendering. */ |
2852 | 50.5M | if (sd < pfs->decomposition_limit * 4) { |
2853 | 13.8M | code = constant_color_triangle(pfs, p2, p0, p1); |
2854 | 13.8M | goto out; |
2855 | 13.8M | } |
2856 | 36.7M | if (pfs->Function != NULL) { |
2857 | 7.34M | double d01 = color_span(pfs, p1->c, p0->c); |
2858 | 7.34M | double d12 = color_span(pfs, p2->c, p1->c); |
2859 | 7.34M | double d20 = color_span(pfs, p0->c, p2->c); |
2860 | | |
2861 | 7.34M | if (d01 <= pfs->smoothness / COLOR_CONTIGUITY && |
2862 | 7.34M | d12 <= pfs->smoothness / COLOR_CONTIGUITY && |
2863 | 7.34M | d20 <= pfs->smoothness / COLOR_CONTIGUITY) { |
2864 | 5.93M | code = constant_color_triangle(pfs, p2, p0, p1); |
2865 | 5.93M | goto out; |
2866 | 5.93M | } |
2867 | 29.3M | } else if (cd <= pfs->smoothness / COLOR_CONTIGUITY) { |
2868 | 25.1M | code = constant_color_triangle(pfs, p2, p0, p1); |
2869 | 25.1M | goto out; |
2870 | 25.1M | } |
2871 | 5.66M | break; |
2872 | 5.66M | case 1: /* decompose to linear color areas */ |
2873 | 455k | if (sd < pfs->decomposition_limit) { |
2874 | 194k | code = constant_color_triangle(pfs, p2, p0, p1); |
2875 | 194k | goto out; |
2876 | 194k | } |
2877 | 260k | break; |
2878 | 260k | default: /* Error. */ |
2879 | 0 | goto out; |
2880 | 91.7M | } |
2881 | 5.92M | if (!inside) { |
2882 | 874k | if (r.p.x == r1.p.x && r.p.y == r1.p.y && |
2883 | 874k | r.q.x == r1.q.x && r.q.y == r1.q.y) |
2884 | 101k | pfs->inside = true; |
2885 | 874k | } |
2886 | 5.92M | divide_bar(pfs, p0, p1, 2, &p01, c[0]); |
2887 | 5.92M | divide_bar(pfs, p1, p2, 2, &p12, c[1]); |
2888 | 5.92M | divide_bar(pfs, p2, p0, 2, &p20, c[2]); |
2889 | 5.92M | if (LAZY_WEDGES) { |
2890 | 5.92M | init_wedge_vertex_list(L, count_of(L)); |
2891 | 5.92M | code = make_wedge_median(pfs, &L01, l01, true, &p0->p, &p1->p, &p01.p); |
2892 | 5.92M | if (code >= 0) |
2893 | 5.92M | code = make_wedge_median(pfs, &L12, l12, true, &p1->p, &p2->p, &p12.p); |
2894 | 5.92M | if (code >= 0) |
2895 | 5.92M | code = make_wedge_median(pfs, &L20, l20, false, &p2->p, &p0->p, &p20.p); |
2896 | 5.92M | } else { |
2897 | 0 | code = fill_triangle_wedge(pfs, p0, p1, &p01); |
2898 | 0 | if (code >= 0) |
2899 | 0 | code = fill_triangle_wedge(pfs, p1, p2, &p12); |
2900 | 0 | if (code >= 0) |
2901 | 0 | code = fill_triangle_wedge(pfs, p2, p0, &p20); |
2902 | 0 | } |
2903 | 5.92M | if (code >= 0) |
2904 | 5.92M | code = triangle_by_4(pfs, p0, &p01, &p20, &L01, &L[0], &L20, cd / 2, sd / 2); |
2905 | 5.92M | if (code >= 0) { |
2906 | 5.92M | if (LAZY_WEDGES) { |
2907 | 5.92M | move_wedge(&L01, l01, true); |
2908 | 5.92M | move_wedge(&L20, l20, false); |
2909 | 5.92M | } |
2910 | 5.92M | code = triangle_by_4(pfs, p1, &p12, &p01, &L12, &L[1], &L01, cd / 2, sd / 2); |
2911 | 5.92M | } |
2912 | 5.92M | if (code >= 0) { |
2913 | 5.92M | if (LAZY_WEDGES) |
2914 | 5.92M | move_wedge(&L12, l12, true); |
2915 | 5.92M | code = triangle_by_4(pfs, p2, &p20, &p12, &L20, &L[2], &L12, cd / 2, sd / 2); |
2916 | 5.92M | } |
2917 | 5.92M | if (code >= 0) { |
2918 | 5.92M | L[0].last_side = L[1].last_side = L[2].last_side = true; |
2919 | 5.92M | code = triangle_by_4(pfs, &p01, &p12, &p20, &L[1], &L[2], &L[0], cd / 2, sd / 2); |
2920 | 5.92M | } |
2921 | 5.92M | if (LAZY_WEDGES) { |
2922 | 5.92M | if (code >= 0) |
2923 | 5.92M | code = close_wedge_median(pfs, l01, p0->c, p1->c); |
2924 | 5.92M | if (code >= 0) |
2925 | 5.92M | code = close_wedge_median(pfs, l12, p1->c, p2->c); |
2926 | 5.92M | if (code >= 0) |
2927 | 5.92M | code = close_wedge_median(pfs, l20, p2->c, p0->c); |
2928 | 5.92M | if (code >= 0) |
2929 | 5.92M | code = terminate_wedge_vertex_list(pfs, &L[0], p01.c, p20.c); |
2930 | 5.92M | if (code >= 0) |
2931 | 5.92M | code = terminate_wedge_vertex_list(pfs, &L[1], p12.c, p01.c); |
2932 | 5.92M | if (code >= 0) |
2933 | 5.92M | code = terminate_wedge_vertex_list(pfs, &L[2], p20.c, p12.c); |
2934 | 5.92M | } |
2935 | 5.92M | pfs->inside = inside_save; |
2936 | 91.7M | out: |
2937 | 91.7M | release_colors_inline(pfs, color_stack_ptr, 3); |
2938 | 91.7M | return code; |
2939 | 5.92M | } |
2940 | | |
2941 | | static inline int |
2942 | | fill_triangle(patch_fill_state_t *pfs, |
2943 | | const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2, |
2944 | | wedge_vertex_list_t *l01, wedge_vertex_list_t *l12, wedge_vertex_list_t *l20) |
2945 | 77.8M | { |
2946 | 77.8M | fixed sd01 = max(any_abs(p1->p.x - p0->p.x), any_abs(p1->p.y - p0->p.y)); |
2947 | 77.8M | fixed sd12 = max(any_abs(p2->p.x - p1->p.x), any_abs(p2->p.y - p1->p.y)); |
2948 | 77.8M | fixed sd20 = max(any_abs(p0->p.x - p2->p.x), any_abs(p0->p.y - p2->p.y)); |
2949 | 77.8M | fixed sd1 = max(sd01, sd12); |
2950 | 77.8M | fixed sd = max(sd1, sd20); |
2951 | 77.8M | double cd = 0; |
2952 | | |
2953 | | # if SKIP_TEST |
2954 | | dbg_triangle_cnt++; |
2955 | | # endif |
2956 | 77.8M | if (pfs->Function == NULL) { |
2957 | 63.3M | double d01 = color_span(pfs, p1->c, p0->c); |
2958 | 63.3M | double d12 = color_span(pfs, p2->c, p1->c); |
2959 | 63.3M | double d20 = color_span(pfs, p0->c, p2->c); |
2960 | 63.3M | double cd1 = max(d01, d12); |
2961 | | |
2962 | 63.3M | cd = max(cd1, d20); |
2963 | 63.3M | } |
2964 | 77.8M | return triangle_by_4(pfs, p0, p1, p2, l01, l12, l20, cd, sd); |
2965 | 77.8M | } |
2966 | | |
2967 | | static int |
2968 | | small_mesh_triangle(patch_fill_state_t *pfs, |
2969 | | const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2) |
2970 | 7.73M | { |
2971 | 7.73M | int code; |
2972 | 7.73M | wedge_vertex_list_t l[3]; |
2973 | | |
2974 | 7.73M | init_wedge_vertex_list(l, count_of(l)); |
2975 | 7.73M | code = fill_triangle(pfs, p0, p1, p2, &l[0], &l[1], &l[2]); |
2976 | 7.73M | if (code < 0) |
2977 | 0 | return code; |
2978 | 7.73M | code = terminate_wedge_vertex_list(pfs, &l[0], p0->c, p1->c); |
2979 | 7.73M | if (code < 0) |
2980 | 0 | return code; |
2981 | 7.73M | code = terminate_wedge_vertex_list(pfs, &l[1], p1->c, p2->c); |
2982 | 7.73M | if (code < 0) |
2983 | 0 | return code; |
2984 | 7.73M | return terminate_wedge_vertex_list(pfs, &l[2], p2->c, p0->c); |
2985 | 7.73M | } |
2986 | | |
2987 | | int |
2988 | | gx_init_patch_fill_state_for_clist(gx_device *dev, patch_fill_state_t *pfs, gs_memory_t *memory) |
2989 | 0 | { |
2990 | 0 | int i; |
2991 | |
|
2992 | 0 | pfs->dev = dev; |
2993 | 0 | pfs->pgs = NULL; |
2994 | 0 | pfs->direct_space = NULL; |
2995 | 0 | pfs->num_components = dev->color_info.num_components; |
2996 | | /* pfs->cc_max_error[GS_CLIENT_COLOR_MAX_COMPONENTS] unused */ |
2997 | 0 | pfs->pshm = NULL; |
2998 | 0 | pfs->Function = NULL; |
2999 | 0 | pfs->function_arg_shift = 0; |
3000 | 0 | pfs->vectorization = false; /* A stub for a while. Will use with pclwrite. */ |
3001 | 0 | pfs->n_color_args = 1; /* unused. */ |
3002 | 0 | pfs->max_small_coord = 0; /* unused. */ |
3003 | 0 | pfs->wedge_vertex_list_elem_buffer = NULL; /* fixme */ |
3004 | 0 | pfs->free_wedge_vertex = NULL; /* fixme */ |
3005 | 0 | pfs->wedge_vertex_list_elem_count = 0; /* fixme */ |
3006 | 0 | pfs->wedge_vertex_list_elem_count_max = 0; /* fixme */ |
3007 | 0 | for (i = 0; i < pfs->num_components; i++) |
3008 | 0 | pfs->color_domain.paint.values[i] = (float)0x7fffffff; |
3009 | | /* decomposition_limit must be same as one in init_patch_fill_state */ |
3010 | | #ifdef MAX_SHADING_RESOLUTION |
3011 | | pfs->decomposition_limit = float2fixed(min(pfs->dev->HWResolution[0], |
3012 | | pfs->dev->HWResolution[1]) / MAX_SHADING_RESOLUTION); |
3013 | | pfs->decomposition_limit = max(pfs->decomposition_limit, fixed_1); |
3014 | | #else |
3015 | 0 | pfs->decomposition_limit = fixed_1; |
3016 | 0 | #endif |
3017 | 0 | pfs->fixed_flat = 0; /* unused */ |
3018 | 0 | pfs->smoothness = 0; /* unused */ |
3019 | 0 | pfs->maybe_self_intersecting = false; /* unused */ |
3020 | 0 | pfs->monotonic_color = true; |
3021 | 0 | pfs->linear_color = true; |
3022 | 0 | pfs->unlinear = false; /* Because it is used when fill_linear_color_triangle was called. */ |
3023 | 0 | pfs->inside = false; |
3024 | 0 | pfs->color_stack_size = 0; |
3025 | 0 | pfs->color_stack_step = dev->color_info.num_components; |
3026 | 0 | pfs->color_stack_ptr = NULL; /* fixme */ |
3027 | 0 | pfs->color_stack = NULL; /* fixme */ |
3028 | 0 | pfs->color_stack_limit = NULL; /* fixme */ |
3029 | 0 | pfs->pcic = NULL; /* Will do someday. */ |
3030 | 0 | pfs->trans_device = NULL; |
3031 | 0 | pfs->icclink = NULL; |
3032 | 0 | return alloc_patch_fill_memory(pfs, memory, NULL); |
3033 | 0 | } |
3034 | | |
3035 | | /* A method for filling a small triangle that the device can't handle. |
3036 | | Used by clist playback. */ |
3037 | | int |
3038 | | gx_fill_triangle_small(gx_device *dev, const gs_fill_attributes *fa, |
3039 | | const gs_fixed_point *p0, const gs_fixed_point *p1, |
3040 | | const gs_fixed_point *p2, |
3041 | | const frac31 *c0, const frac31 *c1, const frac31 *c2) |
3042 | 0 | { |
3043 | 0 | patch_fill_state_t *pfs = fa->pfs; |
3044 | 0 | patch_color_t c[3]; |
3045 | 0 | shading_vertex_t p[3]; |
3046 | 0 | uchar i; |
3047 | | |
3048 | | /* pfs->rect = *fa->clip; unused ? */ |
3049 | 0 | p[0].p = *p0; |
3050 | 0 | p[1].p = *p1; |
3051 | 0 | p[2].p = *p2; |
3052 | 0 | p[0].c = &c[0]; |
3053 | 0 | p[1].c = &c[1]; |
3054 | 0 | p[2].c = &c[2]; |
3055 | 0 | c[0].t[0] = c[0].t[1] = c[1].t[0] = c[1].t[1] = c[2].t[0] = c[2].t[1] = 0; /* Dummy - not used. */ |
3056 | 0 | for (i = 0; i < dev->color_info.num_components; i++) { |
3057 | 0 | c[0].cc.paint.values[i] = (float)c0[i]; |
3058 | 0 | c[1].cc.paint.values[i] = (float)c1[i]; |
3059 | 0 | c[2].cc.paint.values[i] = (float)c2[i]; |
3060 | 0 | } |
3061 | | /* fixme: the cycle above converts frac31 values into floats. |
3062 | | We don't like this because (1) it misses lower bits, |
3063 | | and (2) fixed point values can be faster on some platforms. |
3064 | | We could fix it with coding a template for small_mesh_triangle |
3065 | | and its callees until patch_color_to_device_color_inline. |
3066 | | */ |
3067 | | /* fixme : this function is called from gxclrast.c |
3068 | | after dev->procs.fill_linear_color_triangle returns 0 - "subdivide". |
3069 | | After few moments small_mesh_triangle indirectly calls |
3070 | | same function with same arguments as a part of |
3071 | | try_device_linear_color in triangle_by_4. |
3072 | | Obviusly it will return zero again. |
3073 | | Actually we don't need the second call, |
3074 | | so optimize with skipping the second call. |
3075 | | */ |
3076 | 0 | return small_mesh_triangle(pfs, &p[0], &p[1], &p[2]); |
3077 | 0 | } |
3078 | | |
3079 | | static int |
3080 | | mesh_triangle_rec(patch_fill_state_t *pfs, |
3081 | | const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2) |
3082 | 9.00M | { |
3083 | 9.00M | pfs->unlinear = !is_linear_color_applicable(pfs); |
3084 | 9.00M | if (manhattan_dist(&p0->p, &p1->p) < pfs->max_small_coord && |
3085 | 9.00M | manhattan_dist(&p1->p, &p2->p) < pfs->max_small_coord && |
3086 | 9.00M | manhattan_dist(&p2->p, &p0->p) < pfs->max_small_coord) |
3087 | 7.73M | return small_mesh_triangle(pfs, p0, p1, p2); |
3088 | 1.26M | else { |
3089 | | /* Subdivide into 4 triangles with 3 triangle non-lazy wedges. |
3090 | | Doing so against the wedge_vertex_list_elem_buffer overflow. |
3091 | | We could apply a smarter method, dividing long sides |
3092 | | with no wedges and short sides with lazy wedges. |
3093 | | This needs to start wedges dynamically when |
3094 | | a side becomes short. We don't do so because the |
3095 | | number of checks per call significantly increases |
3096 | | and the logics is complicated, but the performance |
3097 | | advantage appears small due to big meshes are rare. |
3098 | | */ |
3099 | 1.26M | shading_vertex_t p01, p12, p20; |
3100 | 1.26M | patch_color_t *c[3]; |
3101 | 1.26M | int code; |
3102 | 1.26M | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 3); |
3103 | | |
3104 | 1.26M | if (color_stack_ptr == NULL) |
3105 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
3106 | 1.26M | p01.c = c[0]; |
3107 | 1.26M | p12.c = c[1]; |
3108 | 1.26M | p20.c = c[2]; |
3109 | 1.26M | divide_bar(pfs, p0, p1, 2, &p01, c[0]); |
3110 | 1.26M | divide_bar(pfs, p1, p2, 2, &p12, c[1]); |
3111 | 1.26M | divide_bar(pfs, p2, p0, 2, &p20, c[2]); |
3112 | 1.26M | code = fill_triangle_wedge(pfs, p0, p1, &p01); |
3113 | 1.26M | if (code >= 0) |
3114 | 1.26M | code = fill_triangle_wedge(pfs, p1, p2, &p12); |
3115 | 1.26M | if (code >= 0) |
3116 | 1.26M | code = fill_triangle_wedge(pfs, p2, p0, &p20); |
3117 | 1.26M | if (code >= 0) |
3118 | 1.26M | code = mesh_triangle_rec(pfs, p0, &p01, &p20); |
3119 | 1.26M | if (code >= 0) |
3120 | 1.26M | code = mesh_triangle_rec(pfs, p1, &p12, &p01); |
3121 | 1.26M | if (code >= 0) |
3122 | 1.26M | code = mesh_triangle_rec(pfs, p2, &p20, &p12); |
3123 | 1.26M | if (code >= 0) |
3124 | 1.26M | code = mesh_triangle_rec(pfs, &p01, &p12, &p20); |
3125 | 1.26M | release_colors_inline(pfs, color_stack_ptr, 3); |
3126 | 1.26M | return code; |
3127 | 1.26M | } |
3128 | 9.00M | } |
3129 | | |
3130 | | int |
3131 | | mesh_triangle(patch_fill_state_t *pfs, |
3132 | | const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2) |
3133 | 3.92M | { |
3134 | 3.92M | if ((*dev_proc(pfs->dev, dev_spec_op))(pfs->dev, |
3135 | 3.92M | gxdso_pattern_shading_area, NULL, 0) > 0) { |
3136 | | /* Inform the device with the shading coverage area. |
3137 | | First compute the sign of the area, because |
3138 | | all areas to be clipped in same direction. */ |
3139 | 1.65M | gx_device *pdev = pfs->dev; |
3140 | 1.65M | gx_path path; |
3141 | 1.65M | int code; |
3142 | 1.65M | fixed d01x = p1->p.x - p0->p.x, d01y = p1->p.y - p0->p.y; |
3143 | 1.65M | fixed d12x = p2->p.x - p1->p.x, d12y = p2->p.y - p1->p.y; |
3144 | 1.65M | int64_t s1 = (int64_t)d01x * d12y - (int64_t)d01y * d12x; |
3145 | | |
3146 | 1.65M | gx_path_init_local(&path, pdev->memory); |
3147 | 1.65M | code = gx_path_add_point(&path, p0->p.x, p0->p.y); |
3148 | 1.65M | if (code >= 0 && s1 >= 0) |
3149 | 1.65M | code = gx_path_add_line(&path, p1->p.x, p1->p.y); |
3150 | 1.65M | if (code >= 0) |
3151 | 1.65M | code = gx_path_add_line(&path, p2->p.x, p2->p.y); |
3152 | 1.65M | if (code >= 0 && s1 < 0) |
3153 | 9.34k | code = gx_path_add_line(&path, p1->p.x, p1->p.y); |
3154 | 1.65M | if (code >= 0) |
3155 | 1.65M | code = gx_path_close_subpath(&path); |
3156 | 1.65M | if (code >= 0) |
3157 | 1.65M | code = (*dev_proc(pfs->dev, fill_path))(pdev, NULL, &path, NULL, NULL, NULL); |
3158 | 1.65M | gx_path_free(&path, "mesh_triangle"); |
3159 | 1.65M | if (code < 0) |
3160 | 0 | return code; |
3161 | 1.65M | } |
3162 | 3.92M | return mesh_triangle_rec(pfs, p0, p1, p2); |
3163 | 3.92M | } |
3164 | | |
3165 | | static inline int |
3166 | | triangles4(patch_fill_state_t *pfs, const quadrangle_patch *p, bool dummy_argument) |
3167 | 11.0M | { |
3168 | 11.0M | shading_vertex_t p0001, p1011, q; |
3169 | 11.0M | patch_color_t *c[3]; |
3170 | 11.0M | wedge_vertex_list_t l[4]; |
3171 | 11.0M | int code; |
3172 | 11.0M | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 3); |
3173 | | |
3174 | 11.0M | if(color_stack_ptr == NULL) |
3175 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
3176 | 11.0M | p0001.c = c[0]; |
3177 | 11.0M | p1011.c = c[1]; |
3178 | 11.0M | q.c = c[2]; |
3179 | 11.0M | init_wedge_vertex_list(l, count_of(l)); |
3180 | 11.0M | divide_bar(pfs, p->p[0][0], p->p[0][1], 2, &p0001, c[0]); |
3181 | 11.0M | divide_bar(pfs, p->p[1][0], p->p[1][1], 2, &p1011, c[1]); |
3182 | 11.0M | divide_bar(pfs, &p0001, &p1011, 2, &q, c[2]); |
3183 | 11.0M | code = fill_triangle(pfs, p->p[0][0], p->p[0][1], &q, p->l0001, &l[0], &l[3]); |
3184 | 11.0M | if (code >= 0) { |
3185 | 11.0M | l[0].last_side = true; |
3186 | 11.0M | l[3].last_side = true; |
3187 | 11.0M | code = fill_triangle(pfs, p->p[0][1], p->p[1][1], &q, p->l0111, &l[1], &l[0]); |
3188 | 11.0M | } |
3189 | 11.0M | if (code >= 0) { |
3190 | 11.0M | l[1].last_side = true; |
3191 | 11.0M | code = fill_triangle(pfs, p->p[1][1], p->p[1][0], &q, p->l1110, &l[2], &l[1]); |
3192 | 11.0M | } |
3193 | 11.0M | if (code >= 0) { |
3194 | 11.0M | l[2].last_side = true; |
3195 | 11.0M | code = fill_triangle(pfs, p->p[1][0], p->p[0][0], &q, p->l1000, &l[3], &l[2]); |
3196 | 11.0M | } |
3197 | 11.0M | if (code >= 0) |
3198 | 11.0M | code = terminate_wedge_vertex_list(pfs, &l[0], p->p[0][1]->c, q.c); |
3199 | 11.0M | if (code >= 0) |
3200 | 11.0M | code = terminate_wedge_vertex_list(pfs, &l[1], p->p[1][1]->c, q.c); |
3201 | 11.0M | if (code >= 0) |
3202 | 11.0M | code = terminate_wedge_vertex_list(pfs, &l[2], p->p[1][0]->c, q.c); |
3203 | 11.0M | if (code >= 0) |
3204 | 11.0M | code = terminate_wedge_vertex_list(pfs, &l[3], q.c, p->p[0][0]->c); |
3205 | 11.0M | release_colors_inline(pfs, color_stack_ptr, 3); |
3206 | 11.0M | return code; |
3207 | 11.0M | } |
3208 | | |
3209 | | static inline int |
3210 | | triangles2(patch_fill_state_t *pfs, const quadrangle_patch *p, bool dummy_argument) |
3211 | 12.8M | { |
3212 | 12.8M | wedge_vertex_list_t l; |
3213 | 12.8M | int code; |
3214 | | |
3215 | 12.8M | init_wedge_vertex_list(&l, 1); |
3216 | 12.8M | code = fill_triangle(pfs, p->p[0][0], p->p[0][1], p->p[1][1], p->l0001, p->l0111, &l); |
3217 | 12.8M | if (code < 0) |
3218 | 0 | return code; |
3219 | 12.8M | l.last_side = true; |
3220 | 12.8M | code = fill_triangle(pfs, p->p[1][1], p->p[1][0], p->p[0][0], p->l1110, p->l1000, &l); |
3221 | 12.8M | if (code < 0) |
3222 | 0 | return code; |
3223 | 12.8M | code = terminate_wedge_vertex_list(pfs, &l, p->p[1][1]->c, p->p[0][0]->c); |
3224 | 12.8M | if (code < 0) |
3225 | 0 | return code; |
3226 | 12.8M | return 0; |
3227 | 12.8M | } |
3228 | | |
3229 | | static inline void |
3230 | | make_quadrangle(const tensor_patch *p, shading_vertex_t qq[2][2], |
3231 | | wedge_vertex_list_t l[4], quadrangle_patch *q) |
3232 | 25.0M | { |
3233 | 25.0M | qq[0][0].p = p->pole[0][0]; |
3234 | 25.0M | qq[0][1].p = p->pole[0][3]; |
3235 | 25.0M | qq[1][0].p = p->pole[3][0]; |
3236 | 25.0M | qq[1][1].p = p->pole[3][3]; |
3237 | 25.0M | qq[0][0].c = p->c[0][0]; |
3238 | 25.0M | qq[0][1].c = p->c[0][1]; |
3239 | 25.0M | qq[1][0].c = p->c[1][0]; |
3240 | 25.0M | qq[1][1].c = p->c[1][1]; |
3241 | 25.0M | q->p[0][0] = &qq[0][0]; |
3242 | 25.0M | q->p[0][1] = &qq[0][1]; |
3243 | 25.0M | q->p[1][0] = &qq[1][0]; |
3244 | 25.0M | q->p[1][1] = &qq[1][1]; |
3245 | 25.0M | q->l0001 = &l[0]; |
3246 | 25.0M | q->l0111 = &l[1]; |
3247 | 25.0M | q->l1110 = &l[2]; |
3248 | 25.0M | q->l1000 = &l[3]; |
3249 | 25.0M | } |
3250 | | |
3251 | | static inline int |
3252 | | is_quadrangle_color_linear_by_u(const patch_fill_state_t *pfs, const quadrangle_patch *p) |
3253 | 15.9M | { /* returns : 1 = linear, 0 = unlinear, <0 = error. */ |
3254 | 15.9M | int code; |
3255 | | |
3256 | 15.9M | code = is_color_linear(pfs, p->p[0][0]->c, p->p[0][1]->c); |
3257 | 15.9M | if (code <= 0) |
3258 | 987 | return code; |
3259 | 15.9M | return is_color_linear(pfs, p->p[1][0]->c, p->p[1][1]->c); |
3260 | 15.9M | } |
3261 | | |
3262 | | static inline int |
3263 | | is_quadrangle_color_linear_by_v(const patch_fill_state_t *pfs, const quadrangle_patch *p) |
3264 | 1.06M | { /* returns : 1 = linear, 0 = unlinear, <0 = error. */ |
3265 | 1.06M | int code; |
3266 | | |
3267 | 1.06M | code = is_color_linear(pfs, p->p[0][0]->c, p->p[1][0]->c); |
3268 | 1.06M | if (code <= 0) |
3269 | 217k | return code; |
3270 | 851k | return is_color_linear(pfs, p->p[0][1]->c, p->p[1][1]->c); |
3271 | 1.06M | } |
3272 | | |
3273 | | static inline int |
3274 | | is_quadrangle_color_linear_by_diagonals(const patch_fill_state_t *pfs, const quadrangle_patch *p) |
3275 | 979k | { /* returns : 1 = linear, 0 = unlinear, <0 = error. */ |
3276 | 979k | int code; |
3277 | | |
3278 | 979k | code = is_color_linear(pfs, p->p[0][0]->c, p->p[1][1]->c); |
3279 | 979k | if (code <= 0) |
3280 | 169k | return code; |
3281 | 809k | return is_color_linear(pfs, p->p[0][1]->c, p->p[1][0]->c); |
3282 | 979k | } |
3283 | | |
3284 | | typedef enum { |
3285 | | color_change_small, |
3286 | | color_change_gradient, |
3287 | | color_change_linear, |
3288 | | color_change_bilinear, |
3289 | | color_change_general |
3290 | | } color_change_type_t; |
3291 | | |
3292 | | static inline color_change_type_t |
3293 | | quadrangle_color_change(const patch_fill_state_t *pfs, const quadrangle_patch *p, |
3294 | | bool is_big_u, bool is_big_v, double size_u, double size_v, |
3295 | | bool *divide_u, bool *divide_v) |
3296 | 25.4M | { |
3297 | 25.4M | patch_color_t d0001, d1011, d; |
3298 | 25.4M | double D, D0001, D1011, D0010, D0111, D0011, D0110; |
3299 | 25.4M | double Du, Dv; |
3300 | | |
3301 | 25.4M | color_diff(pfs, p->p[0][0]->c, p->p[0][1]->c, &d0001); |
3302 | 25.4M | color_diff(pfs, p->p[1][0]->c, p->p[1][1]->c, &d1011); |
3303 | 25.4M | D0001 = color_norm(pfs, &d0001); |
3304 | 25.4M | D1011 = color_norm(pfs, &d1011); |
3305 | 25.4M | D0010 = color_span(pfs, p->p[0][0]->c, p->p[1][0]->c); |
3306 | 25.4M | D0111 = color_span(pfs, p->p[0][1]->c, p->p[1][1]->c); |
3307 | 25.4M | D0011 = color_span(pfs, p->p[0][0]->c, p->p[1][1]->c); |
3308 | 25.4M | D0110 = color_span(pfs, p->p[0][1]->c, p->p[1][0]->c); |
3309 | 25.4M | if (pfs->unlinear) { |
3310 | 9.11M | if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness && |
3311 | 9.11M | D0010 <= pfs->smoothness && D0111 <= pfs->smoothness && |
3312 | 9.11M | D0011 <= pfs->smoothness && D0110 <= pfs->smoothness) |
3313 | 6.92M | return color_change_small; |
3314 | 2.19M | if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness) { |
3315 | 617k | if (!is_big_v) { |
3316 | | /* The color function looks uncontiguous. */ |
3317 | 116k | return color_change_small; |
3318 | 116k | } |
3319 | 500k | *divide_v = true; |
3320 | 500k | return color_change_gradient; |
3321 | 617k | } |
3322 | 1.57M | if (D0010 <= pfs->smoothness && D0111 <= pfs->smoothness) { |
3323 | 1.51M | if (!is_big_u) { |
3324 | | /* The color function looks uncontiguous. */ |
3325 | 15.4k | return color_change_small; |
3326 | 15.4k | } |
3327 | 1.49M | *divide_u = true; |
3328 | 1.49M | return color_change_gradient; |
3329 | 1.51M | } |
3330 | 1.57M | } |
3331 | 16.3M | color_diff(pfs, &d0001, &d1011, &d); |
3332 | 16.3M | Du = max(D0001, D1011); |
3333 | 16.3M | Dv = max(D0010, D0111); |
3334 | 16.3M | if (Du <= pfs->smoothness / 8 && Dv <= pfs->smoothness / 8) |
3335 | 2.69M | return color_change_small; |
3336 | 13.6M | if (Du <= pfs->smoothness / 8) |
3337 | 358k | return color_change_linear; |
3338 | 13.3M | if (Dv <= pfs->smoothness / 8) |
3339 | 12.5M | return color_change_linear; |
3340 | 787k | D = color_norm(pfs, &d); |
3341 | 787k | if (D <= pfs->smoothness) |
3342 | 673k | return color_change_bilinear; |
3343 | 114k | #if 1 |
3344 | 114k | if (Du > Dv && is_big_u) |
3345 | 59.2k | *divide_u = true; |
3346 | 54.8k | else if (Du < Dv && is_big_v) |
3347 | 40.9k | *divide_v = true; |
3348 | 13.9k | else if (is_big_u && size_u > size_v) |
3349 | 5.52k | *divide_u = true; |
3350 | 8.40k | else if (is_big_v && size_v > size_u) |
3351 | 8.40k | *divide_v = true; |
3352 | 2 | else if (is_big_u) |
3353 | 2 | *divide_u = true; |
3354 | 0 | else if (is_big_v) |
3355 | 0 | *divide_v = true; |
3356 | 0 | else { |
3357 | | /* The color function looks uncontiguous. */ |
3358 | 0 | return color_change_small; |
3359 | 0 | } |
3360 | | #else /* Disabled due to infinite recursion with -r200 09-57.PS |
3361 | | (Standard Test 6.4 - Range 6) (Test05). */ |
3362 | | if (Du > Dv) |
3363 | | *divide_u = true; |
3364 | | else |
3365 | | *divide_v = true; |
3366 | | #endif |
3367 | 114k | return color_change_general; |
3368 | 114k | } |
3369 | | |
3370 | | static int |
3371 | | fill_quadrangle(patch_fill_state_t *pfs, const quadrangle_patch *p, bool big) |
3372 | 29.9M | { |
3373 | | /* The quadrangle is flattened enough by V and U, so ignore inner poles. */ |
3374 | | /* Assuming the XY span is restricted with curve_samples. |
3375 | | It is important for intersection_of_small_bars to compute faster. */ |
3376 | 29.9M | quadrangle_patch s0, s1; |
3377 | 29.9M | wedge_vertex_list_t l0, l1, l2; |
3378 | 29.9M | int code; |
3379 | 29.9M | bool divide_u = false, divide_v = false, big1 = big; |
3380 | 29.9M | shading_vertex_t q[2]; |
3381 | 29.9M | bool monotonic_color_save = pfs->monotonic_color; |
3382 | 29.9M | bool linear_color_save = pfs->linear_color; |
3383 | 29.9M | bool inside_save = pfs->inside; |
3384 | 29.9M | const bool inside = pfs->inside; /* 'const' should help compiler to analyze initializations. */ |
3385 | 29.9M | gs_fixed_rect r = {{0,0},{0,0}}, r1 = {{0,0},{0,0}}; |
3386 | | /* Warning : pfs->monotonic_color is not restored on error. */ |
3387 | | |
3388 | 29.9M | if (!inside) { |
3389 | 9.40M | bbox_of_points(&r, &p->p[0][0]->p, &p->p[0][1]->p, &p->p[1][0]->p, &p->p[1][1]->p); |
3390 | 9.40M | r1 = r; |
3391 | 9.40M | rect_intersect(r, pfs->rect); |
3392 | 9.40M | if (r.q.x <= r.p.x || r.q.y <= r.p.y) |
3393 | 2.89M | return 0; /* Outside. */ |
3394 | 9.40M | } |
3395 | 27.1M | if (big) { |
3396 | | /* Likely 'big' is an unuseful rudiment due to curve_samples |
3397 | | restricts lengthes. We keep it for a while because its implementation |
3398 | | isn't obvious and its time consumption is invisibly small. |
3399 | | */ |
3400 | 22.3M | fixed size_u = max(max(any_abs(p->p[0][0]->p.x - p->p[0][1]->p.x), |
3401 | 22.3M | any_abs(p->p[1][0]->p.x - p->p[1][1]->p.x)), |
3402 | 22.3M | max(any_abs(p->p[0][0]->p.y - p->p[0][1]->p.y), |
3403 | 22.3M | any_abs(p->p[1][0]->p.y - p->p[1][1]->p.y))); |
3404 | 22.3M | fixed size_v = max(max(any_abs(p->p[0][0]->p.x - p->p[1][0]->p.x), |
3405 | 22.3M | any_abs(p->p[0][1]->p.x - p->p[1][1]->p.x)), |
3406 | 22.3M | max(any_abs(p->p[0][0]->p.y - p->p[1][0]->p.y), |
3407 | 22.3M | any_abs(p->p[0][1]->p.y - p->p[1][1]->p.y))); |
3408 | | |
3409 | 22.3M | if (QUADRANGLES && pfs->maybe_self_intersecting) { |
3410 | 0 | if (size_v > pfs->max_small_coord) { |
3411 | | /* constant_color_quadrangle can't handle big self-intersecting areas |
3412 | | because we don't want int64_t in it. */ |
3413 | 0 | divide_v = true; |
3414 | 0 | } else if (size_u > pfs->max_small_coord) { |
3415 | | /* constant_color_quadrangle can't handle big self-intersecting areas, |
3416 | | because we don't want int64_t in it. */ |
3417 | 0 | divide_u = true; |
3418 | 0 | } else |
3419 | 0 | big1 = false; |
3420 | 0 | } else |
3421 | 22.3M | big1 = false; |
3422 | 22.3M | } |
3423 | 27.1M | if (!big1) { |
3424 | 27.1M | bool is_big_u = false, is_big_v = false; |
3425 | 27.1M | double d0001x = any_abs(p->p[0][0]->p.x - p->p[0][1]->p.x); |
3426 | 27.1M | double d1011x = any_abs(p->p[1][0]->p.x - p->p[1][1]->p.x); |
3427 | 27.1M | double d0001y = any_abs(p->p[0][0]->p.y - p->p[0][1]->p.y); |
3428 | 27.1M | double d1011y = any_abs(p->p[1][0]->p.y - p->p[1][1]->p.y); |
3429 | 27.1M | double d0010x = any_abs(p->p[0][0]->p.x - p->p[1][0]->p.x); |
3430 | 27.1M | double d0111x = any_abs(p->p[0][1]->p.x - p->p[1][1]->p.x); |
3431 | 27.1M | double d0010y = any_abs(p->p[0][0]->p.y - p->p[1][0]->p.y); |
3432 | 27.1M | double d0111y = any_abs(p->p[0][1]->p.y - p->p[1][1]->p.y); |
3433 | 27.1M | double size_u = max(max(d0001x, d1011x), max(d0001y, d1011y)); |
3434 | 27.1M | double size_v = max(max(d0010x, d0111x), max(d0010y, d0111y)); |
3435 | | |
3436 | 27.1M | if (size_u > pfs->decomposition_limit) |
3437 | 25.5M | is_big_u = true; |
3438 | 27.1M | if (size_v > pfs->decomposition_limit) |
3439 | 2.56M | is_big_v = true; |
3440 | 24.5M | else if (!is_big_u) |
3441 | 1.33M | return (QUADRANGLES || !pfs->maybe_self_intersecting ? |
3442 | 1.22M | constant_color_quadrangle : triangles4)(pfs, p, |
3443 | 1.33M | pfs->maybe_self_intersecting); |
3444 | 25.7M | if (!pfs->monotonic_color) { |
3445 | 2.32M | bool not_monotonic_by_u = false, not_monotonic_by_v = false; |
3446 | | |
3447 | 2.32M | code = is_quadrangle_color_monotonic(pfs, p, ¬_monotonic_by_u, ¬_monotonic_by_v); |
3448 | 2.32M | if (code < 0) |
3449 | 0 | return code; |
3450 | 2.32M | if (is_big_u) |
3451 | 2.31M | divide_u = not_monotonic_by_u; |
3452 | 2.32M | if (is_big_v) |
3453 | 547k | divide_v = not_monotonic_by_v; |
3454 | 2.32M | if (!divide_u && !divide_v) |
3455 | 2.20M | pfs->monotonic_color = true; |
3456 | 2.32M | } |
3457 | 25.7M | if (pfs->monotonic_color && !pfs->linear_color) { |
3458 | 21.9M | if (divide_v && divide_u) { |
3459 | 0 | if (size_u > size_v) |
3460 | 0 | divide_v = false; |
3461 | 0 | else |
3462 | 0 | divide_u = false; |
3463 | 21.9M | } else if (!divide_u && !divide_v && !pfs->unlinear) { |
3464 | 16.3M | if (d0001x + d1011x + d0001y + d1011y > d0010x + d0111x + d0010y + d0111y) { /* fixme: use size_u, size_v */ |
3465 | 15.9M | code = is_quadrangle_color_linear_by_u(pfs, p); |
3466 | 15.9M | if (code < 0) |
3467 | 0 | return code; |
3468 | 15.9M | divide_u = !code; |
3469 | 15.9M | } |
3470 | 16.3M | if (is_big_v) { |
3471 | 1.06M | code = is_quadrangle_color_linear_by_v(pfs, p); |
3472 | 1.06M | if (code < 0) |
3473 | 0 | return code; |
3474 | 1.06M | divide_v = !code; |
3475 | 1.06M | } |
3476 | 16.3M | if (is_big_u && is_big_v) { |
3477 | 979k | code = is_quadrangle_color_linear_by_diagonals(pfs, p); |
3478 | 979k | if (code < 0) |
3479 | 0 | return code; |
3480 | 979k | if (!code) { |
3481 | 170k | if (d0001x + d1011x + d0001y + d1011y > d0010x + d0111x + d0010y + d0111y) { /* fixme: use size_u, size_v */ |
3482 | 85.1k | divide_u = true; |
3483 | 85.1k | divide_v = false; |
3484 | 85.1k | } else { |
3485 | 85.0k | divide_v = true; |
3486 | 85.0k | divide_u = false; |
3487 | 85.0k | } |
3488 | 170k | } |
3489 | 979k | } |
3490 | 16.3M | } |
3491 | 21.9M | if (!divide_u && !divide_v) |
3492 | 21.7M | pfs->linear_color = true; |
3493 | 21.9M | } |
3494 | 25.7M | if (!pfs->linear_color) { |
3495 | | /* go to divide. */ |
3496 | 25.4M | } else switch(quadrangle_color_change(pfs, p, is_big_u, is_big_v, size_u, size_v, ÷_u, ÷_v)) { |
3497 | 9.75M | case color_change_small: |
3498 | 9.75M | code = (QUADRANGLES || !pfs->maybe_self_intersecting ? |
3499 | 9.17M | constant_color_quadrangle : triangles4)(pfs, p, |
3500 | 9.75M | pfs->maybe_self_intersecting); |
3501 | 9.75M | pfs->monotonic_color = monotonic_color_save; |
3502 | 9.75M | pfs->linear_color = linear_color_save; |
3503 | 9.75M | return code; |
3504 | 673k | case color_change_bilinear: |
3505 | 673k | if (!QUADRANGLES) { |
3506 | 673k | code = triangles4(pfs, p, true); |
3507 | 673k | pfs->monotonic_color = monotonic_color_save; |
3508 | 673k | pfs->linear_color = linear_color_save; |
3509 | 673k | return code; |
3510 | 673k | } |
3511 | 12.8M | case color_change_linear: |
3512 | 12.8M | if (!QUADRANGLES) { |
3513 | 12.8M | code = triangles2(pfs, p, true); |
3514 | 12.8M | pfs->monotonic_color = monotonic_color_save; |
3515 | 12.8M | pfs->linear_color = linear_color_save; |
3516 | 12.8M | return code; |
3517 | 12.8M | } |
3518 | 1.99M | case color_change_gradient: |
3519 | 2.11M | case color_change_general: |
3520 | 2.11M | ; /* goto divide. */ |
3521 | 25.4M | } |
3522 | 25.7M | } |
3523 | 2.45M | if (!inside) { |
3524 | 431k | if (r.p.x == r1.p.x && r.p.y == r1.p.y && |
3525 | 431k | r.q.x == r1.q.x && r.q.y == r1.q.y) |
3526 | 125k | pfs->inside = true; |
3527 | 431k | } |
3528 | 2.45M | if (LAZY_WEDGES) |
3529 | 2.45M | init_wedge_vertex_list(&l0, 1); |
3530 | 2.45M | if (divide_v) { |
3531 | 805k | patch_color_t *c[2]; |
3532 | 805k | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 2); |
3533 | | |
3534 | 805k | if(color_stack_ptr == NULL) |
3535 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
3536 | 805k | q[0].c = c[0]; |
3537 | 805k | q[1].c = c[1]; |
3538 | 805k | divide_quadrangle_by_v(pfs, &s0, &s1, q, p, c); |
3539 | 805k | if (LAZY_WEDGES) { |
3540 | 805k | code = make_wedge_median(pfs, &l1, p->l0111, true, &p->p[0][1]->p, &p->p[1][1]->p, &s0.p[1][1]->p); |
3541 | 805k | if (code >= 0) |
3542 | 805k | code = make_wedge_median(pfs, &l2, p->l1000, false, &p->p[1][0]->p, &p->p[0][0]->p, &s0.p[1][0]->p); |
3543 | 805k | if (code >= 0) { |
3544 | 805k | s0.l1110 = s1.l0001 = &l0; |
3545 | 805k | s0.l0111 = s1.l0111 = &l1; |
3546 | 805k | s0.l1000 = s1.l1000 = &l2; |
3547 | 805k | s0.l0001 = p->l0001; |
3548 | 805k | s1.l1110 = p->l1110; |
3549 | 805k | } |
3550 | 805k | } else { |
3551 | 0 | code = fill_triangle_wedge(pfs, s0.p[0][0], s1.p[1][0], s0.p[1][0]); |
3552 | 0 | if (code >= 0) |
3553 | 0 | code = fill_triangle_wedge(pfs, s0.p[0][1], s1.p[1][1], s0.p[1][1]); |
3554 | 0 | } |
3555 | 805k | if (code >= 0) |
3556 | 805k | code = fill_quadrangle(pfs, &s0, big1); |
3557 | 805k | if (code >= 0) { |
3558 | 805k | if (LAZY_WEDGES) { |
3559 | 805k | l0.last_side = true; |
3560 | 805k | move_wedge(&l1, p->l0111, true); |
3561 | 805k | move_wedge(&l2, p->l1000, false); |
3562 | 805k | } |
3563 | 805k | code = fill_quadrangle(pfs, &s1, big1); |
3564 | 805k | } |
3565 | 805k | if (LAZY_WEDGES) { |
3566 | 805k | if (code >= 0) |
3567 | 805k | code = close_wedge_median(pfs, p->l0111, p->p[0][1]->c, p->p[1][1]->c); |
3568 | 805k | if (code >= 0) |
3569 | 805k | code = close_wedge_median(pfs, p->l1000, p->p[1][0]->c, p->p[0][0]->c); |
3570 | 805k | if (code >= 0) |
3571 | 805k | code = terminate_wedge_vertex_list(pfs, &l0, s0.p[1][0]->c, s0.p[1][1]->c); |
3572 | 805k | release_colors_inline(pfs, color_stack_ptr, 2); |
3573 | 805k | } |
3574 | 1.64M | } else if (divide_u) { |
3575 | 1.64M | patch_color_t *c[2]; |
3576 | 1.64M | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 2); |
3577 | | |
3578 | 1.64M | if(color_stack_ptr == NULL) |
3579 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
3580 | 1.64M | q[0].c = c[0]; |
3581 | 1.64M | q[1].c = c[1]; |
3582 | 1.64M | divide_quadrangle_by_u(pfs, &s0, &s1, q, p, c); |
3583 | 1.64M | if (LAZY_WEDGES) { |
3584 | 1.64M | code = make_wedge_median(pfs, &l1, p->l0001, true, &p->p[0][0]->p, &p->p[0][1]->p, &s0.p[0][1]->p); |
3585 | 1.64M | if (code >= 0) |
3586 | 1.64M | code = make_wedge_median(pfs, &l2, p->l1110, false, &p->p[1][1]->p, &p->p[1][0]->p, &s0.p[1][1]->p); |
3587 | 1.64M | if (code >= 0) { |
3588 | 1.64M | s0.l0111 = s1.l1000 = &l0; |
3589 | 1.64M | s0.l0001 = s1.l0001 = &l1; |
3590 | 1.64M | s0.l1110 = s1.l1110 = &l2; |
3591 | 1.64M | s0.l1000 = p->l1000; |
3592 | 1.64M | s1.l0111 = p->l0111; |
3593 | 1.64M | } |
3594 | 1.64M | } else { |
3595 | 0 | code = fill_triangle_wedge(pfs, s0.p[0][0], s1.p[0][1], s0.p[0][1]); |
3596 | 0 | if (code >= 0) |
3597 | 0 | code = fill_triangle_wedge(pfs, s0.p[1][0], s1.p[1][1], s0.p[1][1]); |
3598 | 0 | } |
3599 | 1.64M | if (code >= 0) |
3600 | 1.64M | code = fill_quadrangle(pfs, &s0, big1); |
3601 | 1.64M | if (code >= 0) { |
3602 | 1.64M | if (LAZY_WEDGES) { |
3603 | 1.64M | l0.last_side = true; |
3604 | 1.64M | move_wedge(&l1, p->l0001, true); |
3605 | 1.64M | move_wedge(&l2, p->l1110, false); |
3606 | 1.64M | } |
3607 | 1.64M | code = fill_quadrangle(pfs, &s1, big1); |
3608 | 1.64M | } |
3609 | 1.64M | if (LAZY_WEDGES) { |
3610 | 1.64M | if (code >= 0) |
3611 | 1.64M | code = close_wedge_median(pfs, p->l0001, p->p[0][0]->c, p->p[0][1]->c); |
3612 | 1.64M | if (code >= 0) |
3613 | 1.64M | code = close_wedge_median(pfs, p->l1110, p->p[1][1]->c, p->p[1][0]->c); |
3614 | 1.64M | if (code >= 0) |
3615 | 1.64M | code = terminate_wedge_vertex_list(pfs, &l0, s0.p[0][1]->c, s0.p[1][1]->c); |
3616 | 1.64M | release_colors_inline(pfs, color_stack_ptr, 2); |
3617 | 1.64M | } |
3618 | 1.64M | } else |
3619 | 0 | code = (QUADRANGLES || !pfs->maybe_self_intersecting ? |
3620 | 0 | constant_color_quadrangle : triangles4)(pfs, p, |
3621 | 0 | pfs->maybe_self_intersecting); |
3622 | 2.45M | pfs->monotonic_color = monotonic_color_save; |
3623 | 2.45M | pfs->linear_color = linear_color_save; |
3624 | 2.45M | pfs->inside = inside_save; |
3625 | 2.45M | return code; |
3626 | 2.45M | } |
3627 | | |
3628 | | /* This splits tensor patch p->pole[v][u] on u to give s0->pole[v][u] and s1->pole[v][u] */ |
3629 | | static inline void |
3630 | | split_stripe(patch_fill_state_t *pfs, tensor_patch *s0, tensor_patch *s1, const tensor_patch *p, patch_color_t *c[2]) |
3631 | 45.5M | { |
3632 | 45.5M | s0->c[0][1] = c[0]; |
3633 | 45.5M | s0->c[1][1] = c[1]; |
3634 | 45.5M | split_curve_s(p->pole[0], s0->pole[0], s1->pole[0], 1); |
3635 | 45.5M | split_curve_s(p->pole[1], s0->pole[1], s1->pole[1], 1); |
3636 | 45.5M | split_curve_s(p->pole[2], s0->pole[2], s1->pole[2], 1); |
3637 | 45.5M | split_curve_s(p->pole[3], s0->pole[3], s1->pole[3], 1); |
3638 | 45.5M | s0->c[0][0] = p->c[0][0]; |
3639 | 45.5M | s0->c[1][0] = p->c[1][0]; |
3640 | 45.5M | s1->c[0][0] = s0->c[0][1]; |
3641 | 45.5M | s1->c[1][0] = s0->c[1][1]; |
3642 | 45.5M | patch_interpolate_color(s0->c[0][1], p->c[0][0], p->c[0][1], pfs, 0.5); |
3643 | 45.5M | patch_interpolate_color(s0->c[1][1], p->c[1][0], p->c[1][1], pfs, 0.5); |
3644 | 45.5M | s1->c[0][1] = p->c[0][1]; |
3645 | 45.5M | s1->c[1][1] = p->c[1][1]; |
3646 | 45.5M | } |
3647 | | |
3648 | | /* This splits tensor patch p->pole[v][u] on v to give s0->pole[v][u] and s1->pole[v][u] */ |
3649 | | static inline void |
3650 | | split_patch(patch_fill_state_t *pfs, tensor_patch *s0, tensor_patch *s1, const tensor_patch *p, patch_color_t *c[2]) |
3651 | 10.2M | { |
3652 | 10.2M | s0->c[1][0] = c[0]; |
3653 | 10.2M | s0->c[1][1] = c[1]; |
3654 | 10.2M | split_curve_s(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4); |
3655 | 10.2M | split_curve_s(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4); |
3656 | 10.2M | split_curve_s(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4); |
3657 | 10.2M | split_curve_s(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4); |
3658 | 10.2M | s0->c[0][0] = p->c[0][0]; |
3659 | 10.2M | s0->c[0][1] = p->c[0][1]; |
3660 | 10.2M | s1->c[0][0] = s0->c[1][0]; |
3661 | 10.2M | s1->c[0][1] = s0->c[1][1]; |
3662 | 10.2M | patch_interpolate_color(s0->c[1][0], p->c[0][0], p->c[1][0], pfs, 0.5); |
3663 | 10.2M | patch_interpolate_color(s0->c[1][1], p->c[0][1], p->c[1][1], pfs, 0.5); |
3664 | 10.2M | s1->c[1][0] = p->c[1][0]; |
3665 | 10.2M | s1->c[1][1] = p->c[1][1]; |
3666 | 10.2M | } |
3667 | | |
3668 | | static inline void |
3669 | | tensor_patch_bbox(gs_fixed_rect *r, const tensor_patch *p) |
3670 | 77.0M | { |
3671 | 77.0M | int i, j; |
3672 | | |
3673 | 77.0M | r->p.x = r->q.x = p->pole[0][0].x; |
3674 | 77.0M | r->p.y = r->q.y = p->pole[0][0].y; |
3675 | 385M | for (i = 0; i < 4; i++) { |
3676 | 1.54G | for (j = 0; j < 4; j++) { |
3677 | 1.23G | const gs_fixed_point *q = &p->pole[i][j]; |
3678 | | |
3679 | 1.23G | if (r->p.x > q->x) |
3680 | 205M | r->p.x = q->x; |
3681 | 1.23G | if (r->p.y > q->y) |
3682 | 177M | r->p.y = q->y; |
3683 | 1.23G | if (r->q.x < q->x) |
3684 | 206M | r->q.x = q->x; |
3685 | 1.23G | if (r->q.y < q->y) |
3686 | 182M | r->q.y = q->y; |
3687 | 1.23G | } |
3688 | 308M | } |
3689 | 77.0M | } |
3690 | | |
3691 | | static int |
3692 | | decompose_stripe(patch_fill_state_t *pfs, const tensor_patch *p, int ku) |
3693 | 101M | { |
3694 | 101M | if (ku > 1) { |
3695 | 76.8M | tensor_patch s0, s1; |
3696 | 76.8M | patch_color_t *c[2]; |
3697 | 76.8M | int code; |
3698 | 76.8M | byte *color_stack_ptr; |
3699 | 76.8M | bool save_inside = pfs->inside; |
3700 | | |
3701 | 76.8M | if (!pfs->inside) { |
3702 | 66.3M | gs_fixed_rect r, r1; |
3703 | | |
3704 | 66.3M | tensor_patch_bbox(&r, p); |
3705 | 66.3M | r1 = r; |
3706 | 66.3M | rect_intersect(r, pfs->rect); |
3707 | 66.3M | if (r.q.x <= r.p.x || r.q.y <= r.p.y) |
3708 | 31.3M | return 0; |
3709 | 35.0M | if (r1.p.x == r.p.x && r1.p.y == r.p.y && |
3710 | 35.0M | r1.q.x == r.q.x && r1.q.y == r.q.y) |
3711 | 2.77M | pfs->inside = true; |
3712 | 35.0M | } |
3713 | 45.5M | color_stack_ptr = reserve_colors_inline(pfs, c, 2); |
3714 | 45.5M | if(color_stack_ptr == NULL) |
3715 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
3716 | 45.5M | split_stripe(pfs, &s0, &s1, p, c); |
3717 | 45.5M | code = decompose_stripe(pfs, &s0, ku / 2); |
3718 | 45.5M | if (code >= 0) |
3719 | 45.5M | code = decompose_stripe(pfs, &s1, ku / 2); |
3720 | 45.5M | release_colors_inline(pfs, color_stack_ptr, 2); |
3721 | 45.5M | pfs->inside = save_inside; |
3722 | 45.5M | return code; |
3723 | 45.5M | } else { |
3724 | 25.0M | quadrangle_patch q; |
3725 | 25.0M | shading_vertex_t qq[2][2]; |
3726 | 25.0M | wedge_vertex_list_t l[4]; |
3727 | 25.0M | int code; |
3728 | | |
3729 | 25.0M | init_wedge_vertex_list(l, count_of(l)); |
3730 | 25.0M | make_quadrangle(p, qq, l, &q); |
3731 | | # if SKIP_TEST |
3732 | | dbg_quad_cnt++; |
3733 | | # endif |
3734 | 25.0M | code = fill_quadrangle(pfs, &q, true); |
3735 | 25.0M | if (code < 0) |
3736 | 0 | return code; |
3737 | 25.0M | if (LAZY_WEDGES) { |
3738 | 25.0M | code = terminate_wedge_vertex_list(pfs, &l[0], q.p[0][0]->c, q.p[0][1]->c); |
3739 | 25.0M | if (code < 0) |
3740 | 0 | return code; |
3741 | 25.0M | code = terminate_wedge_vertex_list(pfs, &l[1], q.p[0][1]->c, q.p[1][1]->c); |
3742 | 25.0M | if (code < 0) |
3743 | 0 | return code; |
3744 | 25.0M | code = terminate_wedge_vertex_list(pfs, &l[2], q.p[1][1]->c, q.p[1][0]->c); |
3745 | 25.0M | if (code < 0) |
3746 | 0 | return code; |
3747 | 25.0M | code = terminate_wedge_vertex_list(pfs, &l[3], q.p[1][0]->c, q.p[0][1]->c); |
3748 | 25.0M | if (code < 0) |
3749 | 0 | return code; |
3750 | 25.0M | } |
3751 | 25.0M | return code; |
3752 | 25.0M | } |
3753 | 101M | } |
3754 | | |
3755 | | static int |
3756 | | fill_stripe(patch_fill_state_t *pfs, const tensor_patch *p) |
3757 | 10.9M | { |
3758 | | /* The stripe is flattened enough by V, so ignore inner poles. */ |
3759 | 10.9M | int ku[4], kum, code; |
3760 | | |
3761 | | /* We would like to apply iterations for enumerating the kum curve parts, |
3762 | | but the roundinmg errors would be too complicated due to |
3763 | | the dependence on the direction. Note that neigbour |
3764 | | patches may use the opposite direction for same bounding curve. |
3765 | | We apply the recursive dichotomy, in which |
3766 | | the rounding errors do not depend on the direction. */ |
3767 | 10.9M | ku[0] = curve_samples(pfs, p->pole[0], 1, pfs->fixed_flat); |
3768 | 10.9M | ku[3] = curve_samples(pfs, p->pole[3], 1, pfs->fixed_flat); |
3769 | 10.9M | kum = max(ku[0], ku[3]); |
3770 | 10.9M | code = fill_wedges(pfs, ku[0], kum, p->pole[0], 1, p->c[0][0], p->c[0][1], inpatch_wedge); |
3771 | 10.9M | if (code < 0) |
3772 | 0 | return code; |
3773 | 10.9M | if (INTERPATCH_PADDING) { |
3774 | 10.9M | code = mesh_padding(pfs, &p->pole[0][0], &p->pole[3][0], p->c[0][0], p->c[1][0]); |
3775 | 10.9M | if (code < 0) |
3776 | 13 | return code; |
3777 | 10.9M | code = mesh_padding(pfs, &p->pole[0][3], &p->pole[3][3], p->c[0][1], p->c[1][1]); |
3778 | 10.9M | if (code < 0) |
3779 | 0 | return code; |
3780 | 10.9M | } |
3781 | 10.9M | code = decompose_stripe(pfs, p, kum); |
3782 | 10.9M | if (code < 0) |
3783 | 0 | return code; |
3784 | 10.9M | return fill_wedges(pfs, ku[3], kum, p->pole[3], 1, p->c[1][0], p->c[1][1], inpatch_wedge); |
3785 | 10.9M | } |
3786 | | |
3787 | | static inline bool neqs(int *a, int b) |
3788 | 32.5M | { /* Unequal signs. Assuming -1, 0, 1 only. */ |
3789 | 32.5M | if (*a * b < 0) |
3790 | 10.0M | return true; |
3791 | 22.5M | if (!*a) |
3792 | 2.88M | *a = b; |
3793 | 22.5M | return false; |
3794 | 32.5M | } |
3795 | | |
3796 | | static inline int |
3797 | | vector_pair_orientation(const gs_fixed_point *p0, const gs_fixed_point *p1, const gs_fixed_point *p2) |
3798 | 43.6M | { fixed dx1 = p1->x - p0->x, dy1 = p1->y - p0->y; |
3799 | 43.6M | fixed dx2 = p2->x - p0->x, dy2 = p2->y - p0->y; |
3800 | 43.6M | int64_t vp = (int64_t)dx1 * dy2 - (int64_t)dy1 * dx2; |
3801 | | |
3802 | 43.6M | return (vp > 0 ? 1 : vp < 0 ? -1 : 0); |
3803 | 43.6M | } |
3804 | | |
3805 | | static inline bool |
3806 | | is_x_bended(const tensor_patch *p) |
3807 | 11.0M | { |
3808 | 11.0M | int sign = vector_pair_orientation(&p->pole[0][0], &p->pole[0][1], &p->pole[1][0]); |
3809 | | |
3810 | 11.0M | if (neqs(&sign, vector_pair_orientation(&p->pole[0][1], &p->pole[0][2], &p->pole[1][1]))) |
3811 | 5.78M | return true; |
3812 | 5.29M | if (neqs(&sign, vector_pair_orientation(&p->pole[0][2], &p->pole[0][3], &p->pole[1][2]))) |
3813 | 3.19M | return true; |
3814 | 2.10M | if (neqs(&sign, -vector_pair_orientation(&p->pole[0][3], &p->pole[0][2], &p->pole[1][3]))) |
3815 | 993k | return true; |
3816 | | |
3817 | 1.11M | if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[1][2], &p->pole[2][1]))) |
3818 | 12.8k | return true; |
3819 | 1.09M | if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[1][2], &p->pole[2][1]))) |
3820 | 0 | return true; |
3821 | 1.09M | if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[1][3], &p->pole[2][2]))) |
3822 | 6.58k | return true; |
3823 | 1.09M | if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[1][2], &p->pole[2][3]))) |
3824 | 5.07k | return true; |
3825 | | |
3826 | 1.08M | if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[2][2], &p->pole[3][1]))) |
3827 | 5.57k | return true; |
3828 | 1.08M | if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[2][2], &p->pole[3][1]))) |
3829 | 0 | return true; |
3830 | 1.08M | if (neqs(&sign, vector_pair_orientation(&p->pole[2][2], &p->pole[2][3], &p->pole[3][2]))) |
3831 | 4.03k | return true; |
3832 | 1.07M | if (neqs(&sign, -vector_pair_orientation(&p->pole[2][3], &p->pole[2][2], &p->pole[3][3]))) |
3833 | 3.79k | return true; |
3834 | | |
3835 | 1.07M | if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[3][2], &p->pole[2][1]))) |
3836 | 1.11k | return true; |
3837 | 1.07M | if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[3][2], &p->pole[2][1]))) |
3838 | 0 | return true; |
3839 | 1.07M | if (neqs(&sign, -vector_pair_orientation(&p->pole[3][2], &p->pole[3][3], &p->pole[2][2]))) |
3840 | 954 | return true; |
3841 | 1.07M | if (neqs(&sign, vector_pair_orientation(&p->pole[3][3], &p->pole[3][2], &p->pole[2][3]))) |
3842 | 640 | return true; |
3843 | 1.07M | return false; |
3844 | 1.07M | } |
3845 | | |
3846 | | static inline bool |
3847 | | is_y_bended(const tensor_patch *p) |
3848 | 69.8k | { |
3849 | 69.8k | int sign = vector_pair_orientation(&p->pole[0][0], &p->pole[1][0], &p->pole[0][1]); |
3850 | | |
3851 | 69.8k | if (neqs(&sign, vector_pair_orientation(&p->pole[1][0], &p->pole[2][0], &p->pole[1][1]))) |
3852 | 540 | return true; |
3853 | 69.3k | if (neqs(&sign, vector_pair_orientation(&p->pole[2][0], &p->pole[3][0], &p->pole[2][1]))) |
3854 | 216 | return true; |
3855 | 69.1k | if (neqs(&sign, -vector_pair_orientation(&p->pole[3][0], &p->pole[2][0], &p->pole[3][1]))) |
3856 | 47 | return true; |
3857 | | |
3858 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[2][1], &p->pole[1][2]))) |
3859 | 0 | return true; |
3860 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[2][1], &p->pole[1][2]))) |
3861 | 0 | return true; |
3862 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[3][1], &p->pole[2][2]))) |
3863 | 2 | return true; |
3864 | 69.0k | if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[2][1], &p->pole[3][2]))) |
3865 | 3 | return true; |
3866 | | |
3867 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[2][2], &p->pole[1][3]))) |
3868 | 12 | return true; |
3869 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[2][2], &p->pole[1][3]))) |
3870 | 0 | return true; |
3871 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[2][2], &p->pole[3][2], &p->pole[2][3]))) |
3872 | 0 | return true; |
3873 | 69.0k | if (neqs(&sign, -vector_pair_orientation(&p->pole[3][2], &p->pole[2][2], &p->pole[3][3]))) |
3874 | 0 | return true; |
3875 | | |
3876 | 69.0k | if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[2][3], &p->pole[1][2]))) |
3877 | 0 | return true; |
3878 | 69.0k | if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[2][3], &p->pole[1][2]))) |
3879 | 0 | return true; |
3880 | 69.0k | if (neqs(&sign, -vector_pair_orientation(&p->pole[2][3], &p->pole[3][3], &p->pole[2][2]))) |
3881 | 0 | return true; |
3882 | 69.0k | if (neqs(&sign, vector_pair_orientation(&p->pole[3][3], &p->pole[2][3], &p->pole[3][2]))) |
3883 | 0 | return true; |
3884 | 69.0k | return false; |
3885 | 69.0k | } |
3886 | | |
3887 | | static inline bool |
3888 | | is_curve_x_small(const patch_fill_state_t *pfs, const gs_fixed_point *pole, int pole_step, fixed fixed_flat) |
3889 | 63.7M | { /* Is curve within a single pixel, or smaller than half pixel ? */ |
3890 | 63.7M | fixed xmin0 = min(pole[0 * pole_step].x, pole[1 * pole_step].x); |
3891 | 63.7M | fixed xmin1 = min(pole[2 * pole_step].x, pole[3 * pole_step].x); |
3892 | 63.7M | fixed xmin = min(xmin0, xmin1); |
3893 | 63.7M | fixed xmax0 = max(pole[0 * pole_step].x, pole[1 * pole_step].x); |
3894 | 63.7M | fixed xmax1 = max(pole[2 * pole_step].x, pole[3 * pole_step].x); |
3895 | 63.7M | fixed xmax = max(xmax0, xmax1); |
3896 | | |
3897 | 63.7M | if(xmax - xmin <= pfs->decomposition_limit) |
3898 | 54.2M | return true; |
3899 | 9.56M | return false; |
3900 | 63.7M | } |
3901 | | |
3902 | | static inline bool |
3903 | | is_curve_y_small(const patch_fill_state_t *pfs, const gs_fixed_point *pole, int pole_step, fixed fixed_flat) |
3904 | 42.5M | { /* Is curve within a single pixel, or smaller than half pixel ? */ |
3905 | 42.5M | fixed ymin0 = min(pole[0 * pole_step].y, pole[1 * pole_step].y); |
3906 | 42.5M | fixed ymin1 = min(pole[2 * pole_step].y, pole[3 * pole_step].y); |
3907 | 42.5M | fixed ymin = min(ymin0, ymin1); |
3908 | 42.5M | fixed ymax0 = max(pole[0 * pole_step].y, pole[1 * pole_step].y); |
3909 | 42.5M | fixed ymax1 = max(pole[2 * pole_step].y, pole[3 * pole_step].y); |
3910 | 42.5M | fixed ymax = max(ymax0, ymax1); |
3911 | | |
3912 | 42.5M | if (ymax - ymin <= pfs->decomposition_limit) |
3913 | 41.1M | return true; |
3914 | 1.34M | return false; |
3915 | 42.5M | } |
3916 | | |
3917 | | static inline bool |
3918 | | is_patch_narrow(const patch_fill_state_t *pfs, const tensor_patch *p) |
3919 | 20.8M | { |
3920 | 20.8M | if (!is_curve_x_small(pfs, &p->pole[0][0], 4, pfs->fixed_flat)) |
3921 | 4.06M | return false; |
3922 | 16.7M | if (!is_curve_x_small(pfs, &p->pole[0][1], 4, pfs->fixed_flat)) |
3923 | 2.72M | return false; |
3924 | 14.0M | if (!is_curve_x_small(pfs, &p->pole[0][2], 4, pfs->fixed_flat)) |
3925 | 1.83M | return false; |
3926 | 12.1M | if (!is_curve_x_small(pfs, &p->pole[0][3], 4, pfs->fixed_flat)) |
3927 | 945k | return false; |
3928 | 11.2M | if (!is_curve_y_small(pfs, &p->pole[0][0], 4, pfs->fixed_flat)) |
3929 | 491k | return false; |
3930 | 10.7M | if (!is_curve_y_small(pfs, &p->pole[0][1], 4, pfs->fixed_flat)) |
3931 | 387k | return false; |
3932 | 10.3M | if (!is_curve_y_small(pfs, &p->pole[0][2], 4, pfs->fixed_flat)) |
3933 | 244k | return false; |
3934 | 10.1M | if (!is_curve_y_small(pfs, &p->pole[0][3], 4, pfs->fixed_flat)) |
3935 | 223k | return false; |
3936 | 9.90M | return true; |
3937 | 10.1M | } |
3938 | | |
3939 | | static int |
3940 | | fill_patch(patch_fill_state_t *pfs, const tensor_patch *p, int kv, int kv0, int kv1) |
3941 | 21.7M | { |
3942 | 21.7M | if (kv <= 1) { |
3943 | 20.8M | if (is_patch_narrow(pfs, p)) |
3944 | 9.90M | return fill_stripe(pfs, p); |
3945 | 10.9M | if (!is_x_bended(p)) |
3946 | 1.00M | return fill_stripe(pfs, p); |
3947 | 10.9M | } |
3948 | 10.8M | { tensor_patch s0, s1; |
3949 | 10.8M | patch_color_t *c[2]; |
3950 | 10.8M | shading_vertex_t q0, q1, q2; |
3951 | 10.8M | int code = 0; |
3952 | 10.8M | byte *color_stack_ptr; |
3953 | 10.8M | bool save_inside = pfs->inside; |
3954 | | |
3955 | 10.8M | if (!pfs->inside) { |
3956 | 10.6M | gs_fixed_rect r, r1; |
3957 | | |
3958 | 10.6M | tensor_patch_bbox(&r, p); |
3959 | 10.6M | r.p.x -= INTERPATCH_PADDING; |
3960 | 10.6M | r.p.y -= INTERPATCH_PADDING; |
3961 | 10.6M | r.q.x += INTERPATCH_PADDING; |
3962 | 10.6M | r.q.y += INTERPATCH_PADDING; |
3963 | 10.6M | r1 = r; |
3964 | 10.6M | rect_intersect(r, pfs->rect); |
3965 | 10.6M | if (r.q.x <= r.p.x || r.q.y <= r.p.y) |
3966 | 514k | return 0; |
3967 | 10.1M | if (r1.p.x == r.p.x && r1.p.y == r.p.y && |
3968 | 10.1M | r1.q.x == r.q.x && r1.q.y == r.q.y) |
3969 | 57.0k | pfs->inside = true; |
3970 | 10.1M | } |
3971 | 10.2M | color_stack_ptr = reserve_colors_inline(pfs, c, 2); |
3972 | 10.2M | if(color_stack_ptr == NULL) |
3973 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
3974 | 10.2M | split_patch(pfs, &s0, &s1, p, c); |
3975 | 10.2M | if (kv0 <= 1) { |
3976 | 9.96M | q0.p = s0.pole[0][0]; |
3977 | 9.96M | q0.c = s0.c[0][0]; |
3978 | 9.96M | q1.p = s1.pole[3][0]; |
3979 | 9.96M | q1.c = s1.c[1][0]; |
3980 | 9.96M | q2.p = s0.pole[3][0]; |
3981 | 9.96M | q2.c = s0.c[1][0]; |
3982 | 9.96M | code = fill_triangle_wedge(pfs, &q0, &q1, &q2); |
3983 | 9.96M | } |
3984 | 10.2M | if (kv1 <= 1 && code >= 0) { |
3985 | 9.96M | q0.p = s0.pole[0][3]; |
3986 | 9.96M | q0.c = s0.c[0][1]; |
3987 | 9.96M | q1.p = s1.pole[3][3]; |
3988 | 9.96M | q1.c = s1.c[1][1]; |
3989 | 9.96M | q2.p = s0.pole[3][3]; |
3990 | 9.96M | q2.c = s0.c[1][1]; |
3991 | 9.96M | code = fill_triangle_wedge(pfs, &q0, &q1, &q2); |
3992 | 9.96M | } |
3993 | 10.2M | if (code >= 0) |
3994 | 10.2M | code = fill_patch(pfs, &s0, kv / 2, kv0 / 2, kv1 / 2); |
3995 | 10.2M | if (code >= 0) |
3996 | 10.2M | code = fill_patch(pfs, &s1, kv / 2, kv0 / 2, kv1 / 2); |
3997 | | /* fixme : To provide the precise filling order, we must |
3998 | | decompose left and right wedges into pieces by intersections |
3999 | | with stripes, and fill each piece with its stripe. |
4000 | | A lazy wedge list would be fine for storing |
4001 | | the necessary information. |
4002 | | |
4003 | | If the patch is created from a radial shading, |
4004 | | the wedge color appears a constant, so the filling order |
4005 | | isn't important. The order is important for other |
4006 | | self-overlapping patches, but the visible effect is |
4007 | | just a slight narrowing of the patch (as its lower layer appears |
4008 | | visible through the upper layer near the side). |
4009 | | This kind of dropout isn't harmful, because |
4010 | | contacting self-overlapping patches are painted |
4011 | | one after one by definition, so that a side coverage break |
4012 | | appears unavoidable by definition. |
4013 | | |
4014 | | Delaying this improvement because it is low importance. |
4015 | | */ |
4016 | 10.2M | release_colors_inline(pfs, color_stack_ptr, 2); |
4017 | 10.2M | pfs->inside = save_inside; |
4018 | 10.2M | return code; |
4019 | 10.2M | } |
4020 | 10.2M | } |
4021 | | |
4022 | | static inline int64_t |
4023 | | lcp1(int64_t p0, int64_t p3) |
4024 | 7.21M | { /* Computing the 1st pole of a 3d order besier, which appears a line. */ |
4025 | 7.21M | return (p0 + p0 + p3); |
4026 | 7.21M | } |
4027 | | static inline int64_t |
4028 | | lcp2(int64_t p0, int64_t p3) |
4029 | 7.21M | { /* Computing the 2nd pole of a 3d order besier, which appears a line. */ |
4030 | 7.21M | return (p0 + p3 + p3); |
4031 | 7.21M | } |
4032 | | |
4033 | | static void |
4034 | | patch_set_color(const patch_fill_state_t *pfs, patch_color_t *c, const float *cc) |
4035 | 4.50M | { |
4036 | 4.50M | if (pfs->Function) { |
4037 | 1.44M | c->t[0] = cc[0]; |
4038 | 1.44M | c->t[1] = cc[1]; |
4039 | 1.44M | } else |
4040 | 3.06M | memcpy(c->cc.paint.values, cc, sizeof(c->cc.paint.values[0]) * pfs->num_components); |
4041 | 4.50M | } |
4042 | | |
4043 | | static void |
4044 | | make_tensor_patch(const patch_fill_state_t *pfs, tensor_patch *p, const patch_curve_t curve[4], |
4045 | | const gs_fixed_point interior[4]) |
4046 | 1.12M | { |
4047 | 1.12M | const gs_color_space *pcs = pfs->direct_space; |
4048 | | |
4049 | 1.12M | p->pole[0][0] = curve[0].vertex.p; |
4050 | 1.12M | p->pole[1][0] = curve[0].control[0]; |
4051 | 1.12M | p->pole[2][0] = curve[0].control[1]; |
4052 | 1.12M | p->pole[3][0] = curve[1].vertex.p; |
4053 | 1.12M | p->pole[3][1] = curve[1].control[0]; |
4054 | 1.12M | p->pole[3][2] = curve[1].control[1]; |
4055 | 1.12M | p->pole[3][3] = curve[2].vertex.p; |
4056 | 1.12M | p->pole[2][3] = curve[2].control[0]; |
4057 | 1.12M | p->pole[1][3] = curve[2].control[1]; |
4058 | 1.12M | p->pole[0][3] = curve[3].vertex.p; |
4059 | 1.12M | p->pole[0][2] = curve[3].control[0]; |
4060 | 1.12M | p->pole[0][1] = curve[3].control[1]; |
4061 | 1.12M | if (interior != NULL) { |
4062 | 766k | p->pole[1][1] = interior[0]; |
4063 | 766k | p->pole[1][2] = interior[1]; |
4064 | 766k | p->pole[2][2] = interior[2]; |
4065 | 766k | p->pole[2][1] = interior[3]; |
4066 | 766k | } else { |
4067 | 360k | p->pole[1][1].x = (fixed)((3*(lcp1(p->pole[0][1].x, p->pole[3][1].x) + |
4068 | 360k | lcp1(p->pole[1][0].x, p->pole[1][3].x)) - |
4069 | 360k | lcp1(lcp1(p->pole[0][0].x, p->pole[0][3].x), |
4070 | 360k | lcp1(p->pole[3][0].x, p->pole[3][3].x)))/9); |
4071 | 360k | p->pole[1][2].x = (fixed)((3*(lcp1(p->pole[0][2].x, p->pole[3][2].x) + |
4072 | 360k | lcp2(p->pole[1][0].x, p->pole[1][3].x)) - |
4073 | 360k | lcp1(lcp2(p->pole[0][0].x, p->pole[0][3].x), |
4074 | 360k | lcp2(p->pole[3][0].x, p->pole[3][3].x)))/9); |
4075 | 360k | p->pole[2][1].x = (fixed)((3*(lcp2(p->pole[0][1].x, p->pole[3][1].x) + |
4076 | 360k | lcp1(p->pole[2][0].x, p->pole[2][3].x)) - |
4077 | 360k | lcp2(lcp1(p->pole[0][0].x, p->pole[0][3].x), |
4078 | 360k | lcp1(p->pole[3][0].x, p->pole[3][3].x)))/9); |
4079 | 360k | p->pole[2][2].x = (fixed)((3*(lcp2(p->pole[0][2].x, p->pole[3][2].x) + |
4080 | 360k | lcp2(p->pole[2][0].x, p->pole[2][3].x)) - |
4081 | 360k | lcp2(lcp2(p->pole[0][0].x, p->pole[0][3].x), |
4082 | 360k | lcp2(p->pole[3][0].x, p->pole[3][3].x)))/9); |
4083 | | |
4084 | 360k | p->pole[1][1].y = (fixed)((3*(lcp1(p->pole[0][1].y, p->pole[3][1].y) + |
4085 | 360k | lcp1(p->pole[1][0].y, p->pole[1][3].y)) - |
4086 | 360k | lcp1(lcp1(p->pole[0][0].y, p->pole[0][3].y), |
4087 | 360k | lcp1(p->pole[3][0].y, p->pole[3][3].y)))/9); |
4088 | 360k | p->pole[1][2].y = (fixed)((3*(lcp1(p->pole[0][2].y, p->pole[3][2].y) + |
4089 | 360k | lcp2(p->pole[1][0].y, p->pole[1][3].y)) - |
4090 | 360k | lcp1(lcp2(p->pole[0][0].y, p->pole[0][3].y), |
4091 | 360k | lcp2(p->pole[3][0].y, p->pole[3][3].y)))/9); |
4092 | 360k | p->pole[2][1].y = (fixed)((3*(lcp2(p->pole[0][1].y, p->pole[3][1].y) + |
4093 | 360k | lcp1(p->pole[2][0].y, p->pole[2][3].y)) - |
4094 | 360k | lcp2(lcp1(p->pole[0][0].y, p->pole[0][3].y), |
4095 | 360k | lcp1(p->pole[3][0].y, p->pole[3][3].y)))/9); |
4096 | 360k | p->pole[2][2].y = (fixed)((3*(lcp2(p->pole[0][2].y, p->pole[3][2].y) + |
4097 | 360k | lcp2(p->pole[2][0].y, p->pole[2][3].y)) - |
4098 | 360k | lcp2(lcp2(p->pole[0][0].y, p->pole[0][3].y), |
4099 | 360k | lcp2(p->pole[3][0].y, p->pole[3][3].y)))/9); |
4100 | 360k | } |
4101 | 1.12M | patch_set_color(pfs, p->c[0][0], curve[0].vertex.cc); |
4102 | 1.12M | patch_set_color(pfs, p->c[1][0], curve[1].vertex.cc); |
4103 | 1.12M | patch_set_color(pfs, p->c[1][1], curve[2].vertex.cc); |
4104 | 1.12M | patch_set_color(pfs, p->c[0][1], curve[3].vertex.cc); |
4105 | 1.12M | patch_resolve_color_inline(p->c[0][0], pfs); |
4106 | 1.12M | patch_resolve_color_inline(p->c[0][1], pfs); |
4107 | 1.12M | patch_resolve_color_inline(p->c[1][0], pfs); |
4108 | 1.12M | patch_resolve_color_inline(p->c[1][1], pfs); |
4109 | 1.12M | if (!pfs->Function) { |
4110 | 766k | pcs->type->restrict_color(&p->c[0][0]->cc, pcs); |
4111 | 766k | pcs->type->restrict_color(&p->c[0][1]->cc, pcs); |
4112 | 766k | pcs->type->restrict_color(&p->c[1][0]->cc, pcs); |
4113 | 766k | pcs->type->restrict_color(&p->c[1][1]->cc, pcs); |
4114 | 766k | } |
4115 | 1.12M | } |
4116 | | |
4117 | | int |
4118 | | gx_shade_background(gx_device *pdev, const gs_fixed_rect *rect, |
4119 | | const gx_device_color *pdevc, gs_logical_operation_t log_op) |
4120 | 201k | { |
4121 | 201k | gs_fixed_edge le, re; |
4122 | | |
4123 | 201k | le.start.x = rect->p.x - INTERPATCH_PADDING; |
4124 | 201k | le.start.y = rect->p.y - INTERPATCH_PADDING; |
4125 | 201k | le.end.x = rect->p.x - INTERPATCH_PADDING; |
4126 | 201k | le.end.y = rect->q.y + INTERPATCH_PADDING; |
4127 | 201k | re.start.x = rect->q.x + INTERPATCH_PADDING; |
4128 | 201k | re.start.y = rect->p.y - INTERPATCH_PADDING; |
4129 | 201k | re.end.x = rect->q.x + INTERPATCH_PADDING; |
4130 | 201k | re.end.y = rect->q.y + INTERPATCH_PADDING; |
4131 | 201k | return dev_proc(pdev, fill_trapezoid)(pdev, |
4132 | 201k | &le, &re, le.start.y, le.end.y, false, pdevc, log_op); |
4133 | 201k | } |
4134 | | |
4135 | | int |
4136 | | patch_fill(patch_fill_state_t *pfs, const patch_curve_t curve[4], |
4137 | | const gs_fixed_point interior[4], |
4138 | | void (*transform) (gs_fixed_point *, const patch_curve_t[4], |
4139 | | const gs_fixed_point[4], double, double)) |
4140 | 1.12M | { |
4141 | 1.12M | tensor_patch p; |
4142 | 1.12M | patch_color_t *c[4]; |
4143 | 1.12M | int kv[4], kvm, ku[4], kum; |
4144 | 1.12M | int code = 0; |
4145 | 1.12M | byte *color_stack_ptr = reserve_colors_inline(pfs, c, 4); /* Can't fail */ |
4146 | | |
4147 | 1.12M | p.c[0][0] = c[0]; |
4148 | 1.12M | p.c[0][1] = c[1]; |
4149 | 1.12M | p.c[1][0] = c[2]; |
4150 | 1.12M | p.c[1][1] = c[3]; |
4151 | | #if SKIP_TEST |
4152 | | dbg_patch_cnt++; |
4153 | | /*if (dbg_patch_cnt != 67 && dbg_patch_cnt != 78) |
4154 | | return 0;*/ |
4155 | | #endif |
4156 | | /* We decompose the patch into tiny quadrangles, |
4157 | | possibly inserting wedges between them against a dropout. */ |
4158 | 1.12M | make_tensor_patch(pfs, &p, curve, interior); |
4159 | 1.12M | pfs->unlinear = !is_linear_color_applicable(pfs); |
4160 | 1.12M | pfs->linear_color = false; |
4161 | 1.12M | if ((*dev_proc(pfs->dev, dev_spec_op))(pfs->dev, |
4162 | 1.12M | gxdso_pattern_shading_area, NULL, 0) > 0) { |
4163 | | /* Inform the device with the shading coverage area. |
4164 | | First compute the sign of the area, because |
4165 | | all areas to be clipped in same direction. */ |
4166 | 167k | gx_device *pdev = pfs->dev; |
4167 | 167k | gx_path path; |
4168 | 167k | fixed d01x = (curve[1].vertex.p.x - curve[0].vertex.p.x) >> 1; |
4169 | 167k | fixed d01y = (curve[1].vertex.p.y - curve[0].vertex.p.y) >> 1; |
4170 | 167k | fixed d12x = (curve[2].vertex.p.x - curve[1].vertex.p.x) >> 1; |
4171 | 167k | fixed d12y = (curve[2].vertex.p.y - curve[1].vertex.p.y) >> 1; |
4172 | 167k | fixed d23x = (curve[3].vertex.p.x - curve[2].vertex.p.x) >> 1; |
4173 | 167k | fixed d23y = (curve[3].vertex.p.y - curve[2].vertex.p.y) >> 1; |
4174 | 167k | fixed d30x = (curve[0].vertex.p.x - curve[3].vertex.p.x) >> 1; |
4175 | 167k | fixed d30y = (curve[0].vertex.p.y - curve[3].vertex.p.y) >> 1; |
4176 | 167k | int64_t s1 = (int64_t)d01x * d12y - (int64_t)d01y * d12x; |
4177 | 167k | int64_t s2 = (int64_t)d23x * d30y - (int64_t)d23y * d30x; |
4178 | 167k | int s = (s1 + s2 > 0 ? 1 : 3), i, j, k, jj, l = (s == 1 ? 0 : 1); |
4179 | | |
4180 | 167k | gx_path_init_local(&path, pdev->memory); |
4181 | 167k | if (is_x_bended(&p) || is_y_bended(&p)) { |
4182 | | /* The patch possibly is self-overlapping, |
4183 | | so the patch coverage may fall outside the patch outline. |
4184 | | In this case we pass an empty path, |
4185 | | and the device must use a bitmap mask instead clipping. */ |
4186 | 98.4k | } else { |
4187 | 69.0k | code = gx_path_add_point(&path, curve[0].vertex.p.x, curve[0].vertex.p.y); |
4188 | 345k | for (i = k = 0; k < 4 && code >= 0; i = j, k++) { |
4189 | 276k | j = (i + s) % 4, jj = (s == 1 ? i : j); |
4190 | 276k | if (curve[jj].straight) |
4191 | 22.8k | code = gx_path_add_line(&path, curve[j].vertex.p.x, |
4192 | 276k | curve[j].vertex.p.y); |
4193 | 253k | else |
4194 | 253k | code = gx_path_add_curve(&path, curve[jj].control[l].x, curve[jj].control[l].y, |
4195 | 276k | curve[jj].control[(l + 1) & 1].x, curve[jj].control[(l + 1) & 1].y, |
4196 | 276k | curve[j].vertex.p.x, |
4197 | 276k | curve[j].vertex.p.y); |
4198 | 276k | } |
4199 | 69.0k | if (code >= 0) |
4200 | 69.0k | code = gx_path_close_subpath(&path); |
4201 | 69.0k | } |
4202 | 167k | if (code >= 0) |
4203 | 167k | code = (*dev_proc(pfs->dev, fill_path))(pdev, NULL, &path, NULL, NULL, NULL); |
4204 | 167k | gx_path_free(&path, "patch_fill"); |
4205 | 167k | if (code < 0) |
4206 | 0 | goto out; |
4207 | 167k | } |
4208 | | /* How many subdivisions of the patch in the u and v direction? */ |
4209 | 1.12M | kv[0] = curve_samples(pfs, &p.pole[0][0], 4, pfs->fixed_flat); |
4210 | 1.12M | kv[1] = curve_samples(pfs, &p.pole[0][1], 4, pfs->fixed_flat); |
4211 | 1.12M | kv[2] = curve_samples(pfs, &p.pole[0][2], 4, pfs->fixed_flat); |
4212 | 1.12M | kv[3] = curve_samples(pfs, &p.pole[0][3], 4, pfs->fixed_flat); |
4213 | 1.12M | kvm = max(max(kv[0], kv[1]), max(kv[2], kv[3])); |
4214 | 1.12M | ku[0] = curve_samples(pfs, p.pole[0], 1, pfs->fixed_flat); |
4215 | 1.12M | ku[1] = curve_samples(pfs, p.pole[1], 1, pfs->fixed_flat); |
4216 | 1.12M | ku[2] = curve_samples(pfs, p.pole[2], 1, pfs->fixed_flat); |
4217 | 1.12M | ku[3] = curve_samples(pfs, p.pole[3], 1, pfs->fixed_flat); |
4218 | 1.12M | kum = max(max(ku[0], ku[1]), max(ku[2], ku[3])); |
4219 | | # if NOFILL_TEST |
4220 | | dbg_nofill = false; |
4221 | | # endif |
4222 | 1.12M | code = fill_wedges(pfs, ku[0], kum, p.pole[0], 1, p.c[0][0], p.c[0][1], |
4223 | 1.12M | interpatch_padding | inpatch_wedge); |
4224 | 1.12M | if (code >= 0) { |
4225 | | /* We would like to apply iterations for enumerating the kvm curve parts, |
4226 | | but the roundinmg errors would be too complicated due to |
4227 | | the dependence on the direction. Note that neigbour |
4228 | | patches may use the opposite direction for same bounding curve. |
4229 | | We apply the recursive dichotomy, in which |
4230 | | the rounding errors do not depend on the direction. */ |
4231 | | # if NOFILL_TEST |
4232 | | dbg_nofill = false; |
4233 | | code = fill_patch(pfs, &p, kvm, kv[0], kv[3]); |
4234 | | dbg_nofill = true; |
4235 | | # endif |
4236 | 1.12M | code = fill_patch(pfs, &p, kvm, kv[0], kv[3]); |
4237 | 1.12M | } |
4238 | 1.12M | if (code >= 0) |
4239 | 1.12M | code = fill_wedges(pfs, ku[3], kum, p.pole[3], 1, p.c[1][0], p.c[1][1], |
4240 | 1.12M | interpatch_padding | inpatch_wedge); |
4241 | 1.12M | out: |
4242 | 1.12M | release_colors_inline(pfs, color_stack_ptr, 4); |
4243 | 1.12M | return code; |
4244 | 1.12M | } |