Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/pdf/pdf_pattern.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-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
/* Pattern operations for the PDF interpreter */
17
18
#include "pdf_int.h"
19
#include "pdf_doc.h"
20
#include "pdf_colour.h"
21
#include "pdf_pattern.h"
22
#include "pdf_stack.h"
23
#include "pdf_array.h"
24
#include "pdf_font_types.h"
25
#include "pdf_gstate.h"
26
#include "pdf_file.h"
27
#include "pdf_dict.h"
28
#include "pdf_loop_detect.h"
29
#include "pdf_func.h"
30
#include "pdf_shading.h"
31
#include "pdf_check.h"
32
33
#include "gsicc_manage.h"
34
#include "gsicc_profilecache.h"
35
#include "gsicc_create.h"
36
#include "gsptype2.h"
37
#include "gxdevsop.h"               /* For special ops : pattern_accum_param_s */
38
#include "gscsepr.h"
39
#include "stream.h"
40
#include "strmio.h"
41
#include "gscdevn.h"
42
#include "gscoord.h"                /* For gs_setmatrix() */
43
44
typedef struct {
45
    pdf_context *ctx;
46
    pdf_dict *page_dict;
47
    pdf_obj *pat_obj;
48
    gs_shading_t *shading;
49
} pdf_pattern_context_t;
50
51
/* See pdf_draw.ps, FixPatternBox
52
 * A BBox where width or height (or both) is 0 should still paint one pixel
53
 * See the ISO 32000-2:2017 spec, section 8.7.4.3, p228 'BBox' and 8.7.3.1
54
 */
55
static void
56
pdfi_pattern_fix_bbox(pdf_context *ctx, gs_rect *rect)
57
8.69k
{
58
8.69k
    if (rect->p.x - rect->q.x == 0)
59
0
        rect->q.x += .00000001;
60
8.69k
    if (rect->p.y - rect->q.y == 0)
61
0
        rect->q.y += .00000001;
62
8.69k
}
63
64
/* Get rect from array, normalize and adjust it */
65
static int
66
pdfi_pattern_get_rect(pdf_context *ctx, pdf_array *array, gs_rect *rect)
67
8.70k
{
68
8.70k
    int code;
69
70
8.70k
    code = pdfi_array_to_gs_rect(ctx, array, rect);
71
8.70k
    if (code != 0)
72
5
        return code;
73
74
8.69k
    pdfi_normalize_rect(ctx, rect);
75
8.69k
    pdfi_pattern_fix_bbox(ctx, rect);
76
77
8.69k
    return code;
78
8.70k
}
79
80
#if 0 /* Not currently using, not sure if needed (and it didn't work anyway) */
81
/* NULL Pattern */
82
static int
83
pdfi_setpattern_null(pdf_context *ctx, gs_client_color *cc)
84
{
85
    int code = 0;
86
    gs_client_pattern templat;
87
    gs_matrix mat;
88
    gs_rect rect;
89
90
    gs_pattern1_init(&templat);
91
92
    /* Init identity matrix */
93
    pdfi_array_to_gs_matrix(ctx, NULL, &mat);
94
    pdfi_pattern_get_rect(ctx, NULL, &rect);
95
    templat.BBox = rect;
96
    templat.PaintProc = NULL;
97
    templat.PaintType = 1;
98
    templat.TilingType = 3;
99
    templat.XStep = 1;
100
    templat.YStep = 1;
101
102
    code = gs_makepattern(cc, &templat, &mat, ctx->pgs, ctx->memory);
103
104
    return code;
105
}
106
#endif
107
108
static void pdfi_free_pattern_context(pdf_pattern_context_t *context)
109
9.25k
{
110
9.25k
    pdfi_countdown(context->page_dict);
111
9.25k
    pdfi_countdown(context->pat_obj);
112
9.25k
    if (context->shading)
113
464
        pdfi_shading_free(context->ctx, context->shading);
114
9.25k
    gs_free_object(context->ctx->memory, context, "Free pattern context");
115
9.25k
}
116
117
void pdfi_pattern_cleanup(gs_memory_t * mem, void *p)
118
9.14k
{
119
9.14k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)p;
120
121
9.14k
    if (pinst->client_data != NULL) {
122
9.14k
        pdfi_free_pattern_context((pdf_pattern_context_t *)pinst->client_data);
123
9.14k
        pinst->client_data = NULL;
124
9.14k
        pinst->notify_free = NULL;
125
9.14k
    }
126
9.14k
}
127
128
/* See px_paint_pattern() */
129
static int
130
pdfi_pattern_paint_stream(pdf_context *ctx, const gs_client_color *pcc)
131
8.44k
{
132
8.44k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
133
8.44k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
134
8.44k
    pdf_dict *page_dict = context->page_dict;
135
8.44k
    pdf_stream *pat_stream = (pdf_stream *)context->pat_obj;
136
8.44k
    int code = 0;
137
8.44k
    int SavedBlockDepth = 0;
138
139
    /* In case we are setting up a pattern for filling or stroking text, we need
140
     * to reset the BlockDepth so that we don't detect the Pattern content as being
141
     * 'inside' a text block, where some operations (eg path contstruction) are
142
     * not permitted.
143
     */
144
8.44k
    SavedBlockDepth = ctx->text.BlockDepth;
145
8.44k
    ctx->text.BlockDepth = 0;
146
147
    /* Interpret inner stream */
148
8.44k
    code = pdfi_run_context(ctx, pat_stream, page_dict, true, "PATTERN");
149
150
8.44k
    ctx->text.BlockDepth = SavedBlockDepth;
151
152
8.44k
    return code;
153
8.44k
}
154
155
/* See px_paint_pattern() */
156
static int
157
pdfi_pattern_paint(const gs_client_color *pcc, gs_gstate *pgs)
158
7.97k
{
159
7.97k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
160
7.97k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
161
7.97k
    pdf_context *ctx = context->ctx;
162
7.97k
    int code = 0;
163
164
#if DEBUG_PATTERN
165
    dbgmprintf(ctx->memory, "BEGIN PATTERN PaintProc\n");
166
#endif
167
7.97k
    code = pdfi_gsave(ctx); /* TODO: This might be redundant? */
168
7.97k
    if (code < 0)
169
0
        return code;
170
7.97k
    code = pdfi_gs_setgstate(ctx->pgs, pgs);
171
7.97k
    if (code < 0)
172
0
        goto exit;
173
174
    /* TODO: This hack here is to emulate some stuff that happens in the PS code.
175
     * Basically gx_pattern_load() gets called twice in PS code path, which causes this
176
     * flag to end up being set, which changes some transparency stuff that might matter, to happen.
177
     * By forcing this flag here, it makes the trace more closely follow what the PS code
178
     * does.  It could turn out to be a meaningless side-effect, or it might be important.
179
     * (sometime in the future, try taking this out and see what happens :)
180
     */
181
7.97k
    if (pinst->templat.uses_transparency) {
182
6.36k
        dbgmprintf(ctx->memory, "pdfi_pattern_paint forcing trans_flags.xtate_change = TRUE\n");
183
6.36k
        ctx->pgs->trans_flags.xstate_change = true;
184
6.36k
    }
185
7.97k
    code = pdfi_op_q(ctx);
186
7.97k
    if (code < 0)
187
0
        goto exit;
188
189
7.97k
    code = pdfi_pattern_paint_stream(ctx, pcc);
190
7.97k
    pdfi_op_Q(ctx);
191
7.97k
    if (code < 0) {
192
0
        dbgmprintf1(ctx->memory, "ERROR: pdfi_pattern_paint: code %d when rendering pattern\n", code);
193
0
        goto exit;
194
0
    }
195
196
7.97k
 exit:
197
7.97k
    pdfi_grestore(ctx);
198
#if DEBUG_PATTERN
199
    dbgmprintf(ctx->memory, "END PATTERN PaintProc\n");
200
#endif
201
7.97k
    return code;
202
7.97k
}
203
204
/* See px_high_level_pattern(), pattern_paint_prepare() */
205
static int
206
pdfi_pattern_paint_high_level(const gs_client_color *pcc, gs_gstate *pgs_ignore)
207
468
{
208
468
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
209
468
    const gs_pattern1_template_t *templat = &pinst->templat;
210
468
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
211
468
    pdf_context *ctx = context->ctx;
212
468
    gs_gstate *pgs = ctx->pgs;
213
468
    gs_matrix m;
214
468
    gs_rect bbox;
215
468
    gs_fixed_rect clip_box;
216
468
    int code;
217
468
    gx_device_color *pdc = gs_currentdevicecolor_inline(pgs);
218
468
    pattern_accum_param_s param;
219
220
468
    code = pdfi_gsave(ctx);
221
468
    if (code < 0)
222
0
        return code;
223
468
    code = pdfi_gs_setgstate(ctx->pgs, pinst->saved);
224
468
    if (code < 0)
225
0
        goto errorExit;
226
227
468
    dev_proc(pgs->device, get_initial_matrix)(pgs->device, &m);
228
468
    gs_setmatrix(pgs, &m);
229
468
    code = gs_bbox_transform(&templat->BBox, &ctm_only(pgs), &bbox);
230
468
    if (code < 0)
231
0
        goto errorExit;
232
468
    clip_box.p.x = float2fixed(bbox.p.x);
233
468
    clip_box.p.y = float2fixed(bbox.p.y);
234
468
    clip_box.q.x = float2fixed(bbox.q.x);
235
468
    clip_box.q.y = float2fixed(bbox.q.y);
236
468
    code = gx_clip_to_rectangle(pgs, &clip_box);
237
468
    if (code < 0)
238
0
        goto errorExit;
239
240
468
    param.pinst = (void *)pinst;
241
468
    param.interpreter_memory = ctx->memory;
242
468
    param.graphics_state = (void *)pgs;
243
468
    param.pinst_id = pinst->id;
244
245
468
    code = (*dev_proc(pgs->device, dev_spec_op))
246
468
        ((gx_device *)pgs->device, gxdso_pattern_start_accum, &param, sizeof(pattern_accum_param_s));
247
248
468
    if (code < 0)
249
0
        goto errorExit;
250
251
#if DEBUG_PATTERN
252
    dbgmprintf(ctx->memory, "PATTERN: BEGIN high level pattern stream\n");
253
#endif
254
468
    code = pdfi_pattern_paint_stream(ctx, &pdc->ccolor);
255
#if DEBUG_PATTERN
256
    dbgmprintf(ctx->memory, "PATTERN: END high level pattern stream\n");
257
#endif
258
468
    if (code < 0)
259
0
        goto errorExit;
260
261
468
    code = dev_proc(pgs->device, dev_spec_op)
262
468
        (pgs->device, gxdso_pattern_finish_accum, &param, sizeof(pattern_accum_param_s));
263
468
    if (code < 0)
264
0
        goto errorExit;
265
266
468
    code = pdfi_grestore(ctx);
267
468
    if (code < 0)
268
0
        return code;
269
270
    /* We create the dummy cache entry last, after we've executed the Pattern PaintProc. This is because
271
     * if we ran another Pattern during the PaintProc, and that pattern has an id which happens to
272
     * collide with the id of this pattern, it would overwrite the entry in the pattern cache.
273
     * Deferring the entry in the cache until we are complete prevents this happening.
274
     * For an example see Bug693422.pdf.
275
     */
276
468
    code = gx_pattern_cache_add_dummy_entry(pgs, pinst, pgs->device->color_info.depth);
277
468
    if (code < 0)
278
0
        return code;
279
280
468
    return gs_error_handled;
281
282
0
 errorExit:
283
0
    pdfi_grestore(ctx);
284
0
    return code;
285
468
}
286
287
/* Called from gx_pattern_load(), see px_remap_pattern()  */
288
static int
289
pdfi_pattern_paintproc(const gs_client_color *pcc, gs_gstate *pgs)
290
8.44k
{
291
8.44k
    const gs_client_pattern *pinst = gs_getpattern(pcc);
292
8.44k
    int code = 0;
293
294
    /* pgs->device is the newly created pattern accumulator, but we want to test the device
295
     * that is 'behind' that, the actual output device, so we use the one from
296
     * the saved graphics state.
297
     */
298
8.44k
    if (pgs->have_pattern_streams) {
299
8.44k
        code = dev_proc(pcc->pattern->saved->device, dev_spec_op)(pcc->pattern->saved->device,
300
8.44k
                                gxdso_pattern_can_accum, (void *)pinst, pinst->uid.id);
301
8.44k
    }
302
303
8.44k
    if (code == 1) {
304
468
        return pdfi_pattern_paint_high_level(pcc, pgs);
305
7.97k
    } else {
306
7.97k
        return pdfi_pattern_paint(pcc, pgs);
307
7.97k
    }
308
8.44k
}
309
310
311
312
/* Setup the correct gstate for a pattern */
313
static int
314
pdfi_pattern_gset(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *ExtGState)
315
9.25k
{
316
9.25k
    int code;
317
9.25k
    float strokealpha, fillalpha;
318
319
9.25k
    strokealpha = gs_getstrokeconstantalpha(ctx->pgs);
320
9.25k
    fillalpha = gs_getfillconstantalpha(ctx->pgs);
321
322
    /* This will preserve the ->level and a couple other things */
323
#if DEBUG_PATTERN
324
    dbgmprintf2(ctx->memory, "PATTERN: setting DefaultQState, old device=%s, new device=%s\n",
325
                ctx->pgs->device->dname, ctx->DefaultQState->device->dname);
326
#endif
327
9.25k
    code = pdfi_gs_setgstate(ctx->pgs, pdfi_get_DefaultQState(ctx));
328
9.25k
    if (code < 0) goto exit;
329
9.25k
    code = gs_setstrokeconstantalpha(ctx->pgs, strokealpha);
330
9.25k
    if (code < 0) goto exit;
331
9.25k
    code = gs_setfillconstantalpha(ctx->pgs, fillalpha);
332
9.25k
    if (code < 0) goto exit;
333
334
    /* Set ExtGState if one is provided */
335
9.25k
    if (ExtGState)
336
0
        code = pdfi_set_ExtGState(ctx, NULL, page_dict, ExtGState);
337
9.25k
 exit:
338
9.25k
    return code;
339
9.25k
}
340
341
/* Setup the pattern gstate and other context */
342
static int
343
pdfi_pattern_setup(pdf_context *ctx, pdf_pattern_context_t **ppcontext,
344
                   pdf_dict *page_dict, pdf_obj *pat_obj, pdf_dict *ExtGState)
345
9.25k
{
346
9.25k
    int code = 0;
347
9.25k
    pdf_pattern_context_t *context = NULL;
348
349
9.25k
    code = pdfi_pattern_gset(ctx, page_dict, ExtGState);
350
9.25k
    if (code < 0)
351
0
        goto errorExit;
352
353
9.25k
    context = (pdf_pattern_context_t *) gs_alloc_bytes(ctx->memory, sizeof(*context),
354
9.25k
                                                       "pdfi_pattern_setup(context)");
355
9.25k
    if (!context) {
356
0
        code = gs_note_error(gs_error_VMerror);
357
0
        goto errorExit;
358
0
    }
359
9.25k
    context->ctx = ctx;
360
9.25k
    context->page_dict = page_dict;
361
9.25k
    context->pat_obj = pat_obj;
362
9.25k
    context->shading = NULL;
363
9.25k
    pdfi_countup(page_dict);
364
9.25k
    pdfi_countup(pat_obj);
365
9.25k
    *ppcontext = context;
366
367
9.25k
    return 0;
368
0
 errorExit:
369
0
    gs_free_object(ctx->memory, context, "pdfi_pattern_setup(context)");
370
0
    return code;
371
9.25k
}
372
373
374
/* Type 1 (tiled) Pattern */
375
static int
376
pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
377
                      pdf_obj *stream, gs_client_color *cc)
378
8.72k
{
379
8.72k
    int code = 0;
380
8.72k
    gs_client_pattern templat;
381
8.72k
    gs_matrix mat;
382
8.72k
    gs_rect rect;
383
8.72k
    int64_t PaintType, TilingType;
384
8.72k
    pdf_array *BBox = NULL;
385
8.72k
    double XStep, YStep;
386
8.72k
    pdf_dict *Resources = NULL, *pdict = NULL;
387
8.72k
    pdf_array *Matrix = NULL;
388
8.72k
    bool transparency = false;
389
8.72k
    pdf_pattern_context_t *context = NULL;
390
391
#if DEBUG_PATTERN
392
    dbgmprintf(ctx->memory, "PATTERN: Type 1 pattern\n");
393
#endif
394
395
8.72k
    gs_pattern1_init(&templat);
396
397
    /* Must be a stream */
398
8.72k
    if (pdfi_type_of(stream) != PDF_STREAM) {
399
20
        code = gs_note_error(gs_error_typecheck);
400
20
        goto exit;
401
20
    }
402
8.70k
    code = pdfi_dict_from_obj(ctx, stream, &pdict);
403
8.70k
    if (code < 0)
404
0
        return code;
405
406
    /* Required */
407
8.70k
    code = pdfi_dict_get_int(ctx, pdict, "PaintType", &PaintType);
408
8.70k
    if (code < 0)
409
2
        goto exit;
410
8.70k
    code = pdfi_dict_get_int(ctx, pdict, "TilingType", &TilingType);
411
8.70k
    if (code < 0)
412
1
        goto exit;
413
8.70k
    code = pdfi_dict_get_type(ctx, pdict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
414
8.70k
    if (code < 0)
415
5
        goto exit;
416
8.70k
    code = pdfi_pattern_get_rect(ctx, BBox, &rect);
417
8.70k
    if (code < 0)
418
5
        goto exit;
419
8.69k
    code = pdfi_dict_get_number(ctx, pdict, "XStep", &XStep);
420
8.69k
    if (code < 0)
421
9
        goto exit;
422
8.68k
    code = pdfi_dict_get_number(ctx, pdict, "YStep", &YStep);
423
8.68k
    if (code < 0)
424
1
        goto exit;
425
426
    /* XStep and YStep must be non-zero; table 425; page 293 of the 1.7 Reference */
427
8.68k
    if (XStep == 0.0 || YStep == 0.0) {
428
2
        code = gs_note_error(gs_error_rangecheck);
429
2
        goto exit;
430
2
    }
431
432
    /* The pattern instance holds the pattern step as floats, make sure they
433
     * will fit.
434
     */
435
8.68k
    if (XStep < -MAX_FLOAT || XStep > MAX_FLOAT || YStep < -MAX_FLOAT || YStep > MAX_FLOAT) {
436
0
        code = gs_note_error(gs_error_rangecheck);
437
0
        goto exit;
438
0
    }
439
440
    /* The spec says Resources are required, but in fact this doesn't seem to be true.
441
     * (tests_private/pdf/sumatra/infinite_pattern_recursion.pdf)
442
     */
443
8.68k
    code = pdfi_dict_get_type(ctx, pdict, "Resources", PDF_DICT, (pdf_obj **)&Resources);
444
8.68k
    if (code < 0) {
445
#if DEBUG_PATTERN
446
        dbgmprintf(ctx->memory, "PATTERN: Missing Resources in Pattern dict\n");
447
#endif
448
95
        pdfi_set_warning(ctx, 0, NULL, W_PDF_BADPATTERN, "pdfi_setpattern_type1", NULL);
449
95
        code = 0;
450
95
    }
451
452
    /* (optional Matrix) */
453
8.68k
    code = pdfi_dict_knownget_type(ctx, pdict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
454
8.68k
    if (code < 0)
455
0
        goto exit;
456
8.68k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &mat);
457
8.68k
    if (code < 0)
458
6
        goto exit;
459
460
8.67k
    if (PaintType != 1 && PaintType != 2) {
461
0
        code = gs_note_error(gs_error_rangecheck);
462
0
        goto exit;
463
0
    }
464
8.67k
    if (TilingType != 1 && TilingType != 2 && TilingType != 3) {
465
0
        code = gs_note_error(gs_error_rangecheck);
466
0
        goto exit;
467
0
    }
468
469
    /* See if pattern uses transparency, or if we are in an overprint
470
       simulation situation */
471
8.67k
    if (ctx->page.simulate_op)
472
0
        transparency = true;
473
8.67k
    else
474
8.67k
        if (ctx->page.has_transparency) {
475
7.20k
            code = pdfi_check_Pattern_transparency(ctx, pdict, page_dict, &transparency);
476
7.20k
            if (code < 0)
477
0
                goto exit;
478
7.20k
    }
479
480
    /* TODO: Resources?  Maybe I should check that they are all valid before proceeding, or something? */
481
482
8.67k
    templat.BBox = rect;
483
    /* (see zPaintProc or px_remap_pattern) */
484
8.67k
    templat.PaintProc = pdfi_pattern_paintproc;
485
8.67k
    templat.PaintType = PaintType;
486
8.67k
    templat.TilingType = TilingType;
487
8.67k
    templat.XStep = XStep;
488
8.67k
    templat.YStep = YStep;
489
8.67k
    templat.uses_transparency = transparency;
490
    //templat.uses_transparency = false; /* disable */
491
492
8.67k
    code = pdfi_gsave(ctx);
493
8.67k
    if (code < 0)
494
0
        goto exit;
495
496
8.67k
    code = pdfi_pattern_setup(ctx, &context, page_dict, stream, NULL);
497
8.67k
    if (code < 0) {
498
0
        (void) pdfi_grestore(ctx);
499
0
        goto exit;
500
0
    }
501
502
    /* We need to use the graphics state memory, in case we are running under Ghostscript. */
503
8.67k
    code = gs_make_pattern(cc, (const gs_pattern_template_t *)&templat, &mat, ctx->pgs, ctx->pgs->memory);
504
8.67k
    if (code < 0) {
505
0
        (void) pdfi_grestore(ctx);
506
0
        goto exit;
507
0
    }
508
509
8.67k
    cc->pattern->client_data = context;
510
8.67k
    cc->pattern->notify_free = pdfi_pattern_cleanup;
511
8.67k
    {
512
8.67k
        unsigned long hash = 5381;
513
8.67k
        unsigned int i;
514
8.67k
        const char *str = (const char *)&ctx->pgs->ctm;
515
516
8.67k
        gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)cc->pattern;
517
518
519
147k
        for (i = 0; i < 4 * sizeof(float); i++)
520
138k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
521
522
8.67k
        str = (const char *)&pdict->object_num;
523
43.3k
        for (i = 0; i < sizeof(uint32_t); i++)
524
34.7k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
525
526
8.67k
        hash = ((hash << 5) + hash) + ctx->pgs->device->color_info.num_components; /* hash * 33 + c */
527
528
        /* Include num_components for case where we have softmask and non-softmask
529
           fills with the same tile. We may need two tiles for this if there is a
530
           change in color space for the transparency group. */
531
8.67k
        pinst->id = hash;
532
8.67k
    }
533
8.67k
    context = NULL;
534
535
8.67k
    code = pdfi_grestore(ctx);
536
8.67k
    if (code < 0)
537
0
        goto exit;
538
8.72k
 exit:
539
8.72k
    gs_free_object(ctx->memory, context, "pdfi_setpattern_type1(context)");
540
8.72k
    pdfi_countdown(Resources);
541
8.72k
    pdfi_countdown(Matrix);
542
8.72k
    pdfi_countdown(BBox);
543
8.72k
    return code;
544
8.67k
}
545
546
/* Type 2 (shading) Pattern */
547
static int
548
pdfi_setpattern_type2(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
549
                      pdf_obj *pattern_obj, gs_client_color *cc)
550
740
{
551
740
    int code = 0;
552
740
    pdf_obj *Shading = NULL;
553
740
    pdf_dict *ExtGState = NULL, *pattern_dict = NULL;
554
740
    pdf_array *Matrix = NULL;
555
740
    gs_matrix mat;
556
740
    gs_shading_t *shading;
557
740
    gs_pattern2_template_t templat;
558
740
    pdf_pattern_context_t *context = NULL;
559
560
    /* See zbuildshadingpattern() */
561
562
740
    code = pdfi_dict_from_obj(ctx, pattern_obj, &pattern_dict);
563
740
    if (code < 0)
564
0
        return code;
565
566
#if DEBUG_PATTERN
567
    dbgmprintf(ctx->memory, "PATTERN: Type 2 pattern\n");
568
#endif
569
570
    /* (optional Matrix) */
571
740
    code = pdfi_dict_knownget_type(ctx, pattern_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
572
740
    if (code < 0)
573
0
        goto exit;
574
740
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &mat);
575
740
    if (code < 0)
576
8
        goto exit;
577
578
    /* Required Shading, can be stream or dict (but a stream is also a dict..) */
579
732
    code = pdfi_dict_knownget(ctx, pattern_dict, "Shading", &Shading);
580
732
    if (code < 0)
581
159
        goto exit;
582
573
    if (code == 0) {
583
0
        dbgmprintf(ctx->memory, "ERROR: Shading not found in Pattern Type 2\n");
584
0
        code = gs_note_error(gs_error_syntaxerror);
585
0
        goto exit;
586
0
    }
587
588
    /* Optional ExtGState */
589
573
    code = pdfi_dict_knownget_type(ctx, pattern_dict, "ExtGState", PDF_DICT, (pdf_obj **)&ExtGState);
590
573
    if (code < 0)
591
0
        goto exit;
592
593
573
    code = pdfi_gsave(ctx);
594
573
    if (code < 0)
595
0
        goto exit;
596
597
573
    gs_pattern2_init(&templat);
598
599
573
    code = pdfi_pattern_setup(ctx, &context, NULL, NULL, ExtGState);
600
573
    if (code < 0) {
601
0
        (void) pdfi_grestore(ctx);
602
0
        goto exit;
603
0
    }
604
605
573
    code = pdfi_shading_build(ctx, stream_dict, page_dict, Shading, &shading);
606
573
    if (code != 0) {
607
109
        (void) pdfi_grestore(ctx);
608
109
        dbgmprintf(ctx->memory, "ERROR: can't build shading structure\n");
609
109
        goto exit;
610
109
    }
611
612
464
    context->shading = shading;
613
614
464
    templat.Shading = shading;
615
464
    code = gs_make_pattern(cc, (const gs_pattern_template_t *)&templat, &mat, ctx->pgs, ctx->memory);
616
464
    if (code < 0) {
617
0
        (void) pdfi_grestore(ctx);
618
0
        goto exit;
619
0
    }
620
464
    cc->pattern->client_data = context;
621
464
    cc->pattern->notify_free = pdfi_pattern_cleanup;
622
464
    context = NULL;
623
624
464
    code = pdfi_grestore(ctx);
625
464
    if (code < 0)
626
0
        goto exit;
627
628
740
 exit:
629
740
    if (context != NULL)
630
109
        pdfi_free_pattern_context(context);
631
740
    pdfi_countdown(Shading);
632
740
    pdfi_countdown(Matrix);
633
740
    pdfi_countdown(ExtGState);
634
740
    return code;
635
464
}
636
637
int
638
pdfi_pattern_set(pdf_context *ctx, pdf_dict *stream_dict,
639
                pdf_dict *page_dict, pdf_name *pname,
640
                gs_client_color *cc)
641
13.9k
{
642
13.9k
    pdf_dict *pattern_dict = NULL;
643
13.9k
    pdf_obj *pattern_obj = NULL;
644
13.9k
    int code;
645
13.9k
    int64_t patternType;
646
647
13.9k
    code = pdfi_loop_detector_mark(ctx);
648
13.9k
    if (code < 0)
649
0
        return code;
650
651
13.9k
    memset(cc, 0, sizeof(*cc));
652
13.9k
    code = pdfi_find_resource(ctx, (unsigned char *)"Pattern", pname, (pdf_dict *)stream_dict,
653
13.9k
                              page_dict, (pdf_obj **)&pattern_obj);
654
13.9k
    if (code < 0) {
655
3.97k
        dbgmprintf(ctx->memory, "WARNING: Pattern object not found in resources\n");
656
3.97k
        goto exit;
657
3.97k
    }
658
659
9.99k
    code = pdfi_dict_from_obj(ctx, pattern_obj, &pattern_dict);
660
9.99k
    if (code < 0) {
661
        /* NOTE: Bug696410.pdf gets a bogus pattern while trying to process pattern.
662
         * Seems like a corrupted file, but this prevents crash
663
         */
664
285
        dbgmprintf(ctx->memory, "ERROR: Pattern found in resources is neither a stream or dict\n");
665
285
        goto exit;
666
285
    }
667
668
#if DEBUG_PATTERN
669
    dbgmprintf1(ctx->memory, "PATTERN: pdfi_setpattern: found pattern object %d\n", pdict->object_num);
670
#endif
671
672
9.71k
    code = pdfi_dict_get_int(ctx, pattern_dict, "PatternType", &patternType);
673
9.71k
    if (code < 0)
674
241
        goto exit;
675
9.47k
    if (patternType == 1) {
676
8.72k
        code = pdfi_setpattern_type1(ctx, stream_dict, page_dict, (pdf_obj *)pattern_obj, cc);
677
8.72k
        if (code < 0)
678
51
            goto exit;
679
8.72k
    } else if (patternType == 2) {
680
740
        code = pdfi_setpattern_type2(ctx, stream_dict, page_dict, pattern_obj, cc);
681
740
        if (code < 0)
682
276
            goto exit;
683
740
    } else {
684
4
        code = gs_note_error(gs_error_syntaxerror);
685
4
        goto exit;
686
4
    }
687
688
13.9k
 exit:
689
13.9k
    pdfi_countdown(pattern_obj);
690
13.9k
    if (code < 0)
691
4.83k
        (void)pdfi_loop_detector_cleartomark(ctx);
692
9.14k
    else
693
9.14k
        code = pdfi_loop_detector_cleartomark(ctx);
694
13.9k
    return code;
695
9.47k
}
696
697
/* Create a Pattern colorspace.
698
 * If ppcs is NULL, then we will set the colorspace
699
 * If ppcs not NULL, point the new colorspace to it
700
 *
701
 * If color_array is NULL, then this is a simple "Pattern" colorspace, e.g. "/Pattern cs".
702
 * If it is an array, then first element is "Pattern" and second element should be the base colorspace.
703
 * e.g. "/CS1 cs" where /CS1 is a ColorSpace Resource containing "[/Pattern /DeviceRGB]"
704
 *
705
 */
706
int
707
pdfi_pattern_create(pdf_context *ctx, pdf_array *color_array, pdf_dict *stream_dict,
708
                    pdf_dict *page_dict, gs_color_space **ppcs)
709
13.5k
{
710
13.5k
    gs_color_space *pcs = NULL;
711
13.5k
    gs_color_space *base_space;
712
13.5k
    pdf_obj *base_obj = NULL;
713
13.5k
    int code = 0;
714
715
    /* TODO: should set to "the initial color is a pattern object that causes nothing to be painted."
716
     * (see page 288 of PDF 1.7)
717
     * Need to make a "nullpattern" (see pdf_ops.c, /nullpattern)
718
     */
719
    /* NOTE: See zcolor.c/setpatternspace */
720
#if DEBUG_PATTERN
721
    dbgmprintf(ctx->memory, "PATTERN: pdfi_create_Pattern\n");
722
#endif
723
    //    return 0;
724
725
13.5k
    pcs = gs_cspace_alloc(ctx->memory, &gs_color_space_type_Pattern);
726
13.5k
    if (pcs == NULL) {
727
0
        return_error(gs_error_VMerror);
728
0
    }
729
13.5k
    if (color_array == NULL || pdfi_array_size(color_array) == 1) {
730
13.4k
        pcs->base_space = NULL;
731
13.4k
        pcs->params.pattern.has_base_space = false;
732
13.4k
    } else {
733
#if DEBUG_PATTERN
734
        dbgmprintf(ctx->memory, "PATTERN: with base space! pdfi_create_Pattern\n");
735
#endif
736
64
        code = pdfi_array_get(ctx, color_array, 1, &base_obj);
737
64
        if (code < 0)
738
0
            goto exit;
739
64
        code = pdfi_create_colorspace(ctx, base_obj, stream_dict, page_dict, &base_space, false);
740
64
        if (code < 0)
741
5
            goto exit;
742
59
        pcs->base_space = base_space;
743
59
        pcs->params.pattern.has_base_space = true;
744
59
    }
745
13.4k
    if (ppcs != NULL) {
746
0
        *ppcs = pcs;
747
0
        rc_increment_cs(pcs);
748
13.4k
    } else {
749
13.4k
        code = pdfi_gs_setcolorspace(ctx, pcs);
750
751
#if 0
752
        /* An attempt to init a "Null" pattern, causes crashes on cluster */
753
        {
754
        gs_client_color cc;
755
        memset(&cc, 0, sizeof(cc));
756
        code = pdfi_setpattern_null(ctx, &cc);
757
        code = gs_setcolor(ctx->pgs, &cc);
758
        }
759
#endif
760
13.4k
    }
761
762
763
13.5k
 exit:
764
    /* release reference from construction */
765
13.5k
    rc_decrement_only_cs(pcs, "create_Pattern");
766
13.5k
    pdfi_countdown(base_obj);
767
13.5k
    return code;
768
13.4k
}