Coverage Report

Created: 2026-02-14 07:09

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