Coverage Report

Created: 2025-06-10 07:24

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