Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevpdfv.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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
/* Color value writing for pdfwrite driver */
18
#include "math_.h"
19
#include "string_.h"
20
#include "gx.h"
21
#include "gscindex.h"
22
#include "gserrors.h"
23
#include "gsiparm3.h"   /* for pattern colors */
24
#include "gsmatrix.h"   /* for gspcolor.h */
25
#include "gscoord.h"    /* for gs_currentmatrix, requires gsmatrix.h */
26
#include "gsptype2.h"
27
#include "gxcolor2.h"   /* for gxpcolor.h */
28
#include "gxdcolor.h"   /* for gxpcolor.h */
29
#include "gxpcolor.h"   /* for pattern device color types */
30
#include "gxshade.h"
31
#include "gdevpdfx.h"
32
#include "gdevpdfg.h"
33
#include "gdevpdfo.h"
34
35
/* Import the PatternType 2 Pattern device color type. */
36
extern const gx_device_color_type_t gx_dc_pattern2;
37
38
/*
39
 * Define the scaling and range of values written for mesh shadings.
40
 * BitsPerCoordinate is always 24; BitsPerComponent (for colors) is
41
 * always 16.
42
 */
43
#define ENCODE_VALUE(v, emax, vmin, vmax)\
44
0
  ( ((v) - (vmin)) * ((double)(emax) / ((vmax) - (vmin))) )
45
/*
46
 * Because of the Acrobat Reader limitation noted in gdevpdfx.h,
47
 * we must limit coordinate values to 14 bits.
48
 */
49
0
#define MIN_MESH_COORDINATE (-0x400000 / 256.0)
50
0
#define MAX_MESH_COORDINATE ( 0x3fffff / 256.0)
51
#define ENCODE_MESH_COORDINATE(v)\
52
0
  ENCODE_VALUE(v, 0xffffff, MIN_MESH_COORDINATE, MAX_MESH_COORDINATE)
53
54
0
#define MIN_MESH_COLOR_INDEX 0
55
0
#define MAX_MESH_COLOR_INDEX 0xffff
56
0
#define ENCODE_MESH_COLOR_INDEX(v) ((v) + MIN_MESH_COLOR_INDEX)
57
58
#define ENCODE_MESH_COMPONENT(v, vmin, vmax)\
59
0
  ENCODE_VALUE(v, 0xffff, vmin, vmax)
60
61
/* ---------------- Utilities ---------------- */
62
63
/* Write a matrix parameter. */
64
static int
65
cos_dict_put_matrix(gx_device_pdf *pdev, cos_dict_t *pscd, const char *key, const gs_matrix *pmat)
66
2.97k
{
67
2.97k
    float matrix[6];
68
69
2.97k
    matrix[0] = pmat->xx;
70
2.97k
    matrix[1] = pmat->xy;
71
2.97k
    matrix[2] = pmat->yx;
72
2.97k
    matrix[3] = pmat->yy;
73
2.97k
    matrix[4] = pmat->tx;
74
2.97k
    matrix[5] = pmat->ty;
75
2.97k
    return cos_dict_put_c_key_floats(pdev, pscd, key, matrix, 6);
76
2.97k
}
77
78
/* ---------------- PatternType 1 colors ---------------- */
79
80
/*
81
 * Create a Pattern resource referencing an image (currently only an XObject).
82
 * p_tile is NULL for uncolored patterns or the NULL pattern.
83
 * m_tile is NULL for colored patterns that fill their bounding box,
84
 * including the NULL pattern.
85
 ****** WE DON'T HANDLE NULL PATTERNS YET ******
86
 */
87
static uint
88
tile_size(const gx_strip_bitmap *tile, int depth)
89
0
{
90
0
    return (tile->rep_width * depth + 7) / 8 * tile->rep_height;
91
0
}
92
static bool
93
tile_size_ok(const gx_device_pdf *pdev, const gx_color_tile *p_tile,
94
             const gx_color_tile *m_tile)
95
6
{
96
    /*
97
     * Acrobat Reader can't handle image Patterns with more than
98
     * 64K of data.  :-(
99
     */
100
6
    uint p_size =
101
6
        (p_tile == 0 ? 0 : tile_size(&p_tile->tbits, p_tile->depth));
102
6
    uint m_size =
103
6
        (m_tile == 0 ? 0 : tile_size(&m_tile->tmask, 1));
104
    /* The image limit only applies to Acrobat versions less than 5
105
     * (PDF 1.4).
106
     */
107
6
    if (pdev->CompatibilityLevel < 1.4)
108
0
        return (max(p_size, m_size) <= 65500);
109
6
    else
110
6
        return 1;
111
6
}
112
113
static int
114
pdf_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
115
            const gx_color_tile *p_tile, const gx_color_tile *m_tile,
116
            cos_stream_t *pcs_image, pdf_resource_t **ppres)
117
0
{
118
0
    pdf_resource_t *pres;
119
0
    int code = pdf_alloc_resource(pdev, resourcePattern, pdc->mask.id, ppres,
120
0
                                  0L);
121
0
    cos_stream_t *pcos;
122
0
    cos_dict_t *pcd;
123
0
    cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
124
0
    const gx_color_tile *tile = (p_tile ? p_tile : m_tile);
125
0
    const gx_strip_bitmap *btile = (p_tile ? &p_tile->tbits : &m_tile->tmask);
126
0
    bool mask = p_tile == 0;
127
0
    gs_point step;
128
0
    gs_matrix smat;
129
130
0
    if (code < 0)
131
0
        return code;
132
0
    if (!tile_size_ok(pdev, p_tile, m_tile))
133
0
        return_error(gs_error_limitcheck);
134
    /*
135
     * We currently can't handle Patterns whose X/Y step isn't parallel
136
     * to the coordinate axes.
137
     */
138
0
    if (is_xxyy(&tile->step_matrix))
139
0
        step.x = tile->step_matrix.xx, step.y = tile->step_matrix.yy;
140
0
    else if (is_xyyx(&tile->step_matrix))
141
0
        step.x = tile->step_matrix.yx, step.y = tile->step_matrix.xy;
142
0
    else
143
0
        return_error(gs_error_rangecheck);
144
0
    if (pcd_Resources == 0)
145
0
        return_error(gs_error_VMerror);
146
0
    gs_make_identity(&smat);
147
0
    smat.xx = btile->rep_width / (pdev->HWResolution[0] / 72.0);
148
0
    smat.yy = btile->rep_height / (pdev->HWResolution[1] / 72.0);
149
0
    smat.tx = tile->step_matrix.tx / (pdev->HWResolution[0] / 72.0);
150
0
    smat.ty = tile->step_matrix.ty / (pdev->HWResolution[1] / 72.0);
151
0
    pres = *ppres;
152
0
    {
153
0
        cos_dict_t *pcd_XObject = cos_dict_alloc(pdev, "pdf_pattern(XObject)");
154
0
        char key[MAX_REF_CHARS + 3];
155
0
        cos_value_t v;
156
0
        cos_object_t *object;
157
158
0
        if (pcd_XObject == 0)
159
0
            return_error(gs_error_VMerror);
160
0
        gs_snprintf(key, sizeof(key), "/R%ld", pcs_image->id);
161
        /* This is non-obvious code. Previously we would put the image object (pcs_image)
162
         * into the Resources dit. When we come to write out the Resources dict
163
         * that code writes a reference (index 0 R) using the ID from the object.
164
         * However that means we have two pointers to the XObject. One in the chain
165
         * of resoruces (which we need in order to write teh XObject) and one from
166
         * the pattern here. That seriously messes up memory handling. So instead
167
         * we now make a new object, and copy the id from the pcs_image. Since that's
168
         * all that the writing code will use, we cna avoid the double pointers.
169
         */
170
0
        object = cos_reference_alloc(pdev, "pdf_pattern(reference copy of XObject)");
171
0
        object->id = pcs_image->id;
172
0
        COS_OBJECT_VALUE(&v, object);
173
0
        if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 ||
174
0
            (code = cos_dict_put_c_key_object(pcd_Resources, "/XObject",
175
0
                                              COS_OBJECT(pcd_XObject))) < 0
176
0
            )
177
0
            return code;
178
0
    }
179
0
    if (pdev->CompatibilityLevel <= 1.7) {
180
0
        if ((code = cos_dict_put_c_strings(pcd_Resources, "/ProcSet",
181
0
                                       (mask ? "[/PDF/ImageB]" :
182
0
                                        "[/PDF/ImageC]"))) < 0)
183
0
            return code;
184
0
    }
185
0
    cos_become(pres->object, cos_type_stream);
186
0
    pcos = (cos_stream_t *)pres->object;
187
0
    pcd = cos_stream_dict(pcos);
188
0
    if ((code = cos_dict_put_c_key_int(pcd, "/PatternType", 1)) < 0 ||
189
0
        (code = cos_dict_put_c_key_int(pcd, "/PaintType",
190
0
                                       (mask ? 2 : 1))) < 0 ||
191
0
        (code = cos_dict_put_c_key_int(pcd, "/TilingType",
192
0
                                       tile->tiling_type)) < 0 ||
193
0
        (code = cos_dict_put_c_key_object(pcd, "/Resources",
194
0
                                          COS_OBJECT(pcd_Resources))) < 0 ||
195
0
        (code = cos_dict_put_c_strings(pcd, "/BBox", "[0 0 1 1]")) < 0 ||
196
0
        (code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat)) < 0 ||
197
0
        (code = cos_dict_put_c_key_real(pcd, "/XStep", step.x / btile->rep_width)) < 0 ||
198
0
        (code = cos_dict_put_c_key_real(pcd, "/YStep", step.y / btile->rep_height)) < 0
199
0
        ) {
200
0
        return code;
201
0
    }
202
203
0
    {
204
0
        char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */
205
206
0
        gs_snprintf(buf, sizeof(buf), "/R%ld Do\n", pcs_image->id);
207
0
        cos_stream_add_bytes(pdev, pcos, (const byte *)buf, strlen(buf));
208
0
    }
209
210
0
    return 0;
211
0
}
212
213
/* Store pattern 1 parameters to cos dictionary. */
214
int
215
pdf_store_pattern1_params(gx_device_pdf *pdev, pdf_resource_t *pres,
216
                        gs_pattern1_instance_t *pinst)
217
468
{
218
468
    gs_pattern1_template_t *t = &pinst->templat;
219
468
    gs_matrix smat2 = ctm_only((gs_gstate *)pinst->saved), smat;
220
468
    double scale_x = pdev->HWResolution[0] / 72.0;
221
468
    double scale_y = pdev->HWResolution[1] / 72.0;
222
468
    cos_dict_t *pcd = cos_stream_dict((cos_stream_t *)pres->object);
223
468
    cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
224
468
    float bbox[4];
225
468
    int code;
226
227
468
    if (pcd == NULL || pcd_Resources == NULL)
228
0
        return_error(gs_error_VMerror);
229
468
    pdev->substream_Resources = pcd_Resources;
230
468
    bbox[0] = t->BBox.p.x;
231
468
    bbox[1] = t->BBox.p.y;
232
468
    bbox[2] = t->BBox.q.x;
233
468
    bbox[3] = t->BBox.q.y;
234
468
    if (pdev->accumulating_charproc) {
235
        /* Assume here we can only be installing a pattern while acumulating a
236
         * charproc if the font is a coloured type 3 font. In this case we will
237
         * have set the CTM to be the identity scaled by 100 (!). See gdevpdtt.c
238
         * install_PS_charproc_accumulator() for details.
239
         */
240
0
        gs_make_identity(&smat2);
241
0
    }
242
    /* The graphics library assumes a shifted origin to provide
243
       positive bitmap pixel indices. Compensate it now. */
244
468
    smat2.tx += pinst->step_matrix.tx;
245
468
    smat2.ty += pinst->step_matrix.ty;
246
    /*
247
     * In PDF, the Matrix is the transformation from the pattern space to
248
     * the *default* user coordinate space, not the current space.
249
     * NB. For a form the default space is the parent. This means that when a
250
     * form is nested inside a form, the default space is the space of the
251
     * first form, and therefore we do *not* remove the resolution scaling.
252
     */
253
468
    if ((pdev->FormDepth == 0 || (pdev->FormDepth > 0 && pdev->PatternsSinceForm > 0)) && !pdev->accumulating_charproc) {
254
468
        gs_matrix scaled;
255
256
468
        gs_make_scaling(1 / scale_x, 1 / scale_y, &scaled);
257
468
        gs_matrix_multiply(&smat2, &scaled, &smat);
258
468
    } else {
259
0
        smat = smat2;
260
0
    }
261
468
    if ((smat.xx == 0.0 && smat.yy == 0.0) && (smat.xy == 0.0 && smat.yx == 0.0))
262
0
        return_error(gs_error_undefinedresult);
263
264
468
    if (pdev->ForOPDFRead) {
265
36
        if (pdev->PatternDepth) {
266
0
            gs_matrix_multiply(&smat, &pdev->AccumulatedPatternMatrix, &smat2);
267
0
            gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix);
268
0
            smat = smat2;
269
36
        } else {
270
36
            gs_make_identity(&pdev->AccumulatedPatternMatrix);
271
36
            gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix);
272
36
        }
273
36
    }
274
468
    if (any_abs(smat.tx) < 0.0001)  /* Noise. */
275
347
        smat.tx = 0;
276
468
    if (any_abs(smat.ty) < 0.0001)
277
350
        smat.ty = 0;
278
468
    code = cos_dict_put_c_strings(pcd, "/Type", "/Pattern");
279
468
    if (code >= 0)
280
468
        code = cos_dict_put_c_key_int(pcd, "/PatternType", 1);
281
468
    if (code >= 0)
282
468
        code = cos_dict_put_c_key_int(pcd, "/PaintType", t->PaintType);
283
468
    if (code >= 0)
284
468
        code = cos_dict_put_c_key_int(pcd, "/TilingType", t->TilingType);
285
468
    if (code >= 0)
286
468
        code = cos_dict_put_c_key_floats(pdev, pcd, "/BBox", bbox, 4);
287
468
    if (code >= 0)
288
468
        code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat);
289
468
    if (code >= 0)
290
468
        code = cos_dict_put_c_key_real(pcd, "/XStep", t->XStep);
291
468
    if (code >= 0)
292
468
        code = cos_dict_put_c_key_real(pcd, "/YStep", t->YStep);
293
468
    if (code >= 0)
294
468
        code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
295
468
    pdev->skip_colors = (t->PaintType == 2);
296
468
    return code;
297
468
}
298
299
/* Set the ImageMatrix, Width, and Height for a Pattern image. */
300
static void
301
pdf_set_pattern_image(gs_data_image_t *pic, const gx_strip_bitmap *tile)
302
0
{
303
0
    pic->ImageMatrix.xx = (float)(pic->Width = tile->rep_width);
304
0
    pic->ImageMatrix.yy = (float)(pic->Height = tile->rep_height);
305
0
}
306
307
/* Write the mask for a Pattern (colored or uncolored). */
308
static int
309
pdf_put_pattern_mask(gx_device_pdf *pdev, const gx_color_tile *m_tile,
310
                     cos_stream_t **ppcs_mask)
311
0
{
312
0
    int w = m_tile->tmask.rep_width, h = m_tile->tmask.rep_height;
313
0
    gs_image1_t image;
314
0
    pdf_image_writer writer;
315
0
    int code;
316
317
0
    gs_image_t_init_mask_adjust(&image, true, false);
318
0
    pdf_set_pattern_image((gs_data_image_t *)&image, &m_tile->tmask);
319
0
    pdf_image_writer_init(&writer);
320
0
    if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 ||
321
0
        (pdev->params.MonoImage.Encode &&
322
0
         (code = psdf_CFE_binary(&writer.binary[0], w, h, true)) < 0) ||
323
0
        (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, NULL, 0)) < 0
324
0
        )
325
0
        return code;
326
    /* Pattern masks are specified in device coordinates, so invert Y. */
327
0
    if ((code = pdf_copy_mask_bits(writer.binary[0].strm, m_tile->tmask.data + (h - 1) * m_tile->tmask.raster, 0, -m_tile->tmask.raster, w, h, 0)) < 0 ||
328
0
        (code = pdf_end_image_binary(pdev, &writer, h)) < 0 ||
329
0
        (code = pdf_end_write_image(pdev, &writer)) < 0
330
0
        )
331
0
        return code;
332
0
    *ppcs_mask = (cos_stream_t *)writer.pres->object;
333
0
    return 0;
334
0
}
335
336
/* Write an uncolored Pattern color. */
337
int
338
pdf_put_uncolored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
339
                          const gs_color_space *pcs,
340
                          const psdf_set_color_commands_t *ppscc,
341
                          const gs_gstate * pgs, pdf_resource_t **ppres)
342
6
{
343
6
    const gx_color_tile *m_tile = pdc->mask.m_tile;
344
6
    gx_drawing_color dc_pure;
345
346
6
    if (!pgs->have_pattern_streams && m_tile == 0) {
347
        /*
348
         * If m_tile == 0, this uncolored Pattern is all 1's,
349
         * equivalent to a pure color.
350
         */
351
0
        *ppres = 0;
352
0
        set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc));
353
0
        return psdf_set_color((gx_device_vector *)pdev, &dc_pure, ppscc);
354
6
    } else {
355
6
        cos_value_t v;
356
6
        stream *s = pdev->strm;
357
6
        int code;
358
6
        cos_stream_t *pcs_image;
359
6
        static const psdf_set_color_commands_t no_scc = {0, 0, 0};
360
361
6
        if (!tile_size_ok(pdev, NULL, m_tile))
362
0
            return_error(gs_error_limitcheck);
363
6
        if (!pgs->have_pattern_streams) {
364
0
            if ((code = pdf_cs_Pattern_uncolored(pdev, &v)) < 0 ||
365
0
                (code = pdf_put_pattern_mask(pdev, m_tile, &pcs_image)) < 0 ||
366
0
                (code = pdf_pattern(pdev, pdc, NULL, m_tile, pcs_image, ppres)) < 0
367
0
                )
368
0
                return code;
369
6
        } else {
370
6
            code = pdf_cs_Pattern_uncolored_hl(pdev, pcs, &v, pgs);
371
6
            if (code < 0)
372
0
                return code;
373
6
            *ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, pdc->mask.id);
374
6
            if (*ppres == NULL)
375
0
                return_error(gs_error_undefined);
376
377
6
            *ppres = pdf_substitute_pattern(*ppres);
378
6
            if (!pdev->AR4_save_bug && pdev->CompatibilityLevel <= 1.3) {
379
                /* We reconnized AR4 behavior as reserving "q Q" stack elements
380
                 * on demand. It looks as processing a pattern stream
381
                 * with PaintType 1 AR4 replaces the topmost stack element
382
                 * instead allocating a new one, if it was not previousely allocated.
383
                 * AR 5 doesn't have this bug. Working around the AR4 bug here.
384
                 */
385
0
                stream_puts(pdev->strm, "q q Q Q\n");
386
0
                pdev->AR4_save_bug = true;
387
0
            }
388
6
            (*ppres)->where_used |= pdev->used_mask;
389
6
        }
390
6
        cos_value_write(&v, pdev);
391
6
        pprints1(s, " %s ", ppscc->setcolorspace);
392
6
        if (pgs->have_pattern_streams)
393
6
            return 0;
394
6
        set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc));
395
0
        return psdf_set_color((gx_device_vector *)pdev, &dc_pure, &no_scc);
396
6
    }
397
6
}
398
399
int
400
pdf_put_colored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
401
                        const gs_color_space *pcs,
402
                        const psdf_set_color_commands_t *ppscc,
403
                        const gs_gstate * pgs, pdf_resource_t **ppres)
404
501
{
405
501
    const gx_color_tile *p_tile = pdc->colors.pattern.p_tile;
406
501
    gs_color_space *pcs_Device;
407
501
    cos_value_t cs_value;
408
501
    cos_value_t v;
409
501
    int code;
410
501
    gs_image1_t image;
411
501
    const gx_color_tile *m_tile = NULL;
412
501
    pdf_image_writer writer;
413
501
    int w = 0, h = 0;
414
415
501
    if (p_tile) {
416
501
        w = p_tile->tbits.rep_width;
417
501
        h = p_tile->tbits.rep_height;
418
501
    }
419
420
501
    if (!pgs->have_pattern_streams) {
421
        /*
422
         * NOTE: We assume here that the color space of the cached Pattern
423
         * is the same as the native color space of the device.  This will
424
         * have to change in the future!
425
         */
426
        /*
427
         * Check whether this colored pattern is actually a masked pure color,
428
         * by testing whether all the colored pixels have the same color.
429
         */
430
0
        m_tile = pdc->mask.m_tile;
431
0
        if (m_tile) {
432
0
            if (p_tile && !(p_tile->depth & 7) && p_tile->depth <= ARCH_SIZEOF_COLOR_INDEX * 8) {
433
0
                int depth_bytes = p_tile->depth >> 3;
434
0
                int width = p_tile->tbits.rep_width;
435
0
                int skip = p_tile->tbits.raster -
436
0
                    p_tile->tbits.rep_width * depth_bytes;
437
0
                const byte *bp;
438
0
                const byte *mp;
439
0
                int i, j, k;
440
0
                gx_color_index color = 0; /* init is arbitrary if not empty */
441
0
                bool first = true;
442
443
0
                for (i = 0, bp = p_tile->tbits.data, mp = p_tile->tmask.data;
444
0
                     i < p_tile->tbits.rep_height;
445
0
                     ++i, bp += skip, mp += p_tile->tmask.raster) {
446
447
0
                    for (j = 0; j < width; ++j) {
448
0
                        if (mp[j >> 3] & (0x80 >> (j & 7))) {
449
0
                            gx_color_index ci = 0;
450
451
0
                            for (k = 0; k < depth_bytes; ++k)
452
0
                                ci = (ci << 8) + *bp++;
453
0
                            if (first)
454
0
                                color = ci, first = false;
455
0
                            else if (ci != color)
456
0
                                goto not_pure;
457
0
                        } else
458
0
                            bp += depth_bytes;
459
0
                    }
460
0
                }
461
0
                {
462
                    /* Set the color, then handle as an uncolored pattern. */
463
0
                    gx_drawing_color dcolor;
464
465
0
                    dcolor = *pdc;
466
0
                    dcolor.colors.pure = color;
467
0
                    return pdf_put_uncolored_pattern(pdev, &dcolor, pcs, ppscc,
468
0
                                pgs, ppres);
469
0
                }
470
0
            not_pure:
471
0
                DO_NOTHING;   /* required by MSVC */
472
0
            }
473
0
            if (pdev->CompatibilityLevel < 1.3) {
474
                /* Masked images are only supported starting in PDF 1.3. */
475
0
                return_error(gs_error_rangecheck);
476
0
            }
477
0
        }
478
        /* Acrobat Reader has a size limit for image Patterns. */
479
0
        if (!tile_size_ok(pdev, p_tile, m_tile))
480
0
            return_error(gs_error_limitcheck);
481
0
    }
482
501
    code = pdf_cs_Pattern_colored(pdev, &v);
483
501
    if (code < 0)
484
0
        return code;
485
501
    pdf_cspace_init_Device(pdev->memory, &pcs_Device, pdev->color_info.num_components);
486
    /*
487
     * We don't have to worry about color space scaling: the color
488
     * space is always a Device space.
489
     */
490
501
    code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs_Device,
491
501
                           &pdf_color_space_names, true, NULL, 0, false);
492
501
    if (code < 0)
493
0
        return code;
494
501
    if (!pgs->have_pattern_streams) {
495
0
        cos_stream_t *pcs_mask = 0;
496
0
        cos_stream_t *pcs_image;
497
498
0
        gs_image_t_init_adjust(&image, pcs_Device, false);
499
0
        image.BitsPerComponent = 8;
500
0
        if (!p_tile)
501
0
            return_error(gs_error_unknownerror);
502
503
0
        pdf_set_pattern_image((gs_data_image_t *)&image, &p_tile->tbits);
504
0
        if (m_tile) {
505
0
            if ((code = pdf_put_pattern_mask(pdev, m_tile, &pcs_mask)) < 0)
506
0
                return code;
507
0
        }
508
0
        pdf_image_writer_init(&writer);
509
0
        pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
510
0
        if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 ||
511
0
            (code = psdf_setup_lossless_filters((gx_device_psdf *)pdev,
512
0
                                                &writer.binary[0],
513
0
                                                (gs_pixel_image_t *)&image, false)) < 0 ||
514
0
            (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, &cs_value, 0)) < 0
515
0
            )
516
0
            return code;
517
        /* Pattern masks are specified in device coordinates, so invert Y. */
518
0
        if ((code = pdf_copy_color_bits(writer.binary[0].strm, p_tile->tbits.data + (h - 1) * p_tile->tbits.raster, 0, -p_tile->tbits.raster, w, h, pdev->color_info.depth >> 3)) < 0 ||
519
0
            (code = pdf_end_image_binary(pdev, &writer, h)) < 0
520
0
            )
521
0
            return code;
522
0
        pcs_image = (cos_stream_t *)writer.pres->object;
523
0
        if ((pcs_mask != 0 &&
524
0
             (code = cos_dict_put_c_key_object(cos_stream_dict(pcs_image), "/Mask",
525
0
                                               COS_OBJECT(pcs_mask))) < 0) ||
526
0
            (code = pdf_end_write_image(pdev, &writer)) < 0
527
0
            )
528
0
            return code;
529
0
        pcs_image = (cos_stream_t *)writer.pres->object; /* pdf_end_write_image may change it. */
530
0
        code = pdf_pattern(pdev, pdc, p_tile, m_tile, pcs_image, ppres);
531
0
        if (code < 0)
532
0
            return code;
533
501
    } else {
534
501
        if (!p_tile)
535
0
            return_error(gs_error_unknownerror);
536
501
        *ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, p_tile->id);
537
501
        *ppres = pdf_substitute_pattern(*ppres);
538
501
        (*ppres)->where_used |= pdev->used_mask;
539
501
    }
540
    /* pcs_Device will leak (picked up by GC in PS) on error, but we'll
541
       tolerate that for now. */
542
501
    rc_decrement_cs(pcs_Device, "pdf_put_colored_pattern");
543
501
    cos_value_write(&v, pdev);
544
501
    pprints1(pdev->strm, " %s", ppscc->setcolorspace);
545
501
    return 0;
546
501
}
547
548
/* ---------------- PatternType 2 colors ---------------- */
549
550
/* Write parameters common to all Shadings. */
551
static int
552
pdf_put_shading_common(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_gstate * pgs, const gs_shading_t *psh,
553
                       bool shfill, const gs_range_t **ppranges)
554
2.50k
{
555
2.50k
    gs_shading_type_t type = ShadingType(psh);
556
2.50k
    const gs_color_space *pcs = psh->params.ColorSpace;
557
2.50k
    int code = cos_dict_put_c_key_int(pscd, "/ShadingType", (int)type);
558
2.50k
    cos_value_t cs_value;
559
560
2.50k
    if (code < 0 ||
561
2.50k
        (psh->params.AntiAlias &&
562
2.50k
         (code = cos_dict_put_c_strings(pscd, "/AntiAlias", "true")) < 0) ||
563
2.50k
        (code = pdf_color_space_named(pdev, pgs, &cs_value, ppranges, pcs,
564
2.50k
                                &pdf_color_space_names, false, NULL, 0, false)) < 0 ||
565
2.50k
        (code = cos_dict_put_c_key(pscd, "/ColorSpace", &cs_value)) < 0
566
2.50k
        )
567
0
        return code;
568
2.50k
    if (psh->params.Background && !shfill) {
569
        /****** SCALE Background ******/
570
1
        code = cos_dict_put_c_key_floats(pdev, pscd, "/Background",
571
1
                                   psh->params.Background->paint.values,
572
1
                                   gs_color_space_num_components(pcs));
573
1
        if (code < 0)
574
0
            return code;
575
1
    }
576
2.50k
    if (psh->params.have_BBox) {
577
4
        float bbox[4];
578
579
4
        bbox[0] = psh->params.BBox.p.x;
580
4
        bbox[1] = psh->params.BBox.p.y;
581
4
        bbox[2] = psh->params.BBox.q.x;
582
4
        bbox[3] = psh->params.BBox.q.y;
583
4
        code = cos_dict_put_c_key_floats(pdev, pscd, "/BBox", bbox, 4);
584
4
        if (code < 0)
585
0
            return code;
586
4
    }
587
2.50k
    return 0;
588
2.50k
}
589
590
/* Write an optional Function parameter. */
591
static int
592
pdf_put_shading_Function(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_function_t *pfn,
593
                         const gs_range_t *pranges)
594
2.50k
{
595
2.50k
    int code = 0;
596
597
2.50k
    if (pfn != 0) {
598
2.45k
        cos_value_t fn_value;
599
600
2.45k
        if ((code = pdf_function_scaled(pdev, pfn, pranges, &fn_value)) >= 0)
601
2.45k
            code = cos_dict_put_c_key(pscd, "/Function", &fn_value);
602
2.45k
    }
603
2.50k
    return code;
604
2.50k
}
605
606
/* Write a linear (Axial / Radial) Shading. */
607
static int
608
pdf_put_linear_shading(gx_device_pdf *pdev, cos_dict_t *pscd, const float *Coords,
609
                       int num_coords, const float *Domain /*[2]*/,
610
                       const gs_function_t *Function,
611
                       const bool *Extend /*[2]*/,
612
                       const gs_range_t *pranges)
613
2.45k
{
614
2.45k
    int code = cos_dict_put_c_key_floats(pdev, pscd, "/Coords", Coords, num_coords);
615
616
2.45k
    if (code < 0 ||
617
2.45k
        ((Domain[0] != 0 || Domain[1] != 1) &&
618
2.45k
         (code = cos_dict_put_c_key_floats(pdev, pscd, "/Domain", Domain, 2)) < 0) ||
619
2.45k
        (code = pdf_put_shading_Function(pdev, pscd, Function, pranges)) < 0
620
2.45k
        )
621
0
        return code;
622
2.45k
    if (Extend[0] | Extend[1]) {
623
2.43k
        char extend_str[1 + 5 + 1 + 5 + 1 + 1]; /* [bool bool] */
624
625
2.43k
        gs_snprintf(extend_str, sizeof(extend_str), "[%s %s]",
626
2.43k
                (Extend[0] ? "true" : "false"),
627
2.43k
                (Extend[1] ? "true" : "false"));
628
2.43k
        code = cos_dict_put_c_key_string(pscd, "/Extend",
629
2.43k
                                         (const byte *)extend_str,
630
2.43k
                                         strlen(extend_str));
631
2.43k
    }
632
2.45k
    return code;
633
2.45k
}
634
635
/* Write a scalar (non-mesh) Shading. */
636
/* (Single-use procedure for readability.) */
637
static int
638
pdf_put_scalar_shading(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_shading_t *psh,
639
                       const gs_range_t *pranges)
640
2.45k
{
641
2.45k
    int code;
642
643
2.45k
    switch (ShadingType(psh)) {
644
0
    case shading_type_Function_based: {
645
0
        const gs_shading_Fb_params_t *const params =
646
0
            (const gs_shading_Fb_params_t *)&psh->params;
647
648
0
        if ((code = cos_dict_put_c_key_floats(pdev, pscd, "/Domain", params->Domain, 4)) < 0 ||
649
0
            (code = pdf_put_shading_Function(pdev, pscd, params->Function, pranges)) < 0 ||
650
0
            (code = cos_dict_put_matrix(pdev, pscd, "/Matrix", &params->Matrix)) < 0
651
0
            )
652
0
            return code;
653
0
        return 0;
654
0
    }
655
2.44k
    case shading_type_Axial: {
656
2.44k
        const gs_shading_A_params_t *const params =
657
2.44k
            (const gs_shading_A_params_t *)&psh->params;
658
659
2.44k
        return pdf_put_linear_shading(pdev, pscd, params->Coords, 4,
660
2.44k
                                      params->Domain, params->Function,
661
2.44k
                                      params->Extend, pranges);
662
0
    }
663
6
    case shading_type_Radial: {
664
6
        const gs_shading_R_params_t *const params =
665
6
            (const gs_shading_R_params_t *)&psh->params;
666
667
6
        return pdf_put_linear_shading(pdev, pscd, params->Coords, 6,
668
6
                                      params->Domain, params->Function,
669
6
                                      params->Extend, pranges);
670
0
    }
671
0
    default:
672
0
        return_error(gs_error_rangecheck);
673
2.45k
    }
674
2.45k
}
675
676
/* Add a floating point range to an array. */
677
static int
678
pdf_array_add_real2(cos_array_t *pca, double lower, double upper)
679
0
{
680
0
    int code = cos_array_add_real(pca, lower);
681
682
0
    if (code >= 0)
683
0
        code = cos_array_add_real(pca, upper);
684
0
    return code;
685
0
}
686
687
/* Define a parameter structure for mesh data. */
688
typedef struct pdf_mesh_data_params_s {
689
    int num_points;
690
    int num_components;
691
    bool is_indexed;
692
    const float *Domain;  /* iff Function */
693
    const gs_range_t *ranges;
694
} pdf_mesh_data_params_t;
695
696
/* Put a clamped value into a data stream.  num_bytes < sizeof(int). */
697
static void
698
put_clamped(byte *p, double v, int num_bytes)
699
0
{
700
0
    int limit = 1 << (num_bytes * 8);
701
0
    int i, shift;
702
703
0
    if (v <= -limit)
704
0
        i = -limit + 1;
705
0
    else if (v >= limit)
706
0
        i = limit - 1;
707
0
    else
708
0
        i = (int)v;
709
0
    for (shift = (num_bytes - 1) * 8; shift >= 0; shift -= 8)
710
0
        *p++ = (byte)(i >> shift);
711
0
}
712
static inline void
713
put_clamped_coord(byte *p, double v, int num_bytes)
714
0
{
715
0
    put_clamped(p, ENCODE_MESH_COORDINATE(v), num_bytes);
716
0
}
717
718
/* Convert floating-point mesh data to packed binary. */
719
/* BitsPerFlag = 8, BitsPerCoordinate = 24, BitsPerComponent = 16, */
720
/* scaling is as defined below. */
721
static int
722
put_float_mesh_data(gx_device_pdf *pdev, cos_stream_t *pscs, shade_coord_stream_t *cs,
723
                    int flag, int num_comps, const pdf_mesh_data_params_t *pmdp)
724
0
{
725
0
    int num_points = pmdp->num_points;
726
0
    byte b[1 + (3 + 3) * 16]; /* flag + x + y or c */
727
0
    gs_fixed_point pts[16];
728
0
    const float *domain = pmdp->Domain;
729
0
    const gs_range_t *pranges = pmdp->ranges;
730
0
    int i, code;
731
732
0
    b[0] = (byte)flag;    /* may be -1 */
733
0
    if ((code = shade_next_coords(cs, pts, num_points)) < 0)
734
0
        return code;
735
0
    for (i = 0; i < num_points; ++i) {
736
0
        put_clamped_coord(b + 1 + i * 6, fixed2float(pts[i].x), 3);
737
0
        put_clamped_coord(b + 4 + i * 6, fixed2float(pts[i].y), 3);
738
0
    }
739
0
    if ((code = cos_stream_add_bytes(pdev, pscs, b + (flag < 0),
740
0
                                     (flag >= 0) + num_points * 6)) < 0)
741
0
        return code;
742
0
    for (i = 0; i < pmdp->num_components; ++i) {
743
0
        float c = 0;
744
0
        double v;
745
746
0
        code = cs->get_decoded(cs, 0, NULL, &c);
747
0
        if (code < 0)
748
0
            return code;
749
750
0
        if (pmdp->is_indexed)
751
0
            v = ENCODE_MESH_COLOR_INDEX(c);
752
0
        else {
753
            /*
754
             * We don't rescale stream data values, only the Decode ranges.
755
             * (We do have to rescale data values from an array, unless
756
             * they are the input parameter for a Function.)
757
             * This makes everything come out as it should.
758
             */
759
0
            double vmin, vmax;
760
761
0
            if (domain)
762
0
                vmin = domain[2 * i], vmax = domain[2 * i + 1];
763
0
            else
764
0
                vmin = 0.0, vmax = 1.0;
765
0
            if (pranges) {
766
0
                double base = pranges[i % num_comps].rmin, factor = pranges[i % num_comps].rmax - base;
767
768
0
                vmin = vmin * factor + base;
769
0
                vmax = vmax * factor + base;
770
0
            }
771
0
            v = ENCODE_MESH_COMPONENT(c, vmin, vmax);
772
0
        }
773
0
        put_clamped(b, v, 2);
774
0
        if ((code = cos_stream_add_bytes(pdev, pscs, b, 2)) < 0)
775
0
            return code;
776
0
    }
777
0
    return 0;
778
0
}
779
780
/* Write a mesh Shading. */
781
static int
782
pdf_put_mesh_shading(gx_device_pdf *pdev, cos_stream_t *pscs, const gs_shading_t *psh,
783
                     const gs_range_t *pranges)
784
50
{
785
50
    cos_dict_t *const pscd = cos_stream_dict(pscs);
786
50
    gs_color_space *pcs = psh->params.ColorSpace;
787
50
    const gs_shading_mesh_params_t *const pmp =
788
50
        (const gs_shading_mesh_params_t *)&psh->params;
789
50
    int code, code1;
790
50
    int bits_per_coordinate, bits_per_component, bits_per_flag;
791
50
    int num_comp;
792
50
    bool from_array = data_source_is_array(pmp->DataSource);
793
50
    pdf_mesh_data_params_t data_params;
794
50
    shade_coord_stream_t cs;
795
50
    gs_matrix_fixed ctm_ident;
796
50
    int flag;
797
798
50
    if (pmp->Function) {
799
5
        data_params.Domain = 0;
800
5
        num_comp = 1;
801
45
    } else {
802
45
        data_params.Domain = (pmp->Decode != 0 ? pmp->Decode + 4 : NULL);
803
45
        num_comp = gs_color_space_num_components(pcs);
804
45
    }
805
50
    data_params.ranges = pranges;
806
807
    /* Write parameters common to all mesh Shadings. */
808
50
    shade_next_init(&cs, pmp, NULL);
809
50
    if (from_array) {
810
0
        cos_array_t *pca = cos_array_alloc(pdev, "pdf_put_mesh_shading");
811
0
        int i;
812
813
0
        if (pca == 0)
814
0
            return_error(gs_error_VMerror);
815
0
        for (i = 0; i < 2; ++i)
816
0
            if ((code = pdf_array_add_real2(pca, MIN_MESH_COORDINATE,
817
0
                                            MAX_MESH_COORDINATE)) < 0)
818
0
                return code;
819
0
        data_params.is_indexed = false;
820
0
        if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
821
0
            data_params.is_indexed = true;
822
0
            if ((code = pdf_array_add_real2(pca, MIN_MESH_COLOR_INDEX,
823
0
                                            MAX_MESH_COLOR_INDEX)) < 0)
824
0
                return code;
825
0
        } else {
826
0
            for (i = 0; i < num_comp; ++i) {
827
0
                double rmin, rmax;
828
829
0
                if (pmp->Function || pranges || data_params.Domain == 0) {
830
0
                    if (pmp->Function && pmp->Function->params.Domain != 0) {
831
0
                        rmin = pmp->Function->params.Domain[0], rmax = pmp->Function->params.Domain[1];
832
0
                    } else {
833
0
                        rmin = 0.0, rmax = 1.0;
834
0
                    }
835
0
                }
836
0
                else
837
0
                    rmin = data_params.Domain[2 * i],
838
0
                        rmax = data_params.Domain[2 * i + 1];
839
0
                if ((code =
840
0
                     pdf_array_add_real2(pca, rmin, rmax)) < 0)
841
0
                    return code;
842
0
            }
843
0
        }
844
0
        code = cos_dict_put_c_key_object(pscd, "/Decode", COS_OBJECT(pca));
845
0
        if (code < 0)
846
0
            return code;
847
0
        bits_per_coordinate = 24;
848
0
        bits_per_component = 16;
849
0
        bits_per_flag = 8;
850
0
        gs_make_identity((gs_matrix *)&ctm_ident);
851
0
        ctm_ident.tx_fixed = ctm_ident.ty_fixed = 0;
852
0
        ctm_ident.txy_fixed_valid = true;
853
0
        cs.pctm = &ctm_ident;
854
0
        if (pmp->Function)
855
0
            data_params.ranges = 0; /* don't scale function parameter */
856
50
    } else {
857
        /****** SCALE Decode ******/
858
50
        code = cos_dict_put_c_key_floats(pdev, pscd, "/Decode", pmp->Decode,
859
50
                                         4 + num_comp * 2);
860
50
        if (code >= 0)
861
50
            code = cos_stream_add_stream_contents(pdev, pscs, cs.s);
862
50
        bits_per_coordinate = pmp->BitsPerCoordinate;
863
50
        bits_per_component = pmp->BitsPerComponent;
864
50
        bits_per_flag = -1;
865
50
    }
866
50
    if (code < 0 ||
867
50
        (code = pdf_put_shading_Function(pdev, pscd, pmp->Function, pranges)) < 0 ||
868
50
        (code = cos_dict_put_c_key_int(pscd, "/BitsPerCoordinate",
869
50
                                       bits_per_coordinate)) < 0 ||
870
50
        (code = cos_dict_put_c_key_int(pscd, "/BitsPerComponent",
871
50
                                       bits_per_component)) < 0
872
50
        )
873
0
        return code;
874
875
50
    switch (ShadingType(psh)) {
876
3
    case shading_type_Free_form_Gouraud_triangle: {
877
3
        const gs_shading_FfGt_params_t *const params =
878
3
            (const gs_shading_FfGt_params_t *)pmp;
879
880
3
        data_params.num_points = 1;
881
3
        data_params.num_components = num_comp;
882
3
        if (from_array) {
883
0
            while ((flag = shade_next_flag(&cs, 0)) >= 0)
884
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, flag,
885
0
                                                num_comp, &data_params)) < 0)
886
0
                    return code;
887
0
            if (!seofp(cs.s))
888
0
                code = gs_note_error(gs_error_rangecheck);
889
0
        }
890
3
        if (bits_per_flag < 0)
891
3
            bits_per_flag = params->BitsPerFlag;
892
3
        break;
893
3
    }
894
3
    case shading_type_Lattice_form_Gouraud_triangle: {
895
3
        const gs_shading_LfGt_params_t *const params =
896
3
            (const gs_shading_LfGt_params_t *)pmp;
897
898
3
        data_params.num_points = 1;
899
3
        data_params.num_components = num_comp;
900
3
        if (from_array)
901
0
            while (!seofp(cs.s))
902
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, -1,
903
0
                                                num_comp, &data_params)) < 0)
904
0
                    return code;
905
3
        code = cos_dict_put_c_key_int(pscd, "/VerticesPerRow",
906
3
                                      params->VerticesPerRow);
907
3
        return code;
908
3
    }
909
1
    case shading_type_Coons_patch: {
910
1
        const gs_shading_Cp_params_t *const params =
911
1
            (const gs_shading_Cp_params_t *)pmp;
912
913
1
        if (from_array) {
914
0
            while ((flag = shade_next_flag(&cs, 0)) >= 0) {
915
0
                data_params.num_points = (flag == 0 ? 12 : 8);
916
0
                data_params.num_components = num_comp * (flag == 0 ? 4 : 2);
917
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, flag,
918
0
                                                num_comp, &data_params)) < 0)
919
0
                    return code;
920
0
            }
921
0
            if (!seofp(cs.s))
922
0
                code = gs_note_error(gs_error_rangecheck);
923
0
        }
924
1
        if (bits_per_flag < 0)
925
1
            bits_per_flag = params->BitsPerFlag;
926
1
        break;
927
1
    }
928
43
    case shading_type_Tensor_product_patch: {
929
43
        const gs_shading_Tpp_params_t *const params =
930
43
            (const gs_shading_Tpp_params_t *)pmp;
931
932
43
        if (from_array) {
933
0
            while ((flag = shade_next_flag(&cs, 0)) >= 0) {
934
0
                data_params.num_points = (flag == 0 ? 16 : 12);
935
0
                data_params.num_components = num_comp * (flag == 0 ? 4 : 2);
936
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, flag, num_comp,
937
0
                                                &data_params)) < 0)
938
0
                    return code;
939
0
            }
940
0
            if (!seofp(cs.s))
941
0
                code = gs_note_error(gs_error_rangecheck);
942
0
        }
943
43
        if (bits_per_flag < 0)
944
43
            bits_per_flag = params->BitsPerFlag;
945
43
        break;
946
43
    }
947
0
    default:
948
0
        return_error(gs_error_rangecheck);
949
50
    }
950
47
    code1 =  cos_dict_put_c_key_int(pscd, "/BitsPerFlag", bits_per_flag);
951
47
    if (code1 < 0)
952
0
        return code;
953
47
    return code;
954
47
}
955
956
/* Write a PatternType 2 (shading pattern) color. */
957
int
958
pdf_put_pattern2(gx_device_pdf *pdev, const gs_gstate * pgs, const gx_drawing_color *pdc,
959
                 const psdf_set_color_commands_t *ppscc,
960
                 pdf_resource_t **ppres)
961
2.50k
{
962
2.50k
    const gs_pattern2_instance_t *pinst =
963
2.50k
        (gs_pattern2_instance_t *)pdc->ccolor.pattern;
964
2.50k
    const gs_shading_t *psh = pinst->templat.Shading;
965
2.50k
    cos_value_t v;
966
2.50k
    pdf_resource_t *pres;
967
2.50k
    pdf_resource_t *psres;
968
2.50k
    cos_dict_t *pcd;
969
2.50k
    cos_object_t *psco;
970
2.50k
    const gs_range_t *pranges;
971
2.50k
    int code = pdf_cs_Pattern_colored(pdev, &v);
972
2.50k
    int code1 = 0;
973
2.50k
    gs_matrix smat;
974
2.50k
    gs_point dist;
975
976
2.50k
    if (code < 0)
977
0
        return code;
978
2.50k
    code = pdf_alloc_resource(pdev, resourcePattern, gs_no_id, ppres, -1);
979
2.50k
    if (code < 0)
980
0
        return code;
981
2.50k
    pres = *ppres;
982
2.50k
    cos_become(pres->object, cos_type_dict);
983
2.50k
    pcd = (cos_dict_t *)pres->object;
984
2.50k
    code = pdf_alloc_resource(pdev, resourceShading, gs_no_id, &psres, -1);
985
2.50k
    if (code < 0)
986
0
        return code;
987
2.50k
    psco = psres->object;
988
2.50k
    if (ShadingType(psh) >= 4) {
989
        /* Shading has an associated data stream. */
990
50
        cos_become(psco, cos_type_stream);
991
50
        code = pdf_put_shading_common(pdev, cos_stream_dict((cos_stream_t *)psco), pgs,
992
50
                                      psh, pinst->shfill, &pranges);
993
50
        if (code >= 0)
994
50
            code1 = pdf_put_mesh_shading(pdev, (cos_stream_t *)psco, psh, pranges);
995
0
        else
996
            /* We won't use this shading, we fall back because we couldn't write it */
997
0
            psres->where_used = 0;
998
2.45k
    } else {
999
2.45k
        cos_become(psco, cos_type_dict);
1000
2.45k
        code = pdf_put_shading_common(pdev, (cos_dict_t *)psco, pgs, psh, pinst->shfill, &pranges);
1001
2.45k
        if (code >= 0)
1002
2.45k
            code1 = pdf_put_scalar_shading(pdev, (cos_dict_t *)psco, psh, pranges);
1003
0
        else
1004
            /* We won't use this shading, we fall back because we couldn't write it */
1005
0
            psres->where_used = 0;
1006
2.45k
    }
1007
2.50k
    if (psres->where_used) {
1008
2.50k
        code = pdf_substitute_resource(pdev, &psres, resourceShading, NULL, false);
1009
2.50k
        if (code < 0)
1010
0
            return code;
1011
2.50k
        psco = psres->object;
1012
2.50k
        psres->where_used |= pdev->used_mask;
1013
2.50k
    }
1014
    /*
1015
     * In PDF, the Matrix is the transformation from the pattern space to
1016
     * the *default* user coordinate space, not the current space.
1017
     * NB. For a form the default space is the parent. This means that when a
1018
     * form is nested inside a form, the default space is the space of the
1019
     * first form, and therefore we do *not* remove the resolution scaling.
1020
     */
1021
2.50k
    gs_currentmatrix(pinst->saved, &smat);
1022
2.50k
    {
1023
2.50k
        double xscale = 1.0, yscale = 1.0;
1024
2.50k
        if (pdev->FormDepth == 0) {
1025
648
            xscale = 72.0 / pdev->HWResolution[0];
1026
648
            yscale = 72.0 / pdev->HWResolution[1];
1027
648
        }
1028
1029
2.50k
        smat.xx *= xscale, smat.yx *= xscale, smat.tx *= xscale;
1030
2.50k
        smat.xy *= yscale, smat.yy *= yscale, smat.ty *= yscale;
1031
2.50k
    }
1032
1033
    /* Bug #697451, if we emit a PDF with a type 2 Pattern where the
1034
     * Matrix is degenerate, Acrobat throws an error and aborts the
1035
     * page content stream. Distiller refuses to embed the shfill,
1036
     * it silently (!) ignores the problem. So here we test to see
1037
     * if the CTM is degenerate, if it is, replace it with the
1038
     * smallest Matrix we can.
1039
     */
1040
2.50k
    code = gs_distance_transform_inverse(1, 1, &smat, &dist);
1041
2.50k
    if (code == gs_error_undefinedresult) {
1042
0
        smat.xx = smat.yy = 0.00000001f;
1043
0
        smat.xy = smat.yx = smat.tx = smat.ty = 0;
1044
0
        code = 0;
1045
0
    }
1046
1047
2.50k
    if (code < 0 ||
1048
2.50k
        (code = cos_dict_put_c_key_int(pcd, "/PatternType", 2)) < 0 ||
1049
2.50k
        (code = cos_dict_put_c_key_object(pcd, "/Shading", psco)) < 0 ||
1050
2.50k
        (code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat)) < 0
1051
        /****** ExtGState ******/
1052
2.50k
        )
1053
0
        return code;
1054
2.50k
    code = pdf_substitute_resource(pdev, &pres, resourcePattern, NULL, false);
1055
2.50k
    if (code < 0)
1056
0
        return code;
1057
2.50k
    pres->where_used |= pdev->used_mask;
1058
2.50k
    *ppres = pres;
1059
1060
2.50k
    cos_value_write(&v, pdev);
1061
2.50k
    pprints1(pdev->strm, " %s\n", ppscc->setcolorspace);
1062
2.50k
    return code1;
1063
2.50k
}
1064
1065
/*
1066
    Include color space.
1067
 */
1068
int
1069
gdev_pdf_include_color_space(gx_device *dev, gs_color_space *cspace, const byte *res_name, int name_length)
1070
0
{
1071
0
    gx_device_pdf * pdev = (gx_device_pdf *)dev;
1072
0
    cos_value_t cs_value;
1073
1074
0
    return pdf_color_space_named(pdev, NULL, &cs_value, NULL, cspace,
1075
0
                                &pdf_color_space_names, true, res_name, name_length, false);
1076
0
}