Coverage Report

Created: 2025-06-10 06:49

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