Coverage Report

Created: 2025-06-10 06:56

/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
3.55k
{
87
3.55k
    if (pfs->color_stack != NULL)
88
0
        return 0;
89
3.55k
    pfs->color_stack_step = offset_of(patch_color_t, cc.paint.values[pfs->num_components]);
90
3.55k
    pfs->color_stack_step = (pfs->color_stack_step + sizeof(void *) - 1) / sizeof(void *) * sizeof(void *); /* Alignment */
91
92
3.55k
    pfs->color_stack_size = pfs->color_stack_step * SHADING_COLOR_STACK_SIZE;
93
3.55k
    pfs->color_stack = gs_alloc_bytes(memory, pfs->color_stack_size, "allocate_color_stack");
94
3.55k
    if (pfs->color_stack == NULL)
95
0
        return_error(gs_error_VMerror);
96
3.55k
    pfs->color_stack_limit = pfs->color_stack + pfs->color_stack_size;
97
3.55k
    pfs->color_stack_ptr = pfs->color_stack;
98
3.55k
    pfs->memory = memory;
99
3.55k
    return 0;
100
3.55k
}
101
102
static inline byte *
103
reserve_colors_inline(patch_fill_state_t *pfs, patch_color_t *c[], int n)
104
25.5M
{
105
25.5M
    int i;
106
25.5M
    byte *ptr0 = pfs->color_stack_ptr, *ptr = ptr0;
107
108
85.2M
    for (i = 0; i < n; i++, ptr += pfs->color_stack_step)
109
59.6M
        c[i] = (patch_color_t *)ptr;
110
25.5M
    if (ptr > pfs->color_stack_limit) {
111
0
        c[0] = NULL; /* safety. */
112
0
        return NULL;
113
0
    }
114
25.5M
    pfs->color_stack_ptr = ptr;
115
25.5M
    return ptr0;
116
25.5M
}
117
118
byte *
119
reserve_colors(patch_fill_state_t *pfs, patch_color_t *c[], int n)
120
28
{
121
28
    return reserve_colors_inline(pfs, c, n);
122
28
}
123
124
static inline void
125
release_colors_inline(patch_fill_state_t *pfs, byte *ptr, int n)
126
25.5M
{
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
25.5M
    pfs->color_stack_ptr = ptr;
132
25.5M
#endif
133
25.5M
}
134
void
135
release_colors(patch_fill_state_t *pfs, byte *ptr, int n)
136
28
{
137
28
    release_colors_inline(pfs, ptr, n);
138
28
}
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
73.6k
{
145
73.6k
    int i, code = 0;
146
147
310k
    for (i = 0; i < num_vertices && code >= 0; ++i) {
148
236k
        curves[i].vertex.cc[1] = 0; /* safety. (patch_fill may assume 2 arguments) */
149
236k
        code = shade_next_color(cs, curves[i].vertex.cc);
150
236k
    }
151
73.6k
    return code;
152
73.6k
}
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
192k
{
158
192k
    int code = shade_next_coords(cs, &curve->vertex.p, 1);
159
160
192k
    if (code >= 0)
161
192k
        code = shade_next_coords(cs, curve->control,
162
192k
                                 countof(curve->control));
163
192k
    return code;
164
192k
}
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
73.8k
{
174
73.8k
    int flag = shade_next_flag(cs, BitsPerFlag);
175
73.8k
    int num_colors, code;
176
177
73.8k
    if (flag < 0) {
178
94
        if (!cs->is_eod(cs))
179
0
            return_error(gs_error_rangecheck);
180
94
        return 1;               /* no more data */
181
94
    }
182
73.7k
    if (cs->first_patch && (flag & 3) != 0) {
183
0
        return_error(gs_error_rangecheck);
184
0
    }
185
73.7k
    cs->first_patch = 0;
186
73.7k
    switch (flag & 3) {
187
0
        default:
188
0
            return_error(gs_error_rangecheck);  /* not possible */
189
44.7k
        case 0:
190
44.7k
            if ((code = shade_next_curve(cs, &curve[0])) < 0 ||
191
44.7k
                (code = shade_next_coords(cs, &curve[1].vertex.p, 1)) < 0
192
44.7k
                )
193
5
                return code;
194
44.7k
            num_colors = 4;
195
44.7k
            goto vx;
196
8.19k
        case 1:
197
8.19k
            curve[0] = curve[1], curve[1].vertex = curve[2].vertex;
198
8.19k
            goto v3;
199
8.52k
        case 2:
200
8.52k
            curve[0] = curve[2], curve[1].vertex = curve[3].vertex;
201
8.52k
            goto v3;
202
12.2k
        case 3:
203
12.2k
            curve[1].vertex = curve[0].vertex, curve[0] = curve[3];
204
28.9k
v3:         num_colors = 2;
205
73.7k
vx:         if ((code = shade_next_coords(cs, curve[1].control, 2)) < 0 ||
206
73.7k
                (code = shade_next_curve(cs, &curve[2])) < 0 ||
207
73.7k
                (code = shade_next_curve(cs, &curve[3])) < 0 ||
208
73.7k
                (interior != 0 &&
209
73.6k
                 (code = shade_next_coords(cs, interior, 4)) < 0) ||
210
73.7k
                (code = shade_next_colors(cs, &curve[4 - num_colors],
211
73.6k
                                          num_colors)) < 0
212
73.7k
                )
213
58
                return code;
214
73.6k
            cs->align(cs, 8); /* See shade_next_vertex. */
215
73.7k
    }
216
73.6k
    return 0;
217
73.7k
}
218
219
static inline bool
220
is_linear_color_applicable(const patch_fill_state_t *pfs)
221
433k
{
222
433k
    if (!USE_LINEAR_COLOR_PROCS)
223
0
        return false;
224
433k
    if (!colors_are_separable_and_linear(&pfs->dev->color_info))
225
399k
        return false;
226
33.7k
    if (gx_get_cmap_procs(pfs->pgs, pfs->dev)->is_halftoned(pfs->pgs, pfs->dev))
227
0
        return false;
228
33.7k
    return true;
229
33.7k
}
230
231
static int
232
alloc_patch_fill_memory(patch_fill_state_t *pfs, gs_memory_t *memory, const gs_color_space *pcs)
233
3.55k
{
234
3.55k
    int code;
235
236
3.55k
    pfs->memory = memory;
237
3.55k
#   if LAZY_WEDGES
238
3.55k
        code = wedge_vertex_list_elem_buffer_alloc(pfs);
239
3.55k
        if (code < 0)
240
0
            return code;
241
3.55k
#   endif
242
3.55k
    pfs->max_small_coord = 1 << ((sizeof(int64_t) * 8 - 1/*sign*/) / 3);
243
3.55k
    code = allocate_color_stack(pfs, memory);
244
3.55k
    if (code < 0)
245
0
        return code;
246
3.55k
    if (pfs->unlinear || pcs == NULL)
247
442
        pfs->pcic = NULL;
248
3.10k
    else {
249
3.10k
        pfs->pcic = gs_color_index_cache_create(memory, pcs, pfs->dev, pfs->pgs, true, pfs->trans_device);
250
3.10k
        if (pfs->pcic == NULL)
251
0
            return_error(gs_error_VMerror);
252
3.10k
    }
253
3.55k
    return 0;
254
3.55k
}
255
256
int
257
init_patch_fill_state(patch_fill_state_t *pfs)
258
3.55k
{
259
    /* Warning : pfs->Function must be set in advance. */
260
3.55k
    const gs_color_space *pcs = pfs->direct_space;
261
3.55k
    gs_client_color fcc0, fcc1;
262
3.55k
    int i;
263
264
12.8k
    for (i = 0; i < pfs->num_components; i++) {
265
9.28k
        fcc0.paint.values[i] = -1000000;
266
9.28k
        fcc1.paint.values[i] = 1000000;
267
9.28k
    }
268
3.55k
    pcs->type->restrict_color(&fcc0, pcs);
269
3.55k
    pcs->type->restrict_color(&fcc1, pcs);
270
12.8k
    for (i = 0; i < pfs->num_components; i++)
271
9.28k
        pfs->color_domain.paint.values[i] = max(fcc1.paint.values[i] - fcc0.paint.values[i], 1);
272
3.55k
    pfs->vectorization = false; /* A stub for a while. Will use with pclwrite. */
273
3.55k
    pfs->maybe_self_intersecting = true;
274
3.55k
    pfs->monotonic_color = (pfs->Function == NULL);
275
3.55k
    pfs->function_arg_shift = 0;
276
3.55k
    pfs->linear_color = false;
277
3.55k
    pfs->inside = false;
278
3.55k
    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
3.55k
    pfs->decomposition_limit = fixed_1;
285
3.55k
#endif
286
3.55k
    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
3.55k
    pfs->smoothness = max(pfs->pgs->smoothness, 1.0 / min_linear_grades);
292
3.55k
    pfs->color_stack_size = 0;
293
3.55k
    pfs->color_stack_step = 0;
294
3.55k
    pfs->color_stack_ptr = NULL;
295
3.55k
    pfs->color_stack = NULL;
296
3.55k
    pfs->color_stack_limit = NULL;
297
3.55k
    pfs->unlinear = !is_linear_color_applicable(pfs);
298
3.55k
    pfs->pcic = NULL;
299
3.55k
    return alloc_patch_fill_memory(pfs, pfs->pgs->memory, pcs);
300
3.55k
}
301
302
bool
303
term_patch_fill_state(patch_fill_state_t *pfs)
304
3.55k
{
305
3.55k
    bool b = (pfs->color_stack_ptr != pfs->color_stack);
306
3.55k
#   if LAZY_WEDGES
307
3.55k
        wedge_vertex_list_elem_buffer_free(pfs);
308
3.55k
#   endif
309
3.55k
    if (pfs->color_stack)
310
3.55k
        gs_free_object(pfs->memory, pfs->color_stack, "term_patch_fill_state");
311
3.55k
    if (pfs->pcic != NULL)
312
3.10k
        gs_color_index_cache_destroy(pfs->pcic);
313
3.55k
    return b;
314
3.55k
}
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
7.60M
{
320
7.60M
    if (pfs->Function) {
321
7.31M
        const gs_color_space *pcs = pfs->direct_space;
322
323
7.31M
        gs_function_evaluate(pfs->Function, ppcr->t, ppcr->cc.paint.values);
324
7.31M
        pcs->type->restrict_color(&ppcr->cc, pcs);
325
7.31M
    }
326
7.60M
}
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
28.7M
{
344
    /* The old code gives -IND on Intel. */
345
28.7M
    if (pfs->Function) {
346
6.60M
        ppcr->t[0] = ppc0->t[0] * (1 - t) + t * ppc1->t[0];
347
6.60M
        ppcr->t[1] = ppc0->t[1] * (1 - t) + t * ppc1->t[1];
348
6.60M
        patch_resolve_color_inline(ppcr, pfs);
349
22.1M
    } else {
350
22.1M
        int ci;
351
352
104M
        for (ci = pfs->num_components - 1; ci >= 0; --ci)
353
82.6M
            ppcr->cc.paint.values[ci] =
354
82.6M
                ppc0->cc.paint.values[ci] * (1 - t) + t * ppc1->cc.paint.values[ci];
355
22.1M
    }
356
28.7M
}
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
3
{
446
3
    const gs_shading_Cp_t * const psh = (const gs_shading_Cp_t *)psh0;
447
3
    patch_fill_state_t state;
448
3
    shade_coord_stream_t cs;
449
3
    patch_curve_t curve[4];
450
3
    int code;
451
452
3
    code = mesh_init_fill_state((mesh_fill_state_t *) &state,
453
3
                         (const gs_shading_mesh_t *)psh0, rect_clip, dev, pgs);
454
3
    if (code < 0) {
455
0
        if (state.icclink != NULL) gsicc_release_link(state.icclink);
456
0
        return code;
457
0
    }
458
3
    state.Function = psh->params.Function;
459
3
    code = init_patch_fill_state(&state);
460
3
    if(code < 0) {
461
0
        if (state.icclink != NULL) gsicc_release_link(state.icclink);
462
0
        return code;
463
0
    }
464
465
3
    curve[0].straight = curve[1].straight = curve[2].straight = curve[3].straight = false;
466
3
    shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, pgs);
467
11
    while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
468
11
                                    curve, NULL)) == 0 &&
469
11
           (code = patch_fill(&state, curve, NULL, Cp_transform)) >= 0
470
8
        ) {
471
8
        DO_NOTHING;
472
8
    }
473
3
    if (term_patch_fill_state(&state))
474
0
        return_error(gs_error_unregistered); /* Must not happen. */
475
3
    if (state.icclink != NULL) gsicc_release_link(state.icclink);
476
3
    return min(code, 0);
477
3
}
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
154
{
535
154
    const gs_shading_Tpp_t * const psh = (const gs_shading_Tpp_t *)psh0;
536
154
    patch_fill_state_t state;
537
154
    shade_coord_stream_t cs;
538
154
    patch_curve_t curve[4];
539
154
    gs_fixed_point interior[4];
540
154
    int code;
541
542
154
    code = mesh_init_fill_state((mesh_fill_state_t *) & state,
543
154
                         (const gs_shading_mesh_t *)psh0, rect_clip, dev, pgs);
544
154
    if (code < 0) {
545
0
        if (state.icclink != NULL) gsicc_release_link(state.icclink);
546
0
        return code;
547
0
    }
548
154
    state.Function = psh->params.Function;
549
154
    code = init_patch_fill_state(&state);
550
154
    if(code < 0)
551
0
        return code;
552
154
    curve[0].straight = curve[1].straight = curve[2].straight = curve[3].straight = false;
553
154
    shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, pgs);
554
73.8k
    while ((code = shade_next_patch(&cs, psh->params.BitsPerFlag,
555
73.8k
                                    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
73.6k
        gs_fixed_point swapped_interior[4];
561
562
73.6k
        swapped_interior[0] = interior[0];
563
73.6k
        swapped_interior[1] = interior[3];
564
73.6k
        swapped_interior[2] = interior[2];
565
73.6k
        swapped_interior[3] = interior[1];
566
73.6k
        code = patch_fill(&state, curve, swapped_interior, Tpp_transform);
567
73.6k
        if (code < 0)
568
0
            break;
569
73.6k
    }
570
154
    if (term_patch_fill_state(&state))
571
0
        return_error(gs_error_unregistered); /* Must not happen. */
572
154
    if (state.icclink != NULL) gsicc_release_link(state.icclink);
573
154
    return min(code, 0);
574
154
}
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
3.55k
{
665
3.55k
    const int max_level = LAZY_WEDGES_MAX_LEVEL;
666
3.55k
    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
3.55k
    pfs->wedge_vertex_list_elem_count_max = max_level * (1 << max_level) * 2;
679
3.55k
    pfs->wedge_vertex_list_elem_buffer = (wedge_vertex_list_elem_t *)gs_alloc_bytes(memory,
680
3.55k
            sizeof(wedge_vertex_list_elem_t) * pfs->wedge_vertex_list_elem_count_max,
681
3.55k
            "alloc_wedge_vertex_list_elem_buffer");
682
3.55k
    if (pfs->wedge_vertex_list_elem_buffer == NULL)
683
0
        return_error(gs_error_VMerror);
684
3.55k
    pfs->free_wedge_vertex = NULL;
685
3.55k
    pfs->wedge_vertex_list_elem_count = 0;
686
3.55k
    return 0;
687
3.55k
}
688
689
void
690
wedge_vertex_list_elem_buffer_free(patch_fill_state_t *pfs)
691
3.55k
{
692
3.55k
    gs_memory_t *memory = pfs->memory;
693
694
3.55k
    gs_free_object(memory, pfs->wedge_vertex_list_elem_buffer,
695
3.55k
                "wedge_vertex_list_elem_buffer_free");
696
3.55k
    pfs->wedge_vertex_list_elem_buffer = NULL;
697
3.55k
    pfs->free_wedge_vertex = NULL;
698
3.55k
}
699
700
static inline wedge_vertex_list_elem_t *
701
wedge_vertex_list_elem_reserve(patch_fill_state_t *pfs)
702
3.10M
{
703
3.10M
    wedge_vertex_list_elem_t *e = pfs->free_wedge_vertex;
704
705
3.10M
    if (e != NULL) {
706
3.04M
        pfs->free_wedge_vertex = e->next;
707
3.04M
        return e;
708
3.04M
    }
709
57.0k
    if (pfs->wedge_vertex_list_elem_count < pfs->wedge_vertex_list_elem_count_max)
710
57.0k
        return pfs->wedge_vertex_list_elem_buffer + pfs->wedge_vertex_list_elem_count++;
711
0
    return NULL;
712
57.0k
}
713
714
static inline void
715
wedge_vertex_list_elem_release(patch_fill_state_t *pfs, wedge_vertex_list_elem_t *e)
716
3.10M
{
717
3.10M
    e->next = pfs->free_wedge_vertex;
718
3.10M
    pfs->free_wedge_vertex = e;
719
3.10M
}
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
1.82M
{
725
1.82M
    wedge_vertex_list_elem_t *e = beg->next, *ee;
726
727
1.82M
    beg->next = end;
728
1.82M
    end->prev = beg;
729
3.31M
    for (; e != end; e = ee) {
730
1.48M
        ee = e->next;
731
1.48M
        wedge_vertex_list_elem_release(pfs, e);
732
1.48M
    }
733
1.82M
}
734
735
static inline int
736
release_wedge_vertex_list(patch_fill_state_t *pfs, wedge_vertex_list_t *ll, int n)
737
808k
{
738
808k
    int i;
739
740
1.61M
    for (i = 0; i < n; i++) {
741
808k
        wedge_vertex_list_t *l = ll + i;
742
743
808k
        if (l->beg != NULL) {
744
808k
            if (l->end == NULL)
745
0
                return_error(gs_error_unregistered); /* Must not happen. */
746
808k
            release_wedge_vertex_list_interval(pfs, l->beg, l->end);
747
808k
            wedge_vertex_list_elem_release(pfs, l->beg);
748
808k
            wedge_vertex_list_elem_release(pfs, l->end);
749
808k
            l->beg = l->end = NULL;
750
808k
        } else if (l->end != NULL)
751
0
            return_error(gs_error_unregistered); /* Must not happen. */
752
808k
    }
753
808k
    return 0;
754
808k
}
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
1.12M
{
760
1.12M
    wedge_vertex_list_elem_t *e = beg;
761
762
1.12M
    if (beg == NULL || end == NULL)
763
0
        return NULL; /* Must not happen. */
764
2.94M
    for (; e != end; e = e->next)
765
2.94M
        if (e->level == level)
766
1.12M
            return e;
767
0
    return NULL;
768
1.12M
}
769
770
static inline void
771
init_wedge_vertex_list(wedge_vertex_list_t *l, int n)
772
7.80M
{
773
7.80M
    memset(l, 0, sizeof(*l) * n);
774
7.80M
}
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
2.32M
{
785
2.32M
    curve_segment s;
786
2.32M
    int k;
787
788
2.32M
    s.p1.x = pole[pole_step].x;
789
2.32M
    s.p1.y = pole[pole_step].y;
790
2.32M
    s.p2.x = pole[pole_step * 2].x;
791
2.32M
    s.p2.y = pole[pole_step * 2].y;
792
2.32M
    s.pt.x = pole[pole_step * 3].x;
793
2.32M
    s.pt.y = pole[pole_step * 3].y;
794
2.32M
    k = gx_curve_log2_samples(pole[0].x, pole[0].y, &s, fixed_flat);
795
2.32M
    {
796
2.32M
#       if LAZY_WEDGES || QUADRANGLES
797
2.32M
            int k1;
798
2.32M
            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
2.32M
                      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
2.32M
                      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
2.32M
#       endif
802
803
2.32M
#       if LAZY_WEDGES
804
            /* Restrict lengths for a reasonable memory consumption : */
805
2.32M
            k1 = ilog2(L / fixed_1 / (1 << (LAZY_WEDGES_MAX_LEVEL - 1)));
806
2.32M
            k = max(k, k1);
807
2.32M
#       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
2.32M
    }
813
2.32M
    return 1 << k;
814
2.32M
}
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
8.09M
{
826
8.09M
    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
3.85M
        *b += fixed_epsilon;
836
3.85M
    }
837
8.09M
}
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
2.10M
{
844
2.10M
    if (!orient) {
845
1.28M
        le->start = q[vi0];
846
1.28M
        le->end = q[vi1];
847
1.28M
        re->start = q[vi2];
848
1.28M
        re->end = q[vi3];
849
1.28M
    } else {
850
821k
        le->start = q[vi2];
851
821k
        le->end = q[vi3];
852
821k
        re->start = q[vi0];
853
821k
        re->end = q[vi1];
854
821k
    }
855
2.10M
    adjust_swapped_boundary(&re->start.x, swap_axes);
856
2.10M
    adjust_swapped_boundary(&re->end.x, swap_axes);
857
2.10M
}
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
61.0k
{
864
61.0k
    gs_fixed_edge le, re;
865
61.0k
    int code;
866
61.0k
    fixed ybot = max(ybot0, swap_axes ? pfs->rect.p.x : pfs->rect.p.y);
867
61.0k
    fixed ytop = min(ytop0, swap_axes ? pfs->rect.q.x : pfs->rect.q.y);
868
61.0k
    fixed xleft  = (swap_axes ? pfs->rect.p.y : pfs->rect.p.x);
869
61.0k
    fixed xright = (swap_axes ? pfs->rect.q.y : pfs->rect.q.x);
870
871
61.0k
    if (ybot >= ytop)
872
27.8k
        return 0;
873
#   if NOFILL_TEST
874
        if (dbg_nofill)
875
            return 0;
876
#   endif
877
33.2k
    make_trapezoid(q, vi0, vi1, vi2, vi3, ybot, ytop, swap_axes, orient, &le, &re);
878
33.2k
    if (!pfs->inside) {
879
15.0k
        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
15.0k
        if (le.start.x > xright) {
890
2.13k
            if (le.end.x > xright) {
891
0
                return 0;
892
0
            }
893
2.13k
            clip = true;
894
12.9k
        } else if (le.end.x > xright) {
895
1.27k
            clip = true;
896
1.27k
        }
897
15.0k
        if (le.start.x < xleft) {
898
3.63k
            if (le.end.x < xleft) {
899
2.31k
                le.start.x = xleft;
900
2.31k
                le.end.x   = xleft;
901
2.31k
                le.start.y = ybot;
902
2.31k
                le.end.y   = ytop;
903
2.31k
            } else {
904
1.32k
                clip = true;
905
1.32k
            }
906
11.3k
        } else if (le.end.x < xleft) {
907
1.95k
            clip = true;
908
1.95k
        }
909
15.0k
        if (re.start.x < xleft) {
910
1.67k
            if (re.end.x < xleft) {
911
0
                return 0;
912
0
            }
913
1.67k
            clip = true;
914
13.3k
        } else if (re.end.x < xleft) {
915
2.04k
            clip = true;
916
2.04k
        }
917
15.0k
        if (re.start.x > xright) {
918
4.03k
            if (re.end.x > xright) {
919
1.98k
                re.start.x = xright;
920
1.98k
                re.end.x   = xright;
921
1.98k
                re.start.y = ybot;
922
1.98k
                re.end.y   = ytop;
923
2.05k
            } else {
924
2.05k
                clip = true;
925
2.05k
            }
926
10.9k
        } else if (re.end.x > xright) {
927
1.15k
            clip = true;
928
1.15k
        }
929
15.0k
        if (clip)
930
8.25k
        {
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
8.25k
            gs_fixed_edge lenew, renew;
935
8.25k
            fixed ybl, ybr, ytl, ytr, ymid;
936
937
            /* Reduce the clipping region horizontally if possible. */
938
8.25k
            if (re.start.x > re.end.x) {
939
3.37k
                if (re.start.x < xright)
940
1.31k
                    xright = re.start.x;
941
4.88k
            } else if (re.end.x < xright)
942
1.84k
                xright = re.end.x;
943
8.25k
            if (le.start.x > le.end.x) {
944
3.35k
                if (le.end.x > xleft)
945
1.39k
                    xleft = le.end.x;
946
4.90k
            } else if (le.start.x > xleft)
947
1.49k
                xleft = le.start.x;
948
949
8.25k
            ybot = max(ybot, min(le.start.y, re.start.y));
950
8.25k
            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
8.25k
            if (ybot >= ytop)
987
0
                return 0;
988
            /* Follow the edges in, so that le.start.y == ybot etc. */
989
8.25k
            if (le.start.y < ybot) {
990
3.24k
                int round = ((le.end.x < le.start.x) ?
991
1.76k
                             (le.end.y-le.start.y-1) : 0);
992
3.24k
                le.start.x += (fixed)(((int64_t)(ybot-le.start.y)*
993
3.24k
                                       (int64_t)(le.end.x-le.start.x)-round)/
994
3.24k
                                      (int64_t)(le.end.y-le.start.y));
995
3.24k
                le.start.y = ybot;
996
3.24k
            }
997
8.25k
            if (le.end.y > ytop) {
998
3.36k
                int round = ((le.end.x > le.start.x) ?
999
1.81k
                             (le.end.y-le.start.y-1) : 0);
1000
3.36k
                le.end.x += (fixed)(((int64_t)(le.end.y-ytop)*
1001
3.36k
                                     (int64_t)(le.start.x-le.end.x)-round)/
1002
3.36k
                                    (int64_t)(le.end.y-le.start.y));
1003
3.36k
                le.end.y = ytop;
1004
3.36k
            }
1005
8.25k
            if ((le.start.x < xleft) && (le.end.x < xleft)) {
1006
496
                le.start.x = xleft;
1007
496
                le.end.x   = xleft;
1008
496
                le.start.y = ybot;
1009
496
                le.end.y   = ytop;
1010
496
            }
1011
8.25k
            if (re.start.y < ybot) {
1012
3.38k
                int round = ((re.end.x > re.start.x) ?
1013
1.84k
                             (re.end.y-re.start.y-1) : 0);
1014
3.38k
                re.start.x += (fixed)(((int64_t)(ybot-re.start.y)*
1015
3.38k
                                       (int64_t)(re.end.x-re.start.x)+round)/
1016
3.38k
                                      (int64_t)(re.end.y-re.start.y));
1017
3.38k
                re.start.y = ybot;
1018
3.38k
            }
1019
8.25k
            if (re.end.y > ytop) {
1020
3.61k
                int round = ((re.end.x < re.start.x) ?
1021
1.85k
                             (re.end.y-re.start.y-1) : 0);
1022
3.61k
                re.end.x += (fixed)(((int64_t)(re.end.y-ytop)*
1023
3.61k
                                     (int64_t)(re.start.x-re.end.x)+round)/
1024
3.61k
                                    (int64_t)(re.end.y-re.start.y));
1025
3.61k
                re.end.y = ytop;
1026
3.61k
            }
1027
8.25k
            if ((re.start.x > xright) && (re.end.x > xright)) {
1028
194
                re.start.x = xright;
1029
194
                re.end.x   = xright;
1030
194
                re.start.y = ybot;
1031
194
                re.end.y   = ytop;
1032
194
            }
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
8.25k
            if (le.start.x > re.start.x) {
1039
2.77k
                if (le.start.x == le.end.x) {
1040
1.37k
                    if (re.start.x == re.end.x)
1041
0
                        return 0;
1042
1.37k
                    ybot += (fixed)((int64_t)(re.end.y-re.start.y)*
1043
1.37k
                                    (int64_t)(le.start.x-re.start.x)/
1044
1.37k
                                    (int64_t)(re.end.x-re.start.x));
1045
1.37k
                    re.start.x = le.start.x;
1046
1.39k
                } else {
1047
1.39k
                    ybot += (fixed)((int64_t)(le.end.y-le.start.y)*
1048
1.39k
                                    (int64_t)(le.start.x-re.start.x)/
1049
1.39k
                                    (int64_t)(le.start.x-le.end.x));
1050
1.39k
                    le.start.x = re.start.x;
1051
1.39k
                }
1052
2.77k
                if (ybot >= ytop)
1053
866
                    return 0;
1054
1.90k
                le.start.y = ybot;
1055
1.90k
                re.start.y = ybot;
1056
1.90k
            }
1057
7.39k
            if (le.end.x > re.end.x) {
1058
1.80k
                if (le.start.x == le.end.x) {
1059
1.15k
                    if (re.start.x == re.end.x)
1060
0
                        return 0;
1061
1.15k
                    ytop -= (fixed)((int64_t)(re.end.y-re.start.y)*
1062
1.15k
                                    (int64_t)(le.end.x-re.end.x)/
1063
1.15k
                                    (int64_t)(re.start.x-re.end.x));
1064
1.15k
                    re.end.x = le.end.x;
1065
1.15k
                } else {
1066
652
                    ytop -= (fixed)((int64_t)(le.end.y-le.start.y)*
1067
652
                                    (int64_t)(le.end.x-re.end.x)/
1068
652
                                    (int64_t)(le.end.x-le.start.x));
1069
652
                    le.end.x = re.end.x;
1070
652
                }
1071
1.80k
                if (ybot >= ytop)
1072
705
                    return 0;
1073
1.09k
                le.end.y = ytop;
1074
1.09k
                re.end.y = ytop;
1075
1.09k
            }
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
6.68k
            lenew.start.x = xleft;
1082
6.68k
            lenew.start.y = ybot;
1083
6.68k
            lenew.end.x   = xleft;
1084
6.68k
            lenew.end.y   = ytop;
1085
6.68k
            renew.start.x = xright;
1086
6.68k
            renew.start.y = ybot;
1087
6.68k
            renew.end.x   = xright;
1088
6.68k
            renew.end.y   = ytop;
1089
            /* Figure out where the left edge intersects with the left at
1090
             * the bottom */
1091
6.68k
            ybl = ybot;
1092
6.68k
            if (le.start.x > le.end.x) {
1093
2.54k
                ybl += (fixed)((int64_t)(le.start.x-xleft) *
1094
2.54k
                               (int64_t)(le.end.y-le.start.y) /
1095
2.54k
                               (int64_t)(le.start.x-le.end.x));
1096
2.54k
                if (ybl > ytop)
1097
979
                    ybl = ytop;
1098
2.54k
            }
1099
            /* Figure out where the right edge intersects with the right at
1100
             * the bottom */
1101
6.68k
            ybr = ybot;
1102
6.68k
            if (re.start.x < re.end.x) {
1103
2.52k
                ybr += (fixed)((int64_t)(xright-re.start.x) *
1104
2.52k
                               (int64_t)(re.end.y-re.start.y) /
1105
2.52k
                               (int64_t)(re.end.x-re.start.x));
1106
2.52k
                if (ybr > ytop)
1107
1.40k
                    ybr = ytop;
1108
2.52k
            }
1109
            /* Figure out where the left edge intersects with the left at
1110
             * the top */
1111
6.68k
            ytl = ytop;
1112
6.68k
            if (le.end.x > le.start.x) {
1113
2.41k
                ytl -= (fixed)((int64_t)(le.end.x-xleft) *
1114
2.41k
                               (int64_t)(le.end.y-le.start.y) /
1115
2.41k
                               (int64_t)(le.end.x-le.start.x));
1116
2.41k
                if (ytl < ybot)
1117
1.19k
                    ytl = ybot;
1118
2.41k
            }
1119
            /* Figure out where the right edge intersects with the right at
1120
             * the bottom */
1121
6.68k
            ytr = ytop;
1122
6.68k
            if (re.end.x < re.start.x) {
1123
2.79k
                ytr -= (fixed)((int64_t)(xright-re.end.x) *
1124
2.79k
                               (int64_t)(re.end.y-re.start.y) /
1125
2.79k
                               (int64_t)(re.start.x-re.end.x));
1126
2.79k
                if (ytr < ybot)
1127
984
                    ytr = ybot;
1128
2.79k
            }
1129
            /* Check for the 2 cases where top and bottom diagonal extents
1130
             * overlap, and deal with them explicitly. */
1131
6.68k
            if (ytl < ybr) {
1132
                /*     |     |
1133
                 *  ---+-----+---
1134
                 *     | /222|
1135
                 *     |/111/|
1136
                 *     |000/ |
1137
                 *  ---+-----+---
1138
                 *     |     |
1139
                 */
1140
1.03k
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1141
1.03k
                                        &lenew, &re, ybot, ytl,
1142
1.03k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1143
1.03k
                if (code < 0)
1144
0
                    return code;
1145
1.03k
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1146
1.03k
                                        &le, &re, ytl, ybr,
1147
1.03k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1148
1.03k
                if (code < 0)
1149
0
                    return code;
1150
1.03k
                ybot = ybr;
1151
1.03k
                return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1152
1.03k
                                        &le, &renew, ybr, ytop,
1153
1.03k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1154
5.65k
            } else if (ytr < ybl) {
1155
                /*     |     |
1156
                 *  ---+-----+----
1157
                 *     |555\ |
1158
                 *     |\444\|
1159
                 *     | \333|
1160
                 *  ---+-----+---
1161
                 *     |     |
1162
                 */
1163
1.13k
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1164
1.13k
                                        &le, &renew, ybot, ytr,
1165
1.13k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1166
1.13k
                if (code < 0)
1167
0
                    return code;
1168
1.13k
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1169
1.13k
                                        &le, &re, ytr, ybl,
1170
1.13k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1171
1.13k
                if (code < 0)
1172
0
                    return code;
1173
1.13k
                return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1174
1.13k
                                        &le, &re, ybl, ytop,
1175
1.13k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1176
1.13k
            }
1177
            /* Fill in any section where both left and right edges are
1178
             * diagonal at the bottom */
1179
4.52k
            ymid = ybl;
1180
4.52k
            if (ymid > ybr)
1181
948
                ymid = ybr;
1182
4.52k
            if (ymid > ybot) {
1183
                /*     |\   |          |   /|
1184
                 *     | \6/|    or    |\6/ |
1185
                 *  ---+----+---    ---+----+---
1186
                 *     |    |          |    |
1187
                 */
1188
331
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1189
331
                                        &le, &re, ybot, ymid,
1190
331
                                        swap_axes, pdevc, pfs->pgs->log_op);
1191
331
                if (code < 0)
1192
0
                    return code;
1193
331
                ybot = ymid;
1194
331
            }
1195
            /* Fill in any section where both left and right edges are
1196
             * diagonal at the top */
1197
4.52k
            ymid = ytl;
1198
4.52k
            if (ymid < ytr)
1199
860
                ymid = ytr;
1200
4.52k
            if (ymid < ytop) {
1201
                /*     |    |          |    |
1202
                 *  ---+----+---    ---+----+---
1203
                 *     |/7\ |    or    | /7\|
1204
                 *     |   \|          |/   |
1205
                 */
1206
435
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1207
435
                                        &le, &re, ymid, ytop,
1208
435
                                        swap_axes, pdevc, pfs->pgs->log_op);
1209
435
                if (code < 0)
1210
0
                    return code;
1211
435
                ytop = ymid;
1212
435
            }
1213
            /* Now do the single diagonal cases at the bottom */
1214
4.52k
            if (ybl > ybot) {
1215
                /*     |    |
1216
                 *     |\666|
1217
                 *  ---+----+---
1218
                 *     |    |
1219
                 */
1220
948
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1221
948
                                        &le, &renew, ybot, ybl,
1222
948
                                        swap_axes, pdevc, pfs->pgs->log_op);
1223
948
                if (code < 0)
1224
0
                    return code;
1225
948
                ybot = ybl;
1226
3.57k
            } else if (ybr > ybot) {
1227
                /*     |    |
1228
                 *     |777/|
1229
                 *  ---+----+---
1230
                 *     |    |
1231
                 */
1232
1.03k
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1233
1.03k
                                        &lenew, &re, ybot, ybr,
1234
1.03k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1235
1.03k
                if (code < 0)
1236
0
                    return code;
1237
1.03k
                ybot = ybr;
1238
1.03k
            }
1239
            /* Now do the single diagonal cases at the top */
1240
4.52k
            if (ytl < ytop) {
1241
                /*     |    |
1242
                 *  ---+----+---
1243
                 *     |/888|
1244
                 *     |    |
1245
                 */
1246
860
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1247
860
                                        &le, &renew, ytl, ytop,
1248
860
                                        swap_axes, pdevc, pfs->pgs->log_op);
1249
860
                if (code < 0)
1250
0
                    return code;
1251
860
                ytop = ytl;
1252
3.66k
            } else if (ytr < ytop) {
1253
                /*     |    |
1254
                 *  ---+----+---
1255
                 *     |999\|
1256
                 *     |    |
1257
                 */
1258
1.09k
                code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1259
1.09k
                                        &lenew, &re, ytr, ytop,
1260
1.09k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1261
1.09k
                if (code < 0)
1262
0
                    return code;
1263
1.09k
                ytop = ytr;
1264
1.09k
            }
1265
            /* And finally just whatever rectangular section is left over in
1266
             * the middle */
1267
4.52k
            if (ybot > ytop)
1268
0
                return 0;
1269
4.52k
            return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1270
4.52k
                                        &lenew, &renew, ybot, ytop,
1271
4.52k
                                        swap_axes, pdevc, pfs->pgs->log_op);
1272
4.52k
        }
1273
15.0k
    }
1274
24.9k
    return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1275
24.9k
            &le, &re, ybot, ytop, swap_axes, pdevc, pfs->pgs->log_op);
1276
33.2k
}
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
100M
#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
25.0M
{
1311
    /* Must return 2 if the color is not pure.
1312
       See try_device_linear_color.
1313
     */
1314
25.0M
    int code;
1315
25.0M
    gx_device_color devc;
1316
1317
25.0M
#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
25.0M
     if (frac_values) {
1345
18.3M
        int i;
1346
18.3M
  int n = pfs->dev->color_info.num_components;
1347
19.2M
  for (i = pfs->num_components; i < n; i++) {
1348
948k
            frac_values[i] = 0;
1349
948k
  }
1350
18.3M
    }
1351
25.0M
#endif
1352
1353
25.0M
    if (DEBUG_COLOR_INDEX_CACHE && pdevc == NULL)
1354
0
        pdevc = &devc;
1355
25.0M
    if (pfs->pcic) {
1356
18.4M
        code = gs_cached_color_index(pfs->pcic, c->cc.paint.values, pdevc, frac_values);
1357
18.4M
        if (code < 0)
1358
0
            return code;
1359
18.4M
    }
1360
25.0M
    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
6.58M
        gs_client_color fcc;
1365
6.58M
        const gs_color_space *pcs = pfs->direct_space;
1366
1367
6.58M
        if (pcs != NULL) {
1368
1369
6.58M
            if (pdevc == NULL)
1370
0
                pdevc = &devc;
1371
6.58M
            memcpy(fcc.paint.values, c->cc.paint.values,
1372
6.58M
                        sizeof(fcc.paint.values[0]) * pfs->num_components);
1373
6.58M
            code = pcs->type->remap_color(&fcc, pcs, pdevc, pfs->pgs,
1374
6.58M
                                      pfs->trans_device, gs_color_select_texture);
1375
6.58M
            if (code < 0)
1376
0
                return code;
1377
6.58M
            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
6.58M
        } 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
6.58M
    }
1401
25.0M
    return 0;
1402
25.0M
}
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
39.3M
{
1413
39.3M
    int n = pfs->num_components, i;
1414
39.3M
    double m;
1415
1416
    /* Dont want to copy colors, which are big things. */
1417
39.3M
    m = any_abs(c1->cc.paint.values[0] - c0->cc.paint.values[0]) / pfs->color_domain.paint.values[0];
1418
150M
    for (i = 1; i < n; i++)
1419
111M
        m = max(m, any_abs(c1->cc.paint.values[i] - c0->cc.paint.values[i]) / pfs->color_domain.paint.values[i]);
1420
39.3M
    return m;
1421
39.3M
}
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
9.23M
{
1426
9.23M
    int n = pfs->num_components, i;
1427
1428
45.2M
    for (i = 0; i < n; i++)
1429
35.9M
        d->cc.paint.values[i] = c1->cc.paint.values[i] - c0->cc.paint.values[i];
1430
9.23M
}
1431
1432
static inline double
1433
color_norm(const patch_fill_state_t *pfs, const patch_color_t *c)
1434
6.70M
{
1435
6.70M
    int n = pfs->num_components, i;
1436
6.70M
    double m;
1437
1438
6.70M
    m = any_abs(c->cc.paint.values[0]) / pfs->color_domain.paint.values[0];
1439
25.9M
    for (i = 1; i < n; i++)
1440
19.2M
        m = max(m, any_abs(c->cc.paint.values[i]) / pfs->color_domain.paint.values[i]);
1441
6.70M
    return m;
1442
6.70M
}
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
798k
{   /* 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
798k
    uint mask;
1462
798k
    int code = gs_function_is_monotonic(pfs->Function, c0->t, c1->t, &mask);
1463
1464
798k
    if (code >= 0)
1465
798k
        return mask;
1466
0
    return code;
1467
798k
}
1468
1469
static inline bool
1470
covers_pixel_centers(fixed ybot, fixed ytop)
1471
2.93M
{
1472
2.93M
    return fixed_pixround(ybot) < fixed_pixround(ytop);
1473
2.93M
}
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
1.29M
{
1479
1.29M
    gx_device_color dc;
1480
1.29M
    int code;
1481
1482
#   if NOFILL_TEST
1483
        /* if (dbg_nofill)
1484
                return 0; */
1485
#   endif
1486
1487
1.29M
    code = patch_color_to_device_color_inline(pfs, c, &dc, NULL);
1488
1.29M
    if (code < 0)
1489
0
        return code;
1490
1491
1.29M
    dc.tag = device_current_tag(pfs->dev);
1492
1493
1.29M
    return dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
1494
1.29M
        le, re, ybot, ytop, swap_axes, &dc, pfs->pgs->log_op);
1495
1.29M
}
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
23.1M
{
1500
23.1M
    float s = 0;
1501
1502
23.1M
    if (pfs->Function != NULL) {
1503
346k
        patch_color_t c;
1504
        /* Solaris 9 (Sun C 5.5) compiler cannot initialize a 'const' */
1505
        /* unless it is 'static const' */
1506
346k
        static const float q[2] = {(float)0.3, (float)0.7};
1507
346k
        int i, j;
1508
1509
984k
        for (j = 0; j < count_of(q); j++) {
1510
666k
            c.t[0] = c0->t[0] * (1 - q[j]) + c1->t[0] * q[j];
1511
666k
            c.t[1] = c0->t[1] * (1 - q[j]) + c1->t[1] * q[j];
1512
666k
            patch_resolve_color_inline(&c, pfs);
1513
2.11M
            for (i = 0; i < pfs->num_components; i++) {
1514
1.47M
                float v = c0->cc.paint.values[i] * (1 - q[j]) + c1->cc.paint.values[i] * q[j];
1515
1.47M
                float d = v - c.cc.paint.values[i];
1516
1.47M
                float s1 = any_abs(d) / pfs->color_domain.paint.values[i];
1517
1518
1.47M
                if (s1 > pfs->smoothness)
1519
28.9k
                    return s1;
1520
1.44M
                if (s < s1)
1521
275k
                    s = s1;
1522
1.44M
            }
1523
666k
        }
1524
346k
    }
1525
23.1M
    return s;
1526
23.1M
}
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
6.59M
{   /* returns : 1 = linear, 0 = unlinear, <0 = error. */
1531
6.59M
    if (pfs->unlinear)
1532
661k
        return 1; /* Disable this check. */
1533
5.93M
    else {
1534
5.93M
        const gs_color_space *cs = pfs->direct_space;
1535
5.93M
        int code;
1536
5.93M
        float s = function_linearity(pfs, c0, c1);
1537
1538
5.93M
        if (s > pfs->smoothness)
1539
9.28k
            return 0;
1540
5.92M
        if (pfs->cs_always_linear)
1541
0
            return 1;
1542
5.92M
        code = cs_is_linear(cs, pfs->pgs, pfs->trans_device,
1543
5.92M
                &c0->cc, &c1->cc, NULL, NULL, pfs->smoothness - s, pfs->icclink);
1544
5.92M
        if (code <= 0)
1545
7.33k
            return code;
1546
5.92M
        return 1;
1547
5.92M
    }
1548
6.59M
}
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
5.18M
{
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
5.18M
    int code;
1559
5.18M
    patch_color_t *c;
1560
5.18M
    byte *color_stack_ptr;
1561
5.18M
    bool save_inside = pfs->inside;
1562
1563
5.18M
    if (!pfs->inside) {
1564
4.49M
        gs_fixed_rect r, r1;
1565
1566
4.49M
        if(swap_axes) {
1567
2.16M
            r.p.y = min(le->start.x, le->end.x);
1568
2.16M
            r.p.x = min(le->start.y, le->end.y);
1569
2.16M
            r.q.y = max(re->start.x, re->end.x);
1570
2.16M
            r.q.x = max(re->start.y, re->end.y);
1571
2.32M
        } else {
1572
2.32M
            r.p.x = min(le->start.x, le->end.x);
1573
2.32M
            r.p.y = min(le->start.y, le->end.y);
1574
2.32M
            r.q.x = max(re->start.x, re->end.x);
1575
2.32M
            r.q.y = max(re->start.y, re->end.y);
1576
2.32M
        }
1577
4.49M
        r1 = r;
1578
4.49M
        rect_intersect(r, pfs->rect);
1579
4.49M
        if (r.q.x <= r.p.x || r.q.y <= r.p.y)
1580
2.74M
            return 0;
1581
1.74M
        if (r1.p.x == r.p.x && r1.p.y == r.p.y &&
1582
1.74M
            r1.q.x == r.q.x && r1.q.y == r.q.y)
1583
705k
            pfs->inside = true;
1584
1.74M
    }
1585
2.43M
    color_stack_ptr = reserve_colors_inline(pfs, &c, 1);
1586
2.43M
    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
2.43M
    patch_interpolate_color(c, c0, c1, pfs, 0.5);
1592
2.43M
    if (ytop - ybot < pfs->decomposition_limit) /* Prevent an infinite color decomposition. */
1593
170k
        code = constant_color_trapezoid(pfs, le, re, ybot, ytop, swap_axes, c);
1594
2.26M
    else {
1595
2.26M
        bool monotonic_color_save = pfs->monotonic_color;
1596
2.26M
        bool linear_color_save = pfs->linear_color;
1597
1598
2.26M
        if (!pfs->monotonic_color) {
1599
584k
            code = isnt_color_monotonic(pfs, c0, c1);
1600
584k
            if (code < 0)
1601
0
                goto out;
1602
584k
            if (!code)
1603
479k
                pfs->monotonic_color = true;
1604
584k
        }
1605
2.26M
        if (pfs->monotonic_color && !pfs->linear_color) {
1606
1.21M
            code = is_color_linear(pfs, c0, c1);
1607
1.21M
            if (code < 0)
1608
0
                goto out;
1609
1.21M
            if (code > 0)
1610
1.21M
                pfs->linear_color =  true;
1611
1.21M
        }
1612
2.26M
        if (!pfs->unlinear && pfs->linear_color) {
1613
553k
            gx_device *pdev = pfs->dev;
1614
553k
            frac31 fc[2][GX_DEVICE_COLOR_MAX_COMPONENTS];
1615
553k
            gs_fill_attributes fa;
1616
553k
            gs_fixed_rect clip;
1617
1618
553k
            memset(fc, 0x99, sizeof(fc));
1619
1620
553k
            clip = pfs->rect;
1621
553k
            if (swap_axes) {
1622
181k
                fixed v;
1623
1624
181k
                v = clip.p.x; clip.p.x = clip.p.y; clip.p.y = v;
1625
181k
                v = clip.q.x; clip.q.x = clip.q.y; clip.q.y = v;
1626
                /* Don't need adjust_swapped_boundary here. */
1627
181k
            }
1628
553k
            clip.p.y = max(clip.p.y, ybot);
1629
553k
            clip.q.y = min(clip.q.y, ytop);
1630
553k
            fa.clip = &clip;
1631
553k
            fa.ht = NULL;
1632
553k
            fa.swap_axes = swap_axes;
1633
553k
            fa.lop = 0;
1634
553k
            fa.ystart = ybot;
1635
553k
            fa.yend = ytop;
1636
553k
            code = patch_color_to_device_color_inline(pfs, c0, NULL, fc[0]);
1637
553k
            if (code < 0)
1638
0
                goto out;
1639
553k
            if (code == 2) {
1640
                /* Must not happen. */
1641
0
                code=gs_note_error(gs_error_unregistered);
1642
0
                goto out;
1643
0
            }
1644
553k
            code = patch_color_to_device_color_inline(pfs, c1, NULL, fc[1]);
1645
553k
            if (code < 0)
1646
0
                goto out;
1647
553k
            code = dev_proc(pdev, fill_linear_color_trapezoid)(pdev, &fa,
1648
553k
                            &le->start, &le->end, &re->start, &re->end,
1649
553k
                            fc[0], fc[1], NULL, NULL);
1650
553k
            if (code == 1) {
1651
553k
                pfs->monotonic_color = monotonic_color_save;
1652
553k
                pfs->linear_color = linear_color_save;
1653
553k
                code = 0; /* The area is filled. */
1654
553k
                goto out;
1655
553k
            }
1656
0
            if (code < 0)
1657
0
                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
0
        }
1663
1.71M
        if (!pfs->unlinear || !pfs->linear_color ||
1664
1.71M
                color_span(pfs, c0, c1) > pfs->smoothness) {
1665
585k
            fixed y = (ybot + ytop) / 2;
1666
1667
585k
            code = decompose_linear_color(pfs, le, re, ybot, y, swap_axes, c0, c);
1668
585k
            if (code >= 0)
1669
585k
                code = decompose_linear_color(pfs, le, re, y, ytop, swap_axes, c, c1);
1670
585k
        } else
1671
1.12M
            code = constant_color_trapezoid(pfs, le, re, ybot, ytop, swap_axes, c);
1672
1.71M
        pfs->monotonic_color = monotonic_color_save;
1673
1.71M
        pfs->linear_color = linear_color_save;
1674
1.71M
    }
1675
2.43M
out:
1676
2.43M
    pfs->inside = save_inside;
1677
2.43M
    release_colors_inline(pfs, color_stack_ptr, 1);
1678
2.43M
    return code;
1679
2.43M
}
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
2.07M
{
1686
    /* Assuming a very narrow trapezoid - ignore the transversal color change. */
1687
2.07M
    gs_fixed_edge le, re;
1688
1689
2.07M
    make_trapezoid(q, i0, i1, i2, i3, ybot, ytop, swap_axes, orient, &le, &re);
1690
2.07M
    return decompose_linear_color(pfs, &le, &re, ybot, ytop, swap_axes, c0, c1);
1691
2.07M
}
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
2.93M
{
1698
    /* Assuming a very narrow trapezoid - ignore the transversal color change. */
1699
2.93M
    fixed dx1, dy1, dx2, dy2;
1700
2.93M
    bool orient;
1701
1702
2.93M
    if (!pfs->vectorization && !covers_pixel_centers(ybot, ytop))
1703
861k
        return 0;
1704
2.07M
    if (ybot == ytop)
1705
0
        return 0;
1706
2.07M
    dx1 = q[1].x - q[0].x, dy1 = q[1].y - q[0].y;
1707
2.07M
    dx2 = q[2].x - q[0].x, dy2 = q[2].y - q[0].y;
1708
2.07M
    if ((int64_t)dx1 * dy2 != (int64_t)dy1 * dx2) {
1709
1.03M
        orient = ((int64_t)dx1 * dy2 > (int64_t)dy1 * dx2);
1710
1.03M
        return linear_color_trapezoid(pfs, q, 0, 1, 2, 3, ybot, ytop, swap_axes, c0, c1, orient);
1711
1.03M
    } else {
1712
1.03M
        fixed dx3 = q[3].x - q[0].x, dy3 = q[3].y - q[0].y;
1713
1714
1.03M
        orient = ((int64_t)dx1 * dy3 > (int64_t)dy1 * dx3);
1715
1.03M
        return linear_color_trapezoid(pfs, q, 0, 1, 2, 3, ybot, ytop, swap_axes, c0, c1, orient);
1716
1.03M
    }
1717
2.07M
}
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
2.93M
{
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
2.93M
    gs_fixed_point p[4];
1727
2.93M
    const patch_color_t *cc0, *cc1;
1728
1729
2.93M
    if (p0->y < p1->y) {
1730
1.42M
        p[2] = *p0;
1731
1.42M
        p[3] = *p1;
1732
1.42M
        cc0 = c0;
1733
1.42M
        cc1 = c1;
1734
1.50M
    } else {
1735
1.50M
        p[2] = *p1;
1736
1.50M
        p[3] = *p0;
1737
1.50M
        cc0 = c1;
1738
1.50M
        cc1 = c0;
1739
1.50M
    }
1740
2.93M
    p[0] = *q0;
1741
2.93M
    p[1] = *q1;
1742
2.93M
    return wedge_trap_decompose(pfs, p, p[2].y, p[3].y, cc0, cc1, swap_axes, self_intersecting);
1743
2.93M
}
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
22.6M
{
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
22.6M
#define midpoint(a,b)\
1757
271M
  (arith_rshift_1(a) + arith_rshift_1(b) + (((a) | (b)) & 1))
1758
22.6M
    fixed x12 = midpoint(pole[1 * pole_step].x, pole[2 * pole_step].x);
1759
22.6M
    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
22.6M
    q0[1 * pole_step].x = midpoint(pole[0 * pole_step].x, pole[1 * pole_step].x);
1763
22.6M
    q0[1 * pole_step].y = midpoint(pole[0 * pole_step].y, pole[1 * pole_step].y);
1764
22.6M
    q1[2 * pole_step].x = midpoint(pole[2 * pole_step].x, pole[3 * pole_step].x);
1765
22.6M
    q1[2 * pole_step].y = midpoint(pole[2 * pole_step].y, pole[3 * pole_step].y);
1766
22.6M
    q0[2 * pole_step].x = midpoint(q0[1 * pole_step].x, x12);
1767
22.6M
    q0[2 * pole_step].y = midpoint(q0[1 * pole_step].y, y12);
1768
22.6M
    q1[1 * pole_step].x = midpoint(x12, q1[2 * pole_step].x);
1769
22.6M
    q1[1 * pole_step].y = midpoint(y12, q1[2 * pole_step].y);
1770
22.6M
    q0[0 * pole_step].x = pole[0 * pole_step].x;
1771
22.6M
    q0[0 * pole_step].y = pole[0 * pole_step].y;
1772
22.6M
    q0[3 * pole_step].x = q1[0 * pole_step].x = midpoint(q0[2 * pole_step].x, q1[1 * pole_step].x);
1773
22.6M
    q0[3 * pole_step].y = q1[0 * pole_step].y = midpoint(q0[2 * pole_step].y, q1[1 * pole_step].y);
1774
22.6M
    q1[3 * pole_step].x = pole[3 * pole_step].x;
1775
22.6M
    q1[3 * pole_step].y = pole[3 * pole_step].y;
1776
22.6M
#undef midpoint
1777
22.6M
}
1778
1779
static void
1780
split_curve(const gs_fixed_point pole[4], gs_fixed_point q0[4], gs_fixed_point q1[4])
1781
479k
{
1782
479k
    split_curve_s(pole, q0, q1, 1);
1783
479k
}
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
932k
{
1826
932k
    fixed dx = any_abs(p1->x - p0->x), dy = any_abs(p1->y - p0->y);
1827
1828
932k
    return max(dx, dy);
1829
932k
}
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
808k
{
1835
808k
    if (l->end != NULL)
1836
0
        return_error(gs_error_unregistered); /* Must not happen. */
1837
808k
    l->beg = wedge_vertex_list_elem_reserve(pfs);
1838
808k
    l->end = wedge_vertex_list_elem_reserve(pfs);
1839
808k
    if (l->beg == NULL)
1840
0
        return_error(gs_error_unregistered); /* Must not happen. */
1841
808k
    if (l->end == NULL)
1842
0
        return_error(gs_error_unregistered); /* Must not happen. */
1843
808k
    l->beg->prev = l->end->next = NULL;
1844
808k
    l->beg->next = l->end;
1845
808k
    l->end->prev = l->beg;
1846
808k
    l->beg->p = *p0;
1847
808k
    l->end->p = *p1;
1848
808k
    l->beg->level = l->end->level = 0;
1849
808k
    return 0;
1850
808k
}
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
1.48M
{
1856
1.48M
    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
1.48M
    if (e == NULL)
1861
0
        return_error(gs_error_unregistered); /* Must not happen. */
1862
1.48M
    if (l->beg->next != l->end)
1863
0
        return_error(gs_error_unregistered); /* Must not happen. */
1864
1.48M
    if (l->end->prev != l->beg)
1865
0
        return_error(gs_error_unregistered); /* Must not happen. */
1866
1.48M
    e->next = l->end;
1867
1.48M
    e->prev = l->beg;
1868
1.48M
    e->p = *p;
1869
1.48M
    e->level = max(l->beg->level, l->end->level) + 1;
1870
1.48M
    e->divide_count = 0;
1871
1.48M
    l->beg->next = l->end->prev = e;
1872
1.48M
    {   int sx = l->beg->p.x < l->end->p.x ? 1 : -1;
1873
1.48M
        int sy = l->beg->p.y < l->end->p.y ? 1 : -1;
1874
1875
1.48M
        if ((p->x - l->beg->p.x) * sx < 0)
1876
0
            return_error(gs_error_unregistered); /* Must not happen. */
1877
1.48M
        if ((p->y - l->beg->p.y) * sy < 0)
1878
0
            return_error(gs_error_unregistered); /* Must not happen. */
1879
1.48M
        if ((l->end->p.x - p->x) * sx < 0)
1880
0
            return_error(gs_error_unregistered); /* Must not happen. */
1881
1.48M
        if ((l->end->p.y - p->y) * sy < 0)
1882
0
            return_error(gs_error_unregistered); /* Must not happen. */
1883
1.48M
    }
1884
1.48M
    *r = e;
1885
1.48M
    return 0;
1886
1.48M
}
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
2.48M
{
1893
2.48M
    wedge_vertex_list_elem_t *e;
1894
2.48M
    int code;
1895
1896
2.48M
    if (!l->last_side) {
1897
1.46M
        if (l->beg == NULL) {
1898
793k
            code = create_wedge_vertex_list(pfs, l, p0, p1);
1899
793k
            if (code < 0)
1900
0
                return code;
1901
793k
        }
1902
1.46M
        if (l->beg->p.x != p0->x)
1903
0
            return_error(gs_error_unregistered); /* Must not happen. */
1904
1.46M
        if (l->beg->p.y != p0->y)
1905
0
            return_error(gs_error_unregistered); /* Must not happen. */
1906
1.46M
        if (l->end->p.x != p1->x)
1907
0
            return_error(gs_error_unregistered); /* Must not happen. */
1908
1.46M
        if (l->end->p.y != p1->y)
1909
0
            return_error(gs_error_unregistered); /* Must not happen. */
1910
1.46M
        code = insert_wedge_vertex_list_elem(pfs, l, pm, &e);
1911
1.46M
        if (code < 0)
1912
0
            return code;
1913
1.46M
        e->divide_count++;
1914
1.46M
    } else if (l->beg == NULL) {
1915
15.3k
        code = create_wedge_vertex_list(pfs, l, p1, p0);
1916
15.3k
        if (code < 0)
1917
0
            return code;
1918
15.3k
        code = insert_wedge_vertex_list_elem(pfs, l, pm, &e);
1919
15.3k
        if (code < 0)
1920
0
            return code;
1921
15.3k
        e->divide_count++;
1922
1.00M
    } else {
1923
1.00M
        if (l->beg->p.x != p1->x)
1924
0
            return_error(gs_error_unregistered); /* Must not happen. */
1925
1.00M
        if (l->beg->p.y != p1->y)
1926
0
            return_error(gs_error_unregistered); /* Must not happen. */
1927
1.00M
        if (l->end->p.x != p0->x)
1928
0
            return_error(gs_error_unregistered); /* Must not happen. */
1929
1.00M
        if (l->end->p.y != p0->y)
1930
0
            return_error(gs_error_unregistered); /* Must not happen. */
1931
1.00M
        if (l->beg->next == l->end) {
1932
6.73k
            code = insert_wedge_vertex_list_elem(pfs, l, pm, &e);
1933
6.73k
            if (code < 0)
1934
0
                return code;
1935
6.73k
            e->divide_count++;
1936
997k
        } else {
1937
997k
            e = wedge_vertex_list_find(l->beg, l->end,
1938
997k
                        max(l->beg->level, l->end->level) + 1);
1939
997k
            if (e == NULL)
1940
0
                return_error(gs_error_unregistered); /* Must not happen. */
1941
997k
            if (e->p.x != pm->x || e->p.y != pm->y)
1942
0
                return_error(gs_error_unregistered); /* Must not happen. */
1943
997k
            e->divide_count++;
1944
997k
        }
1945
1.00M
    }
1946
2.48M
    *r = e;
1947
2.48M
    return 0;
1948
2.48M
}
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
2.48M
{
1955
2.48M
    int code;
1956
1957
2.48M
    l->last_side = l0->last_side;
1958
2.48M
    if (!l->last_side ^ !forth) {
1959
1.43M
        code = open_wedge_median(pfs, l0, p0, p1, pm, &l->end);
1960
1.43M
        l->beg = l0->beg;
1961
1.43M
    } else {
1962
1.05M
        code = open_wedge_median(pfs, l0, p0, p1, pm, &l->beg);
1963
1.05M
        l->end = l0->end;
1964
1.05M
    }
1965
2.48M
    return code;
1966
2.48M
}
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
2.48M
{
1975
2.48M
    int code;
1976
1977
2.48M
    if (!l->last_side)
1978
1.46M
        return 0;
1979
1.01M
    code = fill_wedge_from_list(pfs, l, c1, c0);
1980
1.01M
    if (code < 0)
1981
0
        return code;
1982
1.01M
    release_wedge_vertex_list_interval(pfs, l->beg, l->end);
1983
1.01M
    return 0;
1984
1.01M
}
1985
1986
static inline void
1987
move_wedge(wedge_vertex_list_t *l, const wedge_vertex_list_t *l0, bool forth)
1988
2.48M
{
1989
2.48M
    if (!l->last_side ^ !forth) {
1990
1.43M
        l->beg = l->end;
1991
1.43M
        l->end = l0->end;
1992
1.43M
    } else {
1993
1.05M
        l->end = l->beg;
1994
1.05M
        l->beg = l0->beg;
1995
1.05M
    }
1996
2.48M
}
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
1.46M
{   int code;
2002
1.46M
    const gs_fixed_point *p0, *p1, *p2;
2003
1.46M
    gs_fixed_point qq0, qq1, qq2;
2004
1.46M
    fixed dx = any_abs(q0->p.x - q1->p.x), dy = any_abs(q0->p.y - q1->p.y);
2005
1.46M
    bool swap_axes;
2006
2007
#   if SKIP_TEST
2008
        dbg_wedge_triangle_cnt++;
2009
#   endif
2010
1.46M
    if (dx > dy) {
2011
749k
        swap_axes = true;
2012
749k
        qq0.x = q0->p.y;
2013
749k
        qq0.y = q0->p.x;
2014
749k
        qq1.x = q1->p.y;
2015
749k
        qq1.y = q1->p.x;
2016
749k
        qq2.x = q2->p.y;
2017
749k
        qq2.y = q2->p.x;
2018
749k
        p0 = &qq0;
2019
749k
        p1 = &qq1;
2020
749k
        p2 = &qq2;
2021
749k
    } else {
2022
715k
        swap_axes = false;
2023
715k
        p0 = &q0->p;
2024
715k
        p1 = &q1->p;
2025
715k
        p2 = &q2->p;
2026
715k
    }
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
1.46M
    if (p0->y < p1->y) {
2032
712k
        code = fill_wedge_trap(pfs, p0, p2, p0, p1, q0->c, q2->c, swap_axes, false);
2033
712k
        if (code < 0)
2034
0
            return code;
2035
712k
        return fill_wedge_trap(pfs, p2, p1, p0, p1, q2->c, q1->c, swap_axes, false);
2036
752k
    } else {
2037
752k
        code = fill_wedge_trap(pfs, p0, p2, p1, p0, q0->c, q2->c, swap_axes, false);
2038
752k
        if (code < 0)
2039
0
            return code;
2040
752k
        return fill_wedge_trap(pfs, p2, p1, p1, p0, q2->c, q1->c, swap_axes, false);
2041
752k
    }
2042
1.46M
}
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
10.9M
{
2049
    /*  Returns :
2050
        <0 - error;
2051
        0 - success;
2052
        1 - decompose to linear color areas;
2053
        2 - decompose to constant color areas;
2054
     */
2055
10.9M
    int code;
2056
2057
10.9M
    if (pfs->unlinear)
2058
5.18M
        return 2;
2059
5.75M
    if (!wedge) {
2060
5.75M
        const gs_color_space *cs = pfs->direct_space;
2061
2062
5.75M
        if (cs != NULL) {
2063
5.75M
            float s0, s1, s2, s01, s012;
2064
2065
5.75M
            s0 = function_linearity(pfs, p0->c, p1->c);
2066
5.75M
            if (s0 > pfs->smoothness)
2067
11.1k
                return 1;
2068
5.74M
            s1 = function_linearity(pfs, p1->c, p2->c);
2069
5.74M
            if (s1 > pfs->smoothness)
2070
8.54k
                return 1;
2071
5.73M
            s2 = function_linearity(pfs, p2->c, p0->c);
2072
5.73M
            if (s2 > pfs->smoothness)
2073
0
                return 1;
2074
            /* fixme: check an inner color ? */
2075
5.73M
            s01 = max(s0, s1);
2076
5.73M
            s012 = max(s01, s2);
2077
5.73M
            if (pfs->cs_always_linear)
2078
0
                code = 1;
2079
5.73M
            else
2080
5.73M
                code = cs_is_linear(cs, pfs->pgs, pfs->trans_device,
2081
5.73M
                                  &p0->c->cc, &p1->c->cc, &p2->c->cc, NULL,
2082
5.73M
                                  pfs->smoothness - s012, pfs->icclink);
2083
5.73M
            if (code < 0)
2084
0
                return code;
2085
5.73M
            if (code == 0)
2086
200
                return 1;
2087
5.73M
        }
2088
5.75M
    }
2089
5.73M
    {   gx_device *pdev = pfs->dev;
2090
5.73M
        frac31 fc[3][GX_DEVICE_COLOR_MAX_COMPONENTS];
2091
5.73M
        gs_fill_attributes fa;
2092
5.73M
        gx_device_color dc[3];
2093
2094
5.73M
        fa.clip = &pfs->rect;
2095
5.73M
        fa.ht = NULL;
2096
5.73M
        fa.swap_axes = false;
2097
5.73M
        fa.lop = 0;
2098
5.73M
        code = patch_color_to_device_color_inline(pfs, p0->c, &dc[0], fc[0]);
2099
5.73M
        if (code != 0)
2100
0
            return code;
2101
5.73M
        if (!(dc[0].type == &gx_dc_type_data_pure ||
2102
5.73M
            dc[0].type == &gx_dc_type_data_devn))
2103
0
            return 2;
2104
5.73M
        if (!wedge) {
2105
5.73M
            code = patch_color_to_device_color_inline(pfs, p1->c, &dc[1], fc[1]);
2106
5.73M
            if (code != 0)
2107
0
                return code;
2108
5.73M
        }
2109
5.73M
        code = patch_color_to_device_color_inline(pfs, p2->c, &dc[2], fc[2]);
2110
5.73M
        if (code != 0)
2111
0
            return code;
2112
5.73M
        code = dev_proc(pdev, fill_linear_color_triangle)(pdev, &fa,
2113
5.73M
                        &p0->p, &p1->p, &p2->p,
2114
5.73M
                        fc[0], (wedge ? NULL : fc[1]), fc[2]);
2115
5.73M
        if (code == 1)
2116
5.73M
            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
2.69M
{
2128
2.69M
    if ((int64_t)(q1->p.x - q0->p.x) * (q2->p.y - q0->p.y) ==
2129
2.69M
        (int64_t)(q1->p.y - q0->p.y) * (q2->p.x - q0->p.x))
2130
1.23M
        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
1.46M
    return fill_triangle_wedge_aux(pfs, q0, q1, q2);
2138
2.69M
}
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
490k
{
2146
490k
    shading_vertex_t p[3];
2147
490k
    patch_color_t *c;
2148
490k
    byte *color_stack_ptr = reserve_colors_inline(pfs, &c, 1);
2149
490k
    int code;
2150
2151
490k
    if (color_stack_ptr == NULL)
2152
0
        return_error(gs_error_unregistered); /* Must not happen. */
2153
490k
    p[2].c = c;
2154
490k
    p[0].p = beg->p;
2155
490k
    p[0].c = c0;
2156
490k
    p[1].p = end->p;
2157
490k
    p[1].c = c1;
2158
490k
    p[2].p = mid->p;
2159
490k
    patch_interpolate_color(c, c0, c1, pfs, 0.5);
2160
490k
    code = fill_triangle_wedge(pfs, &p[0], &p[1], &p[2]);
2161
490k
    release_colors_inline(pfs, color_stack_ptr, 1);
2162
490k
    return code;
2163
490k
}
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
2.07M
{
2170
2.07M
    if (beg->next == end)
2171
592k
        return 0;
2172
1.48M
    else if (beg->next->next == end) {
2173
1.36M
        if (beg->next->divide_count != 1 && beg->next->divide_count != 2)
2174
0
            return_error(gs_error_unregistered); /* Must not happen. */
2175
1.36M
        if (beg->next->divide_count != 1)
2176
996k
            return 0;
2177
364k
        return fill_triangle_wedge_from_list(pfs, beg, end, beg->next, c0, c1);
2178
1.36M
    } else {
2179
125k
        gs_fixed_point p;
2180
125k
        wedge_vertex_list_elem_t *e;
2181
125k
        patch_color_t *c;
2182
125k
        int code;
2183
125k
        byte *color_stack_ptr = reserve_colors_inline(pfs, &c, 1);
2184
2185
125k
        if (color_stack_ptr == NULL)
2186
0
            return_error(gs_error_unregistered); /* Must not happen. */
2187
125k
        p.x = (beg->p.x + end->p.x) / 2;
2188
125k
        p.y = (beg->p.y + end->p.y) / 2;
2189
125k
        e = wedge_vertex_list_find(beg, end, level + 1);
2190
125k
        if (e == NULL)
2191
0
            return_error(gs_error_unregistered); /* Must not happen. */
2192
125k
        if (e->p.x != p.x || e->p.y != p.y)
2193
0
            return_error(gs_error_unregistered); /* Must not happen. */
2194
125k
        patch_interpolate_color(c, c0, c1, pfs, 0.5);
2195
125k
        code = fill_wedge_from_list_rec(pfs, beg, e, level + 1, c0, c);
2196
125k
        if (code >= 0)
2197
125k
            code = fill_wedge_from_list_rec(pfs, e, end, level + 1, c, c1);
2198
125k
        if (code >= 0) {
2199
125k
            if (e->divide_count != 1 && e->divide_count != 2)
2200
0
                return_error(gs_error_unregistered); /* Must not happen. */
2201
125k
            if (e->divide_count == 1)
2202
125k
                code = fill_triangle_wedge_from_list(pfs, beg, end, e, c0, c1);
2203
125k
        }
2204
125k
        release_colors_inline(pfs, color_stack_ptr, 1);
2205
125k
        return code;
2206
125k
    }
2207
2.07M
}
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
1.82M
{
2213
1.82M
    return fill_wedge_from_list_rec(pfs, l->beg, l->end,
2214
1.82M
                    max(l->beg->level, l->end->level), c0, c1);
2215
1.82M
}
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
22.4M
{
2221
22.4M
    if (l->beg != NULL) {
2222
808k
        int code = fill_wedge_from_list(pfs, l, c0, c1);
2223
2224
808k
        if (code < 0)
2225
0
            return code;
2226
808k
        return release_wedge_vertex_list(pfs, l, 1);
2227
808k
    }
2228
21.6M
    return 0;
2229
22.4M
}
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
454k
{   /* Assuming ka >= 2, see fill_wedges. */
2235
454k
    gs_fixed_point q[2][4];
2236
454k
    patch_color_t *c;
2237
454k
    shading_vertex_t p[3];
2238
454k
    int code;
2239
454k
    byte *color_stack_ptr = reserve_colors_inline(pfs, &c, 1);
2240
2241
454k
    if (color_stack_ptr == NULL)
2242
0
        return_error(gs_error_unregistered); /* Must not happen. */
2243
454k
    p[2].c = c;
2244
454k
    split_curve(pole, q[0], q[1]);
2245
454k
    p[0].p = pole[0];
2246
454k
    p[0].c = c0;
2247
454k
    p[1].p = pole[3];
2248
454k
    p[1].c = c1;
2249
454k
    p[2].p = q[0][3];
2250
454k
    patch_interpolate_color(c, c0, c1, pfs, 0.5);
2251
454k
    code = fill_triangle_wedge(pfs, &p[0], &p[1], &p[2]);
2252
454k
    if (code >= 0) {
2253
454k
        if (ka == 2)
2254
233k
            goto out;
2255
221k
        code = wedge_by_triangles(pfs, ka / 2, q[0], c0, p[2].c);
2256
221k
    }
2257
221k
    if (code >= 0)
2258
221k
        code = wedge_by_triangles(pfs, ka / 2, q[1], p[2].c, c1);
2259
454k
out:
2260
454k
    release_colors_inline(pfs, color_stack_ptr, 1);
2261
454k
    return code;
2262
221k
}
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
1.94M
{
2268
1.94M
    gs_fixed_point q0, q1;
2269
1.94M
    const patch_color_t *cc0, *cc1;
2270
1.94M
    fixed dx = p1->x - p0->x;
2271
1.94M
    fixed dy = p1->y - p0->y;
2272
1.94M
    bool swap_axes = (any_abs(dx) > any_abs(dy));
2273
1.94M
    gs_fixed_edge le, re;
2274
1.94M
    const fixed adjust = INTERPATCH_PADDING;
2275
2276
1.94M
    if (swap_axes) {
2277
903k
        if (p0->x < p1->x) {
2278
425k
            q0.x = p0->y;
2279
425k
            q0.y = p0->x;
2280
425k
            q1.x = p1->y;
2281
425k
            q1.y = p1->x;
2282
425k
            cc0 = c0;
2283
425k
            cc1 = c1;
2284
478k
        } else {
2285
478k
            q0.x = p1->y;
2286
478k
            q0.y = p1->x;
2287
478k
            q1.x = p0->y;
2288
478k
            q1.y = p0->x;
2289
478k
            cc0 = c1;
2290
478k
            cc1 = c0;
2291
478k
        }
2292
1.03M
    } else if (p0->y < p1->y) {
2293
319k
        q0 = *p0;
2294
319k
        q1 = *p1;
2295
319k
        cc0 = c0;
2296
319k
        cc1 = c1;
2297
719k
    } else {
2298
719k
        q0 = *p1;
2299
719k
        q1 = *p0;
2300
719k
        cc0 = c1;
2301
719k
        cc1 = c0;
2302
719k
    }
2303
1.94M
    le.start.x = q0.x - adjust;
2304
1.94M
    re.start.x = q0.x + adjust;
2305
1.94M
    le.start.y = re.start.y = q0.y - adjust;
2306
1.94M
    le.end.x = q1.x - adjust;
2307
1.94M
    re.end.x = q1.x + adjust;
2308
1.94M
    le.end.y = re.end.y = q1.y + adjust;
2309
1.94M
    adjust_swapped_boundary(&re.start.x, swap_axes);
2310
1.94M
    adjust_swapped_boundary(&re.end.x, swap_axes);
2311
1.94M
    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
1.94M
}
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
2.62M
{
2325
2.62M
    r->p.x = r->q.x = p0->x;
2326
2.62M
    r->p.y = r->q.y = p0->y;
2327
2328
2.62M
    if (r->p.x > p1->x)
2329
1.17M
        r->p.x = p1->x;
2330
2.62M
    if (r->q.x < p1->x)
2331
1.24M
        r->q.x = p1->x;
2332
2.62M
    if (r->p.y > p1->y)
2333
1.23M
        r->p.y = p1->y;
2334
2.62M
    if (r->q.y < p1->y)
2335
1.14M
        r->q.y = p1->y;
2336
2337
2.62M
    if (r->p.x > p2->x)
2338
612k
        r->p.x = p2->x;
2339
2.62M
    if (r->q.x < p2->x)
2340
630k
        r->q.x = p2->x;
2341
2.62M
    if (r->p.y > p2->y)
2342
621k
        r->p.y = p2->y;
2343
2.62M
    if (r->q.y < p2->y)
2344
620k
        r->q.y = p2->y;
2345
2346
2.62M
    if (p3 == NULL)
2347
1.76M
        return;
2348
2349
862k
    if (r->p.x > p3->x)
2350
201k
        r->p.x = p3->x;
2351
862k
    if (r->q.x < p3->x)
2352
239k
        r->q.x = p3->x;
2353
862k
    if (r->p.y > p3->y)
2354
227k
        r->p.y = p3->y;
2355
862k
    if (r->q.y < p3->y)
2356
190k
        r->q.y = p3->y;
2357
862k
}
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
215k
{
2364
215k
    int code;
2365
2366
215k
    if (k > 1) {
2367
97.8k
        gs_fixed_point q[2][4];
2368
97.8k
        patch_color_t *c;
2369
97.8k
        bool save_inside = pfs->inside;
2370
97.8k
        byte *color_stack_ptr;
2371
2372
97.8k
        if (!pfs->inside) {
2373
89.8k
            gs_fixed_rect r, r1;
2374
2375
89.8k
            bbox_of_points(&r, &pole[0], &pole[1], &pole[2], &pole[3]);
2376
89.8k
            r.p.x -= INTERPATCH_PADDING;
2377
89.8k
            r.p.y -= INTERPATCH_PADDING;
2378
89.8k
            r.q.x += INTERPATCH_PADDING;
2379
89.8k
            r.q.y += INTERPATCH_PADDING;
2380
89.8k
            r1 = r;
2381
89.8k
            rect_intersect(r, pfs->rect);
2382
89.8k
            if (r.q.x <= r.p.x || r.q.y <= r.p.y)
2383
73.6k
                return 0;
2384
16.2k
            if (r1.p.x == r.p.x && r1.p.y == r.p.y &&
2385
16.2k
                r1.q.x == r.q.x && r1.q.y == r.q.y)
2386
4.78k
                pfs->inside = true;
2387
16.2k
        }
2388
24.2k
        color_stack_ptr = reserve_colors_inline(pfs, &c, 1);
2389
24.2k
        if (color_stack_ptr == NULL)
2390
0
            return_error(gs_error_unregistered); /* Must not happen. */
2391
24.2k
        patch_interpolate_color(c, c0, c1, pfs, 0.5);
2392
24.2k
        split_curve(pole, q[0], q[1]);
2393
24.2k
        code = fill_wedges_aux(pfs, k / 2, ka, q[0], c0, c, wedge_type);
2394
24.2k
        if (code >= 0)
2395
24.2k
            code = fill_wedges_aux(pfs, k / 2, ka, q[1], c, c1, wedge_type);
2396
24.2k
        release_colors_inline(pfs, color_stack_ptr, 1);
2397
24.2k
        pfs->inside = save_inside;
2398
24.2k
        return code;
2399
117k
    } else {
2400
117k
        if ((INTERPATCH_PADDING != 0) && (wedge_type & interpatch_padding)) {
2401
111k
            code = mesh_padding(pfs, &pole[0], &pole[3], c0, c1);
2402
111k
            if (code < 0)
2403
0
                return code;
2404
111k
        }
2405
117k
        if (ka >= 2 && (wedge_type & inpatch_wedge))
2406
11.4k
            return wedge_by_triangles(pfs, ka, pole, c0, c1);
2407
106k
        return 0;
2408
117k
    }
2409
215k
}
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
1.82M
{
2417
    /* Generate wedges between 2 variants of a curve flattening. */
2418
    /* k0, k1 is a power of 2. */
2419
1.82M
    gs_fixed_point p[4];
2420
2421
1.82M
    if (!(wedge_type & interpatch_padding) && k0 == k1)
2422
1.66M
        return 0; /* Wedges are zero area. */
2423
166k
    if (k0 > k1) { /* Swap if required, so that k0 <= k1 */
2424
0
        k0 ^= k1; k1 ^= k0; k0 ^= k1;
2425
0
    }
2426
166k
    p[0] = pole[0];
2427
166k
    p[1] = pole[pole_step];
2428
166k
    p[2] = pole[pole_step * 2];
2429
166k
    p[3] = pole[pole_step * 3];
2430
166k
    return fill_wedges_aux(pfs, k0, k1 / k0, p, c0, c1, wedge_type);
2431
1.82M
}
2432
2433
static inline void
2434
make_vertices(gs_fixed_point q[4], const quadrangle_patch *p)
2435
20.3k
{
2436
20.3k
    q[0] = p->p[0][0]->p;
2437
20.3k
    q[1] = p->p[0][1]->p;
2438
20.3k
    q[2] = p->p[1][1]->p;
2439
20.3k
    q[3] = p->p[1][0]->p;
2440
20.3k
}
2441
2442
static inline void
2443
wrap_vertices_by_y(gs_fixed_point q[4], const gs_fixed_point s[4])
2444
20.3k
{
2445
20.3k
    fixed y = s[0].y;
2446
20.3k
    int i = 0;
2447
2448
20.3k
    if (y > s[1].y)
2449
6.99k
        i = 1, y = s[1].y;
2450
20.3k
    if (y > s[2].y)
2451
1.96k
        i = 2, y = s[2].y;
2452
20.3k
    if (y > s[3].y)
2453
930
        i = 3, y = s[3].y;
2454
20.3k
    q[0] = s[(i + 0) % 4];
2455
20.3k
    q[1] = s[(i + 1) % 4];
2456
20.3k
    q[2] = s[(i + 2) % 4];
2457
20.3k
    q[3] = s[(i + 3) % 4];
2458
20.3k
}
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
5.39M
{
2463
5.39M
    gs_fixed_edge ue;
2464
5.39M
    int code;
2465
5.39M
    gx_device_color dc;
2466
2467
#   if NOFILL_TEST
2468
        if (dbg_nofill)
2469
            return 0;
2470
#   endif
2471
5.39M
    code = patch_color_to_device_color_inline(pfs, c, &dc, NULL);
2472
5.39M
    if (code < 0)
2473
0
        return code;
2474
5.39M
    if (le->end.y < re->end.y) {
2475
2.26M
        code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
2476
2.26M
            le, re, le->start.y, le->end.y, false, &dc, pfs->pgs->log_op);
2477
2.26M
        if (code >= 0) {
2478
2.26M
            ue.start = le->end;
2479
2.26M
            ue.end = re->end;
2480
2.26M
            code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
2481
2.26M
                &ue, re, le->end.y, re->end.y, false, &dc, pfs->pgs->log_op);
2482
2.26M
        }
2483
3.12M
    } else if (le->end.y > re->end.y) {
2484
2.17M
        code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
2485
2.17M
            le, re, le->start.y, re->end.y, false, &dc, pfs->pgs->log_op);
2486
2.17M
        if (code >= 0) {
2487
2.17M
            ue.start = re->end;
2488
2.17M
            ue.end = le->end;
2489
2.17M
            code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
2490
2.17M
                le, &ue, re->end.y, le->end.y, false, &dc, pfs->pgs->log_op);
2491
2.17M
        }
2492
2.17M
    } else
2493
954k
        code = dev_proc(pfs->dev, fill_trapezoid)(pfs->dev,
2494
954k
            le, re, le->start.y, le->end.y, false, &dc, pfs->pgs->log_op);
2495
5.39M
    return code;
2496
5.39M
}
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
4.46M
{
2502
4.46M
    patch_color_t *c[2];
2503
4.46M
    gs_fixed_edge le, re;
2504
4.46M
    fixed dx0, dy0, dx1, dy1;
2505
4.46M
    const shading_vertex_t *pp;
2506
4.46M
    int i, code = 0;
2507
4.46M
    byte *color_stack_ptr = reserve_colors_inline(pfs, c, 2);
2508
2509
4.46M
    if (color_stack_ptr == NULL)
2510
0
        return_error(gs_error_unregistered); /* Must not happen. */
2511
4.46M
    patch_interpolate_color(c[0], p0->c, p1->c, pfs, 0.5);
2512
4.46M
    patch_interpolate_color(c[1], p2->c, c[0], pfs, 0.5);
2513
17.8M
    for (i = 0; i < 3; i++) {
2514
        /* fixme : does optimizer compiler expand this cycle ? */
2515
13.4M
        if (p0->p.y <= p1->p.y && p0->p.y <= p2->p.y) {
2516
5.39M
            le.start = re.start = p0->p;
2517
5.39M
            le.end = p1->p;
2518
5.39M
            re.end = p2->p;
2519
2520
5.39M
            dx0 = le.end.x - le.start.x;
2521
5.39M
            dy0 = le.end.y - le.start.y;
2522
5.39M
            dx1 = re.end.x - re.start.x;
2523
5.39M
            dy1 = re.end.y - re.start.y;
2524
5.39M
            if ((int64_t)dx0 * dy1 < (int64_t)dy0 * dx1)
2525
2.56M
                code = ordered_triangle(pfs, &le, &re, c[1]);
2526
2.83M
            else
2527
2.83M
                code = ordered_triangle(pfs, &re, &le, c[1]);
2528
5.39M
            if (code < 0)
2529
0
                break;
2530
5.39M
        }
2531
13.4M
        pp = p0; p0 = p1; p1 = p2; p2 = pp;
2532
13.4M
    }
2533
4.46M
    release_colors_inline(pfs, color_stack_ptr, 2);
2534
4.46M
    return code;
2535
4.46M
}
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
20.3k
{
2541
    /* Assuming the XY span is restricted with curve_samples.
2542
       It is important for intersection_of_small_bars to compute faster. */
2543
20.3k
    gs_fixed_point q[4];
2544
20.3k
    fixed ry, ey;
2545
20.3k
    int code;
2546
20.3k
    bool swap_axes = false;
2547
20.3k
    gx_device_color dc;
2548
20.3k
    bool orient;
2549
2550
20.3k
    dc.tag = device_current_tag(pfs->dev);
2551
2552
20.3k
    patch_interpolate_color(c[1], p->p[0][0]->c, p->p[0][1]->c, pfs, 0.5);
2553
20.3k
    patch_interpolate_color(c[2], p->p[1][0]->c, p->p[1][1]->c, pfs, 0.5);
2554
20.3k
    patch_interpolate_color(c[0], c[1], c[2], pfs, 0.5);
2555
20.3k
    code = patch_color_to_device_color_inline(pfs, c[0], &dc, NULL);
2556
20.3k
    if (code < 0)
2557
0
        return code;
2558
20.3k
    {   gs_fixed_point qq[4];
2559
2560
20.3k
        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
20.3k
        wrap_vertices_by_y(q, qq);
2573
20.3k
    }
2574
20.3k
    {   fixed dx1 = q[1].x - q[0].x, dy1 = q[1].y - q[0].y;
2575
20.3k
        fixed dx3 = q[3].x - q[0].x, dy3 = q[3].y - q[0].y;
2576
20.3k
        int64_t g13 = (int64_t)dx1 * dy3, h13 = (int64_t)dy1 * dx3;
2577
2578
20.3k
        if (g13 == h13) {
2579
60
            fixed dx2 = q[2].x - q[0].x, dy2 = q[2].y - q[0].y;
2580
60
            int64_t g23 = (int64_t)dx2 * dy3, h23 = (int64_t)dy2 * dx3;
2581
2582
60
            if (dx1 == 0 && dy1 == 0 && g23 == h23)
2583
0
                return 0;
2584
60
            if (g23 != h23) {
2585
60
                orient = (g23 > h23);
2586
60
                if (q[2].y <= q[3].y) {
2587
60
                    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
60
                    return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient);
2590
60
                } else {
2591
0
                    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
0
                    return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient);
2594
0
                }
2595
60
            } 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
60
        }
2612
20.3k
        orient = ((int64_t)dx1 * dy3 > (int64_t)dy1 * dx3);
2613
20.3k
    }
2614
20.3k
    if (q[1].y <= q[2].y && q[2].y <= q[3].y) {
2615
7.92k
        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
7.92k
        } else {
2624
7.92k
            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
7.92k
            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
7.92k
            return gx_shade_trapezoid(pfs, q, 2, 3, 0, 3, q[2].y, q[3].y, swap_axes, &dc, orient);
2629
7.92k
        }
2630
12.3k
    } else if (q[1].y <= q[3].y && q[3].y <= q[2].y) {
2631
4.20k
        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
4.20k
        } else {
2640
4.20k
            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
4.20k
            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
4.20k
            return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[3].y, q[2].y, swap_axes, &dc, orient);
2645
4.20k
        }
2646
8.18k
    } 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
8.18k
    } else if (q[2].y <= q[3].y && q[3].y <= q[1].y) {
2671
4
        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
4
        } 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
4
        } else {
2690
4
            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
4
            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
4
            return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient);
2695
4
        }
2696
8.18k
    } else if (q[3].y <= q[1].y && q[1].y <= q[2].y) {
2697
8.05k
        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
8.05k
        } else {
2706
8.05k
            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
8.05k
            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
8.05k
            return gx_shade_trapezoid(pfs, q, 1, 2, 3, 2, q[1].y, q[2].y, swap_axes, &dc, orient);
2711
8.05k
        }
2712
8.05k
    } else if (q[3].y <= q[2].y && q[2].y <= q[1].y) {
2713
128
        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
128
        } else {
2722
128
            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
128
            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
128
            return gx_shade_trapezoid(pfs, q, 0, 1, 2, 1, q[2].y, q[1].y, swap_axes, &dc, orient);
2727
128
        }
2728
128
    } else {
2729
        /* Impossible. */
2730
0
        return_error(gs_error_unregistered);
2731
0
    }
2732
20.3k
}
2733
2734
int
2735
constant_color_quadrangle(patch_fill_state_t *pfs, const quadrangle_patch *p, bool self_intersecting)
2736
20.3k
{
2737
20.3k
    patch_color_t *c[3];
2738
20.3k
    byte *color_stack_ptr = reserve_colors_inline(pfs, c, 3);
2739
20.3k
    int code;
2740
2741
20.3k
    if (color_stack_ptr == NULL)
2742
0
        return_error(gs_error_unregistered); /* Must not happen. */
2743
20.3k
    code = constant_color_quadrangle_aux(pfs, p, self_intersecting, c);
2744
20.3k
    release_colors_inline(pfs, color_stack_ptr, 3);
2745
20.3k
    return code;
2746
20.3k
}
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
27.2k
{
2752
27.2k
    q[0].c = c[0];
2753
27.2k
    q[1].c = c[1];
2754
27.2k
    q[0].p.x = (p->p[0][0]->p.x + p->p[1][0]->p.x) / 2;
2755
27.2k
    q[1].p.x = (p->p[0][1]->p.x + p->p[1][1]->p.x) / 2;
2756
27.2k
    q[0].p.y = (p->p[0][0]->p.y + p->p[1][0]->p.y) / 2;
2757
27.2k
    q[1].p.y = (p->p[0][1]->p.y + p->p[1][1]->p.y) / 2;
2758
27.2k
    patch_interpolate_color(c[0], p->p[0][0]->c, p->p[1][0]->c, pfs, 0.5);
2759
27.2k
    patch_interpolate_color(c[1], p->p[0][1]->c, p->p[1][1]->c, pfs, 0.5);
2760
27.2k
    s0->p[0][0] = p->p[0][0];
2761
27.2k
    s0->p[0][1] = p->p[0][1];
2762
27.2k
    s0->p[1][0] = s1->p[0][0] = &q[0];
2763
27.2k
    s0->p[1][1] = s1->p[0][1] = &q[1];
2764
27.2k
    s1->p[1][0] = p->p[1][0];
2765
27.2k
    s1->p[1][1] = p->p[1][1];
2766
27.2k
}
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
107k
{
2772
107k
    q[0].c = c[0];
2773
107k
    q[1].c = c[1];
2774
107k
    q[0].p.x = (p->p[0][0]->p.x + p->p[0][1]->p.x) / 2;
2775
107k
    q[1].p.x = (p->p[1][0]->p.x + p->p[1][1]->p.x) / 2;
2776
107k
    q[0].p.y = (p->p[0][0]->p.y + p->p[0][1]->p.y) / 2;
2777
107k
    q[1].p.y = (p->p[1][0]->p.y + p->p[1][1]->p.y) / 2;
2778
107k
    patch_interpolate_color(c[0], p->p[0][0]->c, p->p[0][1]->c, pfs, 0.5);
2779
107k
    patch_interpolate_color(c[1], p->p[1][0]->c, p->p[1][1]->c, pfs, 0.5);
2780
107k
    s0->p[0][0] = p->p[0][0];
2781
107k
    s0->p[1][0] = p->p[1][0];
2782
107k
    s0->p[0][1] = s1->p[0][0] = &q[0];
2783
107k
    s0->p[1][1] = s1->p[1][0] = &q[1];
2784
107k
    s1->p[0][1] = p->p[0][1];
2785
107k
    s1->p[1][1] = p->p[1][1];
2786
107k
}
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
213k
{   /* returns : 1 = monotonic, 0 = don't know, <0 = error. */
2792
213k
    int code, r;
2793
2794
213k
    code = isnt_color_monotonic(pfs, p->p[0][0]->c, p->p[1][1]->c);
2795
213k
    if (code <= 0)
2796
203k
        return code;
2797
10.3k
    r = code << pfs->function_arg_shift;
2798
10.3k
    if (r & 1)
2799
0
        *not_monotonic_by_u = true;
2800
10.3k
    if (r & 2)
2801
10.3k
        *not_monotonic_by_v = true;
2802
10.3k
    return !code;
2803
213k
}
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
4.83M
{
2810
    /* Assuming p.c == c for providing a non-const access. */
2811
4.83M
    p->p.x = (fixed)((int64_t)p0->p.x * (radix - 1) + p1->p.x) / radix;
2812
4.83M
    p->p.y = (fixed)((int64_t)p0->p.y * (radix - 1) + p1->p.y) / radix;
2813
4.83M
    patch_interpolate_color(c, p0->c, p1->c, pfs, (double)(radix - 1) / radix);
2814
4.83M
}
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
11.3M
{
2822
11.3M
    shading_vertex_t p01, p12, p20;
2823
11.3M
    patch_color_t *c[3];
2824
11.3M
    wedge_vertex_list_t L01, L12, L20, L[3];
2825
11.3M
    bool inside_save = pfs->inside;
2826
11.3M
    gs_fixed_rect r = {{0,0},{0,0}}, r1 =  {{0,0},{0,0}};
2827
11.3M
    int code = 0;
2828
11.3M
    byte *color_stack_ptr;
2829
11.3M
    const bool inside = pfs->inside; /* 'const' should help compiler to analyze initializations. */
2830
2831
11.3M
    if (!inside) {
2832
1.76M
        bbox_of_points(&r, &p0->p, &p1->p, &p2->p, NULL);
2833
1.76M
        r1 = r;
2834
1.76M
        rect_intersect(r, pfs->rect);
2835
1.76M
        if (r.q.x <= r.p.x || r.q.y <= r.p.y)
2836
406k
            return 0;
2837
1.76M
    }
2838
10.9M
    color_stack_ptr = reserve_colors_inline(pfs, c, 3);
2839
10.9M
    if(color_stack_ptr == NULL)
2840
0
        return_error(gs_error_unregistered);
2841
10.9M
    p01.c = c[0];
2842
10.9M
    p12.c = c[1];
2843
10.9M
    p20.c = c[2];
2844
10.9M
    code = try_device_linear_color(pfs, false, p0, p1, p2);
2845
10.9M
    switch(code) {
2846
5.73M
        case 0: /* The area is filled. */
2847
5.73M
            goto out;
2848
5.18M
        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
5.18M
            if (sd < pfs->decomposition_limit * 4) {
2853
891k
                code = constant_color_triangle(pfs, p2, p0, p1);
2854
891k
                goto out;
2855
891k
            }
2856
4.29M
            if (pfs->Function != NULL) {
2857
1.06M
                double d01 = color_span(pfs, p1->c, p0->c);
2858
1.06M
                double d12 = color_span(pfs, p2->c, p1->c);
2859
1.06M
                double d20 = color_span(pfs, p0->c, p2->c);
2860
2861
1.06M
                if (d01 <= pfs->smoothness / COLOR_CONTIGUITY &&
2862
1.06M
                    d12 <= pfs->smoothness / COLOR_CONTIGUITY &&
2863
1.06M
                    d20 <= pfs->smoothness / COLOR_CONTIGUITY) {
2864
905k
                    code = constant_color_triangle(pfs, p2, p0, p1);
2865
905k
                    goto out;
2866
905k
                }
2867
3.23M
            } else if (cd <= pfs->smoothness / COLOR_CONTIGUITY) {
2868
2.66M
                code = constant_color_triangle(pfs, p2, p0, p1);
2869
2.66M
                goto out;
2870
2.66M
            }
2871
727k
            break;
2872
727k
        case 1: /* decompose to linear color areas */
2873
19.8k
            if (sd < pfs->decomposition_limit) {
2874
8.68k
                code = constant_color_triangle(pfs, p2, p0, p1);
2875
8.68k
                goto out;
2876
8.68k
            }
2877
11.1k
            break;
2878
11.1k
        default: /* Error. */
2879
0
            goto out;
2880
10.9M
    }
2881
738k
    if (!inside) {
2882
66.3k
        if (r.p.x == r1.p.x && r.p.y == r1.p.y &&
2883
66.3k
            r.q.x == r1.q.x && r.q.y == r1.q.y)
2884
5.26k
            pfs->inside = true;
2885
66.3k
    }
2886
738k
    divide_bar(pfs, p0, p1, 2, &p01, c[0]);
2887
738k
    divide_bar(pfs, p1, p2, 2, &p12, c[1]);
2888
738k
    divide_bar(pfs, p2, p0, 2, &p20, c[2]);
2889
738k
    if (LAZY_WEDGES) {
2890
738k
        init_wedge_vertex_list(L, count_of(L));
2891
738k
        code = make_wedge_median(pfs, &L01, l01, true,  &p0->p, &p1->p, &p01.p);
2892
738k
        if (code >= 0)
2893
738k
            code = make_wedge_median(pfs, &L12, l12, true,  &p1->p, &p2->p, &p12.p);
2894
738k
        if (code >= 0)
2895
738k
            code = make_wedge_median(pfs, &L20, l20, false, &p2->p, &p0->p, &p20.p);
2896
738k
    } 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
738k
    if (code >= 0)
2904
738k
        code = triangle_by_4(pfs, p0, &p01, &p20, &L01, &L[0], &L20, cd / 2, sd / 2);
2905
738k
    if (code >= 0) {
2906
738k
        if (LAZY_WEDGES) {
2907
738k
            move_wedge(&L01, l01, true);
2908
738k
            move_wedge(&L20, l20, false);
2909
738k
        }
2910
738k
        code = triangle_by_4(pfs, p1, &p12, &p01, &L12, &L[1], &L01, cd / 2, sd / 2);
2911
738k
    }
2912
738k
    if (code >= 0) {
2913
738k
        if (LAZY_WEDGES)
2914
738k
            move_wedge(&L12, l12, true);
2915
738k
        code = triangle_by_4(pfs, p2, &p20, &p12, &L20, &L[2], &L12, cd / 2, sd / 2);
2916
738k
    }
2917
738k
    if (code >= 0) {
2918
738k
        L[0].last_side = L[1].last_side = L[2].last_side = true;
2919
738k
        code = triangle_by_4(pfs, &p01, &p12, &p20, &L[1], &L[2], &L[0], cd / 2, sd / 2);
2920
738k
    }
2921
738k
    if (LAZY_WEDGES) {
2922
738k
        if (code >= 0)
2923
738k
            code = close_wedge_median(pfs, l01, p0->c, p1->c);
2924
738k
        if (code >= 0)
2925
738k
            code = close_wedge_median(pfs, l12, p1->c, p2->c);
2926
738k
        if (code >= 0)
2927
738k
            code = close_wedge_median(pfs, l20, p2->c, p0->c);
2928
738k
        if (code >= 0)
2929
738k
            code = terminate_wedge_vertex_list(pfs, &L[0], p01.c, p20.c);
2930
738k
        if (code >= 0)
2931
738k
            code = terminate_wedge_vertex_list(pfs, &L[1], p12.c, p01.c);
2932
738k
        if (code >= 0)
2933
738k
            code = terminate_wedge_vertex_list(pfs, &L[2], p20.c, p12.c);
2934
738k
    }
2935
738k
    pfs->inside = inside_save;
2936
10.9M
out:
2937
10.9M
    release_colors_inline(pfs, color_stack_ptr, 3);
2938
10.9M
    return code;
2939
738k
}
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
8.39M
{
2946
8.39M
    fixed sd01 = max(any_abs(p1->p.x - p0->p.x), any_abs(p1->p.y - p0->p.y));
2947
8.39M
    fixed sd12 = max(any_abs(p2->p.x - p1->p.x), any_abs(p2->p.y - p1->p.y));
2948
8.39M
    fixed sd20 = max(any_abs(p0->p.x - p2->p.x), any_abs(p0->p.y - p2->p.y));
2949
8.39M
    fixed sd1 = max(sd01, sd12);
2950
8.39M
    fixed sd = max(sd1, sd20);
2951
8.39M
    double cd = 0;
2952
2953
#   if SKIP_TEST
2954
        dbg_triangle_cnt++;
2955
#   endif
2956
8.39M
    if (pfs->Function == NULL) {
2957
7.11M
        double d01 = color_span(pfs, p1->c, p0->c);
2958
7.11M
        double d12 = color_span(pfs, p2->c, p1->c);
2959
7.11M
        double d20 = color_span(pfs, p0->c, p2->c);
2960
7.11M
        double cd1 = max(d01, d12);
2961
2962
7.11M
        cd = max(cd1, d20);
2963
7.11M
    }
2964
8.39M
    return triangle_by_4(pfs, p0, p1, p2, l01, l12, l20, cd, sd);
2965
8.39M
}
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
274k
{
2971
274k
    int code;
2972
274k
    wedge_vertex_list_t l[3];
2973
2974
274k
    init_wedge_vertex_list(l, count_of(l));
2975
274k
    code = fill_triangle(pfs, p0, p1, p2, &l[0], &l[1], &l[2]);
2976
274k
    if (code < 0)
2977
0
        return code;
2978
274k
    code = terminate_wedge_vertex_list(pfs, &l[0], p0->c, p1->c);
2979
274k
    if (code < 0)
2980
0
        return code;
2981
274k
    code = terminate_wedge_vertex_list(pfs, &l[1], p1->c, p2->c);
2982
274k
    if (code < 0)
2983
0
        return code;
2984
274k
    return terminate_wedge_vertex_list(pfs, &l[2], p2->c, p0->c);
2985
274k
}
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
347k
{
3083
347k
    pfs->unlinear = !is_linear_color_applicable(pfs);
3084
347k
    if (manhattan_dist(&p0->p, &p1->p) < pfs->max_small_coord &&
3085
347k
        manhattan_dist(&p1->p, &p2->p) < pfs->max_small_coord &&
3086
347k
        manhattan_dist(&p2->p, &p0->p) < pfs->max_small_coord)
3087
274k
        return small_mesh_triangle(pfs, p0, p1, p2);
3088
72.8k
    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
72.8k
        shading_vertex_t p01, p12, p20;
3100
72.8k
        patch_color_t *c[3];
3101
72.8k
        int code;
3102
72.8k
        byte *color_stack_ptr = reserve_colors_inline(pfs, c, 3);
3103
3104
72.8k
        if (color_stack_ptr == NULL)
3105
0
            return_error(gs_error_unregistered); /* Must not happen. */
3106
72.8k
        p01.c = c[0];
3107
72.8k
        p12.c = c[1];
3108
72.8k
        p20.c = c[2];
3109
72.8k
        divide_bar(pfs, p0, p1, 2, &p01, c[0]);
3110
72.8k
        divide_bar(pfs, p1, p2, 2, &p12, c[1]);
3111
72.8k
        divide_bar(pfs, p2, p0, 2, &p20, c[2]);
3112
72.8k
        code = fill_triangle_wedge(pfs, p0, p1, &p01);
3113
72.8k
        if (code >= 0)
3114
72.8k
            code = fill_triangle_wedge(pfs, p1, p2, &p12);
3115
72.8k
        if (code >= 0)
3116
72.8k
            code = fill_triangle_wedge(pfs, p2, p0, &p20);
3117
72.8k
        if (code >= 0)
3118
72.8k
            code = mesh_triangle_rec(pfs, p0, &p01, &p20);
3119
72.8k
        if (code >= 0)
3120
72.8k
            code = mesh_triangle_rec(pfs, p1, &p12, &p01);
3121
72.8k
        if (code >= 0)
3122
72.8k
            code = mesh_triangle_rec(pfs, p2, &p20, &p12);
3123
72.8k
        if (code >= 0)
3124
72.8k
            code = mesh_triangle_rec(pfs, &p01, &p12, &p20);
3125
72.8k
        release_colors_inline(pfs, color_stack_ptr, 3);
3126
72.8k
        return code;
3127
72.8k
    }
3128
347k
}
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
56.0k
{
3134
56.0k
    if ((*dev_proc(pfs->dev, dev_spec_op))(pfs->dev,
3135
56.0k
            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
0
        gx_device *pdev = pfs->dev;
3140
0
        gx_path path;
3141
0
        int code;
3142
0
        fixed d01x = p1->p.x - p0->p.x, d01y = p1->p.y - p0->p.y;
3143
0
        fixed d12x = p2->p.x - p1->p.x, d12y = p2->p.y - p1->p.y;
3144
0
        int64_t s1 = (int64_t)d01x * d12y - (int64_t)d01y * d12x;
3145
3146
0
        gx_path_init_local(&path, pdev->memory);
3147
0
        code = gx_path_add_point(&path, p0->p.x, p0->p.y);
3148
0
        if (code >= 0 && s1 >= 0)
3149
0
            code = gx_path_add_line(&path, p1->p.x, p1->p.y);
3150
0
        if (code >= 0)
3151
0
            code = gx_path_add_line(&path, p2->p.x, p2->p.y);
3152
0
        if (code >= 0 && s1 < 0)
3153
0
            code = gx_path_add_line(&path, p1->p.x, p1->p.y);
3154
0
        if (code >= 0)
3155
0
            code = gx_path_close_subpath(&path);
3156
0
        if (code >= 0)
3157
0
            code = (*dev_proc(pfs->dev, fill_path))(pdev, NULL, &path, NULL, NULL, NULL);
3158
0
        gx_path_free(&path, "mesh_triangle");
3159
0
        if (code < 0)
3160
0
            return code;
3161
0
    }
3162
56.0k
    return mesh_triangle_rec(pfs, p0, p1, p2);
3163
56.0k
}
3164
3165
static inline int
3166
triangles4(patch_fill_state_t *pfs, const quadrangle_patch *p, bool dummy_argument)
3167
801k
{
3168
801k
    shading_vertex_t p0001, p1011, q;
3169
801k
    patch_color_t *c[3];
3170
801k
    wedge_vertex_list_t l[4];
3171
801k
    int code;
3172
801k
    byte *color_stack_ptr = reserve_colors_inline(pfs, c, 3);
3173
3174
801k
    if(color_stack_ptr == NULL)
3175
0
        return_error(gs_error_unregistered); /* Must not happen. */
3176
801k
    p0001.c = c[0];
3177
801k
    p1011.c = c[1];
3178
801k
    q.c = c[2];
3179
801k
    init_wedge_vertex_list(l, count_of(l));
3180
801k
    divide_bar(pfs, p->p[0][0], p->p[0][1], 2, &p0001, c[0]);
3181
801k
    divide_bar(pfs, p->p[1][0], p->p[1][1], 2, &p1011, c[1]);
3182
801k
    divide_bar(pfs, &p0001, &p1011, 2, &q, c[2]);
3183
801k
    code = fill_triangle(pfs, p->p[0][0], p->p[0][1], &q, p->l0001, &l[0], &l[3]);
3184
801k
    if (code >= 0) {
3185
801k
        l[0].last_side = true;
3186
801k
        l[3].last_side = true;
3187
801k
        code = fill_triangle(pfs, p->p[0][1], p->p[1][1], &q, p->l0111, &l[1], &l[0]);
3188
801k
    }
3189
801k
    if (code >= 0) {
3190
801k
        l[1].last_side = true;
3191
801k
        code = fill_triangle(pfs, p->p[1][1], p->p[1][0], &q, p->l1110, &l[2], &l[1]);
3192
801k
    }
3193
801k
    if (code >= 0) {
3194
801k
        l[2].last_side = true;
3195
801k
        code = fill_triangle(pfs, p->p[1][0], p->p[0][0], &q, p->l1000, &l[3], &l[2]);
3196
801k
    }
3197
801k
    if (code >= 0)
3198
801k
        code = terminate_wedge_vertex_list(pfs, &l[0], p->p[0][1]->c, q.c);
3199
801k
    if (code >= 0)
3200
801k
        code = terminate_wedge_vertex_list(pfs, &l[1], p->p[1][1]->c, q.c);
3201
801k
    if (code >= 0)
3202
801k
        code = terminate_wedge_vertex_list(pfs, &l[2], p->p[1][0]->c, q.c);
3203
801k
    if (code >= 0)
3204
801k
        code = terminate_wedge_vertex_list(pfs, &l[3], q.c, p->p[0][0]->c);
3205
801k
    release_colors_inline(pfs, color_stack_ptr, 3);
3206
801k
    return code;
3207
801k
}
3208
3209
static inline int
3210
triangles2(patch_fill_state_t *pfs, const quadrangle_patch *p, bool dummy_argument)
3211
2.45M
{
3212
2.45M
    wedge_vertex_list_t l;
3213
2.45M
    int code;
3214
3215
2.45M
    init_wedge_vertex_list(&l, 1);
3216
2.45M
    code = fill_triangle(pfs, p->p[0][0], p->p[0][1], p->p[1][1], p->l0001, p->l0111, &l);
3217
2.45M
    if (code < 0)
3218
0
        return code;
3219
2.45M
    l.last_side = true;
3220
2.45M
    code = fill_triangle(pfs, p->p[1][1], p->p[1][0], p->p[0][0], p->l1110, p->l1000, &l);
3221
2.45M
    if (code < 0)
3222
0
        return code;
3223
2.45M
    code = terminate_wedge_vertex_list(pfs, &l, p->p[1][1]->c, p->p[0][0]->c);
3224
2.45M
    if (code < 0)
3225
0
        return code;
3226
2.45M
    return 0;
3227
2.45M
}
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
3.39M
{
3233
3.39M
    qq[0][0].p = p->pole[0][0];
3234
3.39M
    qq[0][1].p = p->pole[0][3];
3235
3.39M
    qq[1][0].p = p->pole[3][0];
3236
3.39M
    qq[1][1].p = p->pole[3][3];
3237
3.39M
    qq[0][0].c = p->c[0][0];
3238
3.39M
    qq[0][1].c = p->c[0][1];
3239
3.39M
    qq[1][0].c = p->c[1][0];
3240
3.39M
    qq[1][1].c = p->c[1][1];
3241
3.39M
    q->p[0][0] = &qq[0][0];
3242
3.39M
    q->p[0][1] = &qq[0][1];
3243
3.39M
    q->p[1][0] = &qq[1][0];
3244
3.39M
    q->p[1][1] = &qq[1][1];
3245
3.39M
    q->l0001 = &l[0];
3246
3.39M
    q->l0111 = &l[1];
3247
3.39M
    q->l1110 = &l[2];
3248
3.39M
    q->l1000 = &l[3];
3249
3.39M
}
3250
3251
static inline int
3252
is_quadrangle_color_linear_by_u(const patch_fill_state_t *pfs, const quadrangle_patch *p)
3253
2.57M
{   /* returns : 1 = linear, 0 = unlinear, <0 = error. */
3254
2.57M
    int code;
3255
3256
2.57M
    code = is_color_linear(pfs, p->p[0][0]->c, p->p[0][1]->c);
3257
2.57M
    if (code <= 0)
3258
1
        return code;
3259
2.57M
    return is_color_linear(pfs, p->p[1][0]->c, p->p[1][1]->c);
3260
2.57M
}
3261
3262
static inline int
3263
is_quadrangle_color_linear_by_v(const patch_fill_state_t *pfs, const quadrangle_patch *p)
3264
67.3k
{   /* returns : 1 = linear, 0 = unlinear, <0 = error. */
3265
67.3k
    int code;
3266
3267
67.3k
    code = is_color_linear(pfs, p->p[0][0]->c, p->p[1][0]->c);
3268
67.3k
    if (code <= 0)
3269
8.32k
        return code;
3270
59.0k
    return is_color_linear(pfs, p->p[0][1]->c, p->p[1][1]->c);
3271
67.3k
}
3272
3273
static inline int
3274
is_quadrangle_color_linear_by_diagonals(const patch_fill_state_t *pfs, const quadrangle_patch *p)
3275
62.3k
{   /* returns : 1 = linear, 0 = unlinear, <0 = error. */
3276
62.3k
    int code;
3277
3278
62.3k
    code = is_color_linear(pfs, p->p[0][0]->c, p->p[1][1]->c);
3279
62.3k
    if (code <= 0)
3280
7.25k
        return code;
3281
55.0k
    return is_color_linear(pfs, p->p[0][1]->c, p->p[1][0]->c);
3282
62.3k
}
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
3.31M
{
3297
3.31M
    patch_color_t d0001, d1011, d;
3298
3.31M
    double D, D0001, D1011, D0010, D0111, D0011, D0110;
3299
3.31M
    double Du, Dv;
3300
3301
3.31M
    color_diff(pfs, p->p[0][0]->c, p->p[0][1]->c, &d0001);
3302
3.31M
    color_diff(pfs, p->p[1][0]->c, p->p[1][1]->c, &d1011);
3303
3.31M
    D0001 = color_norm(pfs, &d0001);
3304
3.31M
    D1011 = color_norm(pfs, &d1011);
3305
3.31M
    D0010 = color_span(pfs, p->p[0][0]->c, p->p[1][0]->c);
3306
3.31M
    D0111 = color_span(pfs, p->p[0][1]->c, p->p[1][1]->c);
3307
3.31M
    D0011 = color_span(pfs, p->p[0][0]->c, p->p[1][1]->c);
3308
3.31M
    D0110 = color_span(pfs, p->p[0][1]->c, p->p[1][0]->c);
3309
3.31M
    if (pfs->unlinear) {
3310
705k
        if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness &&
3311
705k
            D0010 <= pfs->smoothness && D0111 <= pfs->smoothness &&
3312
705k
            D0011 <= pfs->smoothness && D0110 <= pfs->smoothness)
3313
589k
            return color_change_small;
3314
115k
        if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness) {
3315
16.2k
            if (!is_big_v) {
3316
                /* The color function looks uncontiguous. */
3317
5.56k
                return color_change_small;
3318
5.56k
            }
3319
10.6k
            *divide_v = true;
3320
10.6k
            return color_change_gradient;
3321
16.2k
        }
3322
99.4k
        if (D0010 <= pfs->smoothness && D0111 <= pfs->smoothness) {
3323
98.3k
            if (!is_big_u) {
3324
                /* The color function looks uncontiguous. */
3325
7
                return color_change_small;
3326
7
            }
3327
98.3k
            *divide_u = true;
3328
98.3k
            return color_change_gradient;
3329
98.3k
        }
3330
99.4k
    }
3331
2.60M
    color_diff(pfs, &d0001, &d1011, &d);
3332
2.60M
    Du = max(D0001, D1011);
3333
2.60M
    Dv = max(D0010, D0111);
3334
2.60M
    if (Du <= pfs->smoothness / 8 && Dv <= pfs->smoothness / 8)
3335
78.9k
        return color_change_small;
3336
2.53M
    if (Du <= pfs->smoothness / 8)
3337
15.1k
        return color_change_linear;
3338
2.51M
    if (Dv <= pfs->smoothness / 8)
3339
2.44M
        return color_change_linear;
3340
74.1k
    D = color_norm(pfs, &d);
3341
74.1k
    if (D <= pfs->smoothness)
3342
64.2k
        return color_change_bilinear;
3343
9.91k
#if 1
3344
9.91k
    if (Du > Dv && is_big_u)
3345
4.81k
        *divide_u = true;
3346
5.09k
    else if (Du < Dv && is_big_v)
3347
3.84k
        *divide_v = true;
3348
1.25k
    else if (is_big_u && size_u > size_v)
3349
483
        *divide_u = true;
3350
776
    else if (is_big_v && size_v > size_u)
3351
776
        *divide_v = true;
3352
0
    else if (is_big_u)
3353
0
        *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
9.91k
    return color_change_general;
3368
9.91k
}
3369
3370
static int
3371
fill_quadrangle(patch_fill_state_t *pfs, const quadrangle_patch *p, bool big)
3372
3.66M
{
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
3.66M
    quadrangle_patch s0, s1;
3377
3.66M
    wedge_vertex_list_t l0, l1, l2;
3378
3.66M
    int code;
3379
3.66M
    bool divide_u = false, divide_v = false, big1 = big;
3380
3.66M
    shading_vertex_t q[2];
3381
3.66M
    bool monotonic_color_save = pfs->monotonic_color;
3382
3.66M
    bool linear_color_save = pfs->linear_color;
3383
3.66M
    bool inside_save = pfs->inside;
3384
3.66M
    const bool inside = pfs->inside; /* 'const' should help compiler to analyze initializations. */
3385
3.66M
    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
3.66M
    if (!inside) {
3389
773k
        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
773k
        r1 = r;
3391
773k
        rect_intersect(r, pfs->rect);
3392
773k
        if (r.q.x <= r.p.x || r.q.y <= r.p.y)
3393
253k
            return 0; /* Outside. */
3394
773k
    }
3395
3.41M
    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
3.14M
        fixed size_u = max(max(any_abs(p->p[0][0]->p.x - p->p[0][1]->p.x),
3401
3.14M
                               any_abs(p->p[1][0]->p.x - p->p[1][1]->p.x)),
3402
3.14M
                           max(any_abs(p->p[0][0]->p.y - p->p[0][1]->p.y),
3403
3.14M
                               any_abs(p->p[1][0]->p.y - p->p[1][1]->p.y)));
3404
3.14M
        fixed size_v = max(max(any_abs(p->p[0][0]->p.x - p->p[1][0]->p.x),
3405
3.14M
                               any_abs(p->p[0][1]->p.x - p->p[1][1]->p.x)),
3406
3.14M
                           max(any_abs(p->p[0][0]->p.y - p->p[1][0]->p.y),
3407
3.14M
                               any_abs(p->p[0][1]->p.y - p->p[1][1]->p.y)));
3408
3409
3.14M
        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
3.14M
            big1 = false;
3422
3.14M
    }
3423
3.41M
    if (!big1) {
3424
3.41M
        bool is_big_u = false, is_big_v = false;
3425
3.41M
        double d0001x = any_abs(p->p[0][0]->p.x - p->p[0][1]->p.x);
3426
3.41M
        double d1011x = any_abs(p->p[1][0]->p.x - p->p[1][1]->p.x);
3427
3.41M
        double d0001y = any_abs(p->p[0][0]->p.y - p->p[0][1]->p.y);
3428
3.41M
        double d1011y = any_abs(p->p[1][0]->p.y - p->p[1][1]->p.y);
3429
3.41M
        double d0010x = any_abs(p->p[0][0]->p.x - p->p[1][0]->p.x);
3430
3.41M
        double d0111x = any_abs(p->p[0][1]->p.x - p->p[1][1]->p.x);
3431
3.41M
        double d0010y = any_abs(p->p[0][0]->p.y - p->p[1][0]->p.y);
3432
3.41M
        double d0111y = any_abs(p->p[0][1]->p.y - p->p[1][1]->p.y);
3433
3.41M
        double size_u = max(max(d0001x, d1011x), max(d0001y, d1011y));
3434
3.41M
        double size_v = max(max(d0010x, d0111x), max(d0010y, d0111y));
3435
3436
3.41M
        if (size_u > pfs->decomposition_limit)
3437
3.32M
            is_big_u = true;
3438
3.41M
        if (size_v > pfs->decomposition_limit)
3439
117k
            is_big_v = true;
3440
3.29M
        else if (!is_big_u)
3441
82.7k
            return (QUADRANGLES || !pfs->maybe_self_intersecting ?
3442
80.0k
                        constant_color_quadrangle : triangles4)(pfs, p,
3443
82.7k
                            pfs->maybe_self_intersecting);
3444
3.32M
        if (!pfs->monotonic_color) {
3445
213k
            bool not_monotonic_by_u = false, not_monotonic_by_v = false;
3446
3447
213k
            code = is_quadrangle_color_monotonic(pfs, p, &not_monotonic_by_u, &not_monotonic_by_v);
3448
213k
            if (code < 0)
3449
0
                return code;
3450
213k
            if (is_big_u)
3451
212k
                divide_u = not_monotonic_by_u;
3452
213k
            if (is_big_v)
3453
16.1k
                divide_v = not_monotonic_by_v;
3454
213k
            if (!divide_u && !divide_v)
3455
206k
                pfs->monotonic_color = true;
3456
213k
        }
3457
3.32M
        if (pfs->monotonic_color && !pfs->linear_color) {
3458
3.09M
            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
3.09M
            } else if (!divide_u && !divide_v && !pfs->unlinear) {
3464
2.59M
                if (d0001x + d1011x + d0001y + d1011y > d0010x + d0111x + d0010y + d0111y) { /* fixme: use size_u, size_v */
3465
2.57M
                    code = is_quadrangle_color_linear_by_u(pfs, p);
3466
2.57M
                    if (code < 0)
3467
0
                        return code;
3468
2.57M
                    divide_u = !code;
3469
2.57M
                }
3470
2.59M
                if (is_big_v) {
3471
67.3k
                    code = is_quadrangle_color_linear_by_v(pfs, p);
3472
67.3k
                    if (code < 0)
3473
0
                        return code;
3474
67.3k
                    divide_v = !code;
3475
67.3k
                }
3476
2.59M
                if (is_big_u && is_big_v) {
3477
62.3k
                    code = is_quadrangle_color_linear_by_diagonals(pfs, p);
3478
62.3k
                    if (code < 0)
3479
0
                        return code;
3480
62.3k
                    if (!code) {
3481
7.25k
                        if (d0001x + d1011x + d0001y + d1011y > d0010x + d0111x + d0010y + d0111y) { /* fixme: use size_u, size_v */
3482
3.50k
                            divide_u = true;
3483
3.50k
                            divide_v = false;
3484
3.74k
                        } else {
3485
3.74k
                            divide_v = true;
3486
3.74k
                            divide_u = false;
3487
3.74k
                        }
3488
7.25k
                    }
3489
62.3k
                }
3490
2.59M
            }
3491
3.09M
            if (!divide_u && !divide_v)
3492
3.08M
                pfs->linear_color = true;
3493
3.09M
        }
3494
3.32M
        if (!pfs->linear_color) {
3495
            /* go to divide. */
3496
3.31M
        } else switch(quadrangle_color_change(pfs, p, is_big_u, is_big_v, size_u, size_v, &divide_u, &divide_v)) {
3497
674k
            case color_change_small:
3498
674k
                code = (QUADRANGLES || !pfs->maybe_self_intersecting ?
3499
656k
                            constant_color_quadrangle : triangles4)(pfs, p,
3500
674k
                                pfs->maybe_self_intersecting);
3501
674k
                pfs->monotonic_color = monotonic_color_save;
3502
674k
                pfs->linear_color = linear_color_save;
3503
674k
                return code;
3504
64.2k
            case color_change_bilinear:
3505
64.2k
                if (!QUADRANGLES) {
3506
64.2k
                    code = triangles4(pfs, p, true);
3507
64.2k
                    pfs->monotonic_color = monotonic_color_save;
3508
64.2k
                    pfs->linear_color = linear_color_save;
3509
64.2k
                    return code;
3510
64.2k
                }
3511
2.45M
            case color_change_linear:
3512
2.45M
                if (!QUADRANGLES) {
3513
2.45M
                    code = triangles2(pfs, p, true);
3514
2.45M
                    pfs->monotonic_color = monotonic_color_save;
3515
2.45M
                    pfs->linear_color = linear_color_save;
3516
2.45M
                    return code;
3517
2.45M
                }
3518
109k
            case color_change_gradient:
3519
118k
            case color_change_general:
3520
118k
                ; /* goto divide. */
3521
3.31M
        }
3522
3.32M
    }
3523
134k
    if (!inside) {
3524
22.9k
        if (r.p.x == r1.p.x && r.p.y == r1.p.y &&
3525
22.9k
            r.q.x == r1.q.x && r.q.y == r1.q.y)
3526
6.62k
            pfs->inside = true;
3527
22.9k
    }
3528
134k
    if (LAZY_WEDGES)
3529
134k
        init_wedge_vertex_list(&l0, 1);
3530
134k
    if (divide_v) {
3531
27.2k
        patch_color_t *c[2];
3532
27.2k
        byte *color_stack_ptr = reserve_colors_inline(pfs, c, 2);
3533
3534
27.2k
        if(color_stack_ptr == NULL)
3535
0
            return_error(gs_error_unregistered); /* Must not happen. */
3536
27.2k
        q[0].c = c[0];
3537
27.2k
        q[1].c = c[1];
3538
27.2k
        divide_quadrangle_by_v(pfs, &s0, &s1, q, p, c);
3539
27.2k
        if (LAZY_WEDGES) {
3540
27.2k
            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
27.2k
            if (code >= 0)
3542
27.2k
                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
27.2k
            if (code >= 0) {
3544
27.2k
                s0.l1110 = s1.l0001 = &l0;
3545
27.2k
                s0.l0111 = s1.l0111 = &l1;
3546
27.2k
                s0.l1000 = s1.l1000 = &l2;
3547
27.2k
                s0.l0001 = p->l0001;
3548
27.2k
                s1.l1110 = p->l1110;
3549
27.2k
            }
3550
27.2k
        } 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
27.2k
        if (code >= 0)
3556
27.2k
            code = fill_quadrangle(pfs, &s0, big1);
3557
27.2k
        if (code >= 0) {
3558
27.2k
            if (LAZY_WEDGES) {
3559
27.2k
                l0.last_side = true;
3560
27.2k
                move_wedge(&l1, p->l0111, true);
3561
27.2k
                move_wedge(&l2, p->l1000, false);
3562
27.2k
            }
3563
27.2k
            code = fill_quadrangle(pfs, &s1, big1);
3564
27.2k
        }
3565
27.2k
        if (LAZY_WEDGES) {
3566
27.2k
            if (code >= 0)
3567
27.2k
                code = close_wedge_median(pfs, p->l0111, p->p[0][1]->c, p->p[1][1]->c);
3568
27.2k
            if (code >= 0)
3569
27.2k
                code = close_wedge_median(pfs, p->l1000, p->p[1][0]->c, p->p[0][0]->c);
3570
27.2k
            if (code >= 0)
3571
27.2k
                code = terminate_wedge_vertex_list(pfs, &l0, s0.p[1][0]->c, s0.p[1][1]->c);
3572
27.2k
            release_colors_inline(pfs, color_stack_ptr, 2);
3573
27.2k
        }
3574
107k
    } else if (divide_u) {
3575
107k
        patch_color_t *c[2];
3576
107k
        byte *color_stack_ptr = reserve_colors_inline(pfs, c, 2);
3577
3578
107k
        if(color_stack_ptr == NULL)
3579
0
            return_error(gs_error_unregistered); /* Must not happen. */
3580
107k
        q[0].c = c[0];
3581
107k
        q[1].c = c[1];
3582
107k
        divide_quadrangle_by_u(pfs, &s0, &s1, q, p, c);
3583
107k
        if (LAZY_WEDGES) {
3584
107k
            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
107k
            if (code >= 0)
3586
107k
                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
107k
            if (code >= 0) {
3588
107k
                s0.l0111 = s1.l1000 = &l0;
3589
107k
                s0.l0001 = s1.l0001 = &l1;
3590
107k
                s0.l1110 = s1.l1110 = &l2;
3591
107k
                s0.l1000 = p->l1000;
3592
107k
                s1.l0111 = p->l0111;
3593
107k
            }
3594
107k
        } 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
107k
        if (code >= 0)
3600
107k
            code = fill_quadrangle(pfs, &s0, big1);
3601
107k
        if (code >= 0) {
3602
107k
            if (LAZY_WEDGES) {
3603
107k
                l0.last_side = true;
3604
107k
                move_wedge(&l1, p->l0001, true);
3605
107k
                move_wedge(&l2, p->l1110, false);
3606
107k
            }
3607
107k
            code = fill_quadrangle(pfs, &s1, big1);
3608
107k
        }
3609
107k
        if (LAZY_WEDGES) {
3610
107k
            if (code >= 0)
3611
107k
                code = close_wedge_median(pfs, p->l0001, p->p[0][0]->c, p->p[0][1]->c);
3612
107k
            if (code >= 0)
3613
107k
                code = close_wedge_median(pfs, p->l1110, p->p[1][1]->c, p->p[1][0]->c);
3614
107k
            if (code >= 0)
3615
107k
                code = terminate_wedge_vertex_list(pfs, &l0, s0.p[0][1]->c, s0.p[1][1]->c);
3616
107k
            release_colors_inline(pfs, color_stack_ptr, 2);
3617
107k
        }
3618
107k
    } else
3619
0
        code = (QUADRANGLES || !pfs->maybe_self_intersecting ?
3620
0
                    constant_color_quadrangle : triangles4)(pfs, p,
3621
0
                        pfs->maybe_self_intersecting);
3622
134k
    pfs->monotonic_color = monotonic_color_save;
3623
134k
    pfs->linear_color = linear_color_save;
3624
134k
    pfs->inside = inside_save;
3625
134k
    return code;
3626
134k
}
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
4.74M
{
3632
4.74M
    s0->c[0][1] = c[0];
3633
4.74M
    s0->c[1][1] = c[1];
3634
4.74M
    split_curve_s(p->pole[0], s0->pole[0], s1->pole[0], 1);
3635
4.74M
    split_curve_s(p->pole[1], s0->pole[1], s1->pole[1], 1);
3636
4.74M
    split_curve_s(p->pole[2], s0->pole[2], s1->pole[2], 1);
3637
4.74M
    split_curve_s(p->pole[3], s0->pole[3], s1->pole[3], 1);
3638
4.74M
    s0->c[0][0] = p->c[0][0];
3639
4.74M
    s0->c[1][0] = p->c[1][0];
3640
4.74M
    s1->c[0][0] = s0->c[0][1];
3641
4.74M
    s1->c[1][0] = s0->c[1][1];
3642
4.74M
    patch_interpolate_color(s0->c[0][1], p->c[0][0], p->c[0][1], pfs, 0.5);
3643
4.74M
    patch_interpolate_color(s0->c[1][1], p->c[1][0], p->c[1][1], pfs, 0.5);
3644
4.74M
    s1->c[0][1] = p->c[0][1];
3645
4.74M
    s1->c[1][1] = p->c[1][1];
3646
4.74M
}
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
800k
{
3652
800k
    s0->c[1][0] = c[0];
3653
800k
    s0->c[1][1] = c[1];
3654
800k
    split_curve_s(&p->pole[0][0], &s0->pole[0][0], &s1->pole[0][0], 4);
3655
800k
    split_curve_s(&p->pole[0][1], &s0->pole[0][1], &s1->pole[0][1], 4);
3656
800k
    split_curve_s(&p->pole[0][2], &s0->pole[0][2], &s1->pole[0][2], 4);
3657
800k
    split_curve_s(&p->pole[0][3], &s0->pole[0][3], &s1->pole[0][3], 4);
3658
800k
    s0->c[0][0] = p->c[0][0];
3659
800k
    s0->c[0][1] = p->c[0][1];
3660
800k
    s1->c[0][0] = s0->c[1][0];
3661
800k
    s1->c[0][1] = s0->c[1][1];
3662
800k
    patch_interpolate_color(s0->c[1][0], p->c[0][0], p->c[1][0], pfs, 0.5);
3663
800k
    patch_interpolate_color(s0->c[1][1], p->c[0][1], p->c[1][1], pfs, 0.5);
3664
800k
    s1->c[1][0] = p->c[1][0];
3665
800k
    s1->c[1][1] = p->c[1][1];
3666
800k
}
3667
3668
static inline void
3669
tensor_patch_bbox(gs_fixed_rect *r, const tensor_patch *p)
3670
5.72M
{
3671
5.72M
    int i, j;
3672
3673
5.72M
    r->p.x = r->q.x = p->pole[0][0].x;
3674
5.72M
    r->p.y = r->q.y = p->pole[0][0].y;
3675
28.6M
    for (i = 0; i < 4; i++) {
3676
114M
        for (j = 0; j < 4; j++) {
3677
91.6M
            const gs_fixed_point *q = &p->pole[i][j];
3678
3679
91.6M
            if (r->p.x > q->x)
3680
14.0M
                r->p.x = q->x;
3681
91.6M
            if (r->p.y > q->y)
3682
15.1M
                r->p.y = q->y;
3683
91.6M
            if (r->q.x < q->x)
3684
17.4M
                r->q.x = q->x;
3685
91.6M
            if (r->q.y < q->y)
3686
12.6M
                r->q.y = q->y;
3687
91.6M
        }
3688
22.9M
    }
3689
5.72M
}
3690
3691
static int
3692
decompose_stripe(patch_fill_state_t *pfs, const tensor_patch *p, int ku)
3693
10.3M
{
3694
10.3M
    if (ku > 1) {
3695
6.91M
        tensor_patch s0, s1;
3696
6.91M
        patch_color_t *c[2];
3697
6.91M
        int code;
3698
6.91M
        byte *color_stack_ptr;
3699
6.91M
        bool save_inside = pfs->inside;
3700
3701
6.91M
        if (!pfs->inside) {
3702
4.90M
            gs_fixed_rect r, r1;
3703
3704
4.90M
            tensor_patch_bbox(&r, p);
3705
4.90M
            r1 = r;
3706
4.90M
            rect_intersect(r, pfs->rect);
3707
4.90M
            if (r.q.x <= r.p.x || r.q.y <= r.p.y)
3708
2.17M
                return 0;
3709
2.72M
            if (r1.p.x == r.p.x && r1.p.y == r.p.y &&
3710
2.72M
                r1.q.x == r.q.x && r1.q.y == r.q.y)
3711
305k
                pfs->inside = true;
3712
2.72M
        }
3713
4.74M
        color_stack_ptr = reserve_colors_inline(pfs, c, 2);
3714
4.74M
        if(color_stack_ptr == NULL)
3715
0
            return_error(gs_error_unregistered); /* Must not happen. */
3716
4.74M
        split_stripe(pfs, &s0, &s1, p, c);
3717
4.74M
        code = decompose_stripe(pfs, &s0, ku / 2);
3718
4.74M
        if (code >= 0)
3719
4.74M
            code = decompose_stripe(pfs, &s1, ku / 2);
3720
4.74M
        release_colors_inline(pfs, color_stack_ptr, 2);
3721
4.74M
        pfs->inside = save_inside;
3722
4.74M
        return code;
3723
4.74M
    } else {
3724
3.39M
        quadrangle_patch q;
3725
3.39M
        shading_vertex_t qq[2][2];
3726
3.39M
        wedge_vertex_list_t l[4];
3727
3.39M
        int code;
3728
3729
3.39M
        init_wedge_vertex_list(l, count_of(l));
3730
3.39M
        make_quadrangle(p, qq, l, &q);
3731
#       if SKIP_TEST
3732
            dbg_quad_cnt++;
3733
#       endif
3734
3.39M
        code = fill_quadrangle(pfs, &q, true);
3735
3.39M
        if (code < 0)
3736
0
            return code;
3737
3.39M
        if (LAZY_WEDGES) {
3738
3.39M
            code = terminate_wedge_vertex_list(pfs, &l[0], q.p[0][0]->c, q.p[0][1]->c);
3739
3.39M
            if (code < 0)
3740
0
                return code;
3741
3.39M
            code = terminate_wedge_vertex_list(pfs, &l[1], q.p[0][1]->c, q.p[1][1]->c);
3742
3.39M
            if (code < 0)
3743
0
                return code;
3744
3.39M
            code = terminate_wedge_vertex_list(pfs, &l[2], q.p[1][1]->c, q.p[1][0]->c);
3745
3.39M
            if (code < 0)
3746
0
                return code;
3747
3.39M
            code = terminate_wedge_vertex_list(pfs, &l[3], q.p[1][0]->c, q.p[0][1]->c);
3748
3.39M
            if (code < 0)
3749
0
                return code;
3750
3.39M
        }
3751
3.39M
        return code;
3752
3.39M
    }
3753
10.3M
}
3754
3755
static int
3756
fill_stripe(patch_fill_state_t *pfs, const tensor_patch *p)
3757
831k
{
3758
    /* The stripe is flattened enough by V, so ignore inner poles. */
3759
831k
    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
831k
    ku[0] = curve_samples(pfs, p->pole[0], 1, pfs->fixed_flat);
3768
831k
    ku[3] = curve_samples(pfs, p->pole[3], 1, pfs->fixed_flat);
3769
831k
    kum = max(ku[0], ku[3]);
3770
831k
    code = fill_wedges(pfs, ku[0], kum, p->pole[0], 1, p->c[0][0], p->c[0][1], inpatch_wedge);
3771
831k
    if (code < 0)
3772
0
        return code;
3773
831k
    if (INTERPATCH_PADDING) {
3774
831k
        code = mesh_padding(pfs, &p->pole[0][0], &p->pole[3][0], p->c[0][0], p->c[1][0]);
3775
831k
        if (code < 0)
3776
0
            return code;
3777
831k
        code = mesh_padding(pfs, &p->pole[0][3], &p->pole[3][3], p->c[0][1], p->c[1][1]);
3778
831k
        if (code < 0)
3779
0
            return code;
3780
831k
    }
3781
831k
    code = decompose_stripe(pfs, p, kum);
3782
831k
    if (code < 0)
3783
0
        return code;
3784
831k
    return fill_wedges(pfs, ku[3], kum, p->pole[3], 1, p->c[1][0], p->c[1][1], inpatch_wedge);
3785
831k
}
3786
3787
static inline bool neqs(int *a, int b)
3788
2.04M
{   /* Unequal signs. Assuming -1, 0, 1 only. */
3789
2.04M
    if (*a * b < 0)
3790
764k
        return true;
3791
1.27M
    if (!*a)
3792
30.1k
        *a = b;
3793
1.27M
    return false;
3794
2.04M
}
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
2.86M
{   fixed dx1 = p1->x - p0->x, dy1 = p1->y - p0->y;
3799
2.86M
    fixed dx2 = p2->x - p0->x, dy2 = p2->y - p0->y;
3800
2.86M
    int64_t vp = (int64_t)dx1 * dy2 - (int64_t)dy1 * dx2;
3801
3802
2.86M
    return (vp > 0 ? 1 : vp < 0 ? -1 : 0);
3803
2.86M
}
3804
3805
static inline bool
3806
is_x_bended(const tensor_patch *p)
3807
821k
{
3808
821k
    int sign = vector_pair_orientation(&p->pole[0][0], &p->pole[0][1], &p->pole[1][0]);
3809
3810
821k
    if (neqs(&sign, vector_pair_orientation(&p->pole[0][1], &p->pole[0][2], &p->pole[1][1])))
3811
447k
        return true;
3812
373k
    if (neqs(&sign, vector_pair_orientation(&p->pole[0][2], &p->pole[0][3], &p->pole[1][2])))
3813
225k
        return true;
3814
148k
    if (neqs(&sign, -vector_pair_orientation(&p->pole[0][3], &p->pole[0][2], &p->pole[1][3])))
3815
88.8k
        return true;
3816
3817
59.5k
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[1][2], &p->pole[2][1])))
3818
532
        return true;
3819
59.0k
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[1][2], &p->pole[2][1])))
3820
0
        return true;
3821
59.0k
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[1][3], &p->pole[2][2])))
3822
301
        return true;
3823
58.7k
    if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[1][2], &p->pole[2][3])))
3824
299
        return true;
3825
3826
58.4k
    if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[2][2], &p->pole[3][1])))
3827
373
        return true;
3828
58.0k
    if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[2][2], &p->pole[3][1])))
3829
0
        return true;
3830
58.0k
    if (neqs(&sign, vector_pair_orientation(&p->pole[2][2], &p->pole[2][3], &p->pole[3][2])))
3831
329
        return true;
3832
57.7k
    if (neqs(&sign, -vector_pair_orientation(&p->pole[2][3], &p->pole[2][2], &p->pole[3][3])))
3833
347
        return true;
3834
3835
57.3k
    if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[3][2], &p->pole[2][1])))
3836
80
        return true;
3837
57.3k
    if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[3][2], &p->pole[2][1])))
3838
0
        return true;
3839
57.3k
    if (neqs(&sign, -vector_pair_orientation(&p->pole[3][2], &p->pole[3][3], &p->pole[2][2])))
3840
85
        return true;
3841
57.2k
    if (neqs(&sign, vector_pair_orientation(&p->pole[3][3], &p->pole[3][2], &p->pole[2][3])))
3842
81
        return true;
3843
57.1k
    return false;
3844
57.2k
}
3845
3846
static inline bool
3847
is_y_bended(const tensor_patch *p)
3848
0
{
3849
0
    int sign = vector_pair_orientation(&p->pole[0][0], &p->pole[1][0], &p->pole[0][1]);
3850
3851
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][0], &p->pole[2][0], &p->pole[1][1])))
3852
0
        return true;
3853
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[2][0], &p->pole[3][0], &p->pole[2][1])))
3854
0
        return true;
3855
0
    if (neqs(&sign, -vector_pair_orientation(&p->pole[3][0], &p->pole[2][0], &p->pole[3][1])))
3856
0
        return true;
3857
3858
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[2][1], &p->pole[1][2])))
3859
0
        return true;
3860
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][1], &p->pole[2][1], &p->pole[1][2])))
3861
0
        return true;
3862
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[2][1], &p->pole[3][1], &p->pole[2][2])))
3863
0
        return true;
3864
0
    if (neqs(&sign, -vector_pair_orientation(&p->pole[3][1], &p->pole[2][1], &p->pole[3][2])))
3865
0
        return true;
3866
3867
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[2][2], &p->pole[1][3])))
3868
0
        return true;
3869
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[1][2], &p->pole[2][2], &p->pole[1][3])))
3870
0
        return true;
3871
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[2][2], &p->pole[3][2], &p->pole[2][3])))
3872
0
        return true;
3873
0
    if (neqs(&sign, -vector_pair_orientation(&p->pole[3][2], &p->pole[2][2], &p->pole[3][3])))
3874
0
        return true;
3875
3876
0
    if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[2][3], &p->pole[1][2])))
3877
0
        return true;
3878
0
    if (neqs(&sign, -vector_pair_orientation(&p->pole[1][3], &p->pole[2][3], &p->pole[1][2])))
3879
0
        return true;
3880
0
    if (neqs(&sign, -vector_pair_orientation(&p->pole[2][3], &p->pole[3][3], &p->pole[2][2])))
3881
0
        return true;
3882
0
    if (neqs(&sign, vector_pair_orientation(&p->pole[3][3], &p->pole[2][3], &p->pole[3][2])))
3883
0
        return true;
3884
0
    return false;
3885
0
}
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
4.91M
{   /* Is curve within a single pixel, or smaller than half pixel ? */
3890
4.91M
    fixed xmin0 = min(pole[0 * pole_step].x, pole[1 * pole_step].x);
3891
4.91M
    fixed xmin1 = min(pole[2 * pole_step].x, pole[3 * pole_step].x);
3892
4.91M
    fixed xmin =  min(xmin0, xmin1);
3893
4.91M
    fixed xmax0 = max(pole[0 * pole_step].x, pole[1 * pole_step].x);
3894
4.91M
    fixed xmax1 = max(pole[2 * pole_step].x, pole[3 * pole_step].x);
3895
4.91M
    fixed xmax =  max(xmax0, xmax1);
3896
3897
4.91M
    if(xmax - xmin <= pfs->decomposition_limit)
3898
4.21M
        return true;
3899
701k
    return false;
3900
4.91M
}
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
3.35M
{   /* Is curve within a single pixel, or smaller than half pixel ? */
3905
3.35M
    fixed ymin0 = min(pole[0 * pole_step].y, pole[1 * pole_step].y);
3906
3.35M
    fixed ymin1 = min(pole[2 * pole_step].y, pole[3 * pole_step].y);
3907
3.35M
    fixed ymin =  min(ymin0, ymin1);
3908
3.35M
    fixed ymax0 = max(pole[0 * pole_step].y, pole[1 * pole_step].y);
3909
3.35M
    fixed ymax1 = max(pole[2 * pole_step].y, pole[3 * pole_step].y);
3910
3.35M
    fixed ymax =  max(ymax0, ymax1);
3911
3912
3.35M
    if (ymax - ymin <= pfs->decomposition_limit)
3913
3.23M
        return true;
3914
119k
    return false;
3915
3.35M
}
3916
3917
static inline bool
3918
is_patch_narrow(const patch_fill_state_t *pfs, const tensor_patch *p)
3919
1.59M
{
3920
1.59M
    if (!is_curve_x_small(pfs, &p->pole[0][0], 4, pfs->fixed_flat))
3921
311k
        return false;
3922
1.28M
    if (!is_curve_x_small(pfs, &p->pole[0][1], 4, pfs->fixed_flat))
3923
204k
        return false;
3924
1.07M
    if (!is_curve_x_small(pfs, &p->pole[0][2], 4, pfs->fixed_flat))
3925
122k
        return false;
3926
956k
    if (!is_curve_x_small(pfs, &p->pole[0][3], 4, pfs->fixed_flat))
3927
62.6k
        return false;
3928
893k
    if (!is_curve_y_small(pfs, &p->pole[0][0], 4, pfs->fixed_flat))
3929
40.2k
        return false;
3930
853k
    if (!is_curve_y_small(pfs, &p->pole[0][1], 4, pfs->fixed_flat))
3931
35.0k
        return false;
3932
818k
    if (!is_curve_y_small(pfs, &p->pole[0][2], 4, pfs->fixed_flat))
3933
25.6k
        return false;
3934
792k
    if (!is_curve_y_small(pfs, &p->pole[0][3], 4, pfs->fixed_flat))
3935
18.6k
        return false;
3936
773k
    return true;
3937
792k
}
3938
3939
static int
3940
fill_patch(patch_fill_state_t *pfs, const tensor_patch *p, int kv, int kv0, int kv1)
3941
1.68M
{
3942
1.68M
    if (kv <= 1) {
3943
1.59M
        if (is_patch_narrow(pfs, p))
3944
773k
            return fill_stripe(pfs, p);
3945
821k
        if (!is_x_bended(p))
3946
57.1k
            return fill_stripe(pfs, p);
3947
821k
    }
3948
851k
    {   tensor_patch s0, s1;
3949
851k
        patch_color_t *c[2];
3950
851k
        shading_vertex_t q0, q1, q2;
3951
851k
        int code = 0;
3952
851k
        byte *color_stack_ptr;
3953
851k
        bool save_inside = pfs->inside;
3954
3955
851k
        if (!pfs->inside) {
3956
826k
            gs_fixed_rect r, r1;
3957
3958
826k
            tensor_patch_bbox(&r, p);
3959
826k
            r.p.x -= INTERPATCH_PADDING;
3960
826k
            r.p.y -= INTERPATCH_PADDING;
3961
826k
            r.q.x += INTERPATCH_PADDING;
3962
826k
            r.q.y += INTERPATCH_PADDING;
3963
826k
            r1 = r;
3964
826k
            rect_intersect(r, pfs->rect);
3965
826k
            if (r.q.x <= r.p.x || r.q.y <= r.p.y)
3966
51.5k
                return 0;
3967
774k
            if (r1.p.x == r.p.x && r1.p.y == r.p.y &&
3968
774k
                r1.q.x == r.q.x && r1.q.y == r.q.y)
3969
4.66k
                pfs->inside = true;
3970
774k
        }
3971
800k
        color_stack_ptr = reserve_colors_inline(pfs, c, 2);
3972
800k
        if(color_stack_ptr == NULL)
3973
0
            return_error(gs_error_unregistered); /* Must not happen. */
3974
800k
        split_patch(pfs, &s0, &s1, p, c);
3975
800k
        if (kv0 <= 1) {
3976
768k
            q0.p = s0.pole[0][0];
3977
768k
            q0.c = s0.c[0][0];
3978
768k
            q1.p = s1.pole[3][0];
3979
768k
            q1.c = s1.c[1][0];
3980
768k
            q2.p = s0.pole[3][0];
3981
768k
            q2.c = s0.c[1][0];
3982
768k
            code = fill_triangle_wedge(pfs, &q0, &q1, &q2);
3983
768k
        }
3984
800k
        if (kv1 <= 1 && code >= 0) {
3985
767k
            q0.p = s0.pole[0][3];
3986
767k
            q0.c = s0.c[0][1];
3987
767k
            q1.p = s1.pole[3][3];
3988
767k
            q1.c = s1.c[1][1];
3989
767k
            q2.p = s0.pole[3][3];
3990
767k
            q2.c = s0.c[1][1];
3991
767k
            code = fill_triangle_wedge(pfs, &q0, &q1, &q2);
3992
767k
        }
3993
800k
        if (code >= 0)
3994
800k
            code = fill_patch(pfs, &s0, kv / 2, kv0 / 2, kv1 / 2);
3995
800k
        if (code >= 0)
3996
800k
            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
800k
        release_colors_inline(pfs, color_stack_ptr, 2);
4017
800k
        pfs->inside = save_inside;
4018
800k
        return code;
4019
800k
    }
4020
800k
}
4021
4022
static inline int64_t
4023
lcp1(int64_t p0, int64_t p3)
4024
177k
{   /* Computing the 1st pole of a 3d order besier, which appears a line. */
4025
177k
    return (p0 + p0 + p3);
4026
177k
}
4027
static inline int64_t
4028
lcp2(int64_t p0, int64_t p3)
4029
177k
{   /* Computing the 2nd pole of a 3d order besier, which appears a line. */
4030
177k
    return (p0 + p3 + p3);
4031
177k
}
4032
4033
static void
4034
patch_set_color(const patch_fill_state_t *pfs, patch_color_t *c, const float *cc)
4035
330k
{
4036
330k
    if (pfs->Function) {
4037
35.5k
        c->t[0] = cc[0];
4038
35.5k
        c->t[1] = cc[1];
4039
35.5k
    } else
4040
294k
        memcpy(c->cc.paint.values, cc, sizeof(c->cc.paint.values[0]) * pfs->num_components);
4041
330k
}
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
82.5k
{
4047
82.5k
    const gs_color_space *pcs = pfs->direct_space;
4048
4049
82.5k
    p->pole[0][0] = curve[0].vertex.p;
4050
82.5k
    p->pole[1][0] = curve[0].control[0];
4051
82.5k
    p->pole[2][0] = curve[0].control[1];
4052
82.5k
    p->pole[3][0] = curve[1].vertex.p;
4053
82.5k
    p->pole[3][1] = curve[1].control[0];
4054
82.5k
    p->pole[3][2] = curve[1].control[1];
4055
82.5k
    p->pole[3][3] = curve[2].vertex.p;
4056
82.5k
    p->pole[2][3] = curve[2].control[0];
4057
82.5k
    p->pole[1][3] = curve[2].control[1];
4058
82.5k
    p->pole[0][3] = curve[3].vertex.p;
4059
82.5k
    p->pole[0][2] = curve[3].control[0];
4060
82.5k
    p->pole[0][1] = curve[3].control[1];
4061
82.5k
    if (interior != NULL) {
4062
73.6k
        p->pole[1][1] = interior[0];
4063
73.6k
        p->pole[1][2] = interior[1];
4064
73.6k
        p->pole[2][2] = interior[2];
4065
73.6k
        p->pole[2][1] = interior[3];
4066
73.6k
    } else {
4067
8.88k
        p->pole[1][1].x = (fixed)((3*(lcp1(p->pole[0][1].x, p->pole[3][1].x) +
4068
8.88k
                                      lcp1(p->pole[1][0].x, p->pole[1][3].x)) -
4069
8.88k
                                   lcp1(lcp1(p->pole[0][0].x, p->pole[0][3].x),
4070
8.88k
                                        lcp1(p->pole[3][0].x, p->pole[3][3].x)))/9);
4071
8.88k
        p->pole[1][2].x = (fixed)((3*(lcp1(p->pole[0][2].x, p->pole[3][2].x) +
4072
8.88k
                                      lcp2(p->pole[1][0].x, p->pole[1][3].x)) -
4073
8.88k
                                   lcp1(lcp2(p->pole[0][0].x, p->pole[0][3].x),
4074
8.88k
                                        lcp2(p->pole[3][0].x, p->pole[3][3].x)))/9);
4075
8.88k
        p->pole[2][1].x = (fixed)((3*(lcp2(p->pole[0][1].x, p->pole[3][1].x) +
4076
8.88k
                                      lcp1(p->pole[2][0].x, p->pole[2][3].x)) -
4077
8.88k
                                   lcp2(lcp1(p->pole[0][0].x, p->pole[0][3].x),
4078
8.88k
                                        lcp1(p->pole[3][0].x, p->pole[3][3].x)))/9);
4079
8.88k
        p->pole[2][2].x = (fixed)((3*(lcp2(p->pole[0][2].x, p->pole[3][2].x) +
4080
8.88k
                                      lcp2(p->pole[2][0].x, p->pole[2][3].x)) -
4081
8.88k
                                   lcp2(lcp2(p->pole[0][0].x, p->pole[0][3].x),
4082
8.88k
                                        lcp2(p->pole[3][0].x, p->pole[3][3].x)))/9);
4083
4084
8.88k
        p->pole[1][1].y = (fixed)((3*(lcp1(p->pole[0][1].y, p->pole[3][1].y) +
4085
8.88k
                                      lcp1(p->pole[1][0].y, p->pole[1][3].y)) -
4086
8.88k
                                   lcp1(lcp1(p->pole[0][0].y, p->pole[0][3].y),
4087
8.88k
                                        lcp1(p->pole[3][0].y, p->pole[3][3].y)))/9);
4088
8.88k
        p->pole[1][2].y = (fixed)((3*(lcp1(p->pole[0][2].y, p->pole[3][2].y) +
4089
8.88k
                                      lcp2(p->pole[1][0].y, p->pole[1][3].y)) -
4090
8.88k
                                   lcp1(lcp2(p->pole[0][0].y, p->pole[0][3].y),
4091
8.88k
                                        lcp2(p->pole[3][0].y, p->pole[3][3].y)))/9);
4092
8.88k
        p->pole[2][1].y = (fixed)((3*(lcp2(p->pole[0][1].y, p->pole[3][1].y) +
4093
8.88k
                                      lcp1(p->pole[2][0].y, p->pole[2][3].y)) -
4094
8.88k
                                   lcp2(lcp1(p->pole[0][0].y, p->pole[0][3].y),
4095
8.88k
                                        lcp1(p->pole[3][0].y, p->pole[3][3].y)))/9);
4096
8.88k
        p->pole[2][2].y = (fixed)((3*(lcp2(p->pole[0][2].y, p->pole[3][2].y) +
4097
8.88k
                                      lcp2(p->pole[2][0].y, p->pole[2][3].y)) -
4098
8.88k
                                   lcp2(lcp2(p->pole[0][0].y, p->pole[0][3].y),
4099
8.88k
                                        lcp2(p->pole[3][0].y, p->pole[3][3].y)))/9);
4100
8.88k
    }
4101
82.5k
    patch_set_color(pfs, p->c[0][0], curve[0].vertex.cc);
4102
82.5k
    patch_set_color(pfs, p->c[1][0], curve[1].vertex.cc);
4103
82.5k
    patch_set_color(pfs, p->c[1][1], curve[2].vertex.cc);
4104
82.5k
    patch_set_color(pfs, p->c[0][1], curve[3].vertex.cc);
4105
82.5k
    patch_resolve_color_inline(p->c[0][0], pfs);
4106
82.5k
    patch_resolve_color_inline(p->c[0][1], pfs);
4107
82.5k
    patch_resolve_color_inline(p->c[1][0], pfs);
4108
82.5k
    patch_resolve_color_inline(p->c[1][1], pfs);
4109
82.5k
    if (!pfs->Function) {
4110
73.6k
        pcs->type->restrict_color(&p->c[0][0]->cc, pcs);
4111
73.6k
        pcs->type->restrict_color(&p->c[0][1]->cc, pcs);
4112
73.6k
        pcs->type->restrict_color(&p->c[1][0]->cc, pcs);
4113
73.6k
        pcs->type->restrict_color(&p->c[1][1]->cc, pcs);
4114
73.6k
    }
4115
82.5k
}
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
4
{
4121
4
    gs_fixed_edge le, re;
4122
4123
4
    le.start.x = rect->p.x - INTERPATCH_PADDING;
4124
4
    le.start.y = rect->p.y - INTERPATCH_PADDING;
4125
4
    le.end.x = rect->p.x - INTERPATCH_PADDING;
4126
4
    le.end.y = rect->q.y + INTERPATCH_PADDING;
4127
4
    re.start.x = rect->q.x + INTERPATCH_PADDING;
4128
4
    re.start.y = rect->p.y - INTERPATCH_PADDING;
4129
4
    re.end.x = rect->q.x + INTERPATCH_PADDING;
4130
4
    re.end.y = rect->q.y + INTERPATCH_PADDING;
4131
4
    return dev_proc(pdev, fill_trapezoid)(pdev,
4132
4
            &le, &re, le.start.y, le.end.y, false, pdevc, log_op);
4133
4
}
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
82.5k
{
4141
82.5k
    tensor_patch p;
4142
82.5k
    patch_color_t *c[4];
4143
82.5k
    int kv[4], kvm, ku[4], kum;
4144
82.5k
    int code = 0;
4145
82.5k
    byte *color_stack_ptr = reserve_colors_inline(pfs, c, 4); /* Can't fail */
4146
4147
82.5k
    p.c[0][0] = c[0];
4148
82.5k
    p.c[0][1] = c[1];
4149
82.5k
    p.c[1][0] = c[2];
4150
82.5k
    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
82.5k
    make_tensor_patch(pfs, &p, curve, interior);
4159
82.5k
    pfs->unlinear = !is_linear_color_applicable(pfs);
4160
82.5k
    pfs->linear_color = false;
4161
82.5k
    if ((*dev_proc(pfs->dev, dev_spec_op))(pfs->dev,
4162
82.5k
            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
0
        gx_device *pdev = pfs->dev;
4167
0
        gx_path path;
4168
0
        fixed d01x = (curve[1].vertex.p.x - curve[0].vertex.p.x) >> 1;
4169
0
        fixed d01y = (curve[1].vertex.p.y - curve[0].vertex.p.y) >> 1;
4170
0
        fixed d12x = (curve[2].vertex.p.x - curve[1].vertex.p.x) >> 1;
4171
0
        fixed d12y = (curve[2].vertex.p.y - curve[1].vertex.p.y) >> 1;
4172
0
        fixed d23x = (curve[3].vertex.p.x - curve[2].vertex.p.x) >> 1;
4173
0
        fixed d23y = (curve[3].vertex.p.y - curve[2].vertex.p.y) >> 1;
4174
0
        fixed d30x = (curve[0].vertex.p.x - curve[3].vertex.p.x) >> 1;
4175
0
        fixed d30y = (curve[0].vertex.p.y - curve[3].vertex.p.y) >> 1;
4176
0
        int64_t s1 = (int64_t)d01x * d12y - (int64_t)d01y * d12x;
4177
0
        int64_t s2 = (int64_t)d23x * d30y - (int64_t)d23y * d30x;
4178
0
        int s = (s1 + s2 > 0 ? 1 : 3), i, j, k, jj, l = (s == 1 ? 0 : 1);
4179
4180
0
        gx_path_init_local(&path, pdev->memory);
4181
0
        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
0
        } else {
4187
0
            code = gx_path_add_point(&path, curve[0].vertex.p.x, curve[0].vertex.p.y);
4188
0
            for (i = k = 0; k < 4 && code >= 0; i = j, k++) {
4189
0
                j = (i + s) % 4, jj = (s == 1 ? i : j);
4190
0
                if (curve[jj].straight)
4191
0
                    code = gx_path_add_line(&path, curve[j].vertex.p.x,
4192
0
                                                curve[j].vertex.p.y);
4193
0
                else
4194
0
                    code = gx_path_add_curve(&path, curve[jj].control[l].x, curve[jj].control[l].y,
4195
0
                                                    curve[jj].control[(l + 1) & 1].x, curve[jj].control[(l + 1) & 1].y,
4196
0
                                                    curve[j].vertex.p.x,
4197
0
                                                    curve[j].vertex.p.y);
4198
0
            }
4199
0
            if (code >= 0)
4200
0
                code = gx_path_close_subpath(&path);
4201
0
        }
4202
0
        if (code >= 0)
4203
0
            code = (*dev_proc(pfs->dev, fill_path))(pdev, NULL, &path, NULL, NULL, NULL);
4204
0
        gx_path_free(&path, "patch_fill");
4205
0
        if (code < 0)
4206
0
            goto out;
4207
0
    }
4208
    /* How many subdivisions of the patch in the u and v direction? */
4209
82.5k
    kv[0] = curve_samples(pfs, &p.pole[0][0], 4, pfs->fixed_flat);
4210
82.5k
    kv[1] = curve_samples(pfs, &p.pole[0][1], 4, pfs->fixed_flat);
4211
82.5k
    kv[2] = curve_samples(pfs, &p.pole[0][2], 4, pfs->fixed_flat);
4212
82.5k
    kv[3] = curve_samples(pfs, &p.pole[0][3], 4, pfs->fixed_flat);
4213
82.5k
    kvm = max(max(kv[0], kv[1]), max(kv[2], kv[3]));
4214
82.5k
    ku[0] = curve_samples(pfs, p.pole[0], 1, pfs->fixed_flat);
4215
82.5k
    ku[1] = curve_samples(pfs, p.pole[1], 1, pfs->fixed_flat);
4216
82.5k
    ku[2] = curve_samples(pfs, p.pole[2], 1, pfs->fixed_flat);
4217
82.5k
    ku[3] = curve_samples(pfs, p.pole[3], 1, pfs->fixed_flat);
4218
82.5k
    kum = max(max(ku[0], ku[1]), max(ku[2], ku[3]));
4219
#   if NOFILL_TEST
4220
    dbg_nofill = false;
4221
#   endif
4222
82.5k
    code = fill_wedges(pfs, ku[0], kum, p.pole[0], 1, p.c[0][0], p.c[0][1],
4223
82.5k
        interpatch_padding | inpatch_wedge);
4224
82.5k
    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
82.5k
            code = fill_patch(pfs, &p, kvm, kv[0], kv[3]);
4237
82.5k
    }
4238
82.5k
    if (code >= 0)
4239
82.5k
        code = fill_wedges(pfs, ku[3], kum, p.pole[3], 1, p.c[1][0], p.c[1][1],
4240
82.5k
                interpatch_padding | inpatch_wedge);
4241
82.5k
out:
4242
82.5k
    release_colors_inline(pfs, color_stack_ptr, 4);
4243
82.5k
    return code;
4244
82.5k
}