Coverage Report

Created: 2026-04-01 07:17

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
199
{
34
199
    pdf_resource_t *pres_soft_mask_dict = 0;
35
199
    cos_dict_t *soft_mask_dict;
36
199
    int code;
37
38
    /* Fixme : merge redundant objects. */
39
199
    code = pdf_alloc_resource(pdev, resourceSoftMaskDict, gs_no_id, &pres_soft_mask_dict, -1);
40
199
    if (code < 0)
41
0
        return code;
42
199
    cos_become(pres_soft_mask_dict->object, cos_type_dict);
43
199
    pdev->pres_soft_mask_dict = pres_soft_mask_dict;
44
199
    soft_mask_dict = (cos_dict_t *)pres_soft_mask_dict->object;
45
199
    code = cos_dict_put_c_key_string(soft_mask_dict, "/S",
46
199
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? (byte *)"/Alpha" : (byte *)"/Luminosity",
47
199
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? 6 : 11);
48
199
    if (code < 0)
49
0
        return code;
50
199
    if (pparams->Background_components) {
51
131
        cos_array_t *Background;
52
53
131
        Background = cos_array_from_floats(pdev, pparams->Background,
54
131
                    pparams->Background_components, "pdf_write_soft_mask_dict");
55
131
        if (Background == NULL)
56
0
            return_error(gs_error_VMerror);
57
131
        code = cos_dict_put_c_key_object(soft_mask_dict, "/BC", (cos_object_t *)Background);
58
131
        if (code < 0)
59
0
            return code;
60
131
    }
61
199
    if (pdev->CompatibilityLevel <= 1.7 && pparams->transfer_function != NULL && pdev->params.TransferFunctionInfo == tfi_Preserve) {
62
25
        int64_t id;
63
25
        char buf[20];
64
65
25
        code = pdf_write_function(pdev, pparams->transfer_function, &id);
66
25
        if (code < 0)
67
0
            return code;
68
25
        gs_snprintf(buf, sizeof(buf), " %"PRId64" 0 R", id);
69
25
        code = cos_dict_put_c_key_string(soft_mask_dict, "/TR", (const byte *)buf, strlen(buf));
70
25
        if (code < 0)
71
0
            return code;
72
25
    }
73
199
    return 0;
74
75
199
}
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.39k
{
248
6.39k
    pdf_resource_t *pres_group;
249
6.39k
    cos_dict_t *group_dict;
250
6.39k
    int code = 0;
251
6.39k
    cos_value_t cs_value;
252
253
6.39k
    code = pdf_alloc_resource(pdev, resourceGroup, gs_no_id, &pres_group, -1);
254
6.39k
    if (code < 0)
255
0
        return code;
256
6.39k
    cos_become(pres_group->object, cos_type_dict);
257
6.39k
    group_dict = (cos_dict_t *)pres_group->object;
258
6.39k
    code = cos_dict_put_c_key_string(group_dict, "/Type", (const byte *)"/Group", 6);
259
6.39k
    if (code < 0)
260
0
        return code;
261
6.39k
    code = cos_dict_put_c_key_string(group_dict, "/S", (const byte *)"/Transparency", 13);
262
6.39k
    if (code < 0)
263
0
        return code;
264
6.39k
    if (pparams->Isolated) {
265
4.10k
        code = cos_dict_put_c_key_bool(group_dict, "/I", true);
266
4.10k
        if (code < 0)
267
0
            return code;
268
4.10k
    }
269
6.39k
    if (pparams->Knockout) {
270
0
        code = cos_dict_put_c_key_bool(group_dict, "/K", true);
271
0
        if (code < 0)
272
0
            return code;
273
0
    }
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.39k
    if (pgs != NULL && pparams->ColorSpace != NULL) {
280
1.99k
        const gs_color_space *cs = pparams->ColorSpace;
281
282
1.99k
        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.99k
        else
286
1.99k
            code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, pparams->ColorSpace,
287
1.99k
                    &pdf_color_space_names, false, NULL, 0, false);
288
1.99k
        if (code < 0)
289
0
            return code;
290
1.99k
        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
                        return_error(gs_error_rangecheck);
295
0
                    code = WriteDefaultSpaces(pdev, pgs, &cs_value);
296
0
                }
297
0
                if (code < 0)
298
0
                    return code;
299
                /* Fall through */
300
0
            case bcs_None:
301
0
                code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
302
0
                break;
303
1.99k
            case bcs_Simple:
304
1.99k
                switch(pdev->params.ColorConversionStrategy) {
305
1.99k
                    case ccs_LeaveColorUnchanged:
306
1.99k
                        code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
307
1.99k
                        break;
308
0
                    case ccs_UseDeviceIndependentColor:
309
0
                    case ccs_UseDeviceIndependentColorForImages:
310
0
                    case ccs_ByObjectType:
311
0
                    case ccs_sRGB:
312
0
                        return_error(gs_error_rangecheck);
313
0
                        break;
314
315
0
                    case ccs_CMYK:
316
0
                        code = cos_dict_put_c_key_string(group_dict, "/CS", (const byte *)"/DeviceCMYK", 11);
317
0
                        break;
318
0
                    case ccs_Gray:
319
0
                        code = cos_dict_put_c_key_string(group_dict, "/CS", (const byte *)"/DeviceGray", 11);
320
0
                        break;
321
0
                    case ccs_RGB:
322
0
                        code = cos_dict_put_c_key_string(group_dict, "/CS", (const byte *)"/DeviceRGB", 10);
323
0
                        break;
324
1.99k
                }
325
1.99k
                break;
326
1.99k
        }
327
1.99k
    }
328
6.39k
    if (code < 0)
329
0
        return code;
330
6.39k
    group_dict = NULL; /* The next line invalidates it. */
331
6.39k
    code = pdf_substitute_resource(pdev, &pres_group, resourceGroup, NULL, false);
332
6.39k
    if (code < 0)
333
0
        return code;
334
6.39k
    pres_group->where_used |= pdev->used_mask;
335
6.39k
    *pdict = (cos_dict_t *)pres_group->object;
336
6.39k
    return 0;
337
6.39k
}
338
339
static int
340
pdf_make_form_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
341
                            const gs_gstate * pgs,
342
                            const cos_dict_t *group_dict, cos_dict_t *form_dict)
343
2.87k
{
344
2.87k
    cos_array_t *bbox_array;
345
2.87k
    float bbox[4];
346
2.87k
    gs_rect bbox_rect;
347
2.87k
    int code;
348
349
2.87k
    code = gs_bbox_transform(&pparams->bbox, &ctm_only(pgs), &bbox_rect);
350
2.87k
    if (code < 0)
351
0
        return code;
352
2.87k
    bbox[0] = bbox_rect.p.x;
353
2.87k
    bbox[1] = bbox_rect.p.y;
354
2.87k
    bbox[2] = bbox_rect.q.x;
355
2.87k
    bbox[3] = bbox_rect.q.y;
356
2.87k
    code = cos_dict_put_c_key_string(form_dict, "/Type", (const byte *)"/XObject", 8);
357
2.87k
    if (code < 0)
358
0
        return code;
359
2.87k
    code = cos_dict_put_c_key_string(form_dict, "/Subtype", (const byte *)"/Form", 5);
360
2.87k
    if (code < 0)
361
0
        return code;
362
2.87k
    code = cos_dict_put_c_key_int(form_dict, "/FormType", 1);
363
2.87k
    if (code < 0)
364
0
        return code;
365
2.87k
    code = cos_dict_put_c_key_string(form_dict, "/Matrix", (const byte *)"[1 0 0 1 0 0]", 13);
366
2.87k
    if (code < 0)
367
0
        return code;
368
2.87k
    bbox_array = cos_array_from_floats(pdev, bbox, 4, "pdf_begin_transparency_group");
369
2.87k
    if (bbox_array == NULL)
370
0
        return_error(gs_error_VMerror);
371
2.87k
    code = cos_dict_put_c_key_object(form_dict, "/BBox", (cos_object_t *)bbox_array);
372
2.87k
    if (code < 0)
373
0
        return code;
374
2.87k
    if (pdev->PendingOC != 0) {
375
25
        if (pdev->CompatibilityLevel < 1.4999) {
376
0
            if (pdev->PDFA) {
377
0
                switch (pdev->PDFACompatibilityPolicy) {
378
0
                    case 0:
379
0
                        emprintf(pdev->memory,
380
0
                                 "Optional Content not valid in this version of PDF, reverting to normal PDF output\n");
381
0
                        pdev->AbortPDFAX = true;
382
0
                        pdev->PDFA = 0;
383
0
                        break;
384
0
                    case 1:
385
0
                        emprintf(pdev->memory,
386
0
                                 "Optional Content not valid in this version of PDF. Dropping feature to preserve PDF/A compatibility\n");
387
0
                        break;
388
0
                    case 2:
389
0
                        emprintf(pdev->memory,
390
0
                                 "Optional Content not valid in this version of PDF,  aborting conversion\n");
391
0
                        return_error (gs_error_typecheck);
392
0
                        break;
393
0
                    default:
394
0
                        emprintf(pdev->memory,
395
0
                                 "Optional Content not valid in this version of PDF, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
396
0
                        pdev->AbortPDFAX = true;
397
0
                        pdev->PDFA = 0;
398
0
                        break;
399
0
                }
400
0
            } else {
401
0
                emprintf(pdev->memory,
402
0
                         "Optional Content not valid in this version of PDF. Dropping feature to preserve compatibility\n");
403
0
            }
404
25
        } else {
405
25
            char str[256];
406
25
            gs_param_string param;
407
25
            cos_object_t *pco = NULL;
408
409
25
            param.data = (const byte *)pdev->PendingOC;
410
25
            param.size = strlen(pdev->PendingOC);
411
25
            code = pdf_refer_named(pdev, &param, &pco);
412
25
            if(code < 0)
413
0
                return code;
414
415
25
            gs_snprintf(str, sizeof(str), "%"PRId64" 0 R", pco->id);
416
25
            code = cos_dict_put_string_copy(form_dict, "/OC", str);
417
25
            if (code < 0)
418
0
                return code;
419
420
25
            gs_free_object(pdev->memory->non_gc_memory, pdev->PendingOC, "");
421
25
            pdev->PendingOC = NULL;
422
25
        }
423
25
    }
424
2.87k
    return cos_dict_put_c_key_object(form_dict, "/Group", (cos_object_t *)group_dict);
425
2.87k
}
426
427
static int
428
pdf_begin_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev,
429
                                const gs_pdf14trans_params_t * pparams, bool page_group)
430
6.39k
{
431
6.39k
    cos_dict_t *group_dict;
432
6.39k
    int code;
433
434
6.39k
    if (pgs == NULL)
435
0
        return_error(gs_error_unregistered); /* Must not happen. */
436
6.39k
    code = pdf_make_group_dict(pdev, pparams, pgs, &group_dict);
437
6.39k
    if (code < 0)
438
0
        return code;
439
6.39k
    code = pdf_open_page(pdev, PDF_IN_STREAM);
440
6.39k
    if (code < 0)
441
0
        return code;
442
6.39k
    code = pdf_check_soft_mask(pdev, pgs);
443
6.39k
    if (code < 0)
444
0
        return code;
445
6.39k
    if (pdf_must_put_clip_path(pdev, pgs->clip_path)) {
446
1.40k
        code = pdf_put_clip_path(pdev, pgs->clip_path);
447
1.40k
        if (code < 0)
448
0
            return code;
449
1.40k
    }
450
6.39k
    if (page_group)
451
556
        pdev->pages[pdev->next_page].group_id = group_dict->id;
452
5.83k
    else if (pparams->image_with_SMask) {
453
        /* An internal group for the image implementation.
454
           See doimagesmask in gs/lib/pdf_draw.ps .
455
           Just set a flag for skipping pdf_end_transparency_group. */
456
2.96k
        pdev->image_with_SMask |= 1 << ++pdev->FormDepth;
457
2.96k
        pdev->PatternsSinceForm = 0;
458
2.96k
    } else {
459
2.87k
        pdf_resource_t *pres, *pres_gstate = NULL;
460
2.87k
        cos_dict_t *pcd = NULL, *pcd_Resources = NULL;
461
462
2.87k
        code = pdf_prepare_drawing(pdev, pgs, &pres_gstate, false);
463
2.87k
        if (code < 0)
464
0
            return code;
465
2.87k
        code = pdf_end_gstate(pdev, pres_gstate);
466
2.87k
        if (code < 0)
467
0
            return code;
468
2.87k
        code = pdf_enter_substream(pdev, resourceXObject,
469
2.87k
                gs_no_id, &pres, false, pdev->params.CompressPages);
470
2.87k
        if (code < 0)
471
0
            return code;
472
2.87k
        pdev->FormDepth++;
473
2.87k
        pdev->PatternsSinceForm = 0;
474
2.87k
        code = pdf_make_form_dict(pdev, pparams, pgs, group_dict, (cos_dict_t *)pres->object);
475
2.87k
        if (code < 0)
476
0
            return code;
477
478
        /* Create a Resources dictionary and add it to the form dictionary */
479
2.87k
        pcd = cos_stream_dict((cos_stream_t *)pres->object);
480
2.87k
        pcd_Resources = cos_dict_alloc(pdev, "pdf_group(Resources)");
481
2.87k
        if (pcd == NULL || pcd_Resources == NULL)
482
0
            return_error(gs_error_VMerror);
483
2.87k
        code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
484
2.87k
        pdev->substream_Resources = pcd_Resources;
485
2.87k
        return code;
486
2.87k
    }
487
3.52k
    return 0;
488
6.39k
}
489
490
static int
491
pdf_end_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev)
492
6.19k
{
493
6.19k
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
494
495
6.19k
    if (!is_in_page(pdev) && pdev->sbstack_depth == 0)
496
0
        return 0; /* A Group definition at the page level, handled separately. */
497
6.19k
    if (pdev->image_with_SMask & (1 << pdev->FormDepth)) {
498
        /* An internal group for the image implementation.
499
           See pdf_begin_transparency_group. */
500
2.96k
        pdev->image_with_SMask &= ~(1 << pdev->FormDepth--);
501
2.96k
        pdev->PatternsSinceForm = 0;
502
2.96k
        return 0;
503
3.22k
    } else if (pdev->sbstack_depth == bottom) {
504
        /* We're closing the page group. */
505
556
        if (pdev->pages[pdev->next_page].group_id == 0)
506
0
            return_error(gs_error_unregistered); /* Must not happen. */
507
556
        return 0;
508
2.67k
    } else {
509
2.67k
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
510
2.67k
        int code;
511
2.67k
        uint ignore;
512
513
2.67k
        if (pres == NULL)
514
0
            return_error(gs_error_unregistered);
515
2.67k
        pdev->FormDepth--;
516
2.67k
        pdev->PatternsSinceForm = 0;
517
2.67k
        code = pdf_exit_substream(pdev);
518
2.67k
        if (code < 0)
519
0
            return code;
520
2.67k
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
521
2.67k
        if (code < 0)
522
0
            return code;
523
        /* We need to update the 'where_used' field, in case we substituted a resource */
524
2.67k
        pres->where_used |= pdev->used_mask;
525
2.67k
        sputc(pdev->strm,'/');
526
2.67k
        sputs(pdev->strm, (const byte *)pres->rname, strlen(pres->rname), &ignore);
527
2.67k
        sputs(pdev->strm, (const byte *)" Do\n", 4, &ignore);
528
2.67k
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres);
529
2.67k
        return code;
530
2.67k
    }
531
6.19k
}
532
533
static int
534
pdf_begin_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
535
                                const gs_pdf14trans_params_t * pparams)
536
3.17k
{
537
3.17k
    if (pparams->subtype == TRANSPARENCY_MASK_None) {
538
2.98k
        int code;
539
2.98k
        pdf_resource_t *pres = 0L;
540
541
        /* reset the soft mask ID. Apparently this is only used by pdfwrite, if we don't
542
         * reset it, then the pdf_prepare_drawing code doesn't know that the SMask has
543
         * changed, and so doesn't write out the GState
544
         */
545
2.98k
        pgs->soft_mask_id = 0;
546
2.98k
        code = pdf_prepare_drawing(pdev, pgs, &pres, false);
547
2.98k
        if (code == gs_error_interrupt) {
548
            /* */
549
            /* Not in an appropriate context.  Do not restore the soft_mask_id.
550
               Otherwise any group push that occurs following this will use that
551
               softmask, which clearly should be NONE here.
552
             */
553
            /* ignore return code, we don't care about this graphics state as we aren't
554
             * emitting it anyway
555
             */
556
521
            pdf_end_gstate(pdev, pres);
557
521
            return 0;
558
521
        }
559
2.45k
        if (code < 0)
560
0
            return code;
561
2.45k
        code = pdf_end_gstate(pdev, pres);
562
2.45k
        if (code < 0)
563
0
            return code;
564
2.45k
        return 0;
565
2.45k
    }
566
199
    if (pparams->mask_is_image) {
567
        /* HACK :
568
            The control comes here when
569
            the PDF interpreter will make the PS interpreter
570
            to interprete the mask for filling the transparency buffer
571
            with an SMask image.
572
            Since we handle Type 3 images as a high level objects,
573
            we don't install the transparency buffer here
574
            and need to skip the image enumeration for the SMask.
575
            However we have no right method for skipping
576
            an image enumeration due to possible side effect
577
            of the image data proc in Postscript language.
578
            Therefore we do enumerate the image mask and accumulate
579
            it as a PDF stream, but don't create a reference to it.
580
            Later it will be enumerated once again as a part of SMask-ed image,
581
            and the pdfwrite image handler will recognize duplicated images
582
            and won't create the second stream for same image.
583
584
            We could make a special workaround for
585
            skipping mask images either in the graphics library or
586
            in the PS code of the PDF interpreter,
587
            but we don't want to complicate things now.
588
            The performance leak for the second enumeration
589
            shouldn't be harmful.
590
591
            So now just set a flag for pdf_end_and_do_image.
592
        */
593
0
        pdev->image_mask_skip = true;
594
0
        return 0;
595
199
    } else {
596
199
        int code;
597
598
199
        pdev->smask_construction = true;
599
199
        code = pdf_make_soft_mask_dict(pdev, pparams);
600
199
        if (code < 0)
601
0
            return code;
602
199
        code = pdf_open_page(pdev, PDF_IN_STREAM);
603
199
        if (code < 0)
604
0
            return code;
605
199
        return pdf_begin_transparency_group(pgs, pdev, pparams, 0);
606
199
    }
607
199
}
608
609
static int
610
pdf_end_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
611
                                const gs_pdf14trans_params_t * pparams)
612
199
{
613
199
    pdev->smask_construction = false;
614
199
    if (pdev->image_mask_skip)
615
0
        pdev->image_mask_skip = false;
616
199
    else {
617
199
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
618
199
        int code;
619
199
        char buf[20];
620
621
199
        if (pres == NULL)
622
0
            return_error(gs_error_unregistered);
623
199
        code = pdf_exit_substream(pdev);
624
199
        if (code < 0)
625
0
            return code;
626
199
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
627
199
        if (code < 0)
628
0
            return 0;
629
        /* We need to update the 'where_used' field, in case we substituted a resource */
630
199
        pres->where_used |= pdev->used_mask;
631
199
        gs_snprintf(buf, sizeof(buf), "%"PRId64" 0 R", pdf_resource_id(pres));
632
199
        if (pdev->pres_soft_mask_dict == 0L) {
633
            /* something went horribly wrong, we have an 'end' wihtout a matching 'begin'
634
             * Give up, throw an error.
635
             */
636
0
            return_error(gs_error_undefined);
637
0
        }
638
199
        code = cos_dict_put_c_key_string((cos_dict_t *)pdev->pres_soft_mask_dict->object,
639
199
                "/G", (const byte *)buf, strlen(buf));
640
199
        if (code < 0)
641
0
            return code;
642
199
        code = pdf_substitute_resource(pdev, &pdev->pres_soft_mask_dict,
643
199
                                        resourceSoftMaskDict, NULL, false);
644
199
        if (code < 0)
645
0
            return code;
646
199
        pdev->pres_soft_mask_dict->where_used |= pdev->used_mask;
647
199
        pgs->soft_mask_id = pdev->pres_soft_mask_dict->object->id;
648
199
        pdev->pres_soft_mask_dict = NULL;
649
        /* We called pdf_start_trnasparency_group (see pdf_begin_transparency_mask
650
         * above) but we don't call pdf_end_transparency_group, so we must reduce
651
         * the FormDepth ourselves.
652
         */
653
199
        pdev->FormDepth--;
654
199
        pdev->PatternsSinceForm = 0;
655
199
    }
656
199
    return 0;
657
199
}
658
659
static int
660
pdf_set_blend_params(gs_gstate * pgs, gx_device_pdf * dev,
661
                                const gs_pdf14trans_params_t * pparams)
662
0
{
663
0
    return 0;
664
0
}
665
666
int
667
gdev_pdf_composite(gx_device *dev,
668
    gx_device **pcdev, const gs_composite_t *pct,
669
    gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
670
344k
{
671
344k
    gx_device_pdf *pdev = (gx_device_pdf *)dev;
672
673
344k
    if (pdev->HaveTransparency && pdev->CompatibilityLevel >= 1.4 &&
674
331k
            pct->type->comp_id == GX_COMPOSITOR_PDF14_TRANS &&
675
133k
            pdev->PDFA != 1) {
676
133k
        gs_pdf14trans_t *pcte = (gs_pdf14trans_t *)pct;
677
133k
        gs_pdf14trans_params_t *params = &pcte->params;
678
679
133k
        *pcdev = dev;
680
133k
        switch(params->pdf14_op) {
681
1.19k
            case PDF14_PUSH_DEVICE:
682
1.19k
                return 0;
683
1.19k
            case PDF14_POP_DEVICE:
684
1.19k
                return 0;
685
0
            case PDF14_ABORT_DEVICE:
686
0
                return 0;
687
556
            case PDF14_BEGIN_TRANS_PAGE_GROUP:
688
556
                return pdf_begin_transparency_group(pgs, pdev, params, 1);
689
5.64k
            case PDF14_BEGIN_TRANS_GROUP:
690
5.64k
                return pdf_begin_transparency_group(pgs, pdev, params, 0);
691
6.19k
            case PDF14_END_TRANS_GROUP:
692
6.19k
                return pdf_end_transparency_group(pgs, pdev);
693
56.5k
            case PDF14_BEGIN_TRANS_TEXT_GROUP:
694
56.5k
                return 0;
695
58.2k
            case PDF14_END_TRANS_TEXT_GROUP:
696
58.2k
                return 0;
697
3.17k
            case PDF14_BEGIN_TRANS_MASK:
698
3.17k
                return pdf_begin_transparency_mask(pgs, pdev, params);
699
199
            case PDF14_END_TRANS_MASK:
700
199
                return pdf_end_transparency_mask(pgs, pdev, params);
701
0
            case PDF14_SET_BLEND_PARAMS:
702
0
                return pdf_set_blend_params(pgs, pdev, params);
703
0
            case PDF14_PUSH_TRANS_STATE:
704
0
                return 0;
705
112
            case PDF14_POP_TRANS_STATE:
706
112
                return 0;
707
199
            case PDF14_PUSH_SMASK_COLOR:
708
199
                return 0;
709
199
            case PDF14_POP_SMASK_COLOR:
710
199
                return 0;
711
712
0
            default :
713
0
                return_error(gs_error_unregistered); /* Must not happen. */
714
133k
        }
715
0
        return 0;
716
133k
    }
717
211k
    return psdf_composite(dev, pcdev, pct, pgs, memory, cdev);
718
344k
}
719
720
/* We're not sure why the folllowing device methods are never called.
721
   Stub them for a while. */
722
723
int
724
gdev_pdf_begin_transparency_group(gx_device *dev,
725
    const gs_transparency_group_params_t *ptgp,
726
    const gs_rect *pbbox,
727
    gs_gstate *pgs, gs_memory_t *mem)
728
0
{
729
0
    return 0;
730
0
}
731
732
int
733
gdev_pdf_end_transparency_group(gx_device *dev,
734
    gs_gstate *pgs)
735
0
{
736
0
    return 0;
737
0
}
738
739
int
740
gdev_pdf_begin_transparency_mask(gx_device *dev,
741
    const gx_transparency_mask_params_t *ptmp,
742
    const gs_rect *pbbox,
743
    gs_gstate *pgs, gs_memory_t *mem)
744
0
{
745
0
    return 0;
746
0
}
747
748
int
749
gdev_pdf_end_transparency_mask(gx_device *dev,
750
    gs_gstate *pgs)
751
0
{
752
0
    return 0;
753
0
}