Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxshade1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Rendering for non-mesh shadings */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsmatrix.h"   /* for gscoord.h */
23
#include "gscoord.h"
24
#include "gspath.h"
25
#include "gsptype2.h"
26
#include "gxcspace.h"
27
#include "gxdcolor.h"
28
#include "gxfarith.h"
29
#include "gxfixed.h"
30
#include "gxgstate.h"
31
#include "gxpath.h"
32
#include "gxshade.h"
33
#include "gxdevcli.h"
34
#include "gxshade4.h"
35
#include "gsicc_cache.h"
36
37
/* ---------------- Function-based shading ---------------- */
38
39
typedef struct Fb_frame_s { /* A rudiment of old code. */
40
    gs_rect region;
41
    gs_client_color cc[4];  /* colors at 4 corners */
42
    int state;
43
} Fb_frame_t;
44
45
typedef struct Fb_fill_state_s {
46
    shading_fill_state_common;
47
    const gs_shading_Fb_t *psh;
48
    gs_matrix_fixed ptm;  /* parameter space -> device space */
49
    Fb_frame_t frame;
50
} Fb_fill_state_t;
51
/****** NEED GC DESCRIPTOR ******/
52
53
static inline void
54
make_other_poles(patch_curve_t curve[4])
55
45.2k
{
56
45.2k
    int i, j;
57
58
226k
    for (i = 0; i < 4; i++) {
59
181k
        j = (i + 1) % 4;
60
181k
        curve[i].control[0].x = (curve[i].vertex.p.x * 2 + curve[j].vertex.p.x) / 3;
61
181k
        curve[i].control[0].y = (curve[i].vertex.p.y * 2 + curve[j].vertex.p.y) / 3;
62
181k
        curve[i].control[1].x = (curve[i].vertex.p.x + curve[j].vertex.p.x * 2) / 3;
63
181k
        curve[i].control[1].y = (curve[i].vertex.p.y + curve[j].vertex.p.y * 2) / 3;
64
181k
        curve[i].straight = true;
65
181k
    }
66
45.2k
}
67
68
/* Transform a point with a fixed-point result. */
69
static void
70
gs_point_transform2fixed_clamped(const gs_matrix_fixed * pmat,
71
                         double x, double y, gs_fixed_point * ppt)
72
0
{
73
0
    gs_point fpt;
74
75
0
    gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt);
76
0
    ppt->x = clamp_coord(fpt.x);
77
0
    ppt->y = clamp_coord(fpt.y);
78
0
}
79
80
static int
81
Fb_fill_region(Fb_fill_state_t * pfs, const gs_fixed_rect *rect)
82
0
{
83
0
    patch_fill_state_t pfs1;
84
0
    patch_curve_t curve[4];
85
0
    Fb_frame_t * fp = &pfs->frame;
86
0
    int code;
87
88
0
    memcpy(&pfs1, (shading_fill_state_t *)pfs, sizeof(shading_fill_state_t));
89
0
    pfs1.Function = pfs->psh->params.Function;
90
0
    code = init_patch_fill_state(&pfs1);
91
0
    if (code < 0)
92
0
        return code;
93
0
    pfs1.maybe_self_intersecting = false;
94
0
    pfs1.n_color_args = 2;
95
0
    pfs1.rect = *rect;
96
0
    gs_point_transform2fixed(&pfs->ptm, fp->region.p.x, fp->region.p.y, &curve[0].vertex.p);
97
0
    gs_point_transform2fixed(&pfs->ptm, fp->region.q.x, fp->region.p.y, &curve[1].vertex.p);
98
0
    gs_point_transform2fixed(&pfs->ptm, fp->region.q.x, fp->region.q.y, &curve[2].vertex.p);
99
0
    gs_point_transform2fixed(&pfs->ptm, fp->region.p.x, fp->region.q.y, &curve[3].vertex.p);
100
0
    make_other_poles(curve);
101
0
    curve[0].vertex.cc[0] = fp->region.p.x;   curve[0].vertex.cc[1] = fp->region.p.y;
102
0
    curve[1].vertex.cc[0] = fp->region.q.x;   curve[1].vertex.cc[1] = fp->region.p.y;
103
0
    curve[2].vertex.cc[0] = fp->region.q.x;   curve[2].vertex.cc[1] = fp->region.q.y;
104
0
    curve[3].vertex.cc[0] = fp->region.p.x;   curve[3].vertex.cc[1] = fp->region.q.y;
105
0
    code = patch_fill(&pfs1, curve, NULL, NULL);
106
0
    if (term_patch_fill_state(&pfs1))
107
0
        return_error(gs_error_unregistered); /* Must not happen. */
108
0
    return code;
109
0
}
110
111
int
112
gs_shading_Fb_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
113
                             const gs_fixed_rect * rect_clip,
114
                             gx_device * dev, gs_gstate * pgs)
115
0
{
116
0
    const gs_shading_Fb_t * const psh = (const gs_shading_Fb_t *)psh0;
117
0
    gs_matrix save_ctm;
118
0
    int xi, yi, code;
119
0
    float x[2], y[2];
120
0
    Fb_fill_state_t state;
121
122
0
    code = shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pgs);
123
0
    if (code < 0)
124
0
        return code;
125
0
    state.psh = psh;
126
    /****** HACK FOR FIXED-POINT MATRIX MULTIPLY ******/
127
0
    gs_currentmatrix((gs_gstate *) pgs, &save_ctm);
128
0
    gs_concat((gs_gstate *) pgs, &psh->params.Matrix);
129
0
    state.ptm = pgs->ctm;
130
0
    gs_setmatrix((gs_gstate *) pgs, &save_ctm);
131
    /* Compute the parameter X and Y ranges. */
132
0
    {
133
0
        gs_rect pbox;
134
135
0
        code = gs_bbox_transform_inverse(rect, &psh->params.Matrix, &pbox);
136
0
        if (code < 0)
137
0
            return code;
138
0
        x[0] = max(pbox.p.x, psh->params.Domain[0]);
139
0
        x[1] = min(pbox.q.x, psh->params.Domain[1]);
140
0
        y[0] = max(pbox.p.y, psh->params.Domain[2]);
141
0
        y[1] = min(pbox.q.y, psh->params.Domain[3]);
142
0
    }
143
0
    if (x[0] > x[1] || y[0] > y[1]) {
144
        /* The region is outside the shading area. */
145
0
        if (state.icclink != NULL) gsicc_release_link(state.icclink);
146
0
        return 0;
147
0
    }
148
0
    for (xi = 0; xi < 2; ++xi)
149
0
        for (yi = 0; yi < 2; ++yi) {
150
0
            float v[2];
151
152
0
            v[0] = x[xi], v[1] = y[yi];
153
0
            gs_function_evaluate(psh->params.Function, v,
154
0
                                 state.frame.cc[yi * 2 + xi].paint.values);
155
0
        }
156
0
    state.frame.region.p.x = x[0];
157
0
    state.frame.region.p.y = y[0];
158
0
    state.frame.region.q.x = x[1];
159
0
    state.frame.region.q.y = y[1];
160
0
    code = Fb_fill_region(&state, rect_clip);
161
0
    if (state.icclink != NULL) gsicc_release_link(state.icclink);
162
0
    return code;
163
0
}
164
165
/* ---------------- Axial shading ---------------- */
166
167
typedef struct A_fill_state_s {
168
    const gs_shading_A_t *psh;
169
    gs_point delta;
170
    double length;
171
    double t0, t1;
172
    double v0, v1, u0, u1;
173
} A_fill_state_t;
174
/****** NEED GC DESCRIPTOR ******/
175
176
/* Note t0 and t1 vary over [0..1], not the Domain. */
177
178
typedef struct
179
{
180
    patch_curve_t curve[4];
181
    gs_point corners[4];
182
} corners_and_curves;
183
184
/* Ghostscript cannot possibly render any patch whose bounds aren't
185
 * representable in fixed's. In fact, this is a larger limit than
186
 * we need. We notionally have an area defined by coordinates
187
 * that can be represented in fixed point with at least 1 bit to
188
 * spare.
189
 *
190
 * Any patch that lies completely outside this region can be clipped
191
 * away. Any patch that isn't representable by fixed points can be
192
 * subdivided into 4.
193
 *
194
 * This avoids us subdividing patches huge numbers of times because
195
 * one side is just outside the region we will accept.
196
 */
197
198
199
647k
#define MIN_CLIP_LIMIT ((int)(fixed2int(min_fixed)/2))
200
610k
#define MAX_CLIP_LIMIT ((int)(fixed2int(max_fixed)/2))
201
202
static int not_clipped_away(const gs_point *p)
203
90.6k
{
204
90.6k
    if (p[0].x < MIN_CLIP_LIMIT &&
205
90.6k
        p[1].x < MIN_CLIP_LIMIT &&
206
90.6k
        p[2].x < MIN_CLIP_LIMIT &&
207
90.6k
        p[3].x < MIN_CLIP_LIMIT)
208
16.3k
        return 0; /* Clipped away! */
209
74.2k
    if (p[0].x > MAX_CLIP_LIMIT &&
210
74.2k
        p[1].x > MAX_CLIP_LIMIT &&
211
74.2k
        p[2].x > MAX_CLIP_LIMIT &&
212
74.2k
        p[3].x > MAX_CLIP_LIMIT)
213
16.3k
        return 0; /* Clipped away! */
214
57.8k
    if (p[0].y < MIN_CLIP_LIMIT &&
215
57.8k
        p[1].y < MIN_CLIP_LIMIT &&
216
57.8k
        p[2].y < MIN_CLIP_LIMIT &&
217
57.8k
        p[3].y < MIN_CLIP_LIMIT)
218
0
        return 0; /* Clipped away! */
219
57.8k
    if (p[0].y > MAX_CLIP_LIMIT &&
220
57.8k
        p[1].y > MAX_CLIP_LIMIT &&
221
57.8k
        p[2].y > MAX_CLIP_LIMIT &&
222
57.8k
        p[3].y > MAX_CLIP_LIMIT)
223
0
        return 0; /* Clipped away! */
224
57.8k
    return 1;
225
57.8k
}
226
227
188k
#define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
228
229
static int
230
A_fill_region_floats(patch_fill_state_t *pfs1, corners_and_curves *cc, int depth)
231
58.6k
{
232
58.6k
    corners_and_curves sub[4];
233
58.6k
    int code;
234
235
58.6k
    if (depth == 32)
236
785
        return gs_error_limitcheck;
237
238
57.8k
    if (depth > 0 &&
239
57.8k
        f_fits_in_fixed(cc->corners[0].x) &&
240
57.8k
        f_fits_in_fixed(cc->corners[0].y) &&
241
57.8k
        f_fits_in_fixed(cc->corners[1].x) &&
242
57.8k
        f_fits_in_fixed(cc->corners[1].y) &&
243
57.8k
        f_fits_in_fixed(cc->corners[2].x) &&
244
57.8k
        f_fits_in_fixed(cc->corners[2].y) &&
245
57.8k
        f_fits_in_fixed(cc->corners[3].x) &&
246
57.8k
        f_fits_in_fixed(cc->corners[3].y))
247
16.3k
    {
248
16.3k
        cc->curve[0].vertex.p.x = float2fixed(cc->corners[0].x);
249
16.3k
        cc->curve[0].vertex.p.y = float2fixed(cc->corners[0].y);
250
16.3k
        cc->curve[1].vertex.p.x = float2fixed(cc->corners[1].x);
251
16.3k
        cc->curve[1].vertex.p.y = float2fixed(cc->corners[1].y);
252
16.3k
        cc->curve[2].vertex.p.x = float2fixed(cc->corners[2].x);
253
16.3k
        cc->curve[2].vertex.p.y = float2fixed(cc->corners[2].y);
254
16.3k
        cc->curve[3].vertex.p.x = float2fixed(cc->corners[3].x);
255
16.3k
        cc->curve[3].vertex.p.y = float2fixed(cc->corners[3].y);
256
16.3k
        cc->curve[0].vertex.cc[1] = cc->curve[1].vertex.cc[1] =
257
16.3k
                                    cc->curve[2].vertex.cc[1] =
258
16.3k
                                    cc->curve[3].vertex.cc[1] = 0;
259
16.3k
        make_other_poles(cc->curve);
260
16.3k
        return patch_fill(pfs1, cc->curve, NULL, NULL);
261
16.3k
    }
262
263
    /* We have patches with corners:
264
     *  0  1
265
     *  3  2
266
     * We subdivide these into 4 smaller patches:
267
     *
268
     *  0   10   1     Where 0123 are corners
269
     *   [0]  [1]      [0][1][2][3] are patches.
270
     *  3   23   2
271
     *  0   10   1
272
     *   [3]  [2]
273
     *  3   23   2
274
     */
275
276
41.5k
    sub[0].corners[0].x = cc->corners[0].x;
277
41.5k
    sub[0].corners[0].y = cc->corners[0].y;
278
41.5k
    sub[1].corners[1].x = cc->corners[1].x;
279
41.5k
    sub[1].corners[1].y = cc->corners[1].y;
280
41.5k
    sub[2].corners[2].x = cc->corners[2].x;
281
41.5k
    sub[2].corners[2].y = cc->corners[2].y;
282
41.5k
    sub[3].corners[3].x = cc->corners[3].x;
283
41.5k
    sub[3].corners[3].y = cc->corners[3].y;
284
41.5k
    sub[1].corners[0].x = sub[0].corners[1].x = (cc->corners[0].x + cc->corners[1].x)/2;
285
41.5k
    sub[1].corners[0].y = sub[0].corners[1].y = (cc->corners[0].y + cc->corners[1].y)/2;
286
41.5k
    sub[3].corners[2].x = sub[2].corners[3].x = (cc->corners[2].x + cc->corners[3].x)/2;
287
41.5k
    sub[3].corners[2].y = sub[2].corners[3].y = (cc->corners[2].y + cc->corners[3].y)/2;
288
41.5k
    sub[3].corners[0].x = sub[0].corners[3].x = (cc->corners[0].x + cc->corners[3].x)/2;
289
41.5k
    sub[3].corners[0].y = sub[0].corners[3].y = (cc->corners[0].y + cc->corners[3].y)/2;
290
41.5k
    sub[2].corners[1].x = sub[1].corners[2].x = (cc->corners[1].x + cc->corners[2].x)/2;
291
41.5k
    sub[2].corners[1].y = sub[1].corners[2].y = (cc->corners[1].y + cc->corners[2].y)/2;
292
41.5k
    sub[0].corners[2].x = sub[1].corners[3].x =
293
41.5k
                          sub[2].corners[0].x =
294
41.5k
                          sub[3].corners[1].x = (sub[0].corners[3].x + sub[1].corners[2].x)/2;
295
41.5k
    sub[0].corners[2].y = sub[1].corners[3].y =
296
41.5k
                          sub[2].corners[0].y =
297
41.5k
                          sub[3].corners[1].y = (sub[0].corners[3].y + sub[1].corners[2].y)/2;
298
41.5k
    sub[0].curve[0].vertex.cc[0] = sub[0].curve[3].vertex.cc[0] =
299
41.5k
                                   sub[3].curve[0].vertex.cc[0] =
300
41.5k
                                   sub[3].curve[3].vertex.cc[0] = cc->curve[0].vertex.cc[0];
301
41.5k
    sub[1].curve[1].vertex.cc[0] = sub[1].curve[2].vertex.cc[0] =
302
41.5k
                                   sub[2].curve[1].vertex.cc[0] =
303
41.5k
                                   sub[2].curve[2].vertex.cc[0] = cc->curve[1].vertex.cc[0];
304
41.5k
    sub[0].curve[1].vertex.cc[0] = sub[0].curve[2].vertex.cc[0] =
305
41.5k
                                   sub[1].curve[0].vertex.cc[0] =
306
41.5k
                                   sub[1].curve[3].vertex.cc[0] =
307
41.5k
                                   sub[2].curve[0].vertex.cc[0] =
308
41.5k
                                   sub[2].curve[3].vertex.cc[0] =
309
41.5k
                                   sub[3].curve[1].vertex.cc[0] =
310
41.5k
                                   sub[3].curve[2].vertex.cc[0] = (cc->curve[0].vertex.cc[0] + cc->curve[1].vertex.cc[0])/2;
311
312
41.5k
    depth++;
313
41.5k
    if (not_clipped_away(sub[0].corners)) {
314
33.3k
        code = A_fill_region_floats(pfs1, &sub[0], depth);
315
33.3k
        if (code < 0)
316
25.1k
            return code;
317
33.3k
    }
318
16.3k
    if (not_clipped_away(sub[1].corners)) {
319
8.19k
        code = A_fill_region_floats(pfs1, &sub[1], depth);
320
8.19k
        if (code < 0)
321
0
            return code;
322
8.19k
    }
323
16.3k
    if (not_clipped_away(sub[2].corners)) {
324
8.19k
        code = A_fill_region_floats(pfs1, &sub[2], depth);
325
8.19k
        if (code < 0)
326
0
            return code;
327
8.19k
    }
328
16.3k
    if (not_clipped_away(sub[3].corners)) {
329
8.19k
        code = A_fill_region_floats(pfs1, &sub[3], depth);
330
8.19k
        if (code < 0)
331
0
            return code;
332
8.19k
    }
333
334
16.3k
    return 0;
335
16.3k
}
336
337
static int
338
A_fill_region(A_fill_state_t * pfs, patch_fill_state_t *pfs1)
339
29.6k
{
340
29.6k
    const gs_shading_A_t * const psh = pfs->psh;
341
29.6k
    double x0 = psh->params.Coords[0] + pfs->delta.x * pfs->v0;
342
29.6k
    double y0 = psh->params.Coords[1] + pfs->delta.y * pfs->v0;
343
29.6k
    double x1 = psh->params.Coords[0] + pfs->delta.x * pfs->v1;
344
29.6k
    double y1 = psh->params.Coords[1] + pfs->delta.y * pfs->v1;
345
29.6k
    double h0 = pfs->u0, h1 = pfs->u1;
346
29.6k
    corners_and_curves cc;
347
29.6k
    int code;
348
349
29.6k
    double dx0 = pfs->delta.x * h0;
350
29.6k
    double dy0 = pfs->delta.y * h0;
351
29.6k
    double dx1 = pfs->delta.x * h1;
352
29.6k
    double dy1 = pfs->delta.y * h1;
353
354
29.6k
    cc.curve[0].vertex.cc[0] = pfs->t0; /* The element cc[1] is set to a dummy value against */
355
29.6k
    cc.curve[1].vertex.cc[0] = pfs->t1; /* interrupts while an idle priocessing in gxshade.6.c .  */
356
29.6k
    cc.curve[2].vertex.cc[0] = pfs->t1;
357
29.6k
    cc.curve[3].vertex.cc[0] = pfs->t0;
358
29.6k
    cc.curve[0].vertex.cc[1] = 0; /* The element cc[1] is set to a dummy value against */
359
29.6k
    cc.curve[1].vertex.cc[1] = 0; /* interrupts while an idle priocessing in gxshade.6.c .  */
360
29.6k
    cc.curve[2].vertex.cc[1] = 0;
361
29.6k
    cc.curve[3].vertex.cc[1] = 0;
362
29.6k
    cc.corners[0].x = x0 + dy0;
363
29.6k
    cc.corners[0].y = y0 - dx0;
364
29.6k
    cc.corners[1].x = x1 + dy0;
365
29.6k
    cc.corners[1].y = y1 - dx0;
366
29.6k
    cc.corners[2].x = x1 + dy1;
367
29.6k
    cc.corners[2].y = y1 - dx1;
368
29.6k
    cc.corners[3].x = x0 + dy1;
369
29.6k
    cc.corners[3].y = y0 - dx1;
370
29.6k
    code = gs_point_transform2fixed(&pfs1->pgs->ctm, cc.corners[0].x, cc.corners[0].y, &cc.curve[0].vertex.p);
371
29.6k
    if (code < 0)
372
787
        goto fail;
373
28.9k
    code = gs_point_transform2fixed(&pfs1->pgs->ctm, cc.corners[1].x, cc.corners[1].y, &cc.curve[1].vertex.p);
374
28.9k
    if (code < 0)
375
0
        goto fail;
376
28.9k
    code = gs_point_transform2fixed(&pfs1->pgs->ctm, cc.corners[2].x, cc.corners[2].y, &cc.curve[2].vertex.p);
377
28.9k
    if (code < 0)
378
0
        goto fail;
379
28.9k
    code = gs_point_transform2fixed(&pfs1->pgs->ctm, cc.corners[3].x, cc.corners[3].y, &cc.curve[3].vertex.p);
380
28.9k
    if (code < 0)
381
0
        goto fail;
382
28.9k
    make_other_poles(cc.curve);
383
28.9k
    return patch_fill(pfs1, cc.curve, NULL, NULL);
384
787
fail:
385
787
    if (code != gs_error_limitcheck)
386
0
        return code;
387
787
    code = gs_point_transform(cc.corners[0].x, cc.corners[0].y, (const gs_matrix *)&pfs1->pgs->ctm, &cc.corners[0]);
388
787
    if (code < 0)
389
0
        return code;
390
787
    code = gs_point_transform(cc.corners[1].x, cc.corners[1].y, (const gs_matrix *)&pfs1->pgs->ctm, &cc.corners[1]);
391
787
    if (code < 0)
392
0
        return code;
393
787
    code = gs_point_transform(cc.corners[2].x, cc.corners[2].y, (const gs_matrix *)&pfs1->pgs->ctm, &cc.corners[2]);
394
787
    if (code < 0)
395
0
        return code;
396
787
    code = gs_point_transform(cc.corners[3].x, cc.corners[3].y, (const gs_matrix *)&pfs1->pgs->ctm, &cc.corners[3]);
397
787
    if (code < 0)
398
0
        return code;
399
787
    return A_fill_region_floats(pfs1, &cc, 0);
400
787
}
401
402
static inline int
403
gs_shading_A_fill_rectangle_aux(const gs_shading_t * psh0, const gs_rect * rect,
404
                            const gs_fixed_rect *clip_rect,
405
                            gx_device * dev, gs_gstate * pgs)
406
11.6k
{
407
11.6k
    const gs_shading_A_t *const psh = (const gs_shading_A_t *)psh0;
408
11.6k
    gs_function_t * const pfn = psh->params.Function;
409
11.6k
    gs_matrix cmat;
410
11.6k
    gs_rect t_rect;
411
11.6k
    A_fill_state_t state;
412
11.6k
    patch_fill_state_t pfs1;
413
11.6k
    float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1];
414
11.6k
    float dd = d1 - d0;
415
11.6k
    double t0, t1;
416
11.6k
    gs_point dist;
417
11.6k
    int code;
418
419
11.6k
    state.psh = psh;
420
11.6k
    code = shade_init_fill_state((shading_fill_state_t *)&pfs1, psh0, dev, pgs);
421
11.6k
    if (code < 0)
422
7
        return code;
423
11.6k
    pfs1.Function = pfn;
424
11.6k
    pfs1.rect = *clip_rect;
425
11.6k
    code = init_patch_fill_state(&pfs1);
426
11.6k
    if (code < 0)
427
0
        goto fail;
428
11.6k
    pfs1.maybe_self_intersecting = false;
429
11.6k
    pfs1.function_arg_shift = 1;
430
    /*
431
     * Compute the parameter range.  We construct a matrix in which
432
     * (0,0) corresponds to t = 0 and (0,1) corresponds to t = 1,
433
     * and use it to inverse-map the rectangle to be filled.
434
     */
435
11.6k
    cmat.tx = psh->params.Coords[0];
436
11.6k
    cmat.ty = psh->params.Coords[1];
437
11.6k
    state.delta.x = psh->params.Coords[2] - psh->params.Coords[0];
438
11.6k
    state.delta.y = psh->params.Coords[3] - psh->params.Coords[1];
439
11.6k
    cmat.yx = state.delta.x;
440
11.6k
    cmat.yy = state.delta.y;
441
11.6k
    cmat.xx = cmat.yy;
442
11.6k
    cmat.xy = -cmat.yx;
443
11.6k
    code = gs_bbox_transform_inverse(rect, &cmat, &t_rect);
444
11.6k
    if (code < 0) {
445
0
        code = 0; /* Swallow this silently */
446
0
        goto fail;
447
0
    }
448
11.6k
    t0 = min(max(t_rect.p.y, 0), 1);
449
11.6k
    t1 = max(min(t_rect.q.y, 1), 0);
450
11.6k
    state.v0 = t0;
451
11.6k
    state.v1 = t1;
452
11.6k
    state.u0 = t_rect.p.x;
453
11.6k
    state.u1 = t_rect.q.x;
454
11.6k
    state.t0 = t0 * dd + d0;
455
11.6k
    state.t1 = t1 * dd + d0;
456
11.6k
    code = gs_distance_transform(state.delta.x, state.delta.y, &ctm_only(pgs),
457
11.6k
                          &dist);
458
11.6k
    if (code < 0)
459
0
        goto fail;
460
11.6k
    state.length = hypot(dist.x, dist.y); /* device space line length */
461
11.6k
    code = A_fill_region(&state, &pfs1);
462
11.6k
    if (psh->params.Extend[0] && t0 > t_rect.p.y) {
463
9.09k
        if (code < 0)
464
1
            goto fail;
465
        /* Use the general algorithm, because we need the trapping. */
466
9.09k
        state.v0 = t_rect.p.y;
467
9.09k
        state.v1 = t0;
468
9.09k
        state.t0 = state.t1 = t0 * dd + d0;
469
9.09k
        code = A_fill_region(&state, &pfs1);
470
9.09k
    }
471
11.6k
    if (psh->params.Extend[1] && t1 < t_rect.q.y) {
472
8.93k
        if (code < 0)
473
0
            goto fail;
474
        /* Use the general algorithm, because we need the trapping. */
475
8.93k
        state.v0 = t1;
476
8.93k
        state.v1 = t_rect.q.y;
477
8.93k
        state.t0 = state.t1 = t1 * dd + d0;
478
8.93k
        code = A_fill_region(&state, &pfs1);
479
8.93k
    }
480
11.6k
fail:
481
11.6k
    gsicc_release_link(pfs1.icclink);
482
11.6k
    if (term_patch_fill_state(&pfs1))
483
0
        return_error(gs_error_unregistered); /* Must not happen. */
484
11.6k
    return code;
485
11.6k
}
486
487
int
488
gs_shading_A_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
489
                            const gs_fixed_rect * rect_clip,
490
                            gx_device * dev, gs_gstate * pgs)
491
11.6k
{
492
11.6k
    return gs_shading_A_fill_rectangle_aux(psh0, rect, rect_clip, dev, pgs);
493
11.6k
}
494
495
/* ---------------- Radial shading ---------------- */
496
497
/* Some notes on what I have struggled to understand about the following
498
 * function. This function renders the 'tube' given by interpolating one
499
 * circle to another.
500
 *
501
 * The first circle is at (x0, y0) with radius r0, and has 'color' t0.
502
 * The other circle is at (x1, y1) with radius r1, and has 'color' t1.
503
 *
504
 * We perform this rendering by approximating each quadrant of the 'tube'
505
 * by a tensor patch. The tensor patch is formed by taking a curve along
506
 * 1/4 of the circumference of the first circle, a straight line to the
507
 * equivalent point on the circumference of the second circle, a curve
508
 * back along the circumference of the second circle, and then a straight
509
 * line back to where we started.
510
 *
511
 * There is additional logic in this function that forms the directions of
512
 * the curves differently for different quadrants. This is done to ensure
513
 * that we always paint 'around' the tube from the back towards the front,
514
 * so we don't get unexpected regions showing though. This is explained more
515
 * below.
516
 *
517
 * The original code here examined the position change between the two
518
 * circles dx and dy. Based upon this vector it would pick which quadrant/
519
 * tensor patch to draw first. It would draw the quadrants/tensor patches
520
 * in anticlockwise order. Presumably this was intended to be done so that
521
 * the 'top' quadrant would be drawn last.
522
 *
523
 * Unfortunately this did not always work; see bug 692513. If the quadrants
524
 * were rendered in the order 0,1,2,3, the rendering of 1 was leaving traces
525
 * on top of 0, which was unexpected.
526
 *
527
 * I have therefore altered the code slightly; rather than picking a start
528
 * quadrant and moving anticlockwise, we now draw the 'undermost' quadrant,
529
 * then the two adjacent quadrants, then the topmost quadrant.
530
 *
531
 * For the purposes of explanation, we shall label the octants as below:
532
 *
533
 *     \2|1/       and Quadrants as:       |
534
 *     3\|/0                            Q1 | Q0
535
 *    ---+---                          ----+----
536
 *     4/|\7                            Q2 | Q3
537
 *     /5|6\                               |
538
 *
539
 * We find (dx,dy), the difference between the centres of the circles.
540
 * We look to see which octant this falls in. Firstly, this tells us which
541
 * quadrant of the circle we need to draw first (Octant n, starts with
542
 * Quadrant floor(n/2)). Secondly, it tells us which direction to form the
543
 * tensor patch in; we always want to draw from the side 'closest' to
544
 * dx/dy to the side further away. This ensures that we don't overwrite
545
 * pixels in the incorrect order as the patch decomposes.
546
 */
547
static int
548
R_tensor_annulus(patch_fill_state_t *pfs,
549
    double x0, double y0, double r0, double t0,
550
    double x1, double y1, double r1, double t1)
551
79
{
552
79
    double dx = x1 - x0, dy = y1 - y0;
553
79
    double d = hypot(dx, dy);
554
79
    gs_point p0, p1, pc0, pc1;
555
79
    int k, j, code, dirn;
556
79
    bool inside = 0;
557
558
    /* pc0 and pc1 are the centres of the respective circles. */
559
79
    pc0.x = x0, pc0.y = y0;
560
79
    pc1.x = x1, pc1.y = y1;
561
    /* Set p0 up so it's a unit vector giving the direction of 90 degrees
562
     * to the right of the major axis as we move from p0c to p1c. */
563
79
    if (r0 + d <= r1 || r1 + d <= r0) {
564
        /* One circle is inside another one.
565
           Use any subdivision,
566
           but don't depend on dx, dy, which may be too small. */
567
79
        p0.x = 0, p0.y = -1, dirn = 0;
568
        /* Align stripes along radii for faster triangulation : */
569
79
        inside = 1;
570
79
        pfs->function_arg_shift = 1;
571
79
    } else {
572
        /* Must generate canonic quadrangle arcs,
573
           because we approximate them with curves. */
574
0
        if(dx >= 0) {
575
0
            if (dy >= 0)
576
0
                p0.x = 1, p0.y = 0, dirn = (dx >= dy ? 1 : 0);
577
0
            else
578
0
                p0.x = 0, p0.y = -1, dirn = (dx >= -dy ? 0 : 1);
579
0
        } else {
580
0
            if (dy >= 0)
581
0
                p0.x = 0, p0.y = 1, dirn = (-dx >= dy ? 1 : 0);
582
0
            else
583
0
                p0.x = -1, p0.y = 0, dirn = (-dx >= -dy ? 0 : 1);
584
0
        }
585
0
        pfs->function_arg_shift = 0;
586
0
    }
587
    /* fixme: wish: cut invisible parts off.
588
       Note : when r0 != r1 the invisible part is not a half circle. */
589
395
    for (k = 0; k < 4; k++) {
590
316
        gs_point p[12];
591
316
        patch_curve_t curve[4];
592
593
        /* Set p1 to be 90 degrees anticlockwise from p0 */
594
316
        p1.x = -p0.y; p1.y = p0.x;
595
316
        if (dirn == 0) { /* Clockwise */
596
237
            make_quadrant_arc(p + 0, &pc0, &p1, &p0, r0);
597
237
            make_quadrant_arc(p + 6, &pc1, &p0, &p1, r1);
598
237
        } else { /* Anticlockwise */
599
79
            make_quadrant_arc(p + 0, &pc0, &p0, &p1, r0);
600
79
            make_quadrant_arc(p + 6, &pc1, &p1, &p0, r1);
601
79
        }
602
316
        p[4].x = (p[3].x * 2 + p[6].x) / 3;
603
316
        p[4].y = (p[3].y * 2 + p[6].y) / 3;
604
316
        p[5].x = (p[3].x + p[6].x * 2) / 3;
605
316
        p[5].y = (p[3].y + p[6].y * 2) / 3;
606
316
        p[10].x = (p[9].x * 2 + p[0].x) / 3;
607
316
        p[10].y = (p[9].y * 2 + p[0].y) / 3;
608
316
        p[11].x = (p[9].x + p[0].x * 2) / 3;
609
316
        p[11].y = (p[9].y + p[0].y * 2) / 3;
610
1.58k
        for (j = 0; j < 4; j++) {
611
1.26k
            int jj = (j + inside) % 4;
612
613
1.26k
            if (gs_point_transform2fixed(&pfs->pgs->ctm,         p[j*3 + 0].x, p[j*3 + 0].y, &curve[jj].vertex.p) < 0)
614
0
                gs_point_transform2fixed_clamped(&pfs->pgs->ctm, p[j*3 + 0].x, p[j*3 + 0].y, &curve[jj].vertex.p);
615
616
1.26k
            if (gs_point_transform2fixed(&pfs->pgs->ctm,         p[j*3 + 1].x, p[j*3 + 1].y, &curve[jj].control[0]) < 0)
617
0
                gs_point_transform2fixed_clamped(&pfs->pgs->ctm, p[j*3 + 1].x, p[j*3 + 1].y, &curve[jj].control[0]);
618
619
1.26k
            if (gs_point_transform2fixed(&pfs->pgs->ctm,         p[j*3 + 2].x, p[j*3 + 2].y, &curve[jj].control[1]) < 0)
620
0
                gs_point_transform2fixed_clamped(&pfs->pgs->ctm, p[j*3 + 2].x, p[j*3 + 2].y, &curve[jj].control[1]);
621
1.26k
            curve[j].straight = (((j + inside) & 1) != 0);
622
1.26k
        }
623
316
        curve[(0 + inside) % 4].vertex.cc[0] = t0;
624
316
        curve[(1 + inside) % 4].vertex.cc[0] = t0;
625
316
        curve[(2 + inside) % 4].vertex.cc[0] = t1;
626
316
        curve[(3 + inside) % 4].vertex.cc[0] = t1;
627
316
        curve[0].vertex.cc[1] = curve[1].vertex.cc[1] = 0; /* Initialize against FPE. */
628
316
        curve[2].vertex.cc[1] = curve[3].vertex.cc[1] = 0; /* Initialize against FPE. */
629
316
        code = patch_fill(pfs, curve, NULL, NULL);
630
316
        if (code < 0)
631
0
            return code;
632
        /* Move p0 to be ready for the next position */
633
316
        if (k == 0) {
634
            /* p0 moves clockwise */
635
79
            p1 = p0;
636
79
            p0.x = p1.y; p0.y = -p1.x;
637
79
            dirn = 0;
638
237
        } else if (k == 1) {
639
            /* p0 flips sides */
640
79
            p0.x = -p0.x; p0.y = -p0.y;
641
79
            dirn = 1;
642
158
        } else if (k == 2) {
643
            /* p0 moves anti-clockwise */
644
79
            p1 = p0;
645
79
            p0.x = -p1.y; p0.y = p1.x;
646
79
            dirn = 0;
647
79
        }
648
316
    }
649
79
    return 0;
650
79
}
651
652
/* Find the control points for two points on the arc of a circle
653
 * the points must be within the same quadrant.
654
 */
655
static int find_arc_control_points(gs_point *from, gs_point *to, gs_point *from_control, gs_point *to_control, gs_point *centre)
656
0
{
657
0
    double from_tan_alpha, to_tan_alpha, from_alpha, to_alpha;
658
0
    double half_inscribed_angle, intersect_x, intersect_y, intersect_dist;
659
0
    double radius = sqrt(((from->x - centre->x) * (from->x - centre->x)) + ((from->y - centre->y) * (from->y - centre->y)));
660
0
    double tangent_intersect_dist;
661
0
    double F;
662
0
    int quadrant;
663
664
    /* Quadrant 0 is upper right, numbered anti-clockwise.
665
     * If the direction of the from->to is atni-clockwise, add 4
666
     */
667
0
    if (from->x > to->x) {
668
0
        if (from->y > to->y) {
669
0
            if (to->y >= centre->y)
670
0
                quadrant = 1 + 4;
671
0
            else
672
0
                quadrant = 3;
673
0
        } else {
674
0
            if (to->x >= centre->x)
675
0
                quadrant = 0 + 4;
676
0
            else
677
0
                quadrant = 2;
678
0
        }
679
0
    } else {
680
0
        if (from->y > to->y) {
681
0
            if (from->x >= centre->x)
682
0
                quadrant = 0;
683
0
            else
684
0
                quadrant = 2 + 4;
685
0
        } else {
686
0
            if (from->x >= centre->x)
687
0
                quadrant = 3 + 4;
688
0
            else
689
0
                quadrant = 1;
690
0
        }
691
0
    }
692
693
0
    switch(quadrant) {
694
        /* quadrant 0, arc goes clockwise */
695
0
        case 0:
696
0
            if (from->x == centre->x) {
697
0
                from_alpha = M_PI / 2;
698
0
            } else {
699
0
                from_tan_alpha = (from->y - centre->y) / (from->x - centre->x);
700
0
                from_alpha = atan(from_tan_alpha);
701
0
            }
702
0
            to_tan_alpha = (to->y - centre->y) / (to->x - centre->x);
703
0
            to_alpha = atan(to_tan_alpha);
704
705
0
            half_inscribed_angle = (from_alpha - to_alpha) / 2;
706
0
            intersect_dist = radius / cos(half_inscribed_angle);
707
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
708
709
0
            intersect_x = centre->x + cos(to_alpha + half_inscribed_angle) * intersect_dist;
710
0
            intersect_y = centre->y + sin(to_alpha + half_inscribed_angle) * intersect_dist;
711
0
            break;
712
        /* quadrant 1, arc goes clockwise */
713
0
        case 1:
714
0
            from_tan_alpha = (from->y - centre->y) / (centre->x - from->x);
715
0
            from_alpha = atan(from_tan_alpha);
716
717
0
            if (to->x == centre->x) {
718
0
                to_alpha = M_PI / 2;
719
0
            } else {
720
0
                to_tan_alpha = (to->y - centre->y) / (centre->x - to->x);
721
0
                to_alpha = atan(to_tan_alpha);
722
0
            }
723
724
0
            half_inscribed_angle = (to_alpha - from_alpha) / 2;
725
0
            intersect_dist = radius / cos(half_inscribed_angle);
726
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
727
728
0
            intersect_x = centre->x - cos(from_alpha + half_inscribed_angle) * intersect_dist;
729
0
            intersect_y = centre->y + sin(from_alpha + half_inscribed_angle) * intersect_dist;
730
0
            break;
731
        /* quadrant 2, arc goes clockwise */
732
0
        case 2:
733
0
            if (from->x == centre->x) {
734
0
                from_alpha = M_PI / 2;
735
0
            } else {
736
0
                from_tan_alpha = (centre->y - from->y) / (centre->x - from->x);
737
0
                from_alpha = atan(from_tan_alpha);
738
0
            }
739
740
0
            to_tan_alpha = (centre->y - to->y) / (centre->x - to->x);
741
0
            to_alpha = atan(to_tan_alpha);
742
743
0
            half_inscribed_angle = (to_alpha - from_alpha) / 2;
744
0
            intersect_dist = radius / cos(half_inscribed_angle);
745
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
746
747
0
            intersect_x = centre->x - cos(from_alpha + half_inscribed_angle) * intersect_dist;
748
0
            intersect_y = centre->y - sin(from_alpha + half_inscribed_angle) * intersect_dist;
749
0
            break;
750
        /* quadrant 3, arc goes clockwise */
751
0
        case 3:
752
0
            from_tan_alpha = (centre->y - from->y) / (from->x - centre->x);
753
0
            from_alpha = atan(from_tan_alpha);
754
755
0
            if (to->x == centre->x) {
756
0
                to_alpha = M_PI / 2;
757
0
            } else {
758
0
                to_tan_alpha = (centre->y - to->y) / (to->x - centre->x);
759
0
                to_alpha = atan(to_tan_alpha);
760
0
            }
761
762
0
            half_inscribed_angle = (to_alpha - from_alpha) / 2;
763
0
            intersect_dist = radius / cos(half_inscribed_angle);
764
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
765
766
0
            intersect_x = centre->x + cos(from_alpha + half_inscribed_angle) * intersect_dist;
767
0
            intersect_y = centre->y - sin(from_alpha + half_inscribed_angle) * intersect_dist;
768
0
            break;
769
        /* quadrant 0, arc goes anti-clockwise */
770
0
        case 4:
771
0
            from_tan_alpha = (from->y - centre->y) / (from->x - centre->x);
772
0
            from_alpha = atan(from_tan_alpha);
773
774
0
            if (to->y == centre->y)
775
0
                to_alpha = M_PI / 2;
776
0
            else {
777
0
                to_tan_alpha = (to->y - centre->y) / (to->x - centre->x);
778
0
                to_alpha = atan(to_tan_alpha);
779
0
            }
780
781
0
            half_inscribed_angle = (to_alpha - from_alpha) / 2;
782
0
            intersect_dist = radius / cos(half_inscribed_angle);
783
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
784
785
0
            intersect_x = centre->x + cos(from_alpha + half_inscribed_angle) * intersect_dist;
786
0
            intersect_y = centre->y + sin(from_alpha + half_inscribed_angle) * intersect_dist;
787
0
            break;
788
        /* quadrant 1, arc goes anti-clockwise */
789
0
        case 5:
790
0
            from_tan_alpha = (centre->x - from->x) / (from->y - centre->y);
791
0
            from_alpha = atan(from_tan_alpha);
792
793
0
            if (to->y == centre->y) {
794
0
                to_alpha = M_PI / 2;
795
0
            }
796
0
            else {
797
0
                to_tan_alpha = (centre->x - to->x) / (to->y - centre->y);
798
0
                to_alpha = atan(to_tan_alpha);
799
0
            }
800
801
0
            half_inscribed_angle = (to_alpha - from_alpha) / 2;
802
0
            intersect_dist = radius / cos(half_inscribed_angle);
803
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
804
805
0
            intersect_x = centre->x - sin(from_alpha + half_inscribed_angle) * intersect_dist;
806
0
            intersect_y = centre->y + cos(from_alpha + half_inscribed_angle) * intersect_dist;
807
0
            break;
808
        /* quadrant 2, arc goes anti-clockwise */
809
0
        case 6:
810
0
            from_tan_alpha = (from->y - centre->y) / (centre->x - from->x);
811
0
            from_alpha = atan(from_tan_alpha);
812
813
0
            if (to->x == centre->x) {
814
0
                to_alpha = M_PI / 2;
815
0
            } else {
816
0
                to_tan_alpha = (centre->y - to->y) / (centre->x - to->x);
817
0
                to_alpha = atan(to_tan_alpha);
818
0
            }
819
820
0
            half_inscribed_angle = (to_alpha - from_alpha) / 2;
821
0
            intersect_dist = radius / cos(half_inscribed_angle);
822
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
823
824
0
            intersect_x = centre->x - cos(from_alpha + half_inscribed_angle) * intersect_dist;
825
0
            intersect_y = centre->y - sin(from_alpha + half_inscribed_angle) * intersect_dist;
826
0
            break;
827
        /* quadrant 3, arc goes anti-clockwise */
828
0
        case 7:
829
0
            if (from->x == centre->x) {
830
0
                from_alpha = M_PI / 2;
831
0
            } else {
832
0
                from_tan_alpha = (centre->y - from->y) / (from->x - centre->x);
833
0
                from_alpha = atan(from_tan_alpha);
834
0
            }
835
0
            to_tan_alpha = (centre->y - to->y) / (to->x - centre->x);
836
0
            to_alpha = atan(to_tan_alpha);
837
838
0
            half_inscribed_angle = (from_alpha - to_alpha) / 2;
839
0
            intersect_dist = radius / cos(half_inscribed_angle);
840
0
            tangent_intersect_dist = tan(half_inscribed_angle) * radius;
841
842
0
            intersect_x = centre->x + cos(to_alpha + half_inscribed_angle) * intersect_dist;
843
0
            intersect_y = centre->y - sin(to_alpha + half_inscribed_angle) * intersect_dist;
844
0
            break;
845
0
    }
846
847
0
    F = (4.0 / 3.0) / (1 + sqrt(1 + ((tangent_intersect_dist / radius) * (tangent_intersect_dist / radius))));
848
849
0
    from_control->x = from->x - ((from->x - intersect_x) * F);
850
0
    from_control->y = from->y - ((from->y - intersect_y) * F);
851
0
    to_control->x = to->x - ((to->x - intersect_x) * F);
852
0
    to_control->y = to->y - ((to->y - intersect_y) * F);
853
854
0
    return 0;
855
0
}
856
857
/* Create a 'patch_curve' element whch is a straight line between two points */
858
static int patch_lineto(gs_matrix_fixed *ctm, gs_point *from, gs_point *to, patch_curve_t *p, float t)
859
0
{
860
0
    double x_1third, x_2third, y_1third, y_2third;
861
862
0
    x_1third = (to->x - from->x) / 3;
863
0
    x_2third = x_1third * 2;
864
0
    y_1third = (to->y - from->y) / 3;
865
0
    y_2third = y_1third * 2;
866
867
0
    gs_point_transform2fixed(ctm, from->x, from->y, &p->vertex.p);
868
0
    gs_point_transform2fixed(ctm, from->x + x_1third, from->y + y_1third, &p->control[0]);
869
0
    gs_point_transform2fixed(ctm, from->x + x_2third, from->y + y_2third, &p->control[1]);
870
871
0
    p->vertex.cc[0] = t;
872
0
    p->vertex.cc[1] = t;
873
0
    p->straight = 1;
874
875
0
    return 0;
876
0
}
877
878
static int patch_curveto(gs_matrix_fixed *ctm, gs_point *centre, gs_point *from, gs_point *to, patch_curve_t *p, float t)
879
0
{
880
0
    gs_point from_control, to_control;
881
882
0
    find_arc_control_points(from, to, &from_control, &to_control, centre);
883
884
0
    gs_point_transform2fixed(ctm, from->x, from->y, &p->vertex.p);
885
0
    gs_point_transform2fixed(ctm, from_control.x, from_control.y, &p->control[0]);
886
0
    gs_point_transform2fixed(ctm, to_control.x, to_control.y, &p->control[1]);
887
0
    p->vertex.cc[0] = t;
888
0
    p->vertex.cc[1] = t;
889
0
    p->straight = 0;
890
891
0
    return 0;
892
0
}
893
894
static int draw_quarter_annulus(patch_fill_state_t *pfs, gs_point *centre, double radius, gs_point *corner, float t)
895
0
{
896
0
    gs_point p0, p1, initial;
897
0
    patch_curve_t p[4];
898
0
    int code;
899
900
0
    if (corner->x > centre->x) {
901
0
        initial.x = centre->x + radius;
902
0
    }
903
0
    else {
904
0
        initial.x = centre->x - radius;
905
0
    }
906
0
    initial.y = centre->y;
907
908
0
    p1.x = initial.x;
909
0
    p1.y = corner->y;
910
0
    patch_lineto(&pfs->pgs->ctm, &initial, &p1, &p[0], t);
911
0
    p0.x = centre->x;
912
0
    p0.y = p1.y;
913
0
    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &p[1], t);
914
0
    p1.x = centre->x;
915
0
    if (centre->y > corner->y) {
916
0
        p1.y = centre->y - radius;
917
0
    } else {
918
0
        p1.y = centre->y + radius;
919
0
    }
920
0
    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &p[2], t);
921
0
    patch_curveto(&pfs->pgs->ctm, centre, &p1, &initial, &p[3], t);
922
0
    code = patch_fill(pfs, (const patch_curve_t *)&p, NULL, NULL);
923
0
    if (code < 0)
924
0
        return code;
925
926
0
    if (corner->x > centre->x)
927
0
        initial.x = corner->x - (corner->x - (centre->x + radius));
928
0
    else
929
0
        initial.x = centre->x - radius;
930
0
    initial.y = corner->y;
931
0
    patch_lineto(&pfs->pgs->ctm, corner, &initial, &p[0], t);
932
933
0
    p0.x = initial.x;
934
0
    p0.y = centre->y;
935
0
    patch_lineto(&pfs->pgs->ctm, &initial, &p0, &p[1], t);
936
937
0
    p1.y = p0.y;
938
0
    p1.x = corner->x;
939
0
    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &p[2], t);
940
0
    patch_lineto(&pfs->pgs->ctm, &p1, corner, &p[3], t);
941
942
0
    return (patch_fill(pfs, (const patch_curve_t *)&p, NULL, NULL));
943
0
}
944
945
static int R_tensor_annulus_extend_tangent(patch_fill_state_t *pfs,
946
    double x0, double y0, double r0, double t0,
947
    double x1, double y1, double r1, double t1, double r2)
948
0
{
949
0
    patch_curve_t curve[4];
950
0
    gs_point p0, p1;
951
0
    int code = 0, q = 0;
952
953
    /* special case axis aligned circles. Its quicker to handle these specially as it
954
     * avoid lots of trigonometry in the general case code, and avoids us
955
     * having to watch out for infinity as the result of tan() operations.
956
     */
957
0
    if (x0 == x1 || y0 == y1) {
958
0
        if (x0 == x1 && y0 > y1) {
959
            /* tangent at top of circles */
960
0
            p0.x = x1, p0.y = y1;
961
0
            p1.x = x1 + r2, p1.y = y1 - r2;
962
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
963
0
            p1.x = x1 - r2, p1.y = y1 - r2;
964
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
965
0
            p1.x = x1 + r2, p1.y = y1 + r1;
966
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
967
0
            p1.x = x1 - r2, p1.y = y1 + r1;
968
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
969
0
        }
970
0
        if (x0 == x1 && y0 < y1) {
971
            /* tangent at bottom of circles */
972
0
            p0.x = x1, p0.y = y1;
973
0
            p1.x = x1 + r2, p1.y = y1 + r2;
974
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
975
0
            p1.x = x1 - r2, p1.y = y1 + r2;
976
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
977
0
            p1.x = x1 + r2, p1.y = y1 - r1;
978
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
979
0
            p1.x = x1 - r2, p1.y = y1 - r1;
980
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
981
0
        }
982
0
        if (y0 == y1 && x0 > x1) {
983
            /* tangent at right of circles */
984
0
            p0.x = x1, p0.y = y1;
985
0
            p1.x = x1 - r2, p1.y = y1 - r2;
986
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
987
0
            p1.x = x1 - r2, p1.y = y1 + r2;
988
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
989
0
            p1.x = x1 + r1, p1.y = y1 + r2;
990
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
991
0
            p1.x = x1 + r1, p1.y = y1 - r2;
992
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
993
0
        }
994
0
        if (y0 == y1 && x0 < x1) {
995
            /* tangent at left of circles */
996
0
            p0.x = x1, p0.y = y1;
997
0
            p1.x = x1 + r2, p1.y = y1 - r2;
998
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
999
0
            p1.x = x1 + r2, p1.y = y1 + r2;
1000
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1001
0
            p1.x = x1 - r1, p1.y = y1 + r2;
1002
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1003
0
            p1.x = x1 - r1, p1.y = y1 - r2;
1004
0
            draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1005
0
        }
1006
0
    }
1007
0
    else {
1008
0
        double tx, ty, endx, endy, intersectx, intersecty, alpha, sinalpha, cosalpha, tanalpha;
1009
0
        gs_point centre;
1010
1011
        /* First lets figure out which quadrant the smaller circle is in (we always
1012
         * get called to fill from the larger circle), x0, y0, r0 is the smaller circle.
1013
         */
1014
0
        if (x0 < x1) {
1015
0
            if (y0 < y1)
1016
0
                q = 2;
1017
0
            else
1018
0
                q = 1;
1019
0
        } else {
1020
0
            if (y0 < y1)
1021
0
                q = 3;
1022
0
            else
1023
0
                q = 0;
1024
0
        }
1025
0
        switch(q) {
1026
0
            case 0:
1027
                /* We have two four-sided elements, from the tangent point
1028
                 * each side, to the point where the tangent crosses an
1029
                 * axis of the larger circle. A line back to the edge
1030
                 * of the larger circle, a line to the point where an axis
1031
                 * crosses the smaller circle, then an arc back to the starting point.
1032
                 */
1033
                /* Figure out the tangent point */
1034
                /* sin (angle) = y1 - y0 / r1 - r0
1035
                 * ty = ((y1 - y0) / (r1 - r0)) * r1
1036
                 */
1037
0
                ty = y1 + ((y0 - y1) / (r1 - r0)) * r1;
1038
0
                tx = x1 + ((x0 - x1) / (r1 - r0)) * r1;
1039
                /* Now actually calculating the point where the tangent crosses the axis of the larger circle
1040
                 * So we need to know the angle the tangent makes with the axis of the smaller circle
1041
                 * as its the same angle where it crosses the axis of the larger circle.
1042
                 * We know the centres and the tangent are co-linear, so sin(a) = y0 - y1 / r1 - r0
1043
                 * We know the tangent is r1 from the centre of the larger circle, so the hypotenuse
1044
                 * is r0 / cos(a). That gives us 'x' and we already know y as its the centre of the larger
1045
                 * circle
1046
                 */
1047
0
                sinalpha = (y0 - y1) / (r1 - r0);
1048
0
                alpha = asin(sinalpha);
1049
0
                cosalpha = cos(alpha);
1050
0
                intersectx = x1 + (r1 / cosalpha);
1051
0
                intersecty = y1;
1052
1053
0
                p0.x = tx, p0.y = ty;
1054
0
                p1.x = tx + (intersectx - tx) / 2, p1.y = ty - (ty - intersecty) / 2;
1055
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1056
0
                p0.x = intersectx, p0.y = intersecty;
1057
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1058
0
                p1.x = x1 + r1, p1.y = y1;
1059
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1060
0
                p0.x = tx, p0.y = ty;
1061
0
                centre.x = x1, centre.y = y1;
1062
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1063
0
                code = patch_fill(pfs, curve, NULL, NULL);
1064
0
                if (code < 0)
1065
0
                    return code;
1066
1067
0
                if (intersectx < x1 + r2) {
1068
                    /* didn't get all the way to the edge, quadrant 3 is composed of 2 quads :-(
1069
                     * An 'annulus' where the right edge is less than the normal extent and a
1070
                     * quad which is a rectangle with one corner chopped of at an angle.
1071
                     */
1072
0
                    p0.x = x1, p0.y = y1;
1073
0
                    p1.x = intersectx, p1.y = y1 - r2;
1074
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1075
0
                    endx = x1 + r2;
1076
0
                    endy = y1 - (tan ((M_PI / 2) - alpha)) * (endx - intersectx);
1077
0
                    p0.x = intersectx, p0.y = y1;
1078
0
                    p1.x = x1 + r2, p1.y = endy;
1079
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1080
0
                    p0.x = x1 + r2, p0.y = y0 - r2;
1081
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1082
0
                    p1.x = intersectx, p1.y = p0.y;
1083
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1084
0
                    p0.x = intersectx, p0.y = y1;
1085
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1086
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1087
0
                    if (code < 0)
1088
0
                        return code;
1089
1090
0
                } else {
1091
                    /* Quadrant 3 is a normal quarter annulua */
1092
0
                    p0.x = x1, p0.y = y1;
1093
0
                    p1.x = x1 + r2, p1.y = y1 - r2;
1094
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1095
0
                }
1096
1097
                /* Q2 is always a full annulus... */
1098
0
                p0.x = x1, p0.y = y1;
1099
0
                p1.x = x1 - r2, p1.y = y1 - r2;
1100
0
                draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1101
1102
                /* alpha is now the angle between the x axis and the tangent to the
1103
                 * circles.
1104
                 */
1105
0
                alpha = (M_PI / 2) - alpha;
1106
0
                cosalpha = cos(alpha);
1107
0
                endy = y1 + (r1 / cosalpha);
1108
0
                endx = x1;
1109
1110
0
                p0.x = tx, p0.y = ty;
1111
0
                p1.x = endx - ((endx - tx) / 2), p1.y = endy - ((endy - ty) / 2);
1112
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1113
0
                p0.x = endx, p0.y = endy;
1114
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1115
0
                p1.x = x1, p1.y = y1 + r1;
1116
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1117
0
                p0.x = tx, p0.y = ty;
1118
0
                centre.x = x1, centre.y = y1;
1119
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1120
0
                code = patch_fill(pfs, curve, NULL, NULL);
1121
0
                if (code < 0)
1122
0
                    return code;
1123
1124
                /* Q1 is simimlar to Q3, either a full quarter annulus
1125
                 * or a partial one, depending on where the tangent crosses
1126
                 * the y axis
1127
                 */
1128
0
                tanalpha = tan(alpha);
1129
0
                intersecty = y1 + tanalpha * (r2 + (intersectx - x1));
1130
0
                intersectx = x1 - r2;
1131
1132
0
                if (endy < y1 + r2) {
1133
                    /* didn't get all the way to the edge, quadrant 1 is composed of 2 quads :-(
1134
                     * An 'annulus' where the right edge is less than the normal extent and a
1135
                     * quad which is a rectangle with one corner chopped of at an angle.
1136
                     */
1137
0
                    p0.x = x1, p0.y = y1;
1138
0
                    p1.x = x1 - r2, p1.y = endy;
1139
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1140
0
                    p0.x = x1, p0.y = y1 + r1;
1141
0
                    p1.x = x1, p1.y = endy;
1142
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1143
0
                    p0.x = x1 - r2, p0.y = intersecty;
1144
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1145
0
                    p1.x = p0.x, p1.y = y1 + r1;
1146
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1147
0
                    p0.x = x1, p0.y = y1 + r1;
1148
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1149
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1150
0
                    if (code < 0)
1151
0
                        return code;
1152
0
                } else {
1153
                    /* Quadrant 1 is a normal quarter annulua */
1154
0
                    p0.x = x1, p0.y = y1;
1155
0
                    p1.x = x1 - r2, p1.y = y1 + r2;
1156
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1157
0
                }
1158
0
                break;
1159
0
            case 1:
1160
                /* We have two four-sided elements, from the tangent point
1161
                 * each side, to the point where the tangent crosses an
1162
                 * axis of the larger circle. A line back to the edge
1163
                 * of the larger circle, a line to the point where an axis
1164
                 * crosses the smaller circle, then an arc back to the starting point.
1165
                 */
1166
                /* Figure out the tangent point */
1167
                /* sin (angle) = y1 - y0 / r1 - r0
1168
                 * ty = ((y1 - y0) / (r1 - r0)) * r1
1169
                 */
1170
0
                ty = y1 + ((y0 - y1) / (r1 - r0)) * r1;
1171
0
                tx = x1 - ((x1 - x0) / (r1 - r0)) * r1;
1172
                /* Now actually calculating the point where the tangent crosses the axis of the larger circle
1173
                 * So we need to know the angle the tangent makes with the axis of the smaller circle
1174
                 * as its the same angle where it crosses the axis of the larger circle.
1175
                 * We know the centres and the tangent are co-linear, so sin(a) = y0 - y1 / r1 - r0
1176
                 * We know the tangent is r1 from the centre of the larger circle, so the hypotenuse
1177
                 * is r0 / cos(a). That gives us 'x' and we already know y as its the centre of the larger
1178
                 * circle
1179
                 */
1180
0
                sinalpha = (y0 - y1) / (r1 - r0);
1181
0
                alpha = asin(sinalpha);
1182
0
                cosalpha = cos(alpha);
1183
0
                intersectx = x1 - (r1 / cosalpha);
1184
0
                intersecty = y1;
1185
1186
0
                p0.x = tx, p0.y = ty;
1187
0
                p1.x = tx - (tx - intersectx) / 2, p1.y = ty - (ty - intersecty) / 2;
1188
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1189
0
                p0.x = intersectx, p0.y = intersecty;
1190
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1191
0
                p1.x = x1 - r1, p1.y = y1;
1192
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1193
0
                p0.x = tx, p0.y = ty;
1194
0
                centre.x = x1, centre.y = y1;
1195
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1196
0
                code = patch_fill(pfs, curve, NULL, NULL);
1197
0
                if (code < 0)
1198
0
                    return code;
1199
1200
0
                if (intersectx > x1 - r2) {
1201
                    /* didn't get all the way to the edge, quadrant 2 is composed of 2 quads :-(
1202
                     * An 'annulus' where the right edge is less than the normal extent and a
1203
                     * quad which is a rectangle with one corner chopped of at an angle.
1204
                     */
1205
0
                    p0.x = x1, p0.y = y1;
1206
0
                    p1.x = intersectx, p1.y = y1 - r2;
1207
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1208
0
                    endx = x1 - r2;
1209
0
                    endy = y1 - (tan ((M_PI / 2) - alpha)) * (intersectx - endx);
1210
0
                    p0.x = intersectx, p0.y = y1;
1211
0
                    p1.x = x1 - r2, p1.y = endy;
1212
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1213
0
                    p0.x = x1 - r2, p0.y = y0 - r2;
1214
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1215
0
                    p1.x = intersectx, p1.y = p0.y;
1216
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1217
0
                    p0.x = intersectx, p0.y = y1;
1218
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1219
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1220
0
                    if (code < 0)
1221
0
                        return code;
1222
1223
0
                } else {
1224
                    /* Quadrant 2 is a normal quarter annulua */
1225
0
                    p0.x = x1, p0.y = y1;
1226
0
                    p1.x = x1 - r2, p1.y = y1 - r2;
1227
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1228
0
                }
1229
1230
                /* Q3 is always a full annulus... */
1231
0
                p0.x = x1, p0.y = y1;
1232
0
                p1.x = x1 + r2, p1.y = y1 - r2;
1233
0
                draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1234
1235
                /* alpha is now the angle between the x axis and the tangent to the
1236
                 * circles.
1237
                 */
1238
0
                alpha = (M_PI / 2) - alpha;
1239
0
                cosalpha = cos(alpha);
1240
0
                endy = y1 + (r1 / cosalpha);
1241
0
                endx = x1;
1242
1243
0
                p0.x = tx, p0.y = ty;
1244
0
                p1.x = endx + ((tx - endx) / 2), p1.y = endy - ((endy - ty) / 2);
1245
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1246
0
                p0.x = endx, p0.y = endy;
1247
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1248
0
                p1.x = x1, p1.y = y1 + r1;
1249
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1250
0
                p0.x = tx, p0.y = ty;
1251
0
                centre.x = x1, centre.y = y1;
1252
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1253
0
                code = patch_fill(pfs, curve, NULL, NULL);
1254
0
                if (code < 0)
1255
0
                    return code;
1256
1257
                /* Q0 is simimlar to Q2, either a full quarter annulus
1258
                 * or a partial one, depending on where the tangent crosses
1259
                 * the y axis
1260
                 */
1261
0
                tanalpha = tan(alpha);
1262
0
                intersecty = y1 + tanalpha * (r2 + (x1 - intersectx));
1263
0
                intersectx = x1 + r2;
1264
1265
0
                if (endy < y1 + r2) {
1266
                    /* didn't get all the way to the edge, quadrant 0 is composed of 2 quads :-(
1267
                     * An 'annulus' where the right edge is less than the normal extent and a
1268
                     * quad which is a rectangle with one corner chopped of at an angle.
1269
                     */
1270
0
                    p0.x = x1, p0.y = y1;
1271
0
                    p1.x = x1 + r2, p1.y = endy;
1272
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1273
0
                    p0.x = x1, p0.y = y1 + r1;
1274
0
                    p1.x = x1, p1.y = endy;
1275
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1276
0
                    p0.x = x1 + r2, p0.y = intersecty;
1277
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1278
0
                    p1.x = p0.x, p1.y = y1 + r1;
1279
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1280
0
                    p0.x = x1, p0.y = y1 + r1;
1281
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1282
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1283
0
                    if (code < 0)
1284
0
                        return code;
1285
0
                } else {
1286
                    /* Quadrant 0 is a normal quarter annulua */
1287
0
                    p0.x = x1, p0.y = y1;
1288
0
                    p1.x = x1 + r2, p1.y = y1 + r2;
1289
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1290
0
                }
1291
0
                break;
1292
0
            case 2:
1293
                /* We have two four-sided elements, from the tangent point
1294
                 * each side, to the point where the tangent crosses an
1295
                 * axis of the larger circle. A line back to the edge
1296
                 * of the larger circle, a line to the point where an axis
1297
                 * crosses the smaller circle, then an arc back to the starting point.
1298
                 */
1299
                /* Figure out the tangent point */
1300
                /* sin (angle) = y1 - y0 / r1 - r0
1301
                 * ty = ((y1 - y0) / (r1 - r0)) * r1
1302
                 */
1303
0
                ty = y1 - ((y1 - y0) / (r1 - r0)) * r1;
1304
0
                tx = x1 - ((x1 - x0) / (r1 - r0)) * r1;
1305
                /* Now actually calculating the point where the tangent crosses the axis of the larger circle
1306
                 * So we need to know the angle the tangent makes with the axis of the smaller circle
1307
                 * as its the same angle where it crosses the axis of the larger circle.
1308
                 * We know the centres and the tangent are co-linear, so sin(a) = y0 - y1 / r1 - r0
1309
                 * We know the tangent is r1 from the centre of the larger circle, so the hypotenuse
1310
                 * is r0 / cos(a). That gives us 'x' and we already know y as its the centre of the larger
1311
                 * circle
1312
                 */
1313
0
                sinalpha = (y1 - y0) / (r1 - r0);
1314
0
                alpha = asin(sinalpha);
1315
0
                cosalpha = cos(alpha);
1316
0
                intersectx = x1 - (r1 / cosalpha);
1317
0
                intersecty = y1;
1318
1319
0
                p0.x = tx, p0.y = ty;
1320
0
                p1.x = tx + (intersectx - tx) / 2, p1.y = ty - (ty - intersecty) / 2;
1321
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1322
0
                p0.x = intersectx, p0.y = intersecty;
1323
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1324
0
                p1.x = x1 - r1, p1.y = y1;
1325
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1326
0
                p0.x = tx, p0.y = ty;
1327
0
                centre.x = x1, centre.y = y1;
1328
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1329
0
                code = patch_fill(pfs, curve, NULL, NULL);
1330
0
                if (code < 0)
1331
0
                    return code;
1332
0
                if (intersectx > x1 - r2) {
1333
                    /* didn't get all the way to the edge, quadrant 1 is composed of 2 quads :-(
1334
                     * An 'annulus' where the right edge is less than the normal extent and a
1335
                     * quad which is a rectangle with one corner chopped of at an angle.
1336
                     */
1337
0
                    p0.x = x1, p0.y = y1;
1338
0
                    p1.x = intersectx, p1.y = y1 + r2;
1339
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1340
0
                    endy = y1+r2;
1341
0
                    endx = intersectx - ((endy - intersecty) / (tan ((M_PI / 2) - alpha)));
1342
0
                    p0.x = intersectx, p0.y = y1;
1343
0
                    p1.x = endx, p1.y = endy;
1344
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1345
0
                    p0.x = x1 - r1, p0.y = endy;
1346
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1347
0
                    p1.x = x1 - r1, p1.y = y1;
1348
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1349
0
                    p0.x = intersectx, p0.y = y1;
1350
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1351
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1352
0
                    if (code < 0)
1353
0
                        return code;
1354
0
                } else {
1355
                    /* Quadrant 1 is a normal quarter annulua */
1356
0
                    p0.x = x1, p0.y = y1;
1357
0
                    p1.x = x1 - r2, p1.y = y1 + r2;
1358
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1359
0
                }
1360
1361
                /* Q0 is always a full annulus... */
1362
0
                p0.x = x1, p0.y = y1;
1363
0
                p1.x = x1 + r2, p1.y = y1 + r2;
1364
0
                if (p1.y < 0)
1365
0
                    p1.y = 0;
1366
0
                draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1367
1368
                /* alpha is now the angle between the x axis and the tangent to the
1369
                 * circles.
1370
                 */
1371
0
                alpha = (M_PI / 2) - alpha;
1372
0
                cosalpha = cos(alpha);
1373
0
                endy = y1 - (r1 / cosalpha);
1374
0
                endx = x1;
1375
1376
0
                p0.x = tx, p0.y = ty;
1377
0
                p1.x = endx + ((endx - tx) / 2), p1.y = endy - ((ty - endy) / 2);
1378
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1379
0
                p0.x = endx, p0.y = endy;
1380
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1381
0
                p1.x = x1, p1.y = y1 - r1;
1382
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1383
0
                p0.x = tx, p0.y = ty;
1384
0
                centre.x = x1, centre.y = y1;
1385
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1386
0
                code = patch_fill(pfs, curve, NULL, NULL);
1387
0
                if (code < 0)
1388
0
                    return code;
1389
1390
                /* Q3 is simimlar to Q1, either a full quarter annulus
1391
                 * or a partial one, depending on where the tangent crosses
1392
                 * the y axis
1393
                 */
1394
0
                tanalpha = tan(alpha);
1395
0
                intersecty = y1 - tanalpha * (r2 + (x1 - intersectx));
1396
0
                intersectx = x1 + r2;
1397
1398
0
                if (endy > y1 - r2) {
1399
                    /* didn't get all the way to the edge, quadrant 3 is composed of 2 quads :-(
1400
                     * An 'annulus' where the right edge is less than the normal extent and a
1401
                     * quad which is a rectangle with one corner chopped of at an angle.
1402
                     */
1403
0
                    p0.x = x1, p0.y = y1;
1404
0
                    p1.x = x1 + r2, p1.y = endy;
1405
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1406
0
                    p0.x = x1, p0.y = y1 - r1;
1407
0
                    p1.x = x1, p1.y = endy;
1408
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1409
0
                    p0.x = x1 + r2, p0.y = intersecty;
1410
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1411
0
                    p1.x = p0.x, p1.y = y1 - r1;
1412
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1413
0
                    p0.x = x1, p0.y = y1 - r1;
1414
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1415
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1416
0
                    if (code < 0)
1417
0
                        return code;
1418
0
                } else {
1419
                    /* Quadrant 1 is a normal quarter annulua */
1420
0
                    p0.x = x1, p0.y = y1;
1421
0
                    p1.x = x1 + r2, p1.y = y1 - r2;
1422
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1423
0
                }
1424
0
                break;
1425
0
            case 3:
1426
                /* We have two four-sided elements, from the tangent point
1427
                 * each side, to the point where the tangent crosses an
1428
                 * axis of the larger circle. A line back to the edge
1429
                 * of the larger circle, a line to the point where an axis
1430
                 * crosses the smaller circle, then an arc back to the starting point.
1431
                 */
1432
                /* Figure out the tangent point */
1433
                /* sin (angle) = y1 - y0 / r1 - r0
1434
                 * ty = ((y1 - y0) / (r1 - r0)) * r1
1435
                 */
1436
0
                ty = y1 - ((y1 - y0) / (r1 - r0)) * r1;
1437
0
                tx = x1 + ((x0 - x1) / (r1 - r0)) * r1;
1438
                /* Now actually calculating the point where the tangent crosses the axis of the larger circle
1439
                 * So we need to know the angle the tangent makes with the axis of the smaller circle
1440
                 * as its the same angle where it crosses the axis of the larger circle.
1441
                 * We know the centres and the tangent are co-linear, so sin(a) = y0 - y1 / r1 - r0
1442
                 * We know the tangent is r1 from the centre of the larger circle, so the hypotenuse
1443
                 * is r0 / cos(a). That gives us 'x' and we already know y as its the centre of the larger
1444
                 * circle
1445
                 */
1446
0
                sinalpha = (y1 - y0) / (r1 - r0);
1447
0
                alpha = asin(sinalpha);
1448
0
                cosalpha = cos(alpha);
1449
0
                intersectx = x1 + (r1 / cosalpha);
1450
0
                intersecty = y1;
1451
1452
0
                p0.x = tx, p0.y = ty;
1453
0
                p1.x = tx + (intersectx - tx) / 2, p1.y = ty + (intersecty - ty) / 2;
1454
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1455
0
                p0.x = intersectx, p0.y = intersecty;
1456
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1457
0
                p1.x = x1 + r1, p1.y = y1;
1458
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1459
0
                p0.x = tx, p0.y = ty;
1460
0
                centre.x = x1, centre.y = y1;
1461
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1462
0
                code = patch_fill(pfs, curve, NULL, NULL);
1463
0
                if (code < 0)
1464
0
                    return code;
1465
0
                if (intersectx < x1 + r2) {
1466
                    /* didn't get all the way to the edge, quadrant 0 is composed of 2 quads :-(
1467
                     * An 'annulus' where the right edge is less than the normal extent and a
1468
                     * quad which is a rectangle with one corner chopped of at an angle.
1469
                     */
1470
0
                    p0.x = x1, p0.y = y1;
1471
0
                    p1.x = intersectx, p1.y = y1 + r2;
1472
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1473
0
                    endy = y1 + r2;
1474
0
                    endx = intersectx + ((endy - intersecty) / (tan ((M_PI / 2) - alpha)));
1475
0
                    p0.x = intersectx, p0.y = y1;
1476
0
                    p1.x = endx, p1.y = endy;
1477
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1478
0
                    p0.x = x1 + r1, p0.y = endy;
1479
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1480
0
                    p1.x = x1 + r1, p1.y = y1;
1481
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1482
0
                    p0.x = intersectx, p0.y = y1;
1483
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1484
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1485
0
                    if (code < 0)
1486
0
                        return code;
1487
1488
0
                } else {
1489
                    /* Quadrant 0 is a normal quarter annulua */
1490
0
                    p0.x = x1, p0.y = y1;
1491
0
                    p1.x = x1 + r2, p1.y = y1 + r2;
1492
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1493
0
                }
1494
                /* Q1 is always a full annulus... */
1495
0
                p0.x = x1, p0.y = y1;
1496
0
                p1.x = x1 - r2, p1.y = y1 + r2;
1497
0
                draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1498
1499
                /* alpha is now the angle between the x axis and the tangent to the
1500
                 * circles.
1501
                 */
1502
0
                alpha = (M_PI / 2) - alpha;
1503
0
                cosalpha = cos(alpha);
1504
0
                endy = y1 - (r1 / cosalpha);
1505
0
                endx = x1;
1506
1507
0
                p0.x = tx, p0.y = ty;
1508
0
                p1.x = endx + ((tx - endx) / 2), p1.y = endy + ((ty - endy) / 2);
1509
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1510
0
                p0.x = endx, p0.y = endy;
1511
0
                patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1512
0
                p1.x = x1, p1.y = y1 - r1;
1513
0
                patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1514
0
                p0.x = tx, p0.y = ty;
1515
0
                centre.x = x1, centre.y = y1;
1516
0
                patch_curveto(&pfs->pgs->ctm, &centre, &p1, &p0, &curve[3], t0);
1517
0
                code = patch_fill(pfs, curve, NULL, NULL);
1518
0
                if (code < 0)
1519
0
                    return code;
1520
1521
                /* Q3 is simimlar to Q1, either a full quarter annulus
1522
                 * or a partial one, depending on where the tangent crosses
1523
                 * the y axis
1524
                 */
1525
0
                tanalpha = tan(alpha);
1526
0
                intersecty = y1 - tanalpha * (r2 + (intersectx - x1));
1527
0
                intersectx = x1 - r2;
1528
1529
0
                if (endy > y1 - r2) {
1530
                    /* didn't get all the way to the edge, quadrant 3 is composed of 2 quads :-(
1531
                     * An 'annulus' where the right edge is less than the normal extent and a
1532
                     * quad which is a rectangle with one corner chopped of at an angle.
1533
                     */
1534
0
                    p0.x = x1, p0.y = y1;
1535
0
                    p1.x = x1 - r2, p1.y = endy;
1536
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1537
0
                    p0.x = x1, p0.y = y1 - r1;
1538
0
                    p1.x = x1, p1.y = endy;
1539
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[0], t0);
1540
0
                    p0.x = x1 - r2, p0.y = intersecty;
1541
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[1], t0);
1542
0
                    p1.x = p0.x, p1.y = y1 - r1;
1543
0
                    patch_lineto(&pfs->pgs->ctm, &p0, &p1, &curve[2], t0);
1544
0
                    p0.x = x1, p0.y = y1 - r1;
1545
0
                    patch_lineto(&pfs->pgs->ctm, &p1, &p0, &curve[3], t0);
1546
0
                    code = patch_fill(pfs, curve, NULL, NULL);
1547
0
                    if (code < 0)
1548
0
                        return code;
1549
0
                } else {
1550
                    /* Quadrant 1 is a normal quarter annulua */
1551
0
                    p0.x = x1, p0.y = y1;
1552
0
                    p1.x = x1 - r2, p1.y = y1 - r2;
1553
0
                    draw_quarter_annulus(pfs, &p0, r1, &p1, t0);
1554
0
                }
1555
0
                break;
1556
0
        }
1557
0
    }
1558
0
    return 0;
1559
0
}
1560
1561
static int
1562
R_outer_circle(patch_fill_state_t *pfs, const gs_rect *rect,
1563
        double x0, double y0, double r0,
1564
        double x1, double y1, double r1,
1565
        double *x2, double *y2, double *r2)
1566
0
{
1567
0
    double dx = x1 - x0, dy = y1 - y0;
1568
0
    double sp, sq, s;
1569
1570
    /* Compute a cone circle, which contacts the rect externally. */
1571
    /* Don't bother with all 4 sides of the rect,
1572
       just do with the X or Y span only,
1573
       so it's not an exact contact, sorry. */
1574
0
    if (any_abs(dx) > any_abs(dy)) {
1575
        /* Solving :
1576
            x0 + (x1 - x0) * sq + r0 + (r1 - r0) * sq == bbox_px
1577
            (x1 - x0) * sp + (r1 - r0) * sp == bbox_px - x0 - r0
1578
            sp = (bbox_px - x0 - r0) / (x1 - x0 + r1 - r0)
1579
1580
            x0 + (x1 - x0) * sq - r0 - (r1 - r0) * sq == bbox_qx
1581
            (x1 - x0) * sq - (r1 - r0) * sq == bbox_x - x0 + r0
1582
            sq = (bbox_x - x0 + r0) / (x1 - x0 - r1 + r0)
1583
         */
1584
0
        if (x1 - x0 + r1 - r0 ==  0) /* We checked for obtuse cone. */
1585
0
            return_error(gs_error_unregistered); /* Must not happen. */
1586
0
        if (x1 - x0 - r1 + r0 ==  0) /* We checked for obtuse cone. */
1587
0
            return_error(gs_error_unregistered); /* Must not happen. */
1588
0
        sp = (rect->p.x - x0 - r0) / (x1 - x0 + r1 - r0);
1589
0
        sq = (rect->q.x - x0 + r0) / (x1 - x0 - r1 + r0);
1590
0
    } else {
1591
        /* Same by Y. */
1592
0
        if (y1 - y0 + r1 - r0 ==  0) /* We checked for obtuse cone. */
1593
0
            return_error(gs_error_unregistered); /* Must not happen. */
1594
0
        if (y1 - y0 - r1 + r0 ==  0) /* We checked for obtuse cone. */
1595
0
            return_error(gs_error_unregistered); /* Must not happen. */
1596
0
        sp = (rect->p.y - y0 - r0) / (y1 - y0 + r1 - r0);
1597
0
        sq = (rect->q.y - y0 + r0) / (y1 - y0 - r1 + r0);
1598
0
    }
1599
0
    if (sp >= 1 && sq >= 1)
1600
0
        s = max(sp, sq);
1601
0
    else if(sp >= 1)
1602
0
        s = sp;
1603
0
    else if (sq >= 1)
1604
0
        s = sq;
1605
0
    else {
1606
        /* The circle 1 is outside the rect, use it. */
1607
0
        s = 1;
1608
0
    }
1609
0
    if (r0 + (r1 - r0) * s < 0) {
1610
        /* Passed the cone apex, use the apex. */
1611
0
        s = r0 / (r0 - r1);
1612
0
        *r2 = 0;
1613
0
    } else
1614
0
        *r2 = r0 + (r1 - r0) * s;
1615
0
    *x2 = x0 + (x1 - x0) * s;
1616
0
    *y2 = y0 + (y1 - y0) * s;
1617
0
    return 0;
1618
0
}
1619
1620
static double
1621
R_rect_radius(const gs_rect *rect, double x0, double y0)
1622
36
{
1623
36
    double d, dd;
1624
1625
36
    dd = hypot(rect->p.x - x0, rect->p.y - y0);
1626
36
    d = hypot(rect->p.x - x0, rect->q.y - y0);
1627
36
    dd = max(dd, d);
1628
36
    d = hypot(rect->q.x - x0, rect->q.y - y0);
1629
36
    dd = max(dd, d);
1630
36
    d = hypot(rect->q.x - x0, rect->p.y - y0);
1631
36
    dd = max(dd, d);
1632
36
    return dd;
1633
36
}
1634
1635
static int
1636
R_fill_triangle_new(patch_fill_state_t *pfs, const gs_rect *rect,
1637
    double x0, double y0, double x1, double y1, double x2, double y2, double t)
1638
0
{
1639
0
    shading_vertex_t p0, p1, p2;
1640
0
    patch_color_t *c;
1641
0
    int code;
1642
0
    reserve_colors(pfs, &c, 1); /* Can't fail */
1643
1644
0
    p0.c = c;
1645
0
    p1.c = c;
1646
0
    p2.c = c;
1647
0
    code = gs_point_transform2fixed(&pfs->pgs->ctm, x0, y0, &p0.p);
1648
0
    if (code >= 0)
1649
0
        code = gs_point_transform2fixed(&pfs->pgs->ctm, x1, y1, &p1.p);
1650
0
    if (code >= 0)
1651
0
        code = gs_point_transform2fixed(&pfs->pgs->ctm, x2, y2, &p2.p);
1652
0
    if (code >= 0) {
1653
0
        c->t[0] = c->t[1] = t;
1654
0
        patch_resolve_color(c, pfs);
1655
0
        code = mesh_triangle(pfs, &p0, &p1, &p2);
1656
0
    }
1657
0
    release_colors(pfs, pfs->color_stack, 1);
1658
0
    return code;
1659
0
}
1660
1661
static int
1662
R_obtuse_cone(patch_fill_state_t *pfs, const gs_rect *rect,
1663
        double x0, double y0, double r0,
1664
        double x1, double y1, double r1, double t0, double r_rect)
1665
0
{
1666
0
    double dx = x1 - x0, dy = y1 - y0, dr = any_abs(r1 - r0);
1667
0
    double d = hypot(dx, dy);
1668
    /* Assuming dr > d / 3 && d > dr + 1e-7 * (d + dr), see the caller. */
1669
0
    double r = r_rect * 1.4143; /* A few bigger than sqrt(2). */
1670
0
    double ax, ay, as; /* Cone apex. */
1671
0
    double g0; /* The distance from apex to the tangent point of the 0th circle. */
1672
0
    int code;
1673
1674
0
    as = r0 / (r0 - r1);
1675
0
    ax = x0 + (x1 - x0) * as;
1676
0
    ay = y0 + (y1 - y0) * as;
1677
0
    g0 = sqrt(dx * dx + dy * dy - dr * dr) * as;
1678
0
    if (g0 < 1e-7 * r0) {
1679
        /* Nearly degenerate, replace with half-plane. */
1680
        /* Restrict the half plane with triangle, which covers the rect. */
1681
0
        gs_point p0, p1, p2; /* Right tangent limit, apex limit, left tangent linit,
1682
                                (right, left == when looking from the apex). */
1683
1684
0
        p0.x = ax - dy * r / d;
1685
0
        p0.y = ay + dx * r / d;
1686
0
        p1.x = ax - dx * r / d;
1687
0
        p1.y = ay - dy * r / d;
1688
0
        p2.x = ax + dy * r / d;
1689
0
        p2.y = ay - dx * r / d;
1690
        /* Split into 2 triangles at the apex,
1691
           so that the apex is preciselly covered.
1692
           Especially important when it is not exactly degenerate. */
1693
0
        code = R_fill_triangle_new(pfs, rect, ax, ay, p0.x, p0.y, p1.x, p1.y, t0);
1694
0
        if (code < 0)
1695
0
            return code;
1696
0
        return R_fill_triangle_new(pfs, rect, ax, ay, p1.x, p1.y, p2.x, p2.y, t0);
1697
0
    } else {
1698
        /* Compute the "limit" circle so that its
1699
           tangent points are outside the rect. */
1700
        /* Note: this branch is executed when the condition above is false :
1701
           g0 >= 1e-7 * r0 .
1702
           We believe that computing this branch with doubles
1703
           provides enough precision after converting coordinates into 'fixed',
1704
           and that the limit circle radius is not dramatically big.
1705
         */
1706
0
        double es, er; /* The limit circle parameter, radius. */
1707
0
        double ex, ey; /* The limit circle centrum. */
1708
1709
0
        es = as - as * r / g0; /* Always negative. */
1710
0
        er = r * r0 / g0 ;
1711
0
        ex = x0 + dx * es;
1712
0
        ey = y0 + dy * es;
1713
        /* Fill the annulus: */
1714
0
        code = R_tensor_annulus(pfs, x0, y0, r0, t0, ex, ey, er, t0);
1715
0
        if (code < 0)
1716
0
            return code;
1717
        /* Fill entire ending circle to ensure entire rect is covered. */
1718
0
        return R_tensor_annulus(pfs, ex, ey, er, t0, ex, ey, 0, t0);
1719
0
    }
1720
0
}
1721
1722
static int
1723
R_tensor_cone_apex(patch_fill_state_t *pfs, const gs_rect *rect,
1724
        double x0, double y0, double r0,
1725
        double x1, double y1, double r1, double t)
1726
0
{
1727
0
    double as = r0 / (r0 - r1);
1728
0
    double ax = x0 + (x1 - x0) * as;
1729
0
    double ay = y0 + (y1 - y0) * as;
1730
1731
0
    return R_tensor_annulus(pfs, x1, y1, r1, t, ax, ay, 0, t);
1732
0
}
1733
1734
/*
1735
 * A map of this code:
1736
 *
1737
 * R_extensions
1738
 * |-> (R_rect_radius)
1739
 * |-> (R_outer_circle)
1740
 * |-> R_obtuse_cone
1741
 * |   |-> R_fill_triangle_new
1742
 * |   |   '-> mesh_triangle
1743
 * |   |       '-> mesh_triangle_rec <--.
1744
 * |   |           |--------------------'
1745
 * |   |           |-> small_mesh_triangle
1746
 * |   |           |   '-> fill_triangle
1747
 * |   |           |       '-> triangle_by_4 <--.
1748
 * |   |           |           |----------------'
1749
 * |   |           |           |-> constant_color_triangle
1750
 * |   |           |           |-> make_wedge_median (etc)
1751
 * |   |           '-----------+--------------------.
1752
 * |   '-------------------.                        |
1753
 * |-> R_tensor_cone_apex  |                        |
1754
 * |   '-------------------+                        |
1755
 * '-> R_tensor_annulus <--'                       \|/
1756
 *     |-> (make_quadrant_arc)                      |
1757
 *     '-> patch_fill                               |
1758
 *         |-> fill_patch <--.                      |
1759
 *         |   |-------------'                      |
1760
 *         |   |------------------------------------+
1761
 *         |   '-> fill_stripe                      |
1762
 *         |       |-----------------------.        |
1763
 *         |      \|/                      |        |
1764
 *         |-> fill_wedges                 |        |
1765
 *             '-> fill_wedges_aux <--.    |        |
1766
 *                 |------------------'   \|/       |
1767
 *                 |----------------> mesh_padding  '
1768
 *                 |                  '----------------------------------.
1769
 *                 '-> wedge_by_triangles <--.      .                    |
1770
 *                     |---------------------'      |                    |
1771
 *                     '-> fill_triangle_wedge <----'                    |
1772
 *                         '-> fill_triangle_wedge_aux                   |
1773
 *                             '-> fill_wedge_trap                       |
1774
 *                                 '-> wedge_trap_decompose              |
1775
 *                                     '-> linear_color_trapezoid        |
1776
 *                                         '-> decompose_linear_color <--|
1777
 *                                             |-------------------------'
1778
 *                                             '-> constant_color_trapezoid
1779
 */
1780
static int
1781
R_extensions(patch_fill_state_t *pfs, const gs_shading_R_t *psh, const gs_rect *rect,
1782
        double t0, double t1, bool Extend0, bool Extend1)
1783
76
{
1784
76
    float x0 = psh->params.Coords[0], y0 = psh->params.Coords[1];
1785
76
    double r0 = psh->params.Coords[2];
1786
76
    float x1 = psh->params.Coords[3], y1 = psh->params.Coords[4];
1787
76
    double r1 = psh->params.Coords[5];
1788
76
    double dx = x1 - x0, dy = y1 - y0, dr = any_abs(r1 - r0);
1789
76
    double d = hypot(dx, dy), r;
1790
76
    int code;
1791
1792
    /* In order for the circles to be nested, one end circle
1793
     * needs to be sufficiently large to cover the entirety
1794
     * of the other end circle. i.e.
1795
     *
1796
     *     max(r0,r1) >= d + min(r0,r1)
1797
     * === min(r0,r1) + dr >= d + min(r0,r1)
1798
     * === dr >= d
1799
     *
1800
     * This, plus a fudge factor for FP operation is what we use below.
1801
     *
1802
     * An "Obtuse Cone" is defined to be one for which the "opening
1803
     * angle" is obtuse.
1804
     *
1805
     * Consider two circles; one at (r0,r0) of radius r0, and one at
1806
     * (r1,r1) of radius r1. These clearly lie on the acute/obtuse
1807
     * boundary. The distance between the centres of these two circles
1808
     * is d = sqr(2.(r0-r1)^2) by pythagoras. Thus d = sqr(2).dr.
1809
     * By observation if d gets longer, we become acute, shorter, obtuse.
1810
     * i.e. if sqr(2).dr > d we are obtuse, if d > sqr(2).dr we are acute.
1811
     * (Thanks to Paul Gardiner for this reasoning).
1812
     *
1813
     * The code below tests (dr > d/3) (i.e. 3.dr > d). This
1814
     * appears to be a factor of 2 and a bit out, so I am confused
1815
     * by it.
1816
     *
1817
     * Either Igor meant something different to the standard meaning
1818
     * of "Obtuse Cone", or he got his maths wrong. Or he was more
1819
     * cunning than I can understand. Leave it as it until we find
1820
     * an actual example that goes wrong.
1821
     */
1822
1823
    /* Tests with Acrobat seem to indicate that it uses a fudge factor
1824
     * of around .0001. (i.e. [1.0001 0 0 0 0 1] is accepted as a
1825
     * non nested circle, but [1.00009 0 0 0 0 1] is a nested one.
1826
     * Approximate the same sort of value here to appease bug 690831.
1827
     */
1828
76
    if (any_abs (dr - d) < 0.001) {
1829
0
        if ((r0 > r1 && Extend0) || (r1 > r0 && Extend1)) {
1830
0
            r = R_rect_radius(rect, x0, y0);
1831
0
            if (r0 < r1)
1832
0
                code = R_tensor_annulus_extend_tangent(pfs, x0, y0, r0, t1, x1, y1, r1, t1, r);
1833
0
            else
1834
0
                code = R_tensor_annulus_extend_tangent(pfs, x1, y1, r1, t0, x0, y0, r0, t0, r);
1835
0
            if (code < 0)
1836
0
                return code;
1837
0
        } else {
1838
0
            if (r0 > r1) {
1839
0
                if (Extend1 && r1 > 0)
1840
0
                    return R_tensor_annulus(pfs, x1, y1, r1, t1, x1, y1, 0, t1);
1841
0
            }
1842
0
            else {
1843
0
                if (Extend0 && r0 > 0)
1844
0
                    return R_tensor_annulus(pfs, x0, y0, r0, t0, x0, y0, 0, t0);
1845
0
            }
1846
0
        }
1847
0
    } else
1848
76
    if (dr > d - 1e-4 * (d + dr)) {
1849
        /* Nested circles, or degenerate. */
1850
76
        if (r0 > r1) {
1851
0
            if (Extend0) {
1852
0
                r = R_rect_radius(rect, x0, y0);
1853
0
                if (r > r0) {
1854
0
                    code = R_tensor_annulus(pfs, x0, y0, r, t0, x0, y0, r0, t0);
1855
0
                    if (code < 0)
1856
0
                        return code;
1857
0
                }
1858
0
            }
1859
0
            if (Extend1 && r1 > 0)
1860
0
                return R_tensor_annulus(pfs, x1, y1, r1, t1, x1, y1, 0, t1);
1861
76
        } else {
1862
76
            if (Extend1) {
1863
36
                r = R_rect_radius(rect, x1, y1);
1864
36
                if (r > r1) {
1865
36
                    code = R_tensor_annulus(pfs, x1, y1, r, t1, x1, y1, r1, t1);
1866
36
                    if (code < 0)
1867
0
                        return code;
1868
36
                }
1869
36
            }
1870
76
            if (Extend0 && r0 > 0)
1871
0
                return R_tensor_annulus(pfs, x0, y0, r0, t0, x0, y0, 0, t0);
1872
76
        }
1873
76
    } else if (dr > d / 3) {
1874
        /* Obtuse cone. */
1875
0
        if (r0 > r1) {
1876
0
            if (Extend0) {
1877
0
                r = R_rect_radius(rect, x0, y0);
1878
0
                code = R_obtuse_cone(pfs, rect, x0, y0, r0, x1, y1, r1, t0, r);
1879
0
                if (code < 0)
1880
0
                    return code;
1881
0
            }
1882
0
            if (Extend1 && r1 != 0)
1883
0
                return R_tensor_cone_apex(pfs, rect, x0, y0, r0, x1, y1, r1, t1);
1884
0
            return 0;
1885
0
        } else {
1886
0
            if (Extend1) {
1887
0
                r = R_rect_radius(rect, x1, y1);
1888
0
                code = R_obtuse_cone(pfs, rect, x1, y1, r1, x0, y0, r0, t1, r);
1889
0
                if (code < 0)
1890
0
                    return code;
1891
0
            }
1892
0
            if (Extend0 && r0 != 0)
1893
0
                return R_tensor_cone_apex(pfs, rect, x1, y1, r1, x0, y0, r0, t0);
1894
0
        }
1895
0
    } else {
1896
        /* Acute cone or cylinder. */
1897
0
        double x2, y2, r2, x3, y3, r3;
1898
1899
0
        if (Extend0) {
1900
0
            code = R_outer_circle(pfs, rect, x1, y1, r1, x0, y0, r0, &x3, &y3, &r3);
1901
0
            if (code < 0)
1902
0
                return code;
1903
0
            if (x3 != x1 || y3 != y1) {
1904
0
                code = R_tensor_annulus(pfs, x0, y0, r0, t0, x3, y3, r3, t0);
1905
0
                if (code < 0)
1906
0
                    return code;
1907
0
            }
1908
0
        }
1909
0
        if (Extend1) {
1910
0
            code = R_outer_circle(pfs, rect, x0, y0, r0, x1, y1, r1, &x2, &y2, &r2);
1911
0
            if (code < 0)
1912
0
                return code;
1913
0
            if (x2 != x0 || y2 != y0) {
1914
0
                code = R_tensor_annulus(pfs, x1, y1, r1, t1, x2, y2, r2, t1);
1915
0
                if (code < 0)
1916
0
                    return code;
1917
0
            }
1918
0
        }
1919
0
    }
1920
76
    return 0;
1921
76
}
1922
1923
static int
1924
R_fill_rect_with_const_color(patch_fill_state_t *pfs, const gs_fixed_rect *clip_rect, float t)
1925
0
{
1926
#if 0 /* Disabled because the clist writer device doesn't pass
1927
         the clipping path with fill_recatangle. */
1928
    patch_color_t pc;
1929
    const gs_color_space *pcs = pfs->direct_space;
1930
    gx_device_color dc;
1931
    int code;
1932
1933
    code = gs_function_evaluate(pfs->Function, &t, pc.cc.paint.values);
1934
    if (code < 0)
1935
        return code;
1936
    pcs->type->restrict_color(&pc.cc, pcs);
1937
    code = patch_color_to_device_color(pfs, &pc, &dc);
1938
    if (code < 0)
1939
        return code;
1940
    return gx_fill_rectangle_device_rop(fixed2int_pixround(clip_rect->p.x), fixed2int_pixround(clip_rect->p.y),
1941
                                        fixed2int_pixround(clip_rect->q.x) - fixed2int_pixround(clip_rect->p.x),
1942
                                        fixed2int_pixround(clip_rect->q.y) - fixed2int_pixround(clip_rect->p.y),
1943
                                        &dc, pfs->dev, pfs->pgs->log_op);
1944
#else
1945
    /* Can't apply fill_rectangle, because the clist writer device doesn't pass
1946
       the clipping path with fill_recatangle. Convert into trapezoids instead.
1947
    */
1948
0
    quadrangle_patch p;
1949
0
    shading_vertex_t pp[2][2];
1950
0
    const gs_color_space *pcs = pfs->direct_space;
1951
0
    patch_color_t pc;
1952
0
    int code;
1953
1954
0
    code = gs_function_evaluate(pfs->Function, &t, pc.cc.paint.values);
1955
0
    if (code < 0)
1956
0
        return code;
1957
0
    pcs->type->restrict_color(&pc.cc, pcs);
1958
0
    pc.t[0] = pc.t[1] = t;
1959
0
    pp[0][0].p = clip_rect->p;
1960
0
    pp[0][1].p.x = clip_rect->q.x;
1961
0
    pp[0][1].p.y = clip_rect->p.y;
1962
0
    pp[1][0].p.x = clip_rect->p.x;
1963
0
    pp[1][0].p.y = clip_rect->q.y;
1964
0
    pp[1][1].p = clip_rect->q;
1965
0
    pp[0][0].c = pp[0][1].c = pp[1][0].c = pp[1][1].c = &pc;
1966
0
    p.p[0][0] = &pp[0][0];
1967
0
    p.p[0][1] = &pp[0][1];
1968
0
    p.p[1][0] = &pp[1][0];
1969
0
    p.p[1][1] = &pp[1][1];
1970
0
    return constant_color_quadrangle(pfs, &p, false);
1971
0
#endif
1972
0
}
1973
1974
typedef struct radial_shading_attrs_s {
1975
    double x0, y0;
1976
    double x1, y1;
1977
    double span[2][2];
1978
    double apex;
1979
    bool have_apex;
1980
    bool have_root[2]; /* ongoing contact, outgoing contact. */
1981
    bool outer_contact[2];
1982
    gs_point p[6]; /* 4 corners of the rectangle, p[4] = p[0], p[5] = p[1] */
1983
} radial_shading_attrs_t;
1984
1985
672
#define Pw2(a) ((a)*(a))
1986
1987
static void
1988
radial_shading_external_contact(radial_shading_attrs_t *rsa, int point_index, double t, double r0, double r1, bool at_corner, int root_index)
1989
144
{
1990
144
    double cx = rsa->x0 + (rsa->x1 - rsa->x0) * t;
1991
144
    double cy = rsa->y0 + (rsa->y1 - rsa->y0) * t;
1992
144
    double rx = rsa->p[point_index].x - cx;
1993
144
    double ry = rsa->p[point_index].y - cy;
1994
144
    double dx = rsa->p[point_index - 1].x - rsa->p[point_index].x;
1995
144
    double dy = rsa->p[point_index - 1].y - rsa->p[point_index].y;
1996
1997
144
    if (at_corner) {
1998
112
        double Dx = rsa->p[point_index + 1].x - rsa->p[point_index].x;
1999
112
        double Dy = rsa->p[point_index + 1].y - rsa->p[point_index].y;
2000
112
        bool b1 = (dx * rx + dy * ry >= 0);
2001
112
        bool b2 = (Dx * rx + Dy * ry >= 0);
2002
2003
112
        if (b1 & b2)
2004
48
            rsa->outer_contact[root_index] = true;
2005
112
    } else {
2006
32
        if (rx * dy - ry * dx < 0)
2007
0
            rsa->outer_contact[root_index] = true;
2008
32
    }
2009
144
}
2010
2011
static void
2012
store_roots(radial_shading_attrs_t *rsa, const bool have_root[2], const double t[2], double r0, double r1, int point_index, bool at_corner)
2013
192
{
2014
192
    int i;
2015
2016
576
    for (i = 0; i < 2; i++) {
2017
384
        bool good_root;
2018
2019
384
        if (!have_root[i])
2020
160
            continue;
2021
224
        good_root = (!rsa->have_apex || (rsa->apex <= 0 || r0 == 0 ? t[i] >= rsa->apex : t[i] <= rsa->apex));
2022
224
        if (good_root) {
2023
144
            radial_shading_external_contact(rsa, point_index, t[i], r0, r1, at_corner, i);
2024
144
            if (!rsa->have_root[i]) {
2025
7
                rsa->span[i][0] = rsa->span[i][1] = t[i];
2026
7
                rsa->have_root[i] = true;
2027
137
            } else {
2028
137
                if (rsa->span[i][0] > t[i])
2029
5
                    rsa->span[i][0] = t[i];
2030
137
                if (rsa->span[i][1] < t[i])
2031
10
                    rsa->span[i][1] = t[i];
2032
137
            }
2033
144
        }
2034
224
    }
2035
192
}
2036
2037
static void
2038
compute_radial_shading_span_extended_side(radial_shading_attrs_t *rsa, double r0, double r1, int point_index)
2039
96
{
2040
96
    double cc, c;
2041
96
    bool have_root[2] = {false, false};
2042
96
    double t[2];
2043
96
    bool by_x = (rsa->p[point_index].x != rsa->p[point_index + 1].x);
2044
96
    int i;
2045
2046
    /* As t moves from 0 to 1, the circles move from r0 to r1, and from
2047
     * from position p0 to py. For simplicity, adjust so that p0 is at
2048
     * the origin. Consider the projection of the circle drawn at any given
2049
     * time onto the x axis. The range of points would be:
2050
     * p1x*t +/- (r0+(r1-r0)*t). We are interested in the first (and last)
2051
     * moments when the range includes a point c on the x axis. So solve for:
2052
     * p1x*t +/- (r0+(r1-r0)*t) = c. Let cc = p1x.
2053
     * So p1x*t0 + (r1-r0)*t0 = c - r0 => t0 = (c - r0)/(p1x + r1 - r0)
2054
     *    p1x*t1 - (r1-r0)*t1 = c + r0 => t1 = (c + r0)/(p1x - r1 + r0)
2055
     */
2056
96
    if (by_x) {
2057
40
        c = rsa->p[point_index].x - rsa->x0;
2058
40
        cc = rsa->x1 - rsa->x0;
2059
56
    } else {
2060
56
        c = rsa->p[point_index].y - rsa->y0;
2061
56
        cc = rsa->y1 - rsa->y0;
2062
56
    }
2063
96
    t[0] = (c - r0) / (cc + r1 - r0);
2064
96
    t[1] = (c + r0) / (cc - r1 + r0);
2065
96
    if (t[0] > t[1]) {
2066
76
        c    = t[0];
2067
76
        t[0] = t[1];
2068
76
        t[1] = c;
2069
76
    }
2070
288
    for (i = 0; i < 2; i++) {
2071
192
        double d, d0, d1;
2072
2073
192
        if (by_x) {
2074
80
            d = rsa->y1 - rsa->y0 + r0 + (r1 - r0) * t[i];
2075
80
            d0 = rsa->p[point_index].y;
2076
80
            d1 = rsa->p[point_index + 1].y;
2077
112
        } else {
2078
112
            d = rsa->x1 - rsa->x0 + r0 + (r1 - r0) * t[i];
2079
112
            d0 = rsa->p[point_index].x;
2080
112
            d1 = rsa->p[point_index + 1].x;
2081
112
        }
2082
192
        if (d1 > d0 ? d0 <= d && d <= d1 : d1 <= d && d <= d0)
2083
32
            have_root[i] = true;
2084
192
    }
2085
96
    store_roots(rsa, have_root, t, r0, r1, point_index, false);
2086
96
}
2087
2088
static int
2089
compute_radial_shading_span_extended_point(radial_shading_attrs_t *rsa, double r0, double r1, int point_index)
2090
96
{
2091
    /* As t moves from 0 to 1, the circles move from r0 to r1, and from
2092
     * from position p0 to py. At any given time t, therefore, we
2093
     * paint the points that are distance r0+(r1-r0)*t from point
2094
     * (p0x+(p1x-p0x)*t,p0y+(p1y-p0y)*t) = P(t).
2095
     *
2096
     * To simplify our algebra, adjust so that (p0x, p0y) is at the origin.
2097
     * To find the time(s) t at which the a point q is painted, we therefore
2098
     * solve for t in:
2099
     *
2100
     * |q-P(t)| = r0+(r1-r0)*t
2101
     *
2102
     *   (qx-p1x*t)^2 + (qy-p1y*t)^2 - (r0+(r1-r0)*t)^2 = 0
2103
     * = qx^2 - 2qx.p1x.t + p1x^2.t^2 + qy^2 - 2qy.p1y.t + p1y^2.t^2 -
2104
     *                                   (r0^2 + 2r0(r1-r0)t + (r1-r0)^2.t^2)
2105
     * =   qx^2 + qy^2 - r0^2
2106
     *   + -2(qx.p1x + qy.p1y + r0(r1-r0)).t
2107
     *   + (p1x^2 + p1y^2 - (r1-r0)^2).t^2
2108
     *
2109
     * So solve using the usual t = (-b +/- SQRT(b^2 - 4ac)) where
2110
     *   a = p1x^2 + p1y^2 - (r1-r0)^2
2111
     *   b = -2(qx.p1x + qy.p1y + r0(r1-r0))
2112
     *   c = qx^2 + qy^2 - r0^2
2113
     */
2114
96
    double p1x = rsa->x1 - rsa->x0;
2115
96
    double p1y = rsa->y1 - rsa->y0;
2116
96
    double qx  = rsa->p[point_index].x - rsa->x0;
2117
96
    double qy  = rsa->p[point_index].y - rsa->y0;
2118
96
    double a   = (Pw2(p1x) + Pw2(p1y) - Pw2(r0 - r1));
2119
96
    bool have_root[2] = {false, false};
2120
96
    double t[2];
2121
2122
96
    if (fabs(a) < 1e-8) {
2123
        /* Linear equation. */
2124
        /* This case is always the ongoing ellipse contact. */
2125
0
        double cx = rsa->x0 - (rsa->x1 - rsa->x0) * r0 / (r1 - r0);
2126
0
        double cy = rsa->y0 - (rsa->y1 - rsa->y0) * r0 / (r1 - r0);
2127
2128
0
        t[0] = (Pw2(qx) + Pw2(qy))/(cx*qx + cy*qy) / 2;
2129
0
        have_root[0] = true;
2130
96
    } else {
2131
        /* Square equation.  No solution if b^2 - 4ac = 0. Equivalently if
2132
         * (b^2)/4 -a.c = 0 === (b/2)^2 - a.c = 0 ===  (-b/2)^2 - a.c = 0 */
2133
96
        double minushalfb = r0*(r1-r0) + p1x*qx + p1y*qy;
2134
96
        double c          = Pw2(qx) + Pw2(qy) - Pw2(r0);
2135
96
        double desc2      = Pw2(minushalfb) - a*c; /* desc2 = 1/4 (b^2-4ac) */
2136
2137
96
        if (desc2 < 0) {
2138
0
            return -1; /* The point is outside the shading coverage.
2139
                          Do not shorten, because we didn't observe it in practice. */
2140
96
        } else {
2141
96
            double desc1 = sqrt(desc2); /* desc1 = 1/2 SQRT(b^2-4ac) */
2142
2143
96
            if (a > 0) {
2144
0
                t[0] = (minushalfb - desc1) / a;
2145
0
                t[1] = (minushalfb + desc1) / a;
2146
96
            } else {
2147
96
                t[0] = (minushalfb + desc1) / a;
2148
96
                t[1] = (minushalfb - desc1) / a;
2149
96
            }
2150
96
            have_root[0] = have_root[1] = true;
2151
96
        }
2152
96
    }
2153
96
    store_roots(rsa, have_root, t, r0, r1, point_index, true);
2154
96
    if (have_root[0] && have_root[1])
2155
96
        return 15;
2156
0
    if (have_root[0])
2157
0
        return 15 - 4;
2158
0
    if (have_root[1])
2159
0
        return 15 - 2;
2160
0
    return -1;
2161
0
}
2162
2163
#undef Pw2
2164
2165
static int
2166
compute_radial_shading_span_extended(radial_shading_attrs_t *rsa, double r0, double r1)
2167
24
{
2168
24
    int span_type0, span_type1;
2169
2170
24
    span_type0 = compute_radial_shading_span_extended_point(rsa, r0, r1, 1);
2171
24
    if (span_type0 == -1)
2172
0
        return -1;
2173
24
    span_type1 = compute_radial_shading_span_extended_point(rsa, r0, r1, 2);
2174
24
    if (span_type0 != span_type1)
2175
0
        return -1;
2176
24
    span_type1 = compute_radial_shading_span_extended_point(rsa, r0, r1, 3);
2177
24
    if (span_type0 != span_type1)
2178
0
        return -1;
2179
24
    span_type1 = compute_radial_shading_span_extended_point(rsa, r0, r1, 4);
2180
24
    if (span_type0 != span_type1)
2181
0
        return -1;
2182
24
    compute_radial_shading_span_extended_side(rsa, r0, r1, 1);
2183
24
    compute_radial_shading_span_extended_side(rsa, r0, r1, 2);
2184
24
    compute_radial_shading_span_extended_side(rsa, r0, r1, 3);
2185
24
    compute_radial_shading_span_extended_side(rsa, r0, r1, 4);
2186
24
    return span_type0;
2187
24
}
2188
2189
static int
2190
compute_radial_shading_span(radial_shading_attrs_t *rsa, float x0, float y0, double r0, float x1, float y1, double r1, const gs_rect * rect)
2191
6
{
2192
    /* If the shading area is much larger than the path bbox,
2193
       we want to shorten the shading for a faster rendering.
2194
       If any point of the path bbox falls outside the shading area,
2195
       our math is not applicable, and we render entire shading.
2196
       If the path bbox is inside the shading area,
2197
       we compute 1 or 2 'spans' - the shading parameter intervals,
2198
       which covers the bbox. For doing that we need to resolve
2199
       a square eqation by the shading parameter
2200
       for each corner of the bounding box,
2201
       and for each side of the shading bbox.
2202
       Note the equation to be solved in the user space.
2203
       Since each equation gives 2 roots (because the points are
2204
       strongly inside the shading area), we will get 2 parameter intervals -
2205
       the 'lower' one corresponds to the first (ongoing) contact of
2206
       the running circle, and the second one corresponds to the last (outgoing) contact
2207
       (like in a sun eclipse; well our sun is rectangular).
2208
2209
       Here are few exceptions.
2210
2211
       First, the equation degenerates when the distance sqrt((x1-x0)^2 + (y1-y0)^2)
2212
       appears equal to r0-r1. In this case the base circles do contact,
2213
       and the running circle does contact at the same point.
2214
       The equation degenerates to a linear one.
2215
       Since we don't want float precision noize to affect the result,
2216
       we compute this condition in 'fixed' coordinates.
2217
2218
       Second, Postscript approximates any circle with 3d order beziers.
2219
       This approximation may give a 2% error.
2220
       Therefore using the precise roots may cause a dropout.
2221
       To prevetn them, we slightly modify the base radii.
2222
       However the sign of modification smartly depends
2223
       on the relative sizes of the base circles,
2224
       and on the contact number. Currently we don't want to
2225
       define and debug the smart optimal logic for that,
2226
       so we simply try all 4 variants for each source equation,
2227
       and use the union of intervals.
2228
2229
       Third, we could compute which quarter of the circle
2230
       really covers the path bbox. Using it we could skip
2231
       rendering of uncovering quarters. Currently we do not
2232
       implement this optimization. The general tensor patch algorithm
2233
       will skip uncovering parts.
2234
2235
       Fourth, when one base circle is (almost) inside the other,
2236
       the parameter interval must include the shading apex.
2237
       To know that, we determine whether the contacting circle
2238
       is outside the rectangle (the "outer" contact),
2239
       or it is (partially) inside the rectangle.
2240
2241
       At last, a small shortening of a shading won't give a
2242
       sensible speedup, but it may replace a symmetric function domain
2243
       with an assymmetric one, so that the rendering
2244
       would be asymmetyric for a symmetric shading.
2245
       Therefore we do not perform a small sortening.
2246
       Instead we shorten only if the shading span
2247
       is much smaller that the shading domain.
2248
     */
2249
6
    const double extent = 1.02;
2250
6
    int span_type0, span_type1, span_type;
2251
2252
6
    memset(rsa, 0, sizeof(*rsa));
2253
6
    rsa->x0 = x0;
2254
6
    rsa->y0 = y0;
2255
6
    rsa->x1 = x1;
2256
6
    rsa->y1 = y1;
2257
6
    rsa->p[0] = rsa->p[4] = rect->p;
2258
6
    rsa->p[1].x = rsa->p[5].x = rect->p.x;
2259
6
    rsa->p[1].y = rsa->p[5].y = rect->q.y;
2260
6
    rsa->p[2] = rect->q;
2261
6
    rsa->p[3].x = rect->q.x;
2262
6
    rsa->p[3].y = rect->p.y;
2263
6
    rsa->have_apex = any_abs(r1 - r0) > 1e-7 * any_abs(r1 + r0);
2264
6
    rsa->apex = (rsa->have_apex ? -r0 / (r1 - r0) : 0);
2265
6
    span_type0 = compute_radial_shading_span_extended(rsa, r0 / extent, r1 * extent);
2266
6
    if (span_type0 == -1)
2267
0
        return -1;
2268
6
    span_type1 = compute_radial_shading_span_extended(rsa, r0 / extent, r1 / extent);
2269
6
    if (span_type0 != span_type1)
2270
0
        return -1;
2271
6
    span_type1 = compute_radial_shading_span_extended(rsa, r0 * extent, r1 * extent);
2272
6
    if (span_type0 != span_type1)
2273
0
        return -1;
2274
6
    span_type1 = compute_radial_shading_span_extended(rsa, r0 * extent, r1 / extent);
2275
6
    if (span_type1 == -1)
2276
0
        return -1;
2277
6
    if (r0 < r1) {
2278
6
        if (rsa->have_root[0] && !rsa->outer_contact[0])
2279
0
            rsa->span[0][0] = rsa->apex; /* Likely never happens. Remove ? */
2280
6
        if (rsa->have_root[1] && !rsa->outer_contact[1])
2281
1
            rsa->span[1][0] = rsa->apex;
2282
6
    } else if (r0 > r1) {
2283
0
        if (rsa->have_root[0] && !rsa->outer_contact[0])
2284
0
            rsa->span[0][1] = rsa->apex;
2285
0
        if (rsa->have_root[1] && !rsa->outer_contact[1])
2286
0
            rsa->span[1][1] = rsa->apex; /* Likely never happens. Remove ? */
2287
0
    }
2288
6
    span_type = 0;
2289
6
    if (rsa->have_root[0] && rsa->span[0][0] < 0)
2290
0
        span_type |= 1;
2291
6
    if (rsa->have_root[1] && rsa->span[1][0] < 0)
2292
0
        span_type |= 1;
2293
6
    if (rsa->have_root[0] && rsa->span[0][1] > 0 && rsa->span[0][0] < 1)
2294
0
        span_type |= 2;
2295
6
    if (rsa->have_root[1] && rsa->span[1][1] > 0 && rsa->span[1][0] < 1)
2296
5
        span_type |= 4;
2297
6
    if (rsa->have_root[0] && rsa->span[0][1] > 1)
2298
0
        span_type |= 8;
2299
6
    if (rsa->have_root[1] && rsa->span[1][1] > 1)
2300
0
        span_type |= 8;
2301
6
    return span_type;
2302
6
}
2303
2304
static bool
2305
shorten_radial_shading(float *x0, float *y0, double *r0, float *d0, float *x1, float *y1, double *r1, float *d1, double span_[2])
2306
5
{
2307
5
    double s0 = span_[0], s1 = span_[1], w;
2308
2309
5
    if (s0 < 0)
2310
0
        s0 = 0;
2311
5
    if (s1 < 0)
2312
0
        s1 = 0;
2313
5
    if (s0 > 1)
2314
0
        s0 = 1;
2315
5
    if (s1 > 1)
2316
0
        s1 = 1;
2317
5
    w = s1 - s0;
2318
5
    if (w == 0)
2319
0
        return false; /* Don't pass a degenerate shading. */
2320
5
    if (w > 0.3)
2321
5
        return false; /* The span is big, don't shorten it. */
2322
0
    { /* Do shorten. */
2323
0
        double R0 = *r0, X0 = *x0, Y0 = *y0, D0 = *d0;
2324
0
        double R1 = *r1, X1 = *x1, Y1 = *y1, D1 = *d1;
2325
2326
0
        *r0 = R0 + (R1 - R0) * s0;
2327
0
        *x0 = X0 + (X1 - X0) * s0;
2328
0
        *y0 = Y0 + (Y1 - Y0) * s0;
2329
0
        *d0 = D0 + (D1 - D0) * s0;
2330
0
        *r1 = R0 + (R1 - R0) * s1;
2331
0
        *x1 = X0 + (X1 - X0) * s1;
2332
0
        *y1 = Y0 + (Y1 - Y0) * s1;
2333
0
        *d1 = D0 + (D1 - D0) * s1;
2334
0
    }
2335
0
    return true;
2336
5
}
2337
2338
static bool inline
2339
is_radial_shading_large(double x0, double y0, double r0, double x1, double y1, double r1, const gs_rect * rect)
2340
44
{
2341
44
    const double d = hypot(x1 - x0, y1 - y0);
2342
44
    const double area0 = M_PI * r0 * r0 / 2;
2343
44
    const double area1 = M_PI * r1 * r1 / 2;
2344
44
    const double area2 = (r0 + r1) / 2 * d;
2345
44
    const double arbitrary = 8;
2346
44
    double areaX, areaY;
2347
2348
    /* The shading area is not equal to area0 + area1 + area2
2349
       when one circle is (almost) inside the other.
2350
       We believe that the 'arbitrary' coefficient recovers that
2351
       when it is set greater than 2. */
2352
    /* If one dimension is large enough, the shading parameter span is wide. */
2353
44
    areaX = (rect->q.x - rect->p.x) * (rect->q.x - rect->p.x);
2354
44
    if (areaX * arbitrary < area0 + area1 + area2)
2355
5
        return true;
2356
39
    areaY = (rect->q.y - rect->p.y) * (rect->q.y - rect->p.y);
2357
39
    if (areaY * arbitrary < area0 + area1 + area2)
2358
1
        return true;
2359
38
    return false;
2360
39
}
2361
2362
static int
2363
gs_shading_R_fill_rectangle_aux(const gs_shading_t * psh0, const gs_rect * rect,
2364
                            const gs_fixed_rect *clip_rect,
2365
                            gx_device * dev, gs_gstate * pgs)
2366
44
{
2367
44
    const gs_shading_R_t *const psh = (const gs_shading_R_t *)psh0;
2368
44
    float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1];
2369
44
    float x0 = psh->params.Coords[0], y0 = psh->params.Coords[1];
2370
44
    double r0 = psh->params.Coords[2];
2371
44
    float x1 = psh->params.Coords[3], y1 = psh->params.Coords[4];
2372
44
    double r1 = psh->params.Coords[5];
2373
44
    radial_shading_attrs_t rsa;
2374
44
    int span_type; /* <0 - don't shorten, 1 - extent0, 2 - first contact, 4 - last contact, 8 - extent1. */
2375
44
    int code;
2376
44
    patch_fill_state_t pfs1;
2377
2378
44
    if (r0 == 0 && r1 == 0)
2379
0
        return 0; /* PLRM requires to paint nothing. */
2380
44
    code = shade_init_fill_state((shading_fill_state_t *)&pfs1, psh0, dev, pgs);
2381
44
    if (code < 0)
2382
0
        return code;
2383
44
    pfs1.Function = psh->params.Function;
2384
44
    code = init_patch_fill_state(&pfs1);
2385
44
    if (code < 0) {
2386
0
        if (pfs1.icclink != NULL) gsicc_release_link(pfs1.icclink);
2387
0
        return code;
2388
0
    }
2389
44
    pfs1.function_arg_shift = 0;
2390
44
    pfs1.rect = *clip_rect;
2391
44
    pfs1.maybe_self_intersecting = false;
2392
44
    if (is_radial_shading_large(x0, y0, r0, x1, y1, r1, rect))
2393
6
        span_type = compute_radial_shading_span(&rsa, x0, y0, r0, x1, y1, r1, rect);
2394
38
    else
2395
38
        span_type = -1;
2396
44
    if (span_type < 0) {
2397
38
        code = R_extensions(&pfs1, psh, rect, d0, d1, psh->params.Extend[0], false);
2398
38
        if (code >= 0)
2399
38
            code = R_tensor_annulus(&pfs1, x0, y0, r0, d0, x1, y1, r1, d1);
2400
38
        if (code >= 0)
2401
38
            code = R_extensions(&pfs1, psh, rect, d0, d1, false, psh->params.Extend[1]);
2402
38
    } else if (span_type == 1) {
2403
0
        code = R_fill_rect_with_const_color(&pfs1, clip_rect, d0);
2404
6
    } else if (span_type == 8) {
2405
0
        code = R_fill_rect_with_const_color(&pfs1, clip_rect, d1);
2406
6
    } else {
2407
6
        bool second_interval = true;
2408
2409
6
        code = 0;
2410
6
        if (span_type & 1)
2411
0
            code = R_extensions(&pfs1, psh, rect, d0, d1, psh->params.Extend[0], false);
2412
6
        if ((code >= 0) && (span_type & 2)) {
2413
0
            float X0 = x0, Y0 = y0, D0 = d0, X1 = x1, Y1 = y1, D1 = d1;
2414
0
            double R0 = r0, R1 = r1;
2415
2416
0
            if ((span_type & 4) && rsa.span[0][1] >= rsa.span[1][0]) {
2417
0
                double united[2];
2418
2419
0
                united[0] = rsa.span[0][0];
2420
0
                united[1] = rsa.span[1][1];
2421
0
                shorten_radial_shading(&X0, &Y0, &R0, &D0, &X1, &Y1, &R1, &D1, united);
2422
0
                second_interval = false;
2423
0
            } else {
2424
0
                second_interval = shorten_radial_shading(&X0, &Y0, &R0, &D0, &X1, &Y1, &R1, &D1, rsa.span[0]);
2425
0
            }
2426
0
            code = R_tensor_annulus(&pfs1, X0, Y0, R0, D0, X1, Y1, R1, D1);
2427
0
        }
2428
6
        if (code >= 0 && second_interval) {
2429
6
            if (span_type & 4) {
2430
5
                float X0 = x0, Y0 = y0, D0 = d0, X1 = x1, Y1 = y1, D1 = d1;
2431
5
                double R0 = r0, R1 = r1;
2432
2433
5
                shorten_radial_shading(&X0, &Y0, &R0, &D0, &X1, &Y1, &R1, &D1, rsa.span[1]);
2434
5
                code = R_tensor_annulus(&pfs1, X0, Y0, R0, D0, X1, Y1, R1, D1);
2435
5
            }
2436
6
        }
2437
6
        if (code >= 0 && (span_type & 8))
2438
0
            code = R_extensions(&pfs1, psh, rect, d0, d1, false, psh->params.Extend[1]);
2439
6
    }
2440
44
    if (pfs1.icclink != NULL) gsicc_release_link(pfs1.icclink);
2441
44
    if (term_patch_fill_state(&pfs1))
2442
0
        return_error(gs_error_unregistered); /* Must not happen. */
2443
44
    return code;
2444
44
}
2445
2446
int
2447
gs_shading_R_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
2448
                            const gs_fixed_rect * rect_clip,
2449
                            gx_device * dev, gs_gstate * pgs)
2450
44
{
2451
44
    return gs_shading_R_fill_rectangle_aux(psh0, rect, rect_clip, dev, pgs);
2452
44
}