Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/pdf/pdf_pattern.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-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
/* 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
28.2k
{
58
28.2k
    if (rect->p.x - rect->q.x == 0)
59
0
        rect->q.x += .00000001;
60
28.2k
    if (rect->p.y - rect->q.y == 0)
61
0
        rect->q.y += .00000001;
62
28.2k
}
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
28.3k
{
68
28.3k
    int code;
69
70
28.3k
    code = pdfi_array_to_gs_rect(ctx, array, rect);
71
28.3k
    if (code != 0)
72
18
        return code;
73
74
28.2k
    pdfi_normalize_rect(ctx, rect);
75
28.2k
    pdfi_pattern_fix_bbox(ctx, rect);
76
77
28.2k
    return code;
78
28.3k
}
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
30.6k
{
110
30.6k
    pdfi_countdown(context->page_dict);
111
30.6k
    pdfi_countdown(context->pat_obj);
112
30.6k
    if (context->shading)
113
1.99k
        pdfi_shading_free(context->ctx, context->shading);
114
30.6k
    gs_free_object(context->ctx->memory, context, "Free pattern context");
115
30.6k
}
116
117
void pdfi_pattern_cleanup(gs_memory_t * mem, void *p)
118
29.9k
{
119
29.9k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)p;
120
121
29.9k
    if (pinst->client_data != NULL) {
122
29.9k
        pdfi_free_pattern_context((pdf_pattern_context_t *)pinst->client_data);
123
29.9k
        pinst->client_data = NULL;
124
29.9k
        pinst->notify_free = NULL;
125
29.9k
    }
126
29.9k
}
127
128
/* See px_paint_pattern() */
129
static int
130
pdfi_pattern_paint_stream(pdf_context *ctx, const gs_client_color *pcc)
131
26.9k
{
132
26.9k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
133
26.9k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
134
26.9k
    pdf_dict *page_dict = context->page_dict;
135
26.9k
    pdf_stream *pat_stream = (pdf_stream *)context->pat_obj;
136
26.9k
    int code = 0;
137
26.9k
    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
26.9k
    SavedBlockDepth = ctx->text.BlockDepth;
145
26.9k
    ctx->text.BlockDepth = 0;
146
147
    /* Interpret inner stream */
148
26.9k
    code = pdfi_run_context(ctx, pat_stream, page_dict, true, "PATTERN");
149
150
26.9k
    ctx->text.BlockDepth = SavedBlockDepth;
151
152
26.9k
    return code;
153
26.9k
}
154
155
/* See px_paint_pattern() */
156
static int
157
pdfi_pattern_paint(const gs_client_color *pcc, gs_gstate *pgs)
158
23.2k
{
159
23.2k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
160
23.2k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
161
23.2k
    pdf_context *ctx = context->ctx;
162
23.2k
    int code = 0;
163
164
#if DEBUG_PATTERN
165
    dbgmprintf(ctx->memory, "BEGIN PATTERN PaintProc\n");
166
#endif
167
23.2k
    code = pdfi_gsave(ctx); /* TODO: This might be redundant? */
168
23.2k
    if (code < 0)
169
0
        return code;
170
23.2k
    code = pdfi_gs_setgstate(ctx->pgs, pgs);
171
23.2k
    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
23.2k
    if (pinst->templat.uses_transparency) {
182
16.5k
        dbgmprintf(ctx->memory, "pdfi_pattern_paint forcing trans_flags.xtate_change = TRUE\n");
183
16.5k
        ctx->pgs->trans_flags.xstate_change = true;
184
16.5k
    }
185
23.2k
    code = pdfi_op_q(ctx);
186
23.2k
    if (code < 0)
187
0
        goto exit;
188
189
23.2k
    code = pdfi_pattern_paint_stream(ctx, pcc);
190
23.2k
    pdfi_op_Q(ctx);
191
23.2k
    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
23.2k
 exit:
197
23.2k
    pdfi_grestore(ctx);
198
#if DEBUG_PATTERN
199
    dbgmprintf(ctx->memory, "END PATTERN PaintProc\n");
200
#endif
201
23.2k
    return code;
202
23.2k
}
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
3.69k
{
208
3.69k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
209
3.69k
    const gs_pattern1_template_t *templat = &pinst->templat;
210
3.69k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
211
3.69k
    pdf_context *ctx = context->ctx;
212
3.69k
    gs_gstate *pgs = ctx->pgs;
213
3.69k
    gs_matrix m;
214
3.69k
    gs_rect bbox;
215
3.69k
    gs_fixed_rect clip_box;
216
3.69k
    int code;
217
3.69k
    gx_device_color *pdc = gs_currentdevicecolor_inline(pgs);
218
3.69k
    pattern_accum_param_s param;
219
220
3.69k
    code = pdfi_gsave(ctx);
221
3.69k
    if (code < 0)
222
0
        return code;
223
3.69k
    code = pdfi_gs_setgstate(ctx->pgs, pinst->saved);
224
3.69k
    if (code < 0)
225
0
        goto errorExit;
226
227
3.69k
    dev_proc(pgs->device, get_initial_matrix)(pgs->device, &m);
228
3.69k
    gs_setmatrix(pgs, &m);
229
3.69k
    code = gs_bbox_transform(&templat->BBox, &ctm_only(pgs), &bbox);
230
3.69k
    if (code < 0)
231
0
        goto errorExit;
232
3.69k
    clip_box.p.x = float2fixed(bbox.p.x);
233
3.69k
    clip_box.p.y = float2fixed(bbox.p.y);
234
3.69k
    clip_box.q.x = float2fixed(bbox.q.x);
235
3.69k
    clip_box.q.y = float2fixed(bbox.q.y);
236
3.69k
    code = gx_clip_to_rectangle(pgs, &clip_box);
237
3.69k
    if (code < 0)
238
0
        goto errorExit;
239
240
3.69k
    param.pinst = (void *)pinst;
241
3.69k
    param.interpreter_memory = ctx->memory;
242
3.69k
    param.graphics_state = (void *)pgs;
243
3.69k
    param.pinst_id = pinst->id;
244
245
3.69k
    code = (*dev_proc(pgs->device, dev_spec_op))
246
3.69k
        ((gx_device *)pgs->device, gxdso_pattern_start_accum, &param, sizeof(pattern_accum_param_s));
247
248
3.69k
    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
3.69k
    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
3.69k
    if (code < 0)
259
0
        goto errorExit;
260
261
3.69k
    code = dev_proc(pgs->device, dev_spec_op)
262
3.69k
        (pgs->device, gxdso_pattern_finish_accum, &param, sizeof(pattern_accum_param_s));
263
3.69k
    if (code < 0)
264
0
        goto errorExit;
265
266
3.69k
    code = pdfi_grestore(ctx);
267
3.69k
    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
3.69k
    code = gx_pattern_cache_add_dummy_entry(pgs, pinst, pgs->device->color_info.depth);
277
3.69k
    if (code < 0)
278
0
        return code;
279
280
3.69k
    return gs_error_handled;
281
282
0
 errorExit:
283
0
    pdfi_grestore(ctx);
284
0
    return code;
285
3.69k
}
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
26.9k
{
291
26.9k
    const gs_client_pattern *pinst = gs_getpattern(pcc);
292
26.9k
    int code = 0;
293
26.9k
    pdf_context *ctx = ((pdf_pattern_context_t *)((gs_pattern1_instance_t *)pcc->pattern)->client_data)->ctx;
294
26.9k
    text_state_t ts;
295
296
    /* We want to start running the pattern PaintProc with a "clean slate"
297
       so store, clear......."
298
     */
299
26.9k
    memcpy(&ts, &ctx->text, sizeof(ctx->text));
300
26.9k
    memset(&ctx->text, 0x00, sizeof(ctx->text));
301
302
    /* pgs->device is the newly created pattern accumulator, but we want to test the device
303
     * that is 'behind' that, the actual output device, so we use the one from
304
     * the saved graphics state.
305
     */
306
26.9k
    if (pgs->have_pattern_streams) {
307
26.9k
        code = dev_proc(pcc->pattern->saved->device, dev_spec_op)(pcc->pattern->saved->device,
308
26.9k
                                gxdso_pattern_can_accum, (void *)pinst, pinst->uid.id);
309
26.9k
    }
310
311
26.9k
    if (code == 1) {
312
3.69k
        code = pdfi_pattern_paint_high_level(pcc, pgs);
313
23.2k
    } else {
314
23.2k
        code =  pdfi_pattern_paint(pcc, pgs);
315
23.2k
    }
316
317
    /* .... and restore the text state in the context */
318
26.9k
    memcpy(&ctx->text, &ts, sizeof(ctx->text));
319
26.9k
    return code;
320
26.9k
}
321
322
323
324
/* Setup the correct gstate for a pattern */
325
static int
326
pdfi_pattern_gset(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *ExtGState)
327
30.6k
{
328
30.6k
    int code;
329
30.6k
    float strokealpha, fillalpha;
330
331
30.6k
    strokealpha = gs_getstrokeconstantalpha(ctx->pgs);
332
30.6k
    fillalpha = gs_getfillconstantalpha(ctx->pgs);
333
334
    /* This will preserve the ->level and a couple other things */
335
#if DEBUG_PATTERN
336
    dbgmprintf2(ctx->memory, "PATTERN: setting DefaultQState, old device=%s, new device=%s\n",
337
                ctx->pgs->device->dname, ctx->DefaultQState->device->dname);
338
#endif
339
30.6k
    code = pdfi_gs_setgstate(ctx->pgs, pdfi_get_DefaultQState(ctx));
340
30.6k
    if (code < 0) goto exit;
341
30.6k
    code = gs_setstrokeconstantalpha(ctx->pgs, strokealpha);
342
30.6k
    if (code < 0) goto exit;
343
30.6k
    code = gs_setfillconstantalpha(ctx->pgs, fillalpha);
344
30.6k
    if (code < 0) goto exit;
345
346
    /* Set ExtGState if one is provided */
347
30.6k
    if (ExtGState)
348
0
        code = pdfi_set_ExtGState(ctx, NULL, page_dict, ExtGState);
349
30.6k
 exit:
350
30.6k
    return code;
351
30.6k
}
352
353
/* Setup the pattern gstate and other context */
354
static int
355
pdfi_pattern_setup(pdf_context *ctx, pdf_pattern_context_t **ppcontext,
356
                   pdf_dict *page_dict, pdf_obj *pat_obj, pdf_dict *ExtGState)
357
30.6k
{
358
30.6k
    int code = 0;
359
30.6k
    pdf_pattern_context_t *context = NULL;
360
361
30.6k
    code = pdfi_pattern_gset(ctx, page_dict, ExtGState);
362
30.6k
    if (code < 0)
363
0
        goto errorExit;
364
365
30.6k
    context = (pdf_pattern_context_t *) gs_alloc_bytes(ctx->memory, sizeof(*context),
366
30.6k
                                                       "pdfi_pattern_setup(context)");
367
30.6k
    if (!context) {
368
0
        code = gs_note_error(gs_error_VMerror);
369
0
        goto errorExit;
370
0
    }
371
30.6k
    context->ctx = ctx;
372
30.6k
    context->page_dict = page_dict;
373
30.6k
    context->pat_obj = pat_obj;
374
30.6k
    context->shading = NULL;
375
30.6k
    pdfi_countup(page_dict);
376
30.6k
    pdfi_countup(pat_obj);
377
30.6k
    *ppcontext = context;
378
379
30.6k
    return 0;
380
0
 errorExit:
381
0
    gs_free_object(ctx->memory, context, "pdfi_pattern_setup(context)");
382
0
    return code;
383
30.6k
}
384
385
386
/* Type 1 (tiled) Pattern */
387
static int
388
pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
389
                      pdf_obj *stream, gs_client_color *cc)
390
28.5k
{
391
28.5k
    int code = 0;
392
28.5k
    gs_client_pattern templat;
393
28.5k
    gs_matrix mat;
394
28.5k
    gs_rect rect;
395
28.5k
    int64_t PaintType, TilingType;
396
28.5k
    pdf_array *BBox = NULL;
397
28.5k
    double XStep, YStep;
398
28.5k
    pdf_dict *Resources = NULL, *pdict = NULL;
399
28.5k
    pdf_array *Matrix = NULL;
400
28.5k
    bool transparency = false, BM_Not_Normal = false;
401
28.5k
    pdf_pattern_context_t *context = NULL;
402
403
#if DEBUG_PATTERN
404
    dbgmprintf(ctx->memory, "PATTERN: Type 1 pattern\n");
405
#endif
406
407
28.5k
    gs_pattern1_init(&templat);
408
409
    /* Must be a stream */
410
28.5k
    if (pdfi_type_of(stream) != PDF_STREAM) {
411
36
        code = gs_note_error(gs_error_typecheck);
412
36
        goto exit;
413
36
    }
414
28.5k
    code = pdfi_dict_from_obj(ctx, stream, &pdict);
415
28.5k
    if (code < 0)
416
0
        return code;
417
418
    /* Required */
419
28.5k
    code = pdfi_dict_get_int(ctx, pdict, "PaintType", &PaintType);
420
28.5k
    if (code < 0)
421
84
        goto exit;
422
28.4k
    code = pdfi_dict_get_int(ctx, pdict, "TilingType", &TilingType);
423
28.4k
    if (code < 0)
424
64
        goto exit;
425
28.3k
    code = pdfi_dict_get_type(ctx, pdict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
426
28.3k
    if (code < 0)
427
39
        goto exit;
428
28.3k
    code = pdfi_pattern_get_rect(ctx, BBox, &rect);
429
28.3k
    if (code < 0)
430
18
        goto exit;
431
28.2k
    code = pdfi_dict_get_number(ctx, pdict, "XStep", &XStep);
432
28.2k
    if (code < 0)
433
68
        goto exit;
434
28.2k
    code = pdfi_dict_get_number(ctx, pdict, "YStep", &YStep);
435
28.2k
    if (code < 0)
436
55
        goto exit;
437
438
    /* XStep and YStep must be non-zero; table 425; page 293 of the 1.7 Reference */
439
28.1k
    if (XStep == 0.0 || YStep == 0.0) {
440
4
        code = gs_note_error(gs_error_rangecheck);
441
4
        goto exit;
442
4
    }
443
444
    /* The pattern instance holds the pattern step as floats, make sure they
445
     * will fit.
446
     */
447
28.1k
    if (XStep < -MAX_FLOAT || XStep > MAX_FLOAT || YStep < -MAX_FLOAT || YStep > MAX_FLOAT) {
448
0
        code = gs_note_error(gs_error_rangecheck);
449
0
        goto exit;
450
0
    }
451
452
    /* The spec says Resources are required, but in fact this doesn't seem to be true.
453
     * (tests_private/pdf/sumatra/infinite_pattern_recursion.pdf)
454
     */
455
28.1k
    code = pdfi_dict_get_type(ctx, pdict, "Resources", PDF_DICT, (pdf_obj **)&Resources);
456
28.1k
    if (code < 0) {
457
814
        if (code == gs_error_undefined && !ctx->args.pdfstoponwarning) {
458
#if DEBUG_PATTERN
459
        dbgmprintf(ctx->memory, "PATTERN: Missing Resources in Pattern dict\n");
460
#endif
461
714
            pdfi_set_warning(ctx, code, NULL, W_PDF_BADPATTERN, "pdfi_setpattern_type1", "Pattern has no Resources dictionary");
462
714
            code = 0;
463
714
        } else
464
100
            goto exit;
465
814
    }
466
467
    /* (optional Matrix) */
468
28.0k
    code = pdfi_dict_knownget_type(ctx, pdict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
469
28.0k
    if (code < 0)
470
0
        goto exit;
471
28.0k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &mat);
472
28.0k
    if (code < 0)
473
76
        goto exit;
474
475
27.9k
    if (PaintType != 1 && PaintType != 2) {
476
6
        code = gs_note_error(gs_error_rangecheck);
477
6
        goto exit;
478
6
    }
479
27.9k
    if (TilingType != 1 && TilingType != 2 && TilingType != 3) {
480
2
        code = gs_note_error(gs_error_rangecheck);
481
2
        goto exit;
482
2
    }
483
484
    /* See if pattern uses transparency, or if we are in an overprint
485
       simulation situation */
486
27.9k
    if (ctx->page.has_transparency) {
487
20.3k
        code = pdfi_check_Pattern_transparency(ctx, pdict, page_dict, &transparency, &BM_Not_Normal);
488
20.3k
        if (code < 0)
489
0
            goto exit;
490
20.3k
    }
491
27.9k
    if (ctx->page.simulate_op) {
492
0
        transparency = true;
493
0
    }
494
495
    /* TODO: Resources?  Maybe I should check that they are all valid before proceeding, or something? */
496
497
27.9k
    templat.BBox = rect;
498
    /* (see zPaintProc or px_remap_pattern) */
499
27.9k
    templat.PaintProc = pdfi_pattern_paintproc;
500
27.9k
    templat.PaintType = PaintType;
501
27.9k
    templat.TilingType = TilingType;
502
27.9k
    templat.XStep = XStep;
503
27.9k
    templat.YStep = YStep;
504
27.9k
    templat.uses_transparency = transparency;
505
27.9k
    templat.BM_Not_Normal = BM_Not_Normal;
506
    /* templat.uses_transparency = false; /* disable */
507
508
27.9k
    code = pdfi_gsave(ctx);
509
27.9k
    if (code < 0)
510
0
        goto exit;
511
512
27.9k
    code = pdfi_pattern_setup(ctx, &context, page_dict, stream, NULL);
513
27.9k
    if (code < 0) {
514
0
        (void) pdfi_grestore(ctx);
515
0
        goto exit;
516
0
    }
517
518
    /* We need to use the graphics state memory, in case we are running under Ghostscript. */
519
27.9k
    code = gs_make_pattern(cc, (const gs_pattern_template_t *)&templat, &mat, ctx->pgs, ctx->pgs->memory);
520
27.9k
    if (code < 0) {
521
0
        (void) pdfi_grestore(ctx);
522
0
        goto exit;
523
0
    }
524
525
27.9k
    cc->pattern->client_data = context;
526
27.9k
    cc->pattern->notify_free = pdfi_pattern_cleanup;
527
27.9k
    {
528
27.9k
        unsigned long hash = 5381;
529
27.9k
        unsigned int i;
530
27.9k
        const byte *str;
531
532
27.9k
        gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)cc->pattern;
533
534
535
27.9k
        str = (const byte *)&ctx->pgs->ctm.xx;
536
139k
        for (i = 0; i < sizeof(ctx->pgs->ctm.xx); i++) {
537
#if ARCH_IS_BIG_ENDIAN
538
            hash = ((hash << 5) + hash) + str[sizeof(ctx->pgs->ctm.xx) - 1 - i]; /* hash * 33 + c */
539
#else
540
111k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
541
111k
#endif
542
111k
        }
543
27.9k
        str = (const byte *)&ctx->pgs->ctm.xy;
544
139k
        for (i = 0; i < sizeof(ctx->pgs->ctm.xy); i++) {
545
#if ARCH_IS_BIG_ENDIAN
546
            hash = ((hash << 5) + hash) + str[sizeof(ctx->pgs->ctm.xy) - 1 - i]; /* hash * 33 + c */
547
#else
548
111k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
549
111k
#endif
550
111k
        }
551
27.9k
        str = (const byte *)&ctx->pgs->ctm.yx;
552
139k
        for (i = 0; i < sizeof(ctx->pgs->ctm.yx); i++) {
553
#if ARCH_IS_BIG_ENDIAN
554
            hash = ((hash << 5) + hash) + str[sizeof(ctx->pgs->ctm.yx) - 1 - i]; /* hash * 33 + c */
555
#else
556
111k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
557
111k
#endif
558
111k
        }
559
27.9k
        str = (const byte *)&ctx->pgs->ctm.yy;
560
139k
        for (i = 0; i < sizeof(ctx->pgs->ctm.yy); i++) {
561
#if ARCH_IS_BIG_ENDIAN
562
            hash = ((hash << 5) + hash) + str[sizeof(ctx->pgs->ctm.yy) - 1 - i]; /* hash * 33 + c */
563
#else
564
111k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
565
111k
#endif
566
111k
        }
567
568
27.9k
        str = (const byte *)&pdict->object_num;
569
139k
        for (i = 0; i < sizeof(pdict->object_num); i++) {
570
#if ARCH_IS_BIG_ENDIAN
571
            hash = ((hash << 5) + hash) + str[sizeof(pdict->object_num) - 1 - i]; /* hash * 33 + c */
572
#else
573
111k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
574
111k
#endif
575
111k
        }
576
577
27.9k
        hash = ((hash << 5) + hash) + ctx->pgs->device->color_info.num_components; /* hash * 33 + c */
578
579
        /* Include num_components for case where we have softmask and non-softmask
580
           fills with the same tile. We may need two tiles for this if there is a
581
           change in color space for the transparency group. */
582
27.9k
        pinst->id = hash;
583
27.9k
    }
584
27.9k
    context = NULL;
585
586
27.9k
    code = pdfi_grestore(ctx);
587
27.9k
    if (code < 0)
588
0
        goto exit;
589
28.5k
 exit:
590
28.5k
    gs_free_object(ctx->memory, context, "pdfi_setpattern_type1(context)");
591
28.5k
    pdfi_countdown(Resources);
592
28.5k
    pdfi_countdown(Matrix);
593
28.5k
    pdfi_countdown(BBox);
594
28.5k
    return code;
595
27.9k
}
596
597
/* Type 2 (shading) Pattern */
598
static int
599
pdfi_setpattern_type2(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
600
                      pdf_obj *pattern_obj, gs_client_color *cc)
601
3.53k
{
602
3.53k
    int code = 0;
603
3.53k
    pdf_obj *Shading = NULL;
604
3.53k
    pdf_dict *ExtGState = NULL, *pattern_dict = NULL;
605
3.53k
    pdf_array *Matrix = NULL;
606
3.53k
    gs_matrix mat;
607
3.53k
    gs_shading_t *shading;
608
3.53k
    gs_pattern2_template_t templat;
609
3.53k
    pdf_pattern_context_t *context = NULL;
610
611
    /* See zbuildshadingpattern() */
612
613
3.53k
    code = pdfi_dict_from_obj(ctx, pattern_obj, &pattern_dict);
614
3.53k
    if (code < 0)
615
0
        return code;
616
617
#if DEBUG_PATTERN
618
    dbgmprintf(ctx->memory, "PATTERN: Type 2 pattern\n");
619
#endif
620
621
    /* (optional Matrix) */
622
3.53k
    code = pdfi_dict_knownget_type(ctx, pattern_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
623
3.53k
    if (code < 0)
624
0
        goto exit;
625
3.53k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &mat);
626
3.53k
    if (code < 0)
627
15
        goto exit;
628
629
    /* Required Shading, can be stream or dict (but a stream is also a dict..) */
630
3.52k
    code = pdfi_dict_knownget(ctx, pattern_dict, "Shading", &Shading);
631
3.52k
    if (code < 0)
632
893
        goto exit;
633
2.62k
    if (code == 0) {
634
8
        dbgmprintf(ctx->memory, "ERROR: Shading not found in Pattern Type 2\n");
635
8
        code = gs_note_error(gs_error_syntaxerror);
636
8
        goto exit;
637
8
    }
638
639
    /* Optional ExtGState */
640
2.62k
    code = pdfi_dict_knownget_type(ctx, pattern_dict, "ExtGState", PDF_DICT, (pdf_obj **)&ExtGState);
641
2.62k
    if (code < 0)
642
0
        goto exit;
643
644
2.62k
    code = pdfi_gsave(ctx);
645
2.62k
    if (code < 0)
646
0
        goto exit;
647
648
2.62k
    gs_pattern2_init(&templat);
649
650
2.62k
    code = pdfi_pattern_setup(ctx, &context, NULL, NULL, ExtGState);
651
2.62k
    if (code < 0) {
652
0
        (void) pdfi_grestore(ctx);
653
0
        goto exit;
654
0
    }
655
656
2.62k
    code = pdfi_shading_build(ctx, stream_dict, page_dict, Shading, &shading);
657
2.62k
    if (code != 0) {
658
631
        (void) pdfi_grestore(ctx);
659
631
        dbgmprintf(ctx->memory, "ERROR: can't build shading structure\n");
660
631
        goto exit;
661
631
    }
662
663
1.99k
    context->shading = shading;
664
665
1.99k
    templat.Shading = shading;
666
1.99k
    code = gs_make_pattern(cc, (const gs_pattern_template_t *)&templat, &mat, ctx->pgs, ctx->memory);
667
1.99k
    if (code < 0) {
668
0
        (void) pdfi_grestore(ctx);
669
0
        goto exit;
670
0
    }
671
1.99k
    cc->pattern->client_data = context;
672
1.99k
    cc->pattern->notify_free = pdfi_pattern_cleanup;
673
1.99k
    context = NULL;
674
675
1.99k
    code = pdfi_grestore(ctx);
676
1.99k
    if (code < 0)
677
0
        goto exit;
678
679
3.53k
 exit:
680
3.53k
    if (context != NULL)
681
631
        pdfi_free_pattern_context(context);
682
3.53k
    pdfi_countdown(Shading);
683
3.53k
    pdfi_countdown(Matrix);
684
3.53k
    pdfi_countdown(ExtGState);
685
3.53k
    return code;
686
1.99k
}
687
688
int
689
pdfi_pattern_set(pdf_context *ctx, pdf_dict *stream_dict,
690
                pdf_dict *page_dict, pdf_name *pname,
691
                gs_client_color *cc)
692
64.0k
{
693
64.0k
    pdf_dict *pattern_dict = NULL;
694
64.0k
    pdf_obj *pattern_obj = NULL;
695
64.0k
    int code;
696
64.0k
    int64_t patternType;
697
698
64.0k
    code = pdfi_loop_detector_mark(ctx);
699
64.0k
    if (code < 0)
700
0
        return code;
701
702
64.0k
    memset(cc, 0, sizeof(*cc));
703
64.0k
    code = pdfi_find_resource(ctx, (unsigned char *)"Pattern", pname, (pdf_dict *)stream_dict,
704
64.0k
                              page_dict, (pdf_obj **)&pattern_obj);
705
64.0k
    if (code < 0) {
706
31.5k
        dbgmprintf(ctx->memory, "WARNING: Pattern object not found in resources\n");
707
31.5k
        goto exit;
708
31.5k
    }
709
710
32.4k
    code = pdfi_dict_from_obj(ctx, pattern_obj, &pattern_dict);
711
32.4k
    if (code < 0) {
712
        /* NOTE: Bug696410.pdf gets a bogus pattern while trying to process pattern.
713
         * Seems like a corrupted file, but this prevents crash
714
         */
715
100
        dbgmprintf(ctx->memory, "ERROR: Pattern found in resources is neither a stream or dict\n");
716
100
        goto exit;
717
100
    }
718
719
#if DEBUG_PATTERN
720
    dbgmprintf1(ctx->memory, "PATTERN: pdfi_setpattern: found pattern object %d\n", pdict->object_num);
721
#endif
722
723
32.3k
    code = pdfi_dict_get_int(ctx, pattern_dict, "PatternType", &patternType);
724
32.3k
    if (code < 0)
725
286
        goto exit;
726
32.1k
    if (patternType == 1) {
727
28.5k
        code = pdfi_setpattern_type1(ctx, stream_dict, page_dict, (pdf_obj *)pattern_obj, cc);
728
28.5k
        if (code < 0)
729
552
            goto exit;
730
28.5k
    } else if (patternType == 2) {
731
3.53k
        code = pdfi_setpattern_type2(ctx, stream_dict, page_dict, pattern_obj, cc);
732
3.53k
        if (code < 0)
733
1.54k
            goto exit;
734
3.53k
    } else {
735
32
        code = gs_note_error(gs_error_syntaxerror);
736
32
        goto exit;
737
32
    }
738
739
64.0k
 exit:
740
64.0k
    pdfi_countdown(pattern_obj);
741
64.0k
    if (code < 0)
742
34.0k
        (void)pdfi_loop_detector_cleartomark(ctx);
743
29.9k
    else
744
29.9k
        code = pdfi_loop_detector_cleartomark(ctx);
745
64.0k
    return code;
746
32.1k
}
747
748
/* Create a Pattern colorspace.
749
 * If ppcs is NULL, then we will set the colorspace
750
 * If ppcs not NULL, point the new colorspace to it
751
 *
752
 * If color_array is NULL, then this is a simple "Pattern" colorspace, e.g. "/Pattern cs".
753
 * If it is an array, then first element is "Pattern" and second element should be the base colorspace.
754
 * e.g. "/CS1 cs" where /CS1 is a ColorSpace Resource containing "[/Pattern /DeviceRGB]"
755
 *
756
 */
757
int
758
pdfi_pattern_create(pdf_context *ctx, pdf_array *color_array, pdf_dict *stream_dict,
759
                    pdf_dict *page_dict, gs_color_space **ppcs)
760
59.3k
{
761
59.3k
    gs_color_space *pcs = NULL;
762
59.3k
    gs_color_space *base_space;
763
59.3k
    pdf_obj *base_obj = NULL;
764
59.3k
    int code = 0;
765
766
    /* TODO: should set to "the initial color is a pattern object that causes nothing to be painted."
767
     * (see page 288 of PDF 1.7)
768
     * Need to make a "nullpattern" (see pdf_ops.c, /nullpattern)
769
     */
770
    /* NOTE: See zcolor.c/setpatternspace */
771
#if DEBUG_PATTERN
772
    dbgmprintf(ctx->memory, "PATTERN: pdfi_create_Pattern\n");
773
#endif
774
    /*    return 0; */
775
776
59.3k
    pcs = gs_cspace_alloc(ctx->memory, &gs_color_space_type_Pattern);
777
59.3k
    if (pcs == NULL) {
778
0
        return_error(gs_error_VMerror);
779
0
    }
780
59.3k
    if (color_array == NULL || pdfi_array_size(color_array) == 1) {
781
59.0k
        pcs->base_space = NULL;
782
59.0k
        pcs->params.pattern.has_base_space = false;
783
59.0k
    } else {
784
#if DEBUG_PATTERN
785
        dbgmprintf(ctx->memory, "PATTERN: with base space! pdfi_create_Pattern\n");
786
#endif
787
315
        code = pdfi_array_get(ctx, color_array, 1, &base_obj);
788
315
        if (code < 0)
789
0
            goto exit;
790
315
        code = pdfi_create_colorspace(ctx, base_obj, stream_dict, page_dict, &base_space, false);
791
315
        if (code < 0)
792
14
            goto exit;
793
301
        pcs->base_space = base_space;
794
301
        pcs->params.pattern.has_base_space = true;
795
301
    }
796
59.3k
    if (ppcs != NULL) {
797
5
        *ppcs = pcs;
798
5
        rc_increment_cs(pcs);
799
59.3k
    } else {
800
59.3k
        code = pdfi_gs_setcolorspace(ctx, pcs);
801
802
#if 0
803
        /* An attempt to init a "Null" pattern, causes crashes on cluster */
804
        {
805
        gs_client_color cc;
806
        memset(&cc, 0, sizeof(cc));
807
        code = pdfi_setpattern_null(ctx, &cc);
808
        code = gs_setcolor(ctx->pgs, &cc);
809
        }
810
#endif
811
59.3k
    }
812
813
814
59.3k
 exit:
815
    /* release reference from construction */
816
59.3k
    rc_decrement_only_cs(pcs, "create_Pattern");
817
59.3k
    pdfi_countdown(base_obj);
818
59.3k
    return code;
819
59.3k
}