Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpdfv.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* 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
0
#define PDFA_MIN_MESH_COORDINATE (-0x400000 / 128.0)
46
0
#define PDFA_MAX_MESH_COORDINATE ( 0x3fffff / 128.0)
47
#define PDFA_ENCODE_MESH_COORDINATE(v)\
48
0
  ENCODE_VALUE(v, 0xffffff, PDFA_MIN_MESH_COORDINATE, PDFA_MAX_MESH_COORDINATE)
49
0
#define MIN_MESH_COORDINATE (-0x800000 )
50
0
#define MAX_MESH_COORDINATE ( 0x7fffff )
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
12.4k
{
67
12.4k
    float matrix[6];
68
69
12.4k
    matrix[0] = pmat->xx;
70
12.4k
    matrix[1] = pmat->xy;
71
12.4k
    matrix[2] = pmat->yx;
72
12.4k
    matrix[3] = pmat->yy;
73
12.4k
    matrix[4] = pmat->tx;
74
12.4k
    matrix[5] = pmat->ty;
75
12.4k
    return cos_dict_put_c_key_floats(pdev, pscd, key, matrix, 6);
76
12.4k
}
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
92
{
96
    /*
97
     * Acrobat Reader can't handle image Patterns with more than
98
     * 64K of data.  :-(
99
     */
100
92
    uint p_size =
101
92
        (p_tile == 0 ? 0 : tile_size(&p_tile->tbits, p_tile->depth));
102
92
    uint m_size =
103
92
        (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
92
    if (pdev->CompatibilityLevel < 1.4)
108
92
        return (max(p_size, m_size) <= 65500);
109
0
    else
110
0
        return 1;
111
92
}
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%"PRId64"", 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
        if (object == NULL)
172
0
            return_error(gs_error_VMerror);
173
174
0
        object->id = pcs_image->id;
175
0
        COS_OBJECT_VALUE(&v, object);
176
0
        if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 ||
177
0
            (code = cos_dict_put_c_key_object(pcd_Resources, "/XObject",
178
0
                                              COS_OBJECT(pcd_XObject))) < 0
179
0
            )
180
0
            return code;
181
0
    }
182
0
    if (pdev->CompatibilityLevel <= 1.7) {
183
0
        if ((code = cos_dict_put_c_strings(pcd_Resources, "/ProcSet",
184
0
                                       (mask ? "[/PDF/ImageB]" :
185
0
                                        "[/PDF/ImageC]"))) < 0)
186
0
            return code;
187
0
    }
188
0
    cos_become(pres->object, cos_type_stream);
189
0
    pcos = (cos_stream_t *)pres->object;
190
0
    pcd = cos_stream_dict(pcos);
191
0
    if ((code = cos_dict_put_c_key_int(pcd, "/PatternType", 1)) < 0 ||
192
0
        (code = cos_dict_put_c_key_int(pcd, "/PaintType",
193
0
                                       (mask ? 2 : 1))) < 0 ||
194
0
        (code = cos_dict_put_c_key_int(pcd, "/TilingType",
195
0
                                       tile->tiling_type)) < 0 ||
196
0
        (code = cos_dict_put_c_key_object(pcd, "/Resources",
197
0
                                          COS_OBJECT(pcd_Resources))) < 0 ||
198
0
        (code = cos_dict_put_c_strings(pcd, "/BBox", "[0 0 1 1]")) < 0 ||
199
0
        (code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat)) < 0 ||
200
0
        (code = cos_dict_put_c_key_real(pcd, "/XStep", step.x / btile->rep_width)) < 0 ||
201
0
        (code = cos_dict_put_c_key_real(pcd, "/YStep", step.y / btile->rep_height)) < 0
202
0
        ) {
203
0
        return code;
204
0
    }
205
206
0
    {
207
0
        char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */
208
209
0
        gs_snprintf(buf, sizeof(buf), "/R%"PRId64" Do\n", pcs_image->id);
210
0
        cos_stream_add_bytes(pdev, pcos, (const byte *)buf, strlen(buf));
211
0
    }
212
213
0
    return 0;
214
0
}
215
216
/* Store pattern 1 parameters to cos dictionary. */
217
int
218
pdf_store_pattern1_params(gx_device_pdf *pdev, pdf_resource_t *pres,
219
                        gs_pattern1_instance_t *pinst)
220
3.69k
{
221
3.69k
    gs_pattern1_template_t *t = &pinst->templat;
222
3.69k
    gs_matrix smat2 = ctm_only((gs_gstate *)pinst->saved), smat;
223
3.69k
    double scale_x = pdev->HWResolution[0] / 72.0;
224
3.69k
    double scale_y = pdev->HWResolution[1] / 72.0;
225
3.69k
    cos_dict_t *pcd = cos_stream_dict((cos_stream_t *)pres->object);
226
3.69k
    cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
227
3.69k
    float bbox[4];
228
3.69k
    int code;
229
230
3.69k
    if (pcd == NULL || pcd_Resources == NULL)
231
0
        return_error(gs_error_VMerror);
232
3.69k
    pdev->substream_Resources = pcd_Resources;
233
3.69k
    bbox[0] = t->BBox.p.x;
234
3.69k
    bbox[1] = t->BBox.p.y;
235
3.69k
    bbox[2] = t->BBox.q.x;
236
3.69k
    bbox[3] = t->BBox.q.y;
237
3.69k
    if (pdev->accumulating_charproc) {
238
        /* Assume here we can only be installing a pattern while acumulating a
239
         * charproc if the font is a coloured type 3 font. In this case we will
240
         * have set the CTM to be the identity scaled by 100 (!). See gdevpdtt.c
241
         * install_PS_charproc_accumulator() for details.
242
         */
243
10
        gs_make_identity(&smat2);
244
10
    }
245
    /* The graphics library assumes a shifted origin to provide
246
       positive bitmap pixel indices. Compensate it now. */
247
3.69k
    smat2.tx += pinst->step_matrix.tx;
248
3.69k
    smat2.ty += pinst->step_matrix.ty;
249
    /*
250
     * In PDF, the Matrix is the transformation from the pattern space to
251
     * the *default* user coordinate space, not the current space.
252
     * NB. For a form the default space is the parent. This means that when a
253
     * form is nested inside a form, the default space is the space of the
254
     * first form, and therefore we do *not* remove the resolution scaling.
255
     */
256
3.69k
    if ((pdev->FormDepth == 0 || (pdev->FormDepth > 0 && pdev->PatternsSinceForm > 0)) && !pdev->accumulating_charproc) {
257
3.68k
        gs_matrix scaled;
258
259
3.68k
        gs_make_scaling(1 / scale_x, 1 / scale_y, &scaled);
260
3.68k
        gs_matrix_multiply(&smat2, &scaled, &smat);
261
3.68k
    } else {
262
10
        smat = smat2;
263
10
    }
264
3.69k
    if ((smat.xx == 0.0 && smat.yy == 0.0) && (smat.xy == 0.0 && smat.yx == 0.0))
265
0
        return_error(gs_error_undefinedresult);
266
267
3.69k
    if (pdev->ForOPDFRead) {
268
1.66k
        if (pdev->PatternDepth) {
269
5
            gs_matrix_multiply(&smat, &pdev->AccumulatedPatternMatrix, &smat2);
270
5
            gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix);
271
5
            smat = smat2;
272
1.65k
        } else {
273
1.65k
            gs_make_identity(&pdev->AccumulatedPatternMatrix);
274
1.65k
            gs_matrix_multiply(&pdev->AccumulatedPatternMatrix, &smat, &pdev->AccumulatedPatternMatrix);
275
1.65k
        }
276
1.66k
    }
277
3.69k
    if (any_abs(smat.tx) < 0.0001)  /* Noise. */
278
1.54k
        smat.tx = 0;
279
3.69k
    if (any_abs(smat.ty) < 0.0001)
280
1.56k
        smat.ty = 0;
281
3.69k
    code = cos_dict_put_c_strings(pcd, "/Type", "/Pattern");
282
3.69k
    if (code >= 0)
283
3.69k
        code = cos_dict_put_c_key_int(pcd, "/PatternType", 1);
284
3.69k
    if (code >= 0)
285
3.69k
        code = cos_dict_put_c_key_int(pcd, "/PaintType", t->PaintType);
286
3.69k
    if (code >= 0)
287
3.69k
        code = cos_dict_put_c_key_int(pcd, "/TilingType", t->TilingType);
288
3.69k
    if (code >= 0)
289
3.69k
        code = cos_dict_put_c_key_floats(pdev, pcd, "/BBox", bbox, 4);
290
3.69k
    if (code >= 0)
291
3.69k
        code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat);
292
3.69k
    if (code >= 0)
293
3.69k
        code = cos_dict_put_c_key_real(pcd, "/XStep", t->XStep);
294
3.69k
    if (code >= 0)
295
3.69k
        code = cos_dict_put_c_key_real(pcd, "/YStep", t->YStep);
296
3.69k
    if (code >= 0)
297
3.69k
        code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
298
3.69k
    pdev->skip_colors = (t->PaintType == 2);
299
3.69k
    return code;
300
3.69k
}
301
302
/* Set the ImageMatrix, Width, and Height for a Pattern image. */
303
static void
304
pdf_set_pattern_image(gs_data_image_t *pic, const gx_strip_bitmap *tile)
305
0
{
306
0
    pic->ImageMatrix.xx = (float)(pic->Width = tile->rep_width);
307
0
    pic->ImageMatrix.yy = (float)(pic->Height = tile->rep_height);
308
0
}
309
310
/* Write the mask for a Pattern (colored or uncolored). */
311
static int
312
pdf_put_pattern_mask(gx_device_pdf *pdev, const gx_color_tile *m_tile,
313
                     cos_stream_t **ppcs_mask)
314
0
{
315
0
    int w = m_tile->tmask.rep_width, h = m_tile->tmask.rep_height;
316
0
    gs_image1_t image;
317
0
    pdf_image_writer writer;
318
0
    int code;
319
320
0
    gs_image_t_init_mask_adjust(&image, true, false);
321
0
    pdf_set_pattern_image((gs_data_image_t *)&image, &m_tile->tmask);
322
0
    pdf_image_writer_init(&writer);
323
0
    if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 ||
324
0
        (pdev->params.MonoImage.Encode &&
325
0
         (code = psdf_CFE_binary(&writer.binary[0], w, h, true)) < 0) ||
326
0
        (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, NULL, 0)) < 0
327
0
        )
328
0
        return code;
329
    /* Pattern masks are specified in device coordinates, so invert Y. */
330
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 ||
331
0
        (code = pdf_end_image_binary(pdev, &writer, h)) < 0 ||
332
0
        (code = pdf_end_write_image(pdev, &writer)) < 0
333
0
        )
334
0
        return code;
335
0
    *ppcs_mask = (cos_stream_t *)writer.pres->object;
336
0
    return 0;
337
0
}
338
339
/* Write an uncolored Pattern color. */
340
int
341
pdf_put_uncolored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
342
                          const gs_color_space *pcs,
343
                          const psdf_set_color_commands_t *ppscc,
344
                          const gs_gstate * pgs, pdf_resource_t **ppres)
345
92
{
346
92
    const gx_color_tile *m_tile = pdc->mask.m_tile;
347
92
    gx_drawing_color dc_pure;
348
349
92
    if (!pgs->have_pattern_streams && m_tile == 0) {
350
        /*
351
         * If m_tile == 0, this uncolored Pattern is all 1's,
352
         * equivalent to a pure color.
353
         */
354
0
        *ppres = 0;
355
0
        set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc));
356
0
        return psdf_set_color((gx_device_vector *)pdev, &dc_pure, ppscc);
357
92
    } else {
358
92
        cos_value_t v;
359
92
        stream *s = pdev->strm;
360
92
        int code;
361
92
        cos_stream_t *pcs_image;
362
92
        static const psdf_set_color_commands_t no_scc = {0, 0, 0};
363
364
92
        if (!tile_size_ok(pdev, NULL, m_tile))
365
0
            return_error(gs_error_limitcheck);
366
92
        if (!pgs->have_pattern_streams) {
367
0
            if ((code = pdf_cs_Pattern_uncolored(pdev, &v)) < 0 ||
368
0
                (code = pdf_put_pattern_mask(pdev, m_tile, &pcs_image)) < 0 ||
369
0
                (code = pdf_pattern(pdev, pdc, NULL, m_tile, pcs_image, ppres)) < 0
370
0
                )
371
0
                return code;
372
92
        } else {
373
92
            code = pdf_cs_Pattern_uncolored_hl(pdev, pcs, &v, pgs);
374
92
            if (code < 0)
375
0
                return code;
376
92
            *ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, pdc->mask.id);
377
92
            if (*ppres == NULL)
378
0
                return_error(gs_error_undefined);
379
380
92
            *ppres = pdf_substitute_pattern(*ppres);
381
92
            if (!pdev->AR4_save_bug && pdev->CompatibilityLevel <= 1.3) {
382
                /* We reconnized AR4 behavior as reserving "q Q" stack elements
383
                 * on demand. It looks as processing a pattern stream
384
                 * with PaintType 1 AR4 replaces the topmost stack element
385
                 * instead allocating a new one, if it was not previousely allocated.
386
                 * AR 5 doesn't have this bug. Working around the AR4 bug here.
387
                 */
388
15
                stream_puts(pdev->strm, "q q Q Q\n");
389
15
                pdev->AR4_save_bug = true;
390
15
            }
391
92
            (*ppres)->where_used |= pdev->used_mask;
392
92
        }
393
92
        cos_value_write(&v, pdev);
394
92
        pprints1(s, " %s ", ppscc->setcolorspace);
395
92
        if (pgs->have_pattern_streams)
396
92
            return 0;
397
92
        set_nonclient_dev_color(&dc_pure, gx_dc_pure_color(pdc));
398
0
        return psdf_set_color((gx_device_vector *)pdev, &dc_pure, &no_scc);
399
92
    }
400
92
}
401
402
int
403
pdf_put_colored_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc,
404
                        const gs_color_space *pcs,
405
                        const psdf_set_color_commands_t *ppscc,
406
                        const gs_gstate * pgs, pdf_resource_t **ppres)
407
5.86k
{
408
5.86k
    const gx_color_tile *p_tile = pdc->colors.pattern.p_tile;
409
5.86k
    gs_color_space *pcs_Device;
410
5.86k
    cos_value_t cs_value;
411
5.86k
    cos_value_t v;
412
5.86k
    int code;
413
5.86k
    gs_image1_t image;
414
5.86k
    const gx_color_tile *m_tile = NULL;
415
5.86k
    pdf_image_writer writer;
416
5.86k
    int w = 0, h = 0;
417
418
5.86k
    if (p_tile) {
419
5.86k
        w = p_tile->tbits.rep_width;
420
5.86k
        h = p_tile->tbits.rep_height;
421
5.86k
    }
422
423
5.86k
    if (!pgs->have_pattern_streams) {
424
        /*
425
         * NOTE: We assume here that the color space of the cached Pattern
426
         * is the same as the native color space of the device.  This will
427
         * have to change in the future!
428
         */
429
        /*
430
         * Check whether this colored pattern is actually a masked pure color,
431
         * by testing whether all the colored pixels have the same color.
432
         */
433
0
        m_tile = pdc->mask.m_tile;
434
0
        if (m_tile) {
435
0
            if (p_tile && !(p_tile->depth & 7) && p_tile->depth <= ARCH_SIZEOF_COLOR_INDEX * 8) {
436
0
                int depth_bytes = p_tile->depth >> 3;
437
0
                int width = p_tile->tbits.rep_width;
438
0
                int skip = p_tile->tbits.raster -
439
0
                    p_tile->tbits.rep_width * depth_bytes;
440
0
                const byte *bp;
441
0
                const byte *mp;
442
0
                int i, j, k;
443
0
                gx_color_index color = 0; /* init is arbitrary if not empty */
444
0
                bool first = true;
445
446
0
                for (i = 0, bp = p_tile->tbits.data, mp = p_tile->tmask.data;
447
0
                     i < p_tile->tbits.rep_height;
448
0
                     ++i, bp += skip, mp += p_tile->tmask.raster) {
449
450
0
                    for (j = 0; j < width; ++j) {
451
0
                        if (mp[j >> 3] & (0x80 >> (j & 7))) {
452
0
                            gx_color_index ci = 0;
453
454
0
                            for (k = 0; k < depth_bytes; ++k)
455
0
                                ci = (ci << 8) + *bp++;
456
0
                            if (first)
457
0
                                color = ci, first = false;
458
0
                            else if (ci != color)
459
0
                                goto not_pure;
460
0
                        } else
461
0
                            bp += depth_bytes;
462
0
                    }
463
0
                }
464
0
                {
465
                    /* Set the color, then handle as an uncolored pattern. */
466
0
                    gx_drawing_color dcolor;
467
468
0
                    dcolor = *pdc;
469
0
                    dcolor.colors.pure = color;
470
0
                    return pdf_put_uncolored_pattern(pdev, &dcolor, pcs, ppscc,
471
0
                                pgs, ppres);
472
0
                }
473
0
            not_pure:
474
0
                DO_NOTHING;   /* required by MSVC */
475
0
            }
476
0
            if (pdev->CompatibilityLevel < 1.3) {
477
                /* Masked images are only supported starting in PDF 1.3. */
478
0
                return_error(gs_error_rangecheck);
479
0
            }
480
0
        }
481
        /* Acrobat Reader has a size limit for image Patterns. */
482
0
        if (!tile_size_ok(pdev, p_tile, m_tile))
483
0
            return_error(gs_error_limitcheck);
484
0
    }
485
5.86k
    code = pdf_cs_Pattern_colored(pdev, &v);
486
5.86k
    if (code < 0)
487
0
        return code;
488
5.86k
    pdf_cspace_init_Device(pdev->memory, &pcs_Device, pdev->color_info.num_components);
489
    /*
490
     * We don't have to worry about color space scaling: the color
491
     * space is always a Device space.
492
     */
493
5.86k
    code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs_Device,
494
5.86k
                           &pdf_color_space_names, true, NULL, 0, false);
495
5.86k
    if (code < 0)
496
0
        return code;
497
5.86k
    if (!pgs->have_pattern_streams) {
498
0
        cos_stream_t *pcs_mask = 0;
499
0
        cos_stream_t *pcs_image;
500
501
0
        gs_image_t_init_adjust(&image, pcs_Device, false);
502
0
        image.BitsPerComponent = 8;
503
0
        if (!p_tile)
504
0
            return_error(gs_error_unknownerror);
505
506
0
        pdf_set_pattern_image((gs_data_image_t *)&image, &p_tile->tbits);
507
0
        if (m_tile) {
508
0
            if ((code = pdf_put_pattern_mask(pdev, m_tile, &pcs_mask)) < 0)
509
0
                return code;
510
0
        }
511
0
        pdf_image_writer_init(&writer);
512
0
        pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
513
0
        if ((code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, false)) < 0 ||
514
0
            (code = psdf_setup_lossless_filters((gx_device_psdf *)pdev,
515
0
                                                &writer.binary[0],
516
0
                                                (gs_pixel_image_t *)&image, false)) < 0 ||
517
0
            (code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image, &cs_value, 0)) < 0
518
0
            )
519
0
            return code;
520
        /* Pattern masks are specified in device coordinates, so invert Y. */
521
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 ||
522
0
            (code = pdf_end_image_binary(pdev, &writer, h)) < 0
523
0
            )
524
0
            return code;
525
0
        pcs_image = (cos_stream_t *)writer.pres->object;
526
0
        if ((pcs_mask != 0 &&
527
0
             (code = cos_dict_put_c_key_object(cos_stream_dict(pcs_image), "/Mask",
528
0
                                               COS_OBJECT(pcs_mask))) < 0) ||
529
0
            (code = pdf_end_write_image(pdev, &writer)) < 0
530
0
            )
531
0
            return code;
532
0
        pcs_image = (cos_stream_t *)writer.pres->object; /* pdf_end_write_image may change it. */
533
0
        code = pdf_pattern(pdev, pdc, p_tile, m_tile, pcs_image, ppres);
534
0
        if (code < 0)
535
0
            return code;
536
5.86k
    } else {
537
5.86k
        if (!p_tile)
538
0
            return_error(gs_error_unknownerror);
539
5.86k
        *ppres = pdf_find_resource_by_gs_id(pdev, resourcePattern, p_tile->id);
540
5.86k
        *ppres = pdf_substitute_pattern(*ppres);
541
5.86k
        (*ppres)->where_used |= pdev->used_mask;
542
5.86k
    }
543
    /* pcs_Device will leak (picked up by GC in PS) on error, but we'll
544
       tolerate that for now. */
545
5.86k
    rc_decrement_cs(pcs_Device, "pdf_put_colored_pattern");
546
5.86k
    cos_value_write(&v, pdev);
547
5.86k
    pprints1(pdev->strm, " %s", ppscc->setcolorspace);
548
5.86k
    return 0;
549
5.86k
}
550
551
/* ---------------- PatternType 2 colors ---------------- */
552
553
/* Write parameters common to all Shadings. */
554
static int
555
pdf_put_shading_common(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_gstate * pgs, const gs_shading_t *psh,
556
                       bool shfill, const gs_range_t **ppranges)
557
8.76k
{
558
8.76k
    gs_shading_type_t type = ShadingType(psh);
559
8.76k
    const gs_color_space *pcs = psh->params.ColorSpace;
560
8.76k
    int code = cos_dict_put_c_key_int(pscd, "/ShadingType", (int)type);
561
8.76k
    cos_value_t cs_value;
562
563
8.76k
    if (code < 0 ||
564
8.76k
        (psh->params.AntiAlias &&
565
8.76k
         (code = cos_dict_put_c_strings(pscd, "/AntiAlias", "true")) < 0) ||
566
8.76k
        (code = pdf_color_space_named(pdev, pgs, &cs_value, ppranges, pcs,
567
8.76k
                                &pdf_color_space_names, false, NULL, 0, false)) < 0 ||
568
8.76k
        (code = cos_dict_put_c_key(pscd, "/ColorSpace", &cs_value)) < 0
569
8.76k
        )
570
0
        return code;
571
8.76k
    if (psh->params.Background && !shfill) {
572
        /****** SCALE Background ******/
573
1
        code = cos_dict_put_c_key_floats(pdev, pscd, "/Background",
574
1
                                   psh->params.Background->paint.values,
575
1
                                   gs_color_space_num_components(pcs));
576
1
        if (code < 0)
577
0
            return code;
578
1
    }
579
8.76k
    if (psh->params.have_BBox) {
580
0
        float bbox[4];
581
582
0
        bbox[0] = psh->params.BBox.p.x;
583
0
        bbox[1] = psh->params.BBox.p.y;
584
0
        bbox[2] = psh->params.BBox.q.x;
585
0
        bbox[3] = psh->params.BBox.q.y;
586
0
        code = cos_dict_put_c_key_floats(pdev, pscd, "/BBox", bbox, 4);
587
0
        if (code < 0)
588
0
            return code;
589
0
    }
590
8.76k
    return 0;
591
8.76k
}
592
593
/* Write an optional Function parameter. */
594
static int
595
pdf_put_shading_Function(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_function_t *pfn,
596
                         const gs_range_t *pranges)
597
8.76k
{
598
8.76k
    int code = 0;
599
600
8.76k
    if (pfn != 0) {
601
8.76k
        cos_value_t fn_value;
602
603
8.76k
        if ((code = pdf_function_scaled(pdev, pfn, pranges, &fn_value)) >= 0)
604
8.76k
            code = cos_dict_put_c_key(pscd, "/Function", &fn_value);
605
8.76k
    }
606
8.76k
    return code;
607
8.76k
}
608
609
/* Write a linear (Axial / Radial) Shading. */
610
static int
611
pdf_put_linear_shading(gx_device_pdf *pdev, cos_dict_t *pscd, const float *Coords,
612
                       int num_coords, const float *Domain /*[2]*/,
613
                       const gs_function_t *Function,
614
                       const bool *Extend /*[2]*/,
615
                       const gs_range_t *pranges)
616
8.75k
{
617
8.75k
    int code = cos_dict_put_c_key_floats(pdev, pscd, "/Coords", Coords, num_coords);
618
619
8.75k
    if (code < 0 ||
620
8.75k
        ((Domain[0] != 0 || Domain[1] != 1) &&
621
8.75k
         (code = cos_dict_put_c_key_floats(pdev, pscd, "/Domain", Domain, 2)) < 0) ||
622
8.75k
        (code = pdf_put_shading_Function(pdev, pscd, Function, pranges)) < 0
623
8.75k
        )
624
0
        return code;
625
8.75k
    if (Extend[0] | Extend[1]) {
626
8.75k
        char extend_str[1 + 5 + 1 + 5 + 1 + 1]; /* [bool bool] */
627
628
8.75k
        gs_snprintf(extend_str, sizeof(extend_str), "[%s %s]",
629
8.75k
                (Extend[0] ? "true" : "false"),
630
8.75k
                (Extend[1] ? "true" : "false"));
631
8.75k
        code = cos_dict_put_c_key_string(pscd, "/Extend",
632
8.75k
                                         (const byte *)extend_str,
633
8.75k
                                         strlen(extend_str));
634
8.75k
    }
635
8.75k
    return code;
636
8.75k
}
637
638
/* Write a scalar (non-mesh) Shading. */
639
/* (Single-use procedure for readability.) */
640
static int
641
pdf_put_scalar_shading(gx_device_pdf *pdev, cos_dict_t *pscd, const gs_shading_t *psh,
642
                       const gs_range_t *pranges)
643
8.75k
{
644
8.75k
    int code;
645
646
8.75k
    switch (ShadingType(psh)) {
647
0
    case shading_type_Function_based: {
648
0
        const gs_shading_Fb_params_t *const params =
649
0
            (const gs_shading_Fb_params_t *)&psh->params;
650
651
0
        if ((code = cos_dict_put_c_key_floats(pdev, pscd, "/Domain", params->Domain, 4)) < 0 ||
652
0
            (code = pdf_put_shading_Function(pdev, pscd, params->Function, pranges)) < 0 ||
653
0
            (code = cos_dict_put_matrix(pdev, pscd, "/Matrix", &params->Matrix)) < 0
654
0
            )
655
0
            return code;
656
0
        return 0;
657
0
    }
658
8.75k
    case shading_type_Axial: {
659
8.75k
        const gs_shading_A_params_t *const params =
660
8.75k
            (const gs_shading_A_params_t *)&psh->params;
661
662
8.75k
        return pdf_put_linear_shading(pdev, pscd, params->Coords, 4,
663
8.75k
                                      params->Domain, params->Function,
664
8.75k
                                      params->Extend, pranges);
665
0
    }
666
0
    case shading_type_Radial: {
667
0
        const gs_shading_R_params_t *const params =
668
0
            (const gs_shading_R_params_t *)&psh->params;
669
670
0
        return pdf_put_linear_shading(pdev, pscd, params->Coords, 6,
671
0
                                      params->Domain, params->Function,
672
0
                                      params->Extend, pranges);
673
0
    }
674
0
    default:
675
0
        return_error(gs_error_rangecheck);
676
8.75k
    }
677
8.75k
}
678
679
/* Add a floating point range to an array. */
680
static int
681
pdf_array_add_real2(cos_array_t *pca, double lower, double upper)
682
0
{
683
0
    int code = cos_array_add_real(pca, lower);
684
685
0
    if (code >= 0)
686
0
        code = cos_array_add_real(pca, upper);
687
0
    return code;
688
0
}
689
690
/* Define a parameter structure for mesh data. */
691
typedef struct pdf_mesh_data_params_s {
692
    int num_points;
693
    int num_components;
694
    bool is_indexed;
695
    int rescale;            /* If the co-ordinates won't fit into crappy Acrobat values, scale them here and in the pattern Matrix */
696
    bool old_pdf;
697
    const float *Domain;  /* iff Function */
698
    const gs_range_t *ranges;
699
} pdf_mesh_data_params_t;
700
701
/* Put a clamped value into a data stream.  num_bytes < sizeof(int). */
702
static void
703
put_clamped(byte *p, double v, int num_bytes)
704
0
{
705
0
    int limit = 1 << (num_bytes * 8);
706
0
    int i, shift;
707
708
0
    if (v <= -limit)
709
0
        i = -limit + 1;
710
0
    else if (v >= limit)
711
0
        i = limit - 1;
712
0
    else
713
0
        i = (int)v;
714
0
    for (shift = (num_bytes - 1) * 8; shift >= 0; shift -= 8)
715
0
        *p++ = (byte)(i >> shift);
716
0
}
717
static inline void
718
put_clamped_coord(byte *p, double v, int num_bytes, const pdf_mesh_data_params_t *pmdp)
719
0
{
720
0
    if (pmdp->rescale != 1.0 || pmdp->old_pdf) {
721
0
        v = v / pmdp->rescale;
722
0
        put_clamped(p, PDFA_ENCODE_MESH_COORDINATE(v), num_bytes);
723
0
    } else
724
0
        put_clamped(p, ENCODE_MESH_COORDINATE(v), num_bytes);
725
0
}
726
727
/* Convert floating-point mesh data to packed binary. */
728
/* BitsPerFlag = 8, BitsPerCoordinate = 24, BitsPerComponent = 16, */
729
/* scaling is as defined below. */
730
static int
731
put_float_mesh_data(gx_device_pdf *pdev, cos_stream_t *pscs, shade_coord_stream_t *cs,
732
                    int flag, int num_comps, const pdf_mesh_data_params_t *pmdp)
733
0
{
734
0
    int num_points = pmdp->num_points;
735
0
    byte b[1 + (3 + 3) * 16]; /* flag + x + y or c */
736
0
    gs_fixed_point pts[16];
737
0
    const float *domain = pmdp->Domain;
738
0
    const gs_range_t *pranges = pmdp->ranges;
739
0
    int i, code;
740
741
0
    b[0] = (byte)flag;    /* may be -1 */
742
0
    if ((code = shade_next_coords(cs, pts, num_points)) < 0)
743
0
        return code;
744
0
    for (i = 0; i < num_points; ++i) {
745
0
        put_clamped_coord(b + 1 + i * 6, fixed2float(pts[i].x), 3, pmdp);
746
0
        put_clamped_coord(b + 4 + i * 6, fixed2float(pts[i].y), 3, pmdp);
747
0
    }
748
0
    if ((code = cos_stream_add_bytes(pdev, pscs, b + (flag < 0),
749
0
                                     (flag >= 0) + num_points * 6)) < 0)
750
0
        return code;
751
0
    for (i = 0; i < pmdp->num_components; ++i) {
752
0
        float c = 0;
753
0
        double v;
754
755
0
        code = cs->get_decoded(cs, 0, NULL, &c);
756
0
        if (code < 0)
757
0
            return code;
758
759
0
        if (pmdp->is_indexed)
760
0
            v = ENCODE_MESH_COLOR_INDEX(c);
761
0
        else {
762
            /*
763
             * We don't rescale stream data values, only the Decode ranges.
764
             * (We do have to rescale data values from an array, unless
765
             * they are the input parameter for a Function.)
766
             * This makes everything come out as it should.
767
             */
768
0
            double vmin, vmax;
769
770
0
            if (domain)
771
0
                vmin = domain[2 * i], vmax = domain[2 * i + 1];
772
0
            else
773
0
                vmin = 0.0, vmax = 1.0;
774
0
            if (pranges) {
775
0
                double base = pranges[i % num_comps].rmin, factor = pranges[i % num_comps].rmax - base;
776
777
0
                vmin = vmin * factor + base;
778
0
                vmax = vmax * factor + base;
779
0
            }
780
0
            v = ENCODE_MESH_COMPONENT(c, vmin, vmax);
781
0
        }
782
0
        put_clamped(b, v, 2);
783
0
        if ((code = cos_stream_add_bytes(pdev, pscs, b, 2)) < 0)
784
0
            return code;
785
0
    }
786
0
    return 0;
787
0
}
788
789
/* Write a mesh Shading. */
790
static int
791
pdf_put_mesh_shading(gx_device_pdf *pdev, cos_stream_t *pscs, const gs_shading_t *psh,
792
                     const gs_range_t *pranges, int *rescale)
793
11
{
794
11
    cos_dict_t *const pscd = cos_stream_dict(pscs);
795
11
    gs_color_space *pcs = psh->params.ColorSpace;
796
11
    const gs_shading_mesh_params_t *const pmp =
797
11
        (const gs_shading_mesh_params_t *)&psh->params;
798
11
    int code, code1;
799
11
    int bits_per_coordinate, bits_per_component, bits_per_flag;
800
11
    int num_comp;
801
11
    bool from_array = data_source_is_array(pmp->DataSource);
802
11
    pdf_mesh_data_params_t data_params;
803
11
    shade_coord_stream_t cs;
804
11
    gs_matrix_fixed ctm_ident;
805
11
    int flag;
806
807
11
    if (pmp->Function) {
808
6
        data_params.Domain = 0;
809
6
        num_comp = 1;
810
6
    } else {
811
5
        data_params.Domain = (pmp->Decode != 0 ? pmp->Decode + 4 : NULL);
812
5
        num_comp = gs_color_space_num_components(pcs);
813
5
    }
814
11
    data_params.ranges = pranges;
815
11
    data_params.rescale = 1;
816
817
818
    /* Write parameters common to all mesh Shadings. */
819
11
    shade_next_init(&cs, pmp, NULL);
820
11
    if (from_array) {
821
0
        cos_array_t *pca = cos_array_alloc(pdev, "pdf_put_mesh_shading");
822
0
        int i;
823
824
0
        if (pca == 0)
825
0
            return_error(gs_error_VMerror);
826
0
        for (i = 0; i < 2; ++i) {
827
0
            if (pdev->CompatibilityLevel < 1.5) {
828
0
                if ((code = pdf_array_add_real2(pca, PDFA_MIN_MESH_COORDINATE,
829
0
                                            PDFA_MAX_MESH_COORDINATE)) < 0)
830
0
                    return code;
831
0
            }
832
0
            else {
833
0
                if ((code = pdf_array_add_real2(pca, MIN_MESH_COORDINATE,
834
0
                                            MAX_MESH_COORDINATE)) < 0)
835
0
                    return code;
836
0
            }
837
0
        }
838
0
        data_params.is_indexed = false;
839
0
        if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
840
0
            data_params.is_indexed = true;
841
0
            if ((code = pdf_array_add_real2(pca, MIN_MESH_COLOR_INDEX,
842
0
                                            MAX_MESH_COLOR_INDEX)) < 0)
843
0
                return code;
844
0
        } else {
845
0
            for (i = 0; i < num_comp; ++i) {
846
0
                double rmin, rmax;
847
848
0
                if (pmp->Function || pranges || data_params.Domain == 0) {
849
0
                    if (pmp->Function && pmp->Function->params.Domain != 0) {
850
0
                        rmin = pmp->Function->params.Domain[0], rmax = pmp->Function->params.Domain[1];
851
0
                    } else {
852
0
                        rmin = 0.0, rmax = 1.0;
853
0
                    }
854
0
                }
855
0
                else
856
0
                    rmin = data_params.Domain[2 * i],
857
0
                        rmax = data_params.Domain[2 * i + 1];
858
0
                if ((code =
859
0
                     pdf_array_add_real2(pca, rmin, rmax)) < 0)
860
0
                    return code;
861
0
            }
862
0
        }
863
0
        code = cos_dict_put_c_key_object(pscd, "/Decode", COS_OBJECT(pca));
864
0
        if (code < 0)
865
0
            return code;
866
0
        bits_per_coordinate = 24;
867
0
        bits_per_component = 16;
868
0
        bits_per_flag = 8;
869
0
        gs_make_identity((gs_matrix *)&ctm_ident);
870
0
        ctm_ident.tx_fixed = ctm_ident.ty_fixed = 0;
871
0
        ctm_ident.txy_fixed_valid = true;
872
0
        cs.pctm = &ctm_ident;
873
0
        if (pmp->Function)
874
0
            data_params.ranges = 0; /* don't scale function parameter */
875
11
    } else {
876
        /****** SCALE Decode ******/
877
11
        code = cos_dict_put_c_key_floats(pdev, pscd, "/Decode", pmp->Decode,
878
11
                                         4 + num_comp * 2);
879
11
        if (code >= 0)
880
11
            code = cos_stream_add_stream_contents(pdev, pscs, cs.s);
881
11
        bits_per_coordinate = pmp->BitsPerCoordinate;
882
11
        bits_per_component = pmp->BitsPerComponent;
883
11
        bits_per_flag = -1;
884
11
    }
885
11
    if (code < 0 ||
886
11
        (code = pdf_put_shading_Function(pdev, pscd, pmp->Function, pranges)) < 0 ||
887
11
        (code = cos_dict_put_c_key_int(pscd, "/BitsPerCoordinate",
888
11
                                       bits_per_coordinate)) < 0 ||
889
11
        (code = cos_dict_put_c_key_int(pscd, "/BitsPerComponent",
890
11
                                       bits_per_component)) < 0
891
11
        )
892
0
        return code;
893
894
11
    if (from_array && pdev->CompatibilityLevel < 1.5 ) {
895
0
        float min_x, max_x, min_y, max_y, z;
896
0
        int i = 0, j, num_points = 1, num_components = 1;
897
0
        float c = 0;
898
0
        float x, y;
899
900
        /*
901
         * Because of the Acrobat Reader limitation noted in gdevpdfx.h,
902
         * we must limit coordinate values to 16 bits. We no longer
903
         * attempt to support Acrobat 1.3 and below (which only permit 14 bits).
904
         */
905
0
        min_x = min_y = PDFA_MIN_MESH_COORDINATE;
906
0
        max_x = max_y = PDFA_MAX_MESH_COORDINATE;
907
908
0
        switch(ShadingType(psh)){
909
0
            case shading_type_Tensor_product_patch:
910
0
                    while ((flag = shade_next_flag(&cs, 0)) >= 0){
911
0
                        num_points = (flag == 0 ? 16 : 12);
912
0
                        num_components = num_comp * (flag == 0 ? 4 : 2);
913
914
0
                        for (j = 0; j < num_points;j++) {
915
0
                            code = cs.get_decoded(&cs, 0, NULL, &x);
916
0
                            if (code < 0)
917
0
                                break;
918
0
                            code = cs.get_decoded(&cs, 0, NULL, &y);
919
0
                            if (code < 0)
920
0
                                break;
921
0
                            for (i = 0; i < num_components; ++i) {
922
0
                                code = cs.get_decoded(&cs, 0, NULL, &c);
923
0
                                if (code < 0)
924
0
                                    break;
925
0
                            }
926
0
                            if (x < min_x)
927
0
                                min_x = x;
928
0
                            if (y < min_y)
929
0
                                min_y = y;
930
0
                            if (x > max_x)
931
0
                                max_x = x;
932
0
                            if (y > max_y)
933
0
                                max_y = y;
934
0
                        }
935
0
                    }
936
0
                break;
937
0
            case shading_type_Coons_patch:
938
0
                    while ((flag = shade_next_flag(&cs, 0)) >= 0){
939
0
                        num_points = (flag == 0 ? 12 : 8);
940
0
                        num_components = num_comp * (flag == 0 ? 4 : 2);
941
942
0
                        for (j = 0; j < num_points;j++) {
943
0
                            code = cs.get_decoded(&cs, 0, NULL, &x);
944
0
                            if (code < 0)
945
0
                                break;
946
0
                            code = cs.get_decoded(&cs, 0, NULL, &y);
947
0
                            if (code < 0)
948
0
                                break;
949
0
                            for (i = 0; i < num_components; ++i) {
950
0
                                code = cs.get_decoded(&cs, 0, NULL, &c);
951
0
                                if (code < 0)
952
0
                                    break;
953
0
                            }
954
0
                            if (x < min_x)
955
0
                                min_x = x;
956
0
                            if (y < min_y)
957
0
                                min_y = y;
958
0
                            if (x > max_x)
959
0
                                max_x = x;
960
0
                            if (y > max_y)
961
0
                                max_y = y;
962
0
                        }
963
0
                    }
964
0
                break;
965
0
            case shading_type_Free_form_Gouraud_triangle:
966
0
                {
967
0
                    while ((flag = shade_next_flag(&cs, 0)) >= 0){
968
0
                        code = cs.get_decoded(&cs, 0, NULL, &x);
969
0
                        if (code < 0)
970
0
                            break;
971
0
                        code = cs.get_decoded(&cs, 0, NULL, &y);
972
0
                        if (code < 0)
973
0
                            break;
974
0
                        for (i = 0; i < num_comp; ++i) {
975
0
                            code = cs.get_decoded(&cs, 0, NULL, &c);
976
0
                            if (code < 0)
977
0
                                break;
978
0
                        }
979
0
                        if (x < min_x)
980
0
                            min_x = x;
981
0
                        if (y < min_y)
982
0
                            min_y = y;
983
0
                        if (x > max_x)
984
0
                            max_x = x;
985
0
                        if (y > max_y)
986
0
                            max_y = y;
987
0
                    }
988
0
                }
989
0
                break;
990
0
            case shading_type_Lattice_form_Gouraud_triangle:
991
0
                {
992
0
                    while (!seofp(cs.s)) {
993
0
                        code = cs.get_decoded(&cs, 0, NULL, &x);
994
0
                        if (code < 0)
995
0
                            break;
996
0
                        code = cs.get_decoded(&cs, 0, NULL, &y);
997
0
                        if (code < 0)
998
0
                            break;
999
0
                        for (i = 0; i < num_comp; ++i) {
1000
0
                            code = cs.get_decoded(&cs, 0, NULL, &c);
1001
0
                            if (code < 0)
1002
0
                                break;
1003
0
                        }
1004
0
                        if (x < min_x)
1005
0
                            min_x = x;
1006
0
                        if (y < min_y)
1007
0
                            min_y = y;
1008
0
                        if (x > max_x)
1009
0
                            max_x = x;
1010
0
                        if (y > max_y)
1011
0
                            max_y = y;
1012
0
                    }
1013
0
                }
1014
0
                break;
1015
0
            default:
1016
0
                break;
1017
0
        }
1018
0
        s_init(&cs.ds, NULL);
1019
0
        sread_string(&cs.ds, pmp->DataSource.data.str.data,
1020
0
                     pmp->DataSource.data.str.size);
1021
0
        cs.s = &cs.ds;
1022
1023
0
        *rescale = (int)ceil(min_x / PDFA_MIN_MESH_COORDINATE);
1024
0
        z = ceil(min_y / PDFA_MIN_MESH_COORDINATE);
1025
0
        if (z > *rescale)
1026
0
            *rescale = (int)z;
1027
0
        z = ceil(max_x / PDFA_MAX_MESH_COORDINATE);
1028
0
        if (z > *rescale)
1029
0
            *rescale = (int)z;
1030
0
        z = ceil(max_y / PDFA_MAX_MESH_COORDINATE);
1031
0
        if (z > *rescale)
1032
0
            *rescale = (int)z;
1033
0
        data_params.rescale = *rescale;
1034
0
        data_params.old_pdf = 1;
1035
0
    } else
1036
11
        data_params.old_pdf = 0;
1037
1038
11
    switch (ShadingType(psh)) {
1039
3
    case shading_type_Free_form_Gouraud_triangle: {
1040
3
        const gs_shading_FfGt_params_t *const params =
1041
3
            (const gs_shading_FfGt_params_t *)pmp;
1042
1043
3
        data_params.num_points = 1;
1044
3
        data_params.num_components = num_comp;
1045
3
        if (from_array) {
1046
0
            while ((flag = shade_next_flag(&cs, 0)) >= 0)
1047
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, flag,
1048
0
                                                num_comp, &data_params)) < 0)
1049
0
                    return code;
1050
0
            if (!seofp(cs.s))
1051
0
                code = gs_note_error(gs_error_rangecheck);
1052
0
        }
1053
3
        if (bits_per_flag < 0)
1054
3
            bits_per_flag = params->BitsPerFlag;
1055
3
        break;
1056
3
    }
1057
6
    case shading_type_Lattice_form_Gouraud_triangle: {
1058
6
        const gs_shading_LfGt_params_t *const params =
1059
6
            (const gs_shading_LfGt_params_t *)pmp;
1060
1061
6
        data_params.num_points = 1;
1062
6
        data_params.num_components = num_comp;
1063
6
        if (from_array)
1064
0
            while (!seofp(cs.s))
1065
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, -1,
1066
0
                                                num_comp, &data_params)) < 0)
1067
0
                    return code;
1068
6
        code = cos_dict_put_c_key_int(pscd, "/VerticesPerRow",
1069
6
                                      params->VerticesPerRow);
1070
6
        return code;
1071
6
    }
1072
0
    case shading_type_Coons_patch: {
1073
0
        const gs_shading_Cp_params_t *const params =
1074
0
            (const gs_shading_Cp_params_t *)pmp;
1075
1076
0
        if (from_array) {
1077
0
            while ((flag = shade_next_flag(&cs, 0)) >= 0) {
1078
0
                data_params.num_points = (flag == 0 ? 12 : 8);
1079
0
                data_params.num_components = num_comp * (flag == 0 ? 4 : 2);
1080
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, flag,
1081
0
                                                num_comp, &data_params)) < 0)
1082
0
                    return code;
1083
0
            }
1084
0
            if (!seofp(cs.s))
1085
0
                code = gs_note_error(gs_error_rangecheck);
1086
0
        }
1087
0
        if (bits_per_flag < 0)
1088
0
            bits_per_flag = params->BitsPerFlag;
1089
0
        break;
1090
0
    }
1091
2
    case shading_type_Tensor_product_patch: {
1092
2
        const gs_shading_Tpp_params_t *const params =
1093
2
            (const gs_shading_Tpp_params_t *)pmp;
1094
1095
2
        if (from_array) {
1096
0
            while ((flag = shade_next_flag(&cs, 0)) >= 0) {
1097
0
                data_params.num_points = (flag == 0 ? 16 : 12);
1098
0
                data_params.num_components = num_comp * (flag == 0 ? 4 : 2);
1099
0
                if ((code = put_float_mesh_data(pdev, pscs, &cs, flag, num_comp,
1100
0
                                                &data_params)) < 0)
1101
0
                    return code;
1102
0
            }
1103
0
            if (!seofp(cs.s))
1104
0
                code = gs_note_error(gs_error_rangecheck);
1105
0
        }
1106
2
        if (bits_per_flag < 0)
1107
2
            bits_per_flag = params->BitsPerFlag;
1108
2
        break;
1109
2
    }
1110
0
    default:
1111
0
        return_error(gs_error_rangecheck);
1112
11
    }
1113
5
    code1 =  cos_dict_put_c_key_int(pscd, "/BitsPerFlag", bits_per_flag);
1114
5
    if (code1 < 0)
1115
0
        return code1;
1116
5
    return code;
1117
5
}
1118
1119
/* Write a PatternType 2 (shading pattern) color. */
1120
int
1121
pdf_put_pattern2(gx_device_pdf *pdev, const gs_gstate * pgs, const gx_drawing_color *pdc,
1122
                 const psdf_set_color_commands_t *ppscc,
1123
                 pdf_resource_t **ppres)
1124
8.76k
{
1125
8.76k
    const gs_pattern2_instance_t *pinst =
1126
8.76k
        (gs_pattern2_instance_t *)pdc->ccolor.pattern;
1127
8.76k
    const gs_shading_t *psh = pinst->templat.Shading;
1128
8.76k
    cos_value_t v;
1129
8.76k
    pdf_resource_t *pres;
1130
8.76k
    pdf_resource_t *psres;
1131
8.76k
    cos_dict_t *pcd;
1132
8.76k
    cos_object_t *psco;
1133
8.76k
    const gs_range_t *pranges;
1134
8.76k
    int code = pdf_cs_Pattern_colored(pdev, &v);
1135
8.76k
    int code1 = 0, rescale = 1;
1136
8.76k
    gs_matrix smat;
1137
8.76k
    gs_point dist;
1138
1139
8.76k
    if (code < 0)
1140
0
        return code;
1141
8.76k
    code = pdf_alloc_resource(pdev, resourcePattern, gs_no_id, ppres, -1);
1142
8.76k
    if (code < 0)
1143
0
        return code;
1144
8.76k
    pres = *ppres;
1145
8.76k
    cos_become(pres->object, cos_type_dict);
1146
8.76k
    pcd = (cos_dict_t *)pres->object;
1147
8.76k
    code = pdf_alloc_resource(pdev, resourceShading, gs_no_id, &psres, -1);
1148
8.76k
    if (code < 0)
1149
0
        return code;
1150
8.76k
    psco = psres->object;
1151
8.76k
    if (ShadingType(psh) >= 4) {
1152
        /* Shading has an associated data stream. */
1153
11
        cos_become(psco, cos_type_stream);
1154
11
        code = pdf_put_shading_common(pdev, cos_stream_dict((cos_stream_t *)psco), pgs,
1155
11
                                      psh, pinst->shfill, &pranges);
1156
11
        if (code >= 0)
1157
11
            code1 = pdf_put_mesh_shading(pdev, (cos_stream_t *)psco, psh, pranges, &rescale);
1158
0
        else
1159
            /* We won't use this shading, we fall back because we couldn't write it */
1160
0
            psres->where_used = 0;
1161
8.75k
    } else {
1162
8.75k
        cos_become(psco, cos_type_dict);
1163
8.75k
        code = pdf_put_shading_common(pdev, (cos_dict_t *)psco, pgs, psh, pinst->shfill, &pranges);
1164
8.75k
        if (code >= 0)
1165
8.75k
            code1 = pdf_put_scalar_shading(pdev, (cos_dict_t *)psco, psh, pranges);
1166
0
        else
1167
            /* We won't use this shading, we fall back because we couldn't write it */
1168
0
            psres->where_used = 0;
1169
8.75k
    }
1170
8.76k
    if (psres->where_used) {
1171
8.76k
        code = pdf_substitute_resource(pdev, &psres, resourceShading, NULL, false);
1172
8.76k
        if (code < 0)
1173
0
            return code;
1174
8.76k
        psco = psres->object;
1175
8.76k
        psres->where_used |= pdev->used_mask;
1176
8.76k
    }
1177
    /*
1178
     * In PDF, the Matrix is the transformation from the pattern space to
1179
     * the *default* user coordinate space, not the current space.
1180
     * NB. For a form the default space is the parent. This means that when a
1181
     * form is nested inside a form, the default space is the space of the
1182
     * first form, and therefore we do *not* remove the resolution scaling.
1183
     */
1184
8.76k
    gs_currentmatrix(pinst->saved, &smat);
1185
8.76k
    {
1186
8.76k
        double xscale = 1.0, yscale = 1.0;
1187
8.76k
        if (pdev->FormDepth == 0) {
1188
637
            xscale = 72.0 / pdev->HWResolution[0];
1189
637
            yscale = 72.0 / pdev->HWResolution[1];
1190
637
        }
1191
1192
8.76k
        smat.xx *= xscale, smat.yx *= xscale, smat.tx *= xscale;
1193
8.76k
        smat.xy *= yscale, smat.yy *= yscale, smat.ty *= yscale;
1194
1195
8.76k
        if (rescale != 1) {
1196
0
            smat.xx *= rescale, smat.yx *= rescale;
1197
0
            smat.xy *= rescale, smat.yy *= rescale;
1198
0
        }
1199
8.76k
    }
1200
1201
    /* Bug #697451, if we emit a PDF with a type 2 Pattern where the
1202
     * Matrix is degenerate, Acrobat throws an error and aborts the
1203
     * page content stream. Distiller refuses to embed the shfill,
1204
     * it silently (!) ignores the problem. So here we test to see
1205
     * if the CTM is degenerate, if it is, replace it with the
1206
     * smallest Matrix we can.
1207
     */
1208
8.76k
    code = gs_distance_transform_inverse(1, 1, &smat, &dist);
1209
8.76k
    if (code == gs_error_undefinedresult) {
1210
28
        smat.xx = smat.yy = 0.00000001f;
1211
28
        smat.xy = smat.yx = smat.tx = smat.ty = 0;
1212
28
        code = 0;
1213
28
    }
1214
1215
8.76k
    if (code < 0 ||
1216
8.76k
        (code = cos_dict_put_c_key_int(pcd, "/PatternType", 2)) < 0 ||
1217
8.76k
        (code = cos_dict_put_c_key_object(pcd, "/Shading", psco)) < 0 ||
1218
8.76k
        (code = cos_dict_put_matrix(pdev, pcd, "/Matrix", &smat)) < 0
1219
        /****** ExtGState ******/
1220
8.76k
        )
1221
0
        return code;
1222
8.76k
    code = pdf_substitute_resource(pdev, &pres, resourcePattern, NULL, false);
1223
8.76k
    if (code < 0)
1224
0
        return code;
1225
8.76k
    pres->where_used |= pdev->used_mask;
1226
8.76k
    *ppres = pres;
1227
1228
8.76k
    cos_value_write(&v, pdev);
1229
8.76k
    pprints1(pdev->strm, " %s\n", ppscc->setcolorspace);
1230
8.76k
    return code1;
1231
8.76k
}
1232
1233
/*
1234
    Include color space.
1235
 */
1236
int
1237
gdev_pdf_include_color_space(gx_device *dev, gs_color_space *cspace, const byte *res_name, int name_length)
1238
0
{
1239
0
    gx_device_pdf * pdev = (gx_device_pdf *)dev;
1240
0
    cos_value_t cs_value;
1241
1242
0
    return pdf_color_space_named(pdev, NULL, &cs_value, NULL, cspace,
1243
0
                                &pdf_color_space_names, true, res_name, name_length, false);
1244
0
}