Coverage Report

Created: 2025-06-10 07:27

/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
29.5k
{
58
29.5k
    if (rect->p.x - rect->q.x == 0)
59
0
        rect->q.x += .00000001;
60
29.5k
    if (rect->p.y - rect->q.y == 0)
61
0
        rect->q.y += .00000001;
62
29.5k
}
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
29.5k
{
68
29.5k
    int code;
69
70
29.5k
    code = pdfi_array_to_gs_rect(ctx, array, rect);
71
29.5k
    if (code != 0)
72
14
        return code;
73
74
29.5k
    pdfi_normalize_rect(ctx, rect);
75
29.5k
    pdfi_pattern_fix_bbox(ctx, rect);
76
77
29.5k
    return code;
78
29.5k
}
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
31.7k
{
110
31.7k
    pdfi_countdown(context->page_dict);
111
31.7k
    pdfi_countdown(context->pat_obj);
112
31.7k
    if (context->shading)
113
1.85k
        pdfi_shading_free(context->ctx, context->shading);
114
31.7k
    gs_free_object(context->ctx->memory, context, "Free pattern context");
115
31.7k
}
116
117
void pdfi_pattern_cleanup(gs_memory_t * mem, void *p)
118
31.1k
{
119
31.1k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)p;
120
121
31.1k
    if (pinst->client_data != NULL) {
122
31.1k
        pdfi_free_pattern_context((pdf_pattern_context_t *)pinst->client_data);
123
31.1k
        pinst->client_data = NULL;
124
31.1k
        pinst->notify_free = NULL;
125
31.1k
    }
126
31.1k
}
127
128
/* See px_paint_pattern() */
129
static int
130
pdfi_pattern_paint_stream(pdf_context *ctx, const gs_client_color *pcc)
131
28.1k
{
132
28.1k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
133
28.1k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
134
28.1k
    pdf_dict *page_dict = context->page_dict;
135
28.1k
    pdf_stream *pat_stream = (pdf_stream *)context->pat_obj;
136
28.1k
    int code = 0;
137
28.1k
    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
28.1k
    SavedBlockDepth = ctx->text.BlockDepth;
145
28.1k
    ctx->text.BlockDepth = 0;
146
147
    /* Interpret inner stream */
148
28.1k
    code = pdfi_run_context(ctx, pat_stream, page_dict, true, "PATTERN");
149
150
28.1k
    ctx->text.BlockDepth = SavedBlockDepth;
151
152
28.1k
    return code;
153
28.1k
}
154
155
/* See px_paint_pattern() */
156
static int
157
pdfi_pattern_paint(const gs_client_color *pcc, gs_gstate *pgs)
158
22.1k
{
159
22.1k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
160
22.1k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
161
22.1k
    pdf_context *ctx = context->ctx;
162
22.1k
    int code = 0;
163
164
#if DEBUG_PATTERN
165
    dbgmprintf(ctx->memory, "BEGIN PATTERN PaintProc\n");
166
#endif
167
22.1k
    code = pdfi_gsave(ctx); /* TODO: This might be redundant? */
168
22.1k
    if (code < 0)
169
0
        return code;
170
22.1k
    code = pdfi_gs_setgstate(ctx->pgs, pgs);
171
22.1k
    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
22.1k
    if (pinst->templat.uses_transparency) {
182
15.8k
        dbgmprintf(ctx->memory, "pdfi_pattern_paint forcing trans_flags.xtate_change = TRUE\n");
183
15.8k
        ctx->pgs->trans_flags.xstate_change = true;
184
15.8k
    }
185
22.1k
    code = pdfi_op_q(ctx);
186
22.1k
    if (code < 0)
187
0
        goto exit;
188
189
22.1k
    code = pdfi_pattern_paint_stream(ctx, pcc);
190
22.1k
    pdfi_op_Q(ctx);
191
22.1k
    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
22.1k
 exit:
197
22.1k
    pdfi_grestore(ctx);
198
#if DEBUG_PATTERN
199
    dbgmprintf(ctx->memory, "END PATTERN PaintProc\n");
200
#endif
201
22.1k
    return code;
202
22.1k
}
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
5.98k
{
208
5.98k
    gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)pcc->pattern;
209
5.98k
    const gs_pattern1_template_t *templat = &pinst->templat;
210
5.98k
    pdf_pattern_context_t *context = (pdf_pattern_context_t *)pinst->client_data;
211
5.98k
    pdf_context *ctx = context->ctx;
212
5.98k
    gs_gstate *pgs = ctx->pgs;
213
5.98k
    gs_matrix m;
214
5.98k
    gs_rect bbox;
215
5.98k
    gs_fixed_rect clip_box;
216
5.98k
    int code;
217
5.98k
    gx_device_color *pdc = gs_currentdevicecolor_inline(pgs);
218
5.98k
    pattern_accum_param_s param;
219
220
5.98k
    code = pdfi_gsave(ctx);
221
5.98k
    if (code < 0)
222
0
        return code;
223
5.98k
    code = pdfi_gs_setgstate(ctx->pgs, pinst->saved);
224
5.98k
    if (code < 0)
225
0
        goto errorExit;
226
227
5.98k
    dev_proc(pgs->device, get_initial_matrix)(pgs->device, &m);
228
5.98k
    gs_setmatrix(pgs, &m);
229
5.98k
    code = gs_bbox_transform(&templat->BBox, &ctm_only(pgs), &bbox);
230
5.98k
    if (code < 0)
231
0
        goto errorExit;
232
5.98k
    clip_box.p.x = float2fixed(bbox.p.x);
233
5.98k
    clip_box.p.y = float2fixed(bbox.p.y);
234
5.98k
    clip_box.q.x = float2fixed(bbox.q.x);
235
5.98k
    clip_box.q.y = float2fixed(bbox.q.y);
236
5.98k
    code = gx_clip_to_rectangle(pgs, &clip_box);
237
5.98k
    if (code < 0)
238
0
        goto errorExit;
239
240
5.98k
    param.pinst = (void *)pinst;
241
5.98k
    param.interpreter_memory = ctx->memory;
242
5.98k
    param.graphics_state = (void *)pgs;
243
5.98k
    param.pinst_id = pinst->id;
244
245
5.98k
    code = (*dev_proc(pgs->device, dev_spec_op))
246
5.98k
        ((gx_device *)pgs->device, gxdso_pattern_start_accum, &param, sizeof(pattern_accum_param_s));
247
248
5.98k
    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
5.98k
    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
5.98k
    if (code < 0)
259
2
        goto errorExit;
260
261
5.98k
    code = dev_proc(pgs->device, dev_spec_op)
262
5.98k
        (pgs->device, gxdso_pattern_finish_accum, &param, sizeof(pattern_accum_param_s));
263
5.98k
    if (code < 0)
264
0
        goto errorExit;
265
266
5.98k
    code = pdfi_grestore(ctx);
267
5.98k
    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
5.98k
    code = gx_pattern_cache_add_dummy_entry(pgs, pinst, pgs->device->color_info.depth);
277
5.98k
    if (code < 0)
278
0
        return code;
279
280
5.98k
    return gs_error_handled;
281
282
2
 errorExit:
283
2
    pdfi_grestore(ctx);
284
2
    return code;
285
5.98k
}
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
28.1k
{
291
28.1k
    const gs_client_pattern *pinst = gs_getpattern(pcc);
292
28.1k
    int code = 0;
293
28.1k
    pdf_context *ctx = ((pdf_pattern_context_t *)((gs_pattern1_instance_t *)pcc->pattern)->client_data)->ctx;
294
28.1k
    text_state_t ts;
295
296
    /* We want to start running the pattern PaintProc with a "clean slate"
297
       so store, clear......."
298
     */
299
28.1k
    memcpy(&ts, &ctx->text, sizeof(ctx->text));
300
28.1k
    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
28.1k
    if (pgs->have_pattern_streams) {
307
28.1k
        code = dev_proc(pcc->pattern->saved->device, dev_spec_op)(pcc->pattern->saved->device,
308
28.1k
                                gxdso_pattern_can_accum, (void *)pinst, pinst->uid.id);
309
28.1k
    }
310
311
28.1k
    if (code == 1) {
312
5.98k
        code = pdfi_pattern_paint_high_level(pcc, pgs);
313
22.1k
    } else {
314
22.1k
        code =  pdfi_pattern_paint(pcc, pgs);
315
22.1k
    }
316
317
    /* .... and restore the text state in the context */
318
28.1k
    memcpy(&ctx->text, &ts, sizeof(ctx->text));
319
28.1k
    return code;
320
28.1k
}
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
31.7k
{
328
31.7k
    int code;
329
31.7k
    float strokealpha, fillalpha;
330
331
31.7k
    strokealpha = gs_getstrokeconstantalpha(ctx->pgs);
332
31.7k
    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
31.7k
    code = pdfi_gs_setgstate(ctx->pgs, pdfi_get_DefaultQState(ctx));
340
31.7k
    if (code < 0) goto exit;
341
31.7k
    code = gs_setstrokeconstantalpha(ctx->pgs, strokealpha);
342
31.7k
    if (code < 0) goto exit;
343
31.7k
    code = gs_setfillconstantalpha(ctx->pgs, fillalpha);
344
31.7k
    if (code < 0) goto exit;
345
346
    /* Set ExtGState if one is provided */
347
31.7k
    if (ExtGState)
348
0
        code = pdfi_set_ExtGState(ctx, NULL, page_dict, ExtGState);
349
31.7k
 exit:
350
31.7k
    return code;
351
31.7k
}
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
31.7k
{
358
31.7k
    int code = 0;
359
31.7k
    pdf_pattern_context_t *context = NULL;
360
361
31.7k
    code = pdfi_pattern_gset(ctx, page_dict, ExtGState);
362
31.7k
    if (code < 0)
363
0
        goto errorExit;
364
365
31.7k
    context = (pdf_pattern_context_t *) gs_alloc_bytes(ctx->memory, sizeof(*context),
366
31.7k
                                                       "pdfi_pattern_setup(context)");
367
31.7k
    if (!context) {
368
0
        code = gs_note_error(gs_error_VMerror);
369
0
        goto errorExit;
370
0
    }
371
31.7k
    context->ctx = ctx;
372
31.7k
    context->page_dict = page_dict;
373
31.7k
    context->pat_obj = pat_obj;
374
31.7k
    context->shading = NULL;
375
31.7k
    pdfi_countup(page_dict);
376
31.7k
    pdfi_countup(pat_obj);
377
31.7k
    *ppcontext = context;
378
379
31.7k
    return 0;
380
0
 errorExit:
381
0
    gs_free_object(ctx->memory, context, "pdfi_pattern_setup(context)");
382
0
    return code;
383
31.7k
}
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
29.8k
{
391
29.8k
    int code = 0;
392
29.8k
    gs_client_pattern templat;
393
29.8k
    gs_matrix mat;
394
29.8k
    gs_rect rect;
395
29.8k
    int64_t PaintType, TilingType;
396
29.8k
    pdf_array *BBox = NULL;
397
29.8k
    double XStep, YStep;
398
29.8k
    pdf_dict *Resources = NULL, *pdict = NULL;
399
29.8k
    pdf_array *Matrix = NULL;
400
29.8k
    bool transparency = false, BM_Not_Normal = false;
401
29.8k
    pdf_pattern_context_t *context = NULL;
402
403
#if DEBUG_PATTERN
404
    dbgmprintf(ctx->memory, "PATTERN: Type 1 pattern\n");
405
#endif
406
407
29.8k
    gs_pattern1_init(&templat);
408
409
    /* Must be a stream */
410
29.8k
    if (pdfi_type_of(stream) != PDF_STREAM) {
411
46
        code = gs_note_error(gs_error_typecheck);
412
46
        goto exit;
413
46
    }
414
29.7k
    code = pdfi_dict_from_obj(ctx, stream, &pdict);
415
29.7k
    if (code < 0)
416
0
        return code;
417
418
    /* Required */
419
29.7k
    code = pdfi_dict_get_int(ctx, pdict, "PaintType", &PaintType);
420
29.7k
    if (code < 0)
421
72
        goto exit;
422
29.6k
    code = pdfi_dict_get_int(ctx, pdict, "TilingType", &TilingType);
423
29.6k
    if (code < 0)
424
65
        goto exit;
425
29.6k
    code = pdfi_dict_get_type(ctx, pdict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
426
29.6k
    if (code < 0)
427
40
        goto exit;
428
29.5k
    code = pdfi_pattern_get_rect(ctx, BBox, &rect);
429
29.5k
    if (code < 0)
430
14
        goto exit;
431
29.5k
    code = pdfi_dict_get_number(ctx, pdict, "XStep", &XStep);
432
29.5k
    if (code < 0)
433
62
        goto exit;
434
29.5k
    code = pdfi_dict_get_number(ctx, pdict, "YStep", &YStep);
435
29.5k
    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
29.4k
    if (XStep == 0.0 || YStep == 0.0) {
440
3
        code = gs_note_error(gs_error_rangecheck);
441
3
        goto exit;
442
3
    }
443
444
    /* The pattern instance holds the pattern step as floats, make sure they
445
     * will fit.
446
     */
447
29.4k
    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
29.4k
    code = pdfi_dict_get_type(ctx, pdict, "Resources", PDF_DICT, (pdf_obj **)&Resources);
456
29.4k
    if (code < 0) {
457
822
        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
721
            pdfi_set_warning(ctx, code, NULL, W_PDF_BADPATTERN, "pdfi_setpattern_type1", "Pattern has no Resources dictionary");
462
721
            code = 0;
463
721
        } else
464
101
            goto exit;
465
822
    }
466
467
    /* (optional Matrix) */
468
29.3k
    code = pdfi_dict_knownget_type(ctx, pdict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
469
29.3k
    if (code < 0)
470
0
        goto exit;
471
29.3k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &mat);
472
29.3k
    if (code < 0)
473
77
        goto exit;
474
475
29.2k
    if (PaintType != 1 && PaintType != 2) {
476
0
        code = gs_note_error(gs_error_rangecheck);
477
0
        goto exit;
478
0
    }
479
29.2k
    if (TilingType != 1 && TilingType != 2 && TilingType != 3) {
480
1
        code = gs_note_error(gs_error_rangecheck);
481
1
        goto exit;
482
1
    }
483
484
    /* See if pattern uses transparency, or if we are in an overprint
485
       simulation situation */
486
29.2k
    if (ctx->page.has_transparency) {
487
21.4k
        code = pdfi_check_Pattern_transparency(ctx, pdict, page_dict, &transparency, &BM_Not_Normal);
488
21.4k
        if (code < 0)
489
0
            goto exit;
490
21.4k
    }
491
29.2k
    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
29.2k
    templat.BBox = rect;
498
    /* (see zPaintProc or px_remap_pattern) */
499
29.2k
    templat.PaintProc = pdfi_pattern_paintproc;
500
29.2k
    templat.PaintType = PaintType;
501
29.2k
    templat.TilingType = TilingType;
502
29.2k
    templat.XStep = XStep;
503
29.2k
    templat.YStep = YStep;
504
29.2k
    templat.uses_transparency = transparency;
505
29.2k
    templat.BM_Not_Normal = BM_Not_Normal;
506
    /* templat.uses_transparency = false; /* disable */
507
508
29.2k
    code = pdfi_gsave(ctx);
509
29.2k
    if (code < 0)
510
0
        goto exit;
511
512
29.2k
    code = pdfi_pattern_setup(ctx, &context, page_dict, stream, NULL);
513
29.2k
    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
29.2k
    code = gs_make_pattern(cc, (const gs_pattern_template_t *)&templat, &mat, ctx->pgs, ctx->pgs->memory);
520
29.2k
    if (code < 0) {
521
0
        (void) pdfi_grestore(ctx);
522
0
        goto exit;
523
0
    }
524
525
29.2k
    cc->pattern->client_data = context;
526
29.2k
    cc->pattern->notify_free = pdfi_pattern_cleanup;
527
29.2k
    {
528
29.2k
        unsigned long hash = 5381;
529
29.2k
        unsigned int i;
530
29.2k
        const byte *str;
531
532
29.2k
        gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)cc->pattern;
533
534
535
29.2k
        str = (const byte *)&ctx->pgs->ctm.xx;
536
146k
        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
117k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
541
117k
#endif
542
117k
        }
543
29.2k
        str = (const byte *)&ctx->pgs->ctm.xy;
544
146k
        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
117k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
549
117k
#endif
550
117k
        }
551
29.2k
        str = (const byte *)&ctx->pgs->ctm.yx;
552
146k
        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
117k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
557
117k
#endif
558
117k
        }
559
29.2k
        str = (const byte *)&ctx->pgs->ctm.yy;
560
146k
        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
117k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
565
117k
#endif
566
117k
        }
567
568
29.2k
        str = (const byte *)&pdict->object_num;
569
146k
        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
117k
            hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
574
117k
#endif
575
117k
        }
576
577
29.2k
        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
29.2k
        pinst->id = hash;
583
29.2k
    }
584
29.2k
    context = NULL;
585
586
29.2k
    code = pdfi_grestore(ctx);
587
29.2k
    if (code < 0)
588
0
        goto exit;
589
29.8k
 exit:
590
29.8k
    gs_free_object(ctx->memory, context, "pdfi_setpattern_type1(context)");
591
29.8k
    pdfi_countdown(Resources);
592
29.8k
    pdfi_countdown(Matrix);
593
29.8k
    pdfi_countdown(BBox);
594
29.8k
    return code;
595
29.2k
}
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.40k
{
602
3.40k
    int code = 0;
603
3.40k
    pdf_obj *Shading = NULL;
604
3.40k
    pdf_dict *ExtGState = NULL, *pattern_dict = NULL;
605
3.40k
    pdf_array *Matrix = NULL;
606
3.40k
    gs_matrix mat;
607
3.40k
    gs_shading_t *shading;
608
3.40k
    gs_pattern2_template_t templat;
609
3.40k
    pdf_pattern_context_t *context = NULL;
610
611
    /* See zbuildshadingpattern() */
612
613
3.40k
    code = pdfi_dict_from_obj(ctx, pattern_obj, &pattern_dict);
614
3.40k
    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.40k
    code = pdfi_dict_knownget_type(ctx, pattern_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
623
3.40k
    if (code < 0)
624
0
        goto exit;
625
3.40k
    code = pdfi_array_to_gs_matrix(ctx, Matrix, &mat);
626
3.40k
    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.38k
    code = pdfi_dict_knownget(ctx, pattern_dict, "Shading", &Shading);
631
3.38k
    if (code < 0)
632
873
        goto exit;
633
2.51k
    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.50k
    code = pdfi_dict_knownget_type(ctx, pattern_dict, "ExtGState", PDF_DICT, (pdf_obj **)&ExtGState);
641
2.50k
    if (code < 0)
642
0
        goto exit;
643
644
2.50k
    code = pdfi_gsave(ctx);
645
2.50k
    if (code < 0)
646
0
        goto exit;
647
648
2.50k
    gs_pattern2_init(&templat);
649
650
2.50k
    code = pdfi_pattern_setup(ctx, &context, NULL, NULL, ExtGState);
651
2.50k
    if (code < 0) {
652
0
        (void) pdfi_grestore(ctx);
653
0
        goto exit;
654
0
    }
655
656
2.50k
    code = pdfi_shading_build(ctx, stream_dict, page_dict, Shading, &shading);
657
2.50k
    if (code != 0) {
658
650
        (void) pdfi_grestore(ctx);
659
650
        dbgmprintf(ctx->memory, "ERROR: can't build shading structure\n");
660
650
        goto exit;
661
650
    }
662
663
1.85k
    context->shading = shading;
664
665
1.85k
    templat.Shading = shading;
666
1.85k
    code = gs_make_pattern(cc, (const gs_pattern_template_t *)&templat, &mat, ctx->pgs, ctx->memory);
667
1.85k
    if (code < 0) {
668
0
        (void) pdfi_grestore(ctx);
669
0
        goto exit;
670
0
    }
671
1.85k
    cc->pattern->client_data = context;
672
1.85k
    cc->pattern->notify_free = pdfi_pattern_cleanup;
673
1.85k
    context = NULL;
674
675
1.85k
    code = pdfi_grestore(ctx);
676
1.85k
    if (code < 0)
677
0
        goto exit;
678
679
3.40k
 exit:
680
3.40k
    if (context != NULL)
681
650
        pdfi_free_pattern_context(context);
682
3.40k
    pdfi_countdown(Shading);
683
3.40k
    pdfi_countdown(Matrix);
684
3.40k
    pdfi_countdown(ExtGState);
685
3.40k
    return code;
686
1.85k
}
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
67.7k
{
693
67.7k
    pdf_dict *pattern_dict = NULL;
694
67.7k
    pdf_obj *pattern_obj = NULL;
695
67.7k
    int code;
696
67.7k
    int64_t patternType;
697
698
67.7k
    code = pdfi_loop_detector_mark(ctx);
699
67.7k
    if (code < 0)
700
0
        return code;
701
702
67.7k
    memset(cc, 0, sizeof(*cc));
703
67.7k
    code = pdfi_find_resource(ctx, (unsigned char *)"Pattern", pname, (pdf_dict *)stream_dict,
704
67.7k
                              page_dict, (pdf_obj **)&pattern_obj);
705
67.7k
    if (code < 0) {
706
34.1k
        dbgmprintf(ctx->memory, "WARNING: Pattern object not found in resources\n");
707
34.1k
        goto exit;
708
34.1k
    }
709
710
33.6k
    code = pdfi_dict_from_obj(ctx, pattern_obj, &pattern_dict);
711
33.6k
    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
104
        dbgmprintf(ctx->memory, "ERROR: Pattern found in resources is neither a stream or dict\n");
716
104
        goto exit;
717
104
    }
718
719
#if DEBUG_PATTERN
720
    dbgmprintf1(ctx->memory, "PATTERN: pdfi_setpattern: found pattern object %d\n", pdict->object_num);
721
#endif
722
723
33.5k
    code = pdfi_dict_get_int(ctx, pattern_dict, "PatternType", &patternType);
724
33.5k
    if (code < 0)
725
323
        goto exit;
726
33.2k
    if (patternType == 1) {
727
29.8k
        code = pdfi_setpattern_type1(ctx, stream_dict, page_dict, (pdf_obj *)pattern_obj, cc);
728
29.8k
        if (code < 0)
729
536
            goto exit;
730
29.8k
    } else if (patternType == 2) {
731
3.40k
        code = pdfi_setpattern_type2(ctx, stream_dict, page_dict, pattern_obj, cc);
732
3.40k
        if (code < 0)
733
1.54k
            goto exit;
734
3.40k
    } else {
735
31
        code = gs_note_error(gs_error_syntaxerror);
736
31
        goto exit;
737
31
    }
738
739
67.7k
 exit:
740
67.7k
    pdfi_countdown(pattern_obj);
741
67.7k
    if (code < 0)
742
36.6k
        (void)pdfi_loop_detector_cleartomark(ctx);
743
31.1k
    else
744
31.1k
        code = pdfi_loop_detector_cleartomark(ctx);
745
67.7k
    return code;
746
33.2k
}
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
63.8k
{
761
63.8k
    gs_color_space *pcs = NULL;
762
63.8k
    gs_color_space *base_space;
763
63.8k
    pdf_obj *base_obj = NULL;
764
63.8k
    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
63.8k
    pcs = gs_cspace_alloc(ctx->memory, &gs_color_space_type_Pattern);
777
63.8k
    if (pcs == NULL) {
778
0
        return_error(gs_error_VMerror);
779
0
    }
780
63.8k
    if (color_array == NULL || pdfi_array_size(color_array) == 1) {
781
63.5k
        pcs->base_space = NULL;
782
63.5k
        pcs->params.pattern.has_base_space = false;
783
63.5k
    } else {
784
#if DEBUG_PATTERN
785
        dbgmprintf(ctx->memory, "PATTERN: with base space! pdfi_create_Pattern\n");
786
#endif
787
288
        code = pdfi_array_get(ctx, color_array, 1, &base_obj);
788
288
        if (code < 0)
789
0
            goto exit;
790
288
        code = pdfi_create_colorspace(ctx, base_obj, stream_dict, page_dict, &base_space, false);
791
288
        if (code < 0)
792
12
            goto exit;
793
276
        pcs->base_space = base_space;
794
276
        pcs->params.pattern.has_base_space = true;
795
276
    }
796
63.8k
    if (ppcs != NULL) {
797
6
        *ppcs = pcs;
798
6
        rc_increment_cs(pcs);
799
63.8k
    } else {
800
63.8k
        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
63.8k
    }
812
813
814
63.8k
 exit:
815
    /* release reference from construction */
816
63.8k
    rc_decrement_only_cs(pcs, "create_Pattern");
817
63.8k
    pdfi_countdown(base_obj);
818
63.8k
    return code;
819
63.8k
}