Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpdft.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* transparency processing for PDF-writing driver */
18
#include "gx.h"
19
#include "string_.h"
20
#include "gserrors.h"
21
#include "gstrans.h"
22
#include "gscolor2.h"
23
#include "gzstate.h"
24
#include "gdevpdfx.h"
25
#include "gdevpdfg.h"
26
#include "gdevpdfo.h"
27
#include "gsccolor.h"
28
#include "gsicc_manage.h"
29
#include "gdevpdfc.h"
30
31
static int
32
pdf_make_soft_mask_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams)
33
137
{
34
137
    pdf_resource_t *pres_soft_mask_dict = 0;
35
137
    cos_dict_t *soft_mask_dict;
36
137
    int code;
37
38
    /* Fixme : merge redundant objects. */
39
137
    code = pdf_alloc_resource(pdev, resourceSoftMaskDict, gs_no_id, &pres_soft_mask_dict, -1);
40
137
    if (code < 0)
41
0
        return code;
42
137
    cos_become(pres_soft_mask_dict->object, cos_type_dict);
43
137
    pdev->pres_soft_mask_dict = pres_soft_mask_dict;
44
137
    soft_mask_dict = (cos_dict_t *)pres_soft_mask_dict->object;
45
137
    code = cos_dict_put_c_key_string(soft_mask_dict, "/S",
46
137
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? (byte *)"/Alpha" : (byte *)"/Luminosity",
47
137
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? 6 : 11);
48
137
    if (code < 0)
49
0
        return code;
50
137
    if (pparams->Background_components) {
51
112
        cos_array_t *Background;
52
53
112
        Background = cos_array_from_floats(pdev, pparams->Background,
54
112
                    pparams->Background_components, "pdf_write_soft_mask_dict");
55
112
        if (Background == NULL)
56
0
            return_error(gs_error_VMerror);
57
112
        code = cos_dict_put_c_key_object(soft_mask_dict, "/BC", (cos_object_t *)Background);
58
112
        if (code < 0)
59
0
            return code;
60
112
    }
61
137
    if (pdev->CompatibilityLevel <= 1.7 && pparams->transfer_function != NULL && pdev->params.TransferFunctionInfo == tfi_Preserve) {
62
26
        int64_t id;
63
26
        char buf[20];
64
65
26
        code = pdf_write_function(pdev, pparams->transfer_function, &id);
66
26
        if (code < 0)
67
0
            return code;
68
26
        gs_snprintf(buf, sizeof(buf), " %"PRId64" 0 R", id);
69
26
        code = cos_dict_put_c_key_string(soft_mask_dict, "/TR", (const byte *)buf, strlen(buf));
70
26
        if (code < 0)
71
0
            return code;
72
26
    }
73
137
    return 0;
74
75
137
}
76
77
static int WriteDefaultSpaces(gx_device_pdf * pdev, const gs_gstate * pgs, cos_value_t *cs_value)
78
0
{
79
0
    cmm_profile_t *pprofile = NULL;
80
0
    gs_color_space cs, *pcs;
81
0
    gs_color_space_type t;
82
0
    cos_array_t *pca;
83
0
    cos_dict_t *Resources = NULL, *ColorSpaces = NULL;
84
0
    int code = 0;
85
0
    const cos_value_t *pcos = NULL;
86
0
    pdf_color_space_t *ppcs;
87
0
    pdf_resource_t *pres = NULL;
88
0
    gs_color_space_index target;
89
90
    /* Check type before using */
91
0
    if (cs_value->value_type != COS_VALUE_CONST)
92
0
        return_error(gs_error_typecheck);
93
    /* Compare its value to find out which space we want */
94
0
    if (strncmp((const char *)cs_value->contents.chars.data, "/DeviceGray", 11) == 0)
95
0
        target = gs_color_space_index_DeviceGray;
96
0
    else
97
0
        if (strncmp((const char *)cs_value->contents.chars.data, "/DeviceRGB", 10) == 0)
98
0
            target = gs_color_space_index_DeviceRGB;
99
0
        else
100
0
            if (strncmp((const char *)cs_value->contents.chars.data, "/DeviceCMYK", 11) == 0)
101
0
                target = gs_color_space_index_DeviceCMYK;
102
0
            else
103
0
                return_error(gs_error_rangecheck);
104
105
    /* Retrieve/Create the Resources->ColorSpace dictionary in the Pages tree */
106
0
    Resources = (cos_dict_t *)cos_dict_find(pdev->Pages, (const byte *)"/Resources", 10);
107
0
    if (Resources == NULL) {
108
0
        Resources = cos_dict_alloc(pdev, "WriteDefaultSpaces");
109
0
        if (Resources == NULL)
110
0
            return_error(gs_error_undefined);
111
0
        code = cos_dict_put_c_key_object(pdev->Pages, "/Resources", (cos_object_t *)Resources);
112
0
        if (code < 0)
113
0
            return code;
114
0
    }
115
116
    /* Then the ColorSpace sub-dictionary */
117
0
    ColorSpaces = (cos_dict_t *)cos_dict_find(Resources, (const byte *)"/ColorSpace", 11);
118
0
    if(ColorSpaces == NULL) {
119
0
        ColorSpaces = cos_dict_alloc(pdev, "WriteDefaultSpaces");
120
0
        if (ColorSpaces == NULL)
121
0
            return_error(gs_error_undefined);
122
0
        code = cos_dict_put_c_key_object(Resources, "/ColorSpace", (cos_object_t *)ColorSpaces);
123
0
        if (code < 0)
124
0
            return code;
125
0
    }
126
127
    /* Now check to see if we already have a /Default space, if so just exit. */
128
0
    switch(target) {
129
0
        case gs_color_space_index_DeviceGray:
130
0
            pcos = cos_dict_find_c_key(ColorSpaces, "/DefaultGray");
131
0
            break;
132
0
        case gs_color_space_index_DeviceRGB:
133
0
            pcos = cos_dict_find_c_key(ColorSpaces, "/DefaultRGB");
134
0
            break;
135
0
        case gs_color_space_index_DeviceCMYK:
136
0
            pcos = cos_dict_find_c_key(ColorSpaces, "/DefaultCMYK");
137
0
            break;
138
0
        default:
139
0
            return_error(gs_error_rangecheck);
140
0
            break;
141
0
    }
142
    /* If we've already written the relevant Default space, don't write another one! */
143
0
    if (pcos != NULL)
144
0
        return 0;
145
146
    /* This is all a bit hairy, but there seems to be no easy way to achieve this
147
     * Probably could export some static functions from the ICC code, but this works too. Just manufacture
148
     * enough of a colour space to retrieve the ICC profile.
149
     */
150
0
    cs.cmm_icc_profile_data = NULL;
151
0
    t.index = target;
152
0
    cs.type = &t;
153
0
    pprofile = gsicc_get_gscs_profile(&cs, pgs->icc_manager);
154
0
    if (pprofile == NULL)
155
0
        return_error(gs_error_undefined);
156
    /* gsicc_get_gscs_profile() does not count up the returned reference. We
157
     * deliberately don't count it up here; we're only using it temporarily.
158
     */
159
160
    /* Now manufacture a colour space to attach the profile to. */
161
0
    pcs = gs_cspace_new_ICC(pdev->memory, (gs_gstate *)pgs, 4);
162
0
    if (pcs == NULL)
163
0
        return_error(gs_error_undefined);
164
165
0
    switch(target) {
166
0
        case gs_color_space_index_DeviceGray:
167
0
            pcs->ICC_Alternate_space = gs_ICC_Alternate_DeviceGray;
168
0
            break;
169
0
        case gs_color_space_index_DeviceRGB:
170
0
            pcs->ICC_Alternate_space = gs_ICC_Alternate_DeviceRGB;
171
0
            break;
172
0
        case gs_color_space_index_DeviceCMYK:
173
0
            pcs->ICC_Alternate_space = gs_ICC_Alternate_DeviceCMYK;
174
0
            break;
175
0
        default:
176
0
            return_error(gs_error_undefined);
177
0
    }
178
179
0
    pcs->cmm_icc_profile_data = pprofile;
180
181
    /* Create an array. */
182
0
    pca = cos_array_alloc(pdev, "WriteDefaultSpaces");
183
0
    if (pca == 0) {
184
0
        rc_decrement(pcs, "WriteDefaultSpaces");
185
0
        return_error(gs_error_VMerror);
186
0
    }
187
188
    /* Turn the array in to a PDF colour space, using the GS colour space */
189
0
    code = pdf_iccbased_color_space(pdev, pgs, NULL, pcs, pca);
190
0
    if (code < 0) {
191
0
        rc_decrement(pcs, "WriteDefaultSpaces");
192
0
        cos_release((cos_object_t *)pca, "WriteDefaultSpaces");
193
0
        return code;
194
0
    }
195
196
    /*
197
     * Register the color space as a resource, since it must be referenced
198
     * by name rather than directly.
199
     */
200
0
    {
201
0
        if (code < 0 ||
202
0
            (code = pdf_alloc_resource(pdev, resourceColorSpace, pcs->id,
203
0
                                       &pres, -1)) < 0
204
0
            ) {
205
0
            COS_FREE(pca, "pdf_color_space");
206
0
            return code;
207
0
        }
208
0
        pdf_reserve_object_id(pdev, pres, 0);
209
210
0
        switch(target) {
211
0
            case gs_color_space_index_DeviceGray:
212
0
                memcpy(pres->rname, "DefaultGray", 11);
213
0
                pres->rname[11] = 0;
214
0
                break;
215
0
            case gs_color_space_index_DeviceRGB:
216
0
                memcpy(pres->rname, "DefaultRGB", 10);
217
0
                pres->rname[10] = 0;
218
0
                break;
219
0
            case gs_color_space_index_DeviceCMYK:
220
0
                memcpy(pres->rname, "DefaultCMYK", 11);
221
0
                pres->rname[11] = 0;
222
0
                break;
223
0
            default:
224
0
                 return_error(gs_error_undefined);
225
0
        }
226
227
0
        ppcs = (pdf_color_space_t *)pres;
228
0
        ppcs->serialized = 0;
229
0
        ppcs->serialized_size = 0;
230
0
        ppcs->ranges = 0;
231
0
        pca->id = pres->object->id;
232
0
        COS_FREE(pres->object, "pdf_color_space");
233
0
        pres->object = (cos_object_t *)pca;
234
0
        cos_write_object(COS_OBJECT(pca), pdev, resourceColorSpace);
235
0
    }
236
237
0
    code = pdf_add_resource(pdev, Resources, "/ColorSpace", pres);
238
239
0
    rc_decrement(pcs, "WriteDefaultSpaces");
240
0
    cos_release((cos_object_t *)pca, "WriteDefaultSpaces");
241
0
    return code;
242
0
}
243
244
static int
245
pdf_make_group_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
246
                            const gs_gstate * pgs, cos_dict_t **pdict)
247
6.59k
{
248
6.59k
    pdf_resource_t *pres_group;
249
6.59k
    cos_dict_t *group_dict;
250
6.59k
    int code = 0;
251
6.59k
    cos_value_t cs_value;
252
253
6.59k
    code = pdf_alloc_resource(pdev, resourceGroup, gs_no_id, &pres_group, -1);
254
6.59k
    if (code < 0)
255
0
        return code;
256
6.59k
    cos_become(pres_group->object, cos_type_dict);
257
6.59k
    group_dict = (cos_dict_t *)pres_group->object;
258
6.59k
    code = cos_dict_put_c_key_string(group_dict, "/Type", (const byte *)"/Group", 6);
259
6.59k
    if (code < 0)
260
0
        return code;
261
6.59k
    code = cos_dict_put_c_key_string(group_dict, "/S", (const byte *)"/Transparency", 13);
262
6.59k
    if (code < 0)
263
0
        return code;
264
6.59k
    if (pparams->Isolated) {
265
5.47k
        code = cos_dict_put_c_key_bool(group_dict, "/I", true);
266
5.47k
        if (code < 0)
267
0
            return code;
268
5.47k
    }
269
6.59k
    if (pparams->Knockout) {
270
3
        code = cos_dict_put_c_key_bool(group_dict, "/K", true);
271
3
        if (code < 0)
272
0
            return code;
273
3
    }
274
    /* Note that we should not add in the graphic state
275
       color space for the group color if there was not
276
       a group color specified.
277
       In this case, the parent group is inherited from
278
       the previous group or the device color space */
279
6.59k
    if (pgs != NULL && pparams->ColorSpace != NULL) {
280
1.35k
        const gs_color_space *cs = pparams->ColorSpace;
281
282
1.35k
        if (pparams->ColorSpace == NULL)
283
0
            code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, cs,
284
0
                    &pdf_color_space_names, false, NULL, 0, false);
285
1.35k
        else
286
1.35k
            code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, pparams->ColorSpace,
287
1.35k
                    &pdf_color_space_names, false, NULL, 0, false);
288
1.35k
        if (code < 0)
289
0
            return code;
290
1.35k
        switch(pdev->params.BlendConversionStrategy) {
291
0
            case bcs_Managed:
292
0
                if (pdev->params.ColorConversionStrategy != ccs_LeaveColorUnchanged) {
293
0
                    if (pdev->params.ColorConversionStrategy < ccs_CMYK || pdev->params.ColorConversionStrategy == ccs_ByObjectType) {
294
0
                        dmprintf(pdev->memory, "\tCannot use DeviceIndependentColor for a Blending colour space.\n\tCannot use /Managed or /Simple replacement strategy with DeviceIndependentColor.\n\tChange ColorConversionStrategy or BlendConversionStrategy.\n\n");
295
0
                        return_error(gs_error_rangecheck);
296
0
                    }
297
0
                    code = WriteDefaultSpaces(pdev, pgs, &cs_value);
298
0
                }
299
0
                if (code < 0)
300
0
                    return code;
301
                /* Fall through */
302
0
            case bcs_None:
303
0
                code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
304
0
                break;
305
1.35k
            case bcs_Simple:
306
1.35k
                switch(pdev->params.ColorConversionStrategy) {
307
1.35k
                    case ccs_LeaveColorUnchanged:
308
1.35k
                        code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
309
1.35k
                        break;
310
0
                    case ccs_UseDeviceIndependentColor:
311
0
                    case ccs_UseDeviceIndependentColorForImages:
312
0
                    case ccs_ByObjectType:
313
0
                    case ccs_sRGB:
314
0
                        dmprintf(pdev->memory, "\tCannot use DeviceIndependentColor for a Blending colour space.\n\tCannot use /Managed or /Simple replacement strategy with DeviceIndependentColor.\n\tChange ColorConversionStrategy or BlendConversionStrategy.\n\n");
315
0
                        return_error(gs_error_rangecheck);
316
0
                        break;
317
318
0
                    case ccs_CMYK:
319
0
                        code = cos_dict_put_c_key_string(group_dict, "/CS", (const byte *)"/DeviceCMYK", 11);
320
0
                        break;
321
0
                    case ccs_Gray:
322
0
                        code = cos_dict_put_c_key_string(group_dict, "/CS", (const byte *)"/DeviceGray", 11);
323
0
                        break;
324
0
                    case ccs_RGB:
325
0
                        code = cos_dict_put_c_key_string(group_dict, "/CS", (const byte *)"/DeviceRGB", 10);
326
0
                        break;
327
1.35k
                }
328
1.35k
                break;
329
1.35k
        }
330
1.35k
    }
331
6.59k
    if (code < 0)
332
0
        return code;
333
6.59k
    group_dict = NULL; /* The next line invalidates it. */
334
6.59k
    code = pdf_substitute_resource(pdev, &pres_group, resourceGroup, NULL, false);
335
6.59k
    if (code < 0)
336
0
        return code;
337
6.59k
    pres_group->where_used |= pdev->used_mask;
338
6.59k
    *pdict = (cos_dict_t *)pres_group->object;
339
6.59k
    return 0;
340
6.59k
}
341
342
static int
343
pdf_make_form_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
344
                            const gs_gstate * pgs,
345
                            const cos_dict_t *group_dict, cos_dict_t *form_dict)
346
1.61k
{
347
1.61k
    cos_array_t *bbox_array;
348
1.61k
    float bbox[4];
349
1.61k
    gs_rect bbox_rect;
350
1.61k
    int code;
351
352
1.61k
    code = gs_bbox_transform(&pparams->bbox, &ctm_only(pgs), &bbox_rect);
353
1.61k
    if (code < 0)
354
0
        return code;
355
1.61k
    bbox[0] = bbox_rect.p.x;
356
1.61k
    bbox[1] = bbox_rect.p.y;
357
1.61k
    bbox[2] = bbox_rect.q.x;
358
1.61k
    bbox[3] = bbox_rect.q.y;
359
1.61k
    code = cos_dict_put_c_key_string(form_dict, "/Type", (const byte *)"/XObject", 8);
360
1.61k
    if (code < 0)
361
0
        return code;
362
1.61k
    code = cos_dict_put_c_key_string(form_dict, "/Subtype", (const byte *)"/Form", 5);
363
1.61k
    if (code < 0)
364
0
        return code;
365
1.61k
    code = cos_dict_put_c_key_int(form_dict, "/FormType", 1);
366
1.61k
    if (code < 0)
367
0
        return code;
368
1.61k
    code = cos_dict_put_c_key_string(form_dict, "/Matrix", (const byte *)"[1 0 0 1 0 0]", 13);
369
1.61k
    if (code < 0)
370
0
        return code;
371
1.61k
    bbox_array = cos_array_from_floats(pdev, bbox, 4, "pdf_begin_transparency_group");
372
1.61k
    if (bbox_array == NULL)
373
0
        return_error(gs_error_VMerror);
374
1.61k
    code = cos_dict_put_c_key_object(form_dict, "/BBox", (cos_object_t *)bbox_array);
375
1.61k
    if (code < 0)
376
0
        return code;
377
1.61k
    if (pdev->PendingOC != 0) {
378
1
        if (pdev->CompatibilityLevel < 1.4999) {
379
0
            if (pdev->PDFA) {
380
0
                switch (pdev->PDFACompatibilityPolicy) {
381
0
                    case 0:
382
0
                        emprintf(pdev->memory,
383
0
                                 "Optional Content not valid in this version of PDF, reverting to normal PDF output\n");
384
0
                        pdev->AbortPDFAX = true;
385
0
                        pdev->PDFA = 0;
386
0
                        break;
387
0
                    case 1:
388
0
                        emprintf(pdev->memory,
389
0
                                 "Optional Content not valid in this version of PDF. Dropping feature to preserve PDF/A compatibility\n");
390
0
                        break;
391
0
                    case 2:
392
0
                        emprintf(pdev->memory,
393
0
                                 "Optional Content not valid in this version of PDF,  aborting conversion\n");
394
0
                        return_error (gs_error_typecheck);
395
0
                        break;
396
0
                    default:
397
0
                        emprintf(pdev->memory,
398
0
                                 "Optional Content not valid in this version of PDF, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
399
0
                        pdev->AbortPDFAX = true;
400
0
                        pdev->PDFA = 0;
401
0
                        break;
402
0
                }
403
0
            } else {
404
0
                emprintf(pdev->memory,
405
0
                         "Optional Content not valid in this version of PDF. Dropping feature to preserve compatibility\n");
406
0
            }
407
1
        } else {
408
1
            char str[256];
409
1
            gs_param_string param;
410
1
            cos_object_t *pco = NULL;
411
412
1
            param.data = (const byte *)pdev->PendingOC;
413
1
            param.size = strlen(pdev->PendingOC);
414
1
            code = pdf_refer_named(pdev, &param, &pco);
415
1
            if(code < 0)
416
0
                return code;
417
418
1
            gs_snprintf(str, sizeof(str), "%"PRId64" 0 R", pco->id);
419
1
            code = cos_dict_put_string_copy(form_dict, "/OC", str);
420
1
            if (code < 0)
421
0
                return code;
422
423
1
            gs_free_object(pdev->memory->non_gc_memory, pdev->PendingOC, "");
424
1
            pdev->PendingOC = NULL;
425
1
        }
426
1
    }
427
1.61k
    return cos_dict_put_c_key_object(form_dict, "/Group", (cos_object_t *)group_dict);
428
1.61k
}
429
430
static int
431
pdf_begin_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev,
432
                                const gs_pdf14trans_params_t * pparams, bool page_group)
433
6.59k
{
434
6.59k
    cos_dict_t *group_dict;
435
6.59k
    int code;
436
437
6.59k
    if (pgs == NULL)
438
0
        return_error(gs_error_unregistered); /* Must not happen. */
439
6.59k
    code = pdf_make_group_dict(pdev, pparams, pgs, &group_dict);
440
6.59k
    if (code < 0)
441
0
        return code;
442
6.59k
    code = pdf_open_page(pdev, PDF_IN_STREAM);
443
6.59k
    if (code < 0)
444
0
        return code;
445
6.59k
    code = pdf_check_soft_mask(pdev, pgs);
446
6.59k
    if (code < 0)
447
0
        return code;
448
6.59k
    if (pdf_must_put_clip_path(pdev, pgs->clip_path)) {
449
634
        code = pdf_put_clip_path(pdev, pgs->clip_path);
450
634
        if (code < 0)
451
0
            return code;
452
634
    }
453
6.59k
    if (page_group)
454
602
        pdev->pages[pdev->next_page].group_id = group_dict->id;
455
5.99k
    else if (pparams->image_with_SMask) {
456
        /* An internal group for the image implementation.
457
           See doimagesmask in gs/lib/pdf_draw.ps .
458
           Just set a flag for skipping pdf_end_transparency_group. */
459
4.37k
        pdev->image_with_SMask |= 1 << ++pdev->FormDepth;
460
4.37k
        pdev->PatternsSinceForm = 0;
461
4.37k
    } else {
462
1.61k
        pdf_resource_t *pres, *pres_gstate = NULL;
463
1.61k
        cos_dict_t *pcd = NULL, *pcd_Resources = NULL;
464
465
1.61k
        code = pdf_prepare_drawing(pdev, pgs, &pres_gstate, false);
466
1.61k
        if (code < 0)
467
0
            return code;
468
1.61k
        code = pdf_end_gstate(pdev, pres_gstate);
469
1.61k
        if (code < 0)
470
0
            return code;
471
1.61k
        code = pdf_enter_substream(pdev, resourceXObject,
472
1.61k
                gs_no_id, &pres, false, pdev->params.CompressPages);
473
1.61k
        if (code < 0)
474
0
            return code;
475
1.61k
        pdev->FormDepth++;
476
1.61k
        pdev->PatternsSinceForm = 0;
477
1.61k
        code = pdf_make_form_dict(pdev, pparams, pgs, group_dict, (cos_dict_t *)pres->object);
478
1.61k
        if (code < 0)
479
0
            return code;
480
481
        /* Create a Resources dictionary and add it to the form dictionary */
482
1.61k
        pcd = cos_stream_dict((cos_stream_t *)pres->object);
483
1.61k
        pcd_Resources = cos_dict_alloc(pdev, "pdf_group(Resources)");
484
1.61k
        if (pcd == NULL || pcd_Resources == NULL)
485
0
            return_error(gs_error_VMerror);
486
1.61k
        code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
487
1.61k
        pdev->substream_Resources = pcd_Resources;
488
1.61k
        return code;
489
1.61k
    }
490
4.98k
    return 0;
491
6.59k
}
492
493
static int
494
pdf_end_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev)
495
6.46k
{
496
6.46k
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
497
498
6.46k
    if (!is_in_page(pdev) && pdev->sbstack_depth == 0)
499
0
        return 0; /* A Group definition at the page level, handled separately. */
500
6.46k
    if (pdev->image_with_SMask & (1 << pdev->FormDepth)) {
501
        /* An internal group for the image implementation.
502
           See pdf_begin_transparency_group. */
503
4.37k
        pdev->image_with_SMask &= ~(1 << pdev->FormDepth--);
504
4.37k
        pdev->PatternsSinceForm = 0;
505
4.37k
        return 0;
506
4.37k
    } else if (pdev->sbstack_depth == bottom) {
507
        /* We're closing the page group. */
508
602
        if (pdev->pages[pdev->next_page].group_id == 0)
509
0
            return_error(gs_error_unregistered); /* Must not happen. */
510
602
        return 0;
511
1.47k
    } else {
512
1.47k
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
513
1.47k
        int code;
514
1.47k
        uint ignore;
515
516
1.47k
        if (pres == NULL)
517
0
            return_error(gs_error_unregistered);
518
1.47k
        pdev->FormDepth--;
519
1.47k
        pdev->PatternsSinceForm = 0;
520
1.47k
        code = pdf_exit_substream(pdev);
521
1.47k
        if (code < 0)
522
0
            return code;
523
1.47k
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
524
1.47k
        if (code < 0)
525
0
            return code;
526
        /* We need to update the 'where_used' field, in case we substituted a resource */
527
1.47k
        pres->where_used |= pdev->used_mask;
528
1.47k
        sputc(pdev->strm,'/');
529
1.47k
        sputs(pdev->strm, (const byte *)pres->rname, strlen(pres->rname), &ignore);
530
1.47k
        sputs(pdev->strm, (const byte *)" Do\n", 4, &ignore);
531
1.47k
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres);
532
1.47k
        return code;
533
1.47k
    }
534
6.46k
}
535
536
static int
537
pdf_begin_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
538
                                const gs_pdf14trans_params_t * pparams)
539
2.09k
{
540
2.09k
    if (pparams->subtype == TRANSPARENCY_MASK_None) {
541
1.95k
        int code;
542
1.95k
        pdf_resource_t *pres = 0L;
543
544
        /* reset the soft mask ID. Apparently this is only used by pdfwrite, if we don't
545
         * reset it, then the pdf_prepare_drawing code doesn't know that the SMask has
546
         * changed, and so doesn't write out the GState
547
         */
548
1.95k
        pgs->soft_mask_id = 0;
549
1.95k
        code = pdf_prepare_drawing(pdev, pgs, &pres, false);
550
1.95k
        if (code == gs_error_interrupt) {
551
            /* */
552
            /* Not in an appropriate context.  Do not restore the soft_mask_id.
553
               Otherwise any group push that occurs following this will use that
554
               softmask, which clearly should be NONE here.
555
             */
556
            /* ignore return code, we don't care about this graphics state as we aren't
557
             * emitting it anyway
558
             */
559
360
            pdf_end_gstate(pdev, pres);
560
360
            return 0;
561
360
        }
562
1.59k
        if (code < 0)
563
0
            return code;
564
1.59k
        code = pdf_end_gstate(pdev, pres);
565
1.59k
        if (code < 0)
566
0
            return code;
567
1.59k
        return 0;
568
1.59k
    }
569
137
    if (pparams->mask_is_image) {
570
        /* HACK :
571
            The control comes here when
572
            the PDF interpreter will make the PS interpreter
573
            to interprete the mask for filling the transparency buffer
574
            with an SMask image.
575
            Since we handle Type 3 images as a high level objects,
576
            we don't install the transparency buffer here
577
            and need to skip the image enumeration for the SMask.
578
            However we have no right method for skipping
579
            an image enumeration due to possible side effect
580
            of the image data proc in Postscript language.
581
            Therefore we do enumerate the image mask and accumulate
582
            it as a PDF stream, but don't create a reference to it.
583
            Later it will be enumerated once again as a part of SMask-ed image,
584
            and the pdfwrite image handler will recognize duplicated images
585
            and won't create the second stream for same image.
586
587
            We could make a special workaround for
588
            skipping mask images either in the graphics library or
589
            in the PS code of the PDF interpreter,
590
            but we don't want to complicate things now.
591
            The performance leak for the second enumeration
592
            shouldn't be harmful.
593
594
            So now just set a flag for pdf_end_and_do_image.
595
        */
596
0
        pdev->image_mask_skip = true;
597
0
        return 0;
598
137
    } else {
599
137
        int code;
600
601
137
        pdev->smask_construction = true;
602
137
        code = pdf_make_soft_mask_dict(pdev, pparams);
603
137
        if (code < 0)
604
0
            return code;
605
137
        code = pdf_open_page(pdev, PDF_IN_STREAM);
606
137
        if (code < 0)
607
0
            return code;
608
137
        return pdf_begin_transparency_group(pgs, pdev, pparams, 0);
609
137
    }
610
137
}
611
612
static int
613
pdf_end_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
614
                                const gs_pdf14trans_params_t * pparams)
615
137
{
616
137
    pdev->smask_construction = false;
617
137
    if (pdev->image_mask_skip)
618
0
        pdev->image_mask_skip = false;
619
137
    else {
620
137
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
621
137
        int code;
622
137
        char buf[20];
623
624
137
        if (pres == NULL)
625
0
            return_error(gs_error_unregistered);
626
137
        code = pdf_exit_substream(pdev);
627
137
        if (code < 0)
628
0
            return code;
629
137
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
630
137
        if (code < 0)
631
0
            return 0;
632
        /* We need to update the 'where_used' field, in case we substituted a resource */
633
137
        pres->where_used |= pdev->used_mask;
634
137
        gs_snprintf(buf, sizeof(buf), "%"PRId64" 0 R", pdf_resource_id(pres));
635
137
        if (pdev->pres_soft_mask_dict == 0L) {
636
            /* something went horribly wrong, we have an 'end' wihtout a matching 'begin'
637
             * Give up, throw an error.
638
             */
639
0
            return_error(gs_error_undefined);
640
0
        }
641
137
        code = cos_dict_put_c_key_string((cos_dict_t *)pdev->pres_soft_mask_dict->object,
642
137
                "/G", (const byte *)buf, strlen(buf));
643
137
        if (code < 0)
644
0
            return code;
645
137
        code = pdf_substitute_resource(pdev, &pdev->pres_soft_mask_dict,
646
137
                                        resourceSoftMaskDict, NULL, false);
647
137
        if (code < 0)
648
0
            return code;
649
137
        pdev->pres_soft_mask_dict->where_used |= pdev->used_mask;
650
137
        pgs->soft_mask_id = pdev->pres_soft_mask_dict->object->id;
651
137
        pdev->pres_soft_mask_dict = NULL;
652
        /* We called pdf_start_trnasparency_group (see pdf_begin_transparency_mask
653
         * above) but we don't call pdf_end_transparency_group, so we must reduce
654
         * the FormDepth ourselves.
655
         */
656
137
        pdev->FormDepth--;
657
137
        pdev->PatternsSinceForm = 0;
658
137
    }
659
137
    return 0;
660
137
}
661
662
static int
663
pdf_set_blend_params(gs_gstate * pgs, gx_device_pdf * dev,
664
                                const gs_pdf14trans_params_t * pparams)
665
0
{
666
0
    return 0;
667
0
}
668
669
int
670
gdev_pdf_composite(gx_device *dev,
671
    gx_device **pcdev, const gs_composite_t *pct,
672
    gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
673
224k
{
674
224k
    gx_device_pdf *pdev = (gx_device_pdf *)dev;
675
676
224k
    if (pdev->HaveTransparency && pdev->CompatibilityLevel >= 1.4 &&
677
211k
            pct->type->comp_id == GX_COMPOSITOR_PDF14_TRANS &&
678
72.2k
            pdev->PDFA != 1) {
679
72.2k
        gs_pdf14trans_t *pcte = (gs_pdf14trans_t *)pct;
680
72.2k
        gs_pdf14trans_params_t *params = &pcte->params;
681
682
72.2k
        *pcdev = dev;
683
72.2k
        switch(params->pdf14_op) {
684
913
            case PDF14_PUSH_DEVICE:
685
913
                return 0;
686
913
            case PDF14_POP_DEVICE:
687
913
                return 0;
688
0
            case PDF14_ABORT_DEVICE:
689
0
                return 0;
690
602
            case PDF14_BEGIN_TRANS_PAGE_GROUP:
691
602
                return pdf_begin_transparency_group(pgs, pdev, params, 1);
692
5.85k
            case PDF14_BEGIN_TRANS_GROUP:
693
5.85k
                return pdf_begin_transparency_group(pgs, pdev, params, 0);
694
6.46k
            case PDF14_END_TRANS_GROUP:
695
6.46k
                return pdf_end_transparency_group(pgs, pdev);
696
26.3k
            case PDF14_BEGIN_TRANS_TEXT_GROUP:
697
26.3k
                return 0;
698
28.5k
            case PDF14_END_TRANS_TEXT_GROUP:
699
28.5k
                return 0;
700
2.09k
            case PDF14_BEGIN_TRANS_MASK:
701
2.09k
                return pdf_begin_transparency_mask(pgs, pdev, params);
702
137
            case PDF14_END_TRANS_MASK:
703
137
                return pdf_end_transparency_mask(pgs, pdev, params);
704
0
            case PDF14_SET_BLEND_PARAMS:
705
0
                return pdf_set_blend_params(pgs, pdev, params);
706
0
            case PDF14_PUSH_TRANS_STATE:
707
0
                return 0;
708
96
            case PDF14_POP_TRANS_STATE:
709
96
                return 0;
710
137
            case PDF14_PUSH_SMASK_COLOR:
711
137
                return 0;
712
137
            case PDF14_POP_SMASK_COLOR:
713
137
                return 0;
714
715
0
            default :
716
0
                return_error(gs_error_unregistered); /* Must not happen. */
717
72.2k
        }
718
0
        return 0;
719
72.2k
    }
720
151k
    return psdf_composite(dev, pcdev, pct, pgs, memory, cdev);
721
224k
}
722
723
/* We're not sure why the folllowing device methods are never called.
724
   Stub them for a while. */
725
726
int
727
gdev_pdf_begin_transparency_group(gx_device *dev,
728
    const gs_transparency_group_params_t *ptgp,
729
    const gs_rect *pbbox,
730
    gs_gstate *pgs, gs_memory_t *mem)
731
0
{
732
0
    return 0;
733
0
}
734
735
int
736
gdev_pdf_end_transparency_group(gx_device *dev,
737
    gs_gstate *pgs)
738
0
{
739
0
    return 0;
740
0
}
741
742
int
743
gdev_pdf_begin_transparency_mask(gx_device *dev,
744
    const gx_transparency_mask_params_t *ptmp,
745
    const gs_rect *pbbox,
746
    gs_gstate *pgs, gs_memory_t *mem)
747
0
{
748
0
    return 0;
749
0
}
750
751
int
752
gdev_pdf_end_transparency_mask(gx_device *dev,
753
    gs_gstate *pgs)
754
0
{
755
0
    return 0;
756
0
}