Coverage Report

Created: 2025-06-10 07:26

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