Coverage Report

Created: 2026-04-09 07:06

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
87
{
34
87
    pdf_resource_t *pres_soft_mask_dict = 0;
35
87
    cos_dict_t *soft_mask_dict;
36
87
    int code;
37
38
    /* Fixme : merge redundant objects. */
39
87
    code = pdf_alloc_resource(pdev, resourceSoftMaskDict, gs_no_id, &pres_soft_mask_dict, -1);
40
87
    if (code < 0)
41
0
        return code;
42
87
    cos_become(pres_soft_mask_dict->object, cos_type_dict);
43
87
    pdev->pres_soft_mask_dict = pres_soft_mask_dict;
44
87
    soft_mask_dict = (cos_dict_t *)pres_soft_mask_dict->object;
45
87
    code = cos_dict_put_c_key_string(soft_mask_dict, "/S",
46
87
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? (byte *)"/Alpha" : (byte *)"/Luminosity",
47
87
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? 6 : 11);
48
87
    if (code < 0)
49
0
        return code;
50
87
    if (pparams->Background_components) {
51
60
        cos_array_t *Background;
52
53
60
        Background = cos_array_from_floats(pdev, pparams->Background,
54
60
                    pparams->Background_components, "pdf_write_soft_mask_dict");
55
60
        if (Background == NULL)
56
0
            return_error(gs_error_VMerror);
57
60
        code = cos_dict_put_c_key_object(soft_mask_dict, "/BC", (cos_object_t *)Background);
58
60
        if (code < 0)
59
0
            return code;
60
60
    }
61
87
    if (pdev->CompatibilityLevel <= 1.7 && pparams->transfer_function != NULL && pdev->params.TransferFunctionInfo == tfi_Preserve) {
62
20
        int64_t id;
63
20
        char buf[20];
64
65
20
        code = pdf_write_function(pdev, pparams->transfer_function, &id);
66
20
        if (code < 0)
67
0
            return code;
68
20
        gs_snprintf(buf, sizeof(buf), " %"PRId64" 0 R", id);
69
20
        code = cos_dict_put_c_key_string(soft_mask_dict, "/TR", (const byte *)buf, strlen(buf));
70
20
        if (code < 0)
71
0
            return code;
72
20
    }
73
87
    return 0;
74
75
87
}
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
2.70k
{
248
2.70k
    pdf_resource_t *pres_group;
249
2.70k
    cos_dict_t *group_dict;
250
2.70k
    int code = 0;
251
2.70k
    cos_value_t cs_value;
252
253
2.70k
    code = pdf_alloc_resource(pdev, resourceGroup, gs_no_id, &pres_group, -1);
254
2.70k
    if (code < 0)
255
0
        return code;
256
2.70k
    cos_become(pres_group->object, cos_type_dict);
257
2.70k
    group_dict = (cos_dict_t *)pres_group->object;
258
2.70k
    code = cos_dict_put_c_key_string(group_dict, "/Type", (const byte *)"/Group", 6);
259
2.70k
    if (code < 0)
260
0
        return code;
261
2.70k
    code = cos_dict_put_c_key_string(group_dict, "/S", (const byte *)"/Transparency", 13);
262
2.70k
    if (code < 0)
263
0
        return code;
264
2.70k
    if (pparams->Isolated) {
265
2.01k
        code = cos_dict_put_c_key_bool(group_dict, "/I", true);
266
2.01k
        if (code < 0)
267
0
            return code;
268
2.01k
    }
269
2.70k
    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
2.70k
    if (pgs != NULL && pparams->ColorSpace != NULL) {
280
579
        const gs_color_space *cs = pparams->ColorSpace;
281
282
579
        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
579
        else
286
579
            code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, pparams->ColorSpace,
287
579
                    &pdf_color_space_names, false, NULL, 0, false);
288
579
        if (code < 0)
289
0
            return code;
290
579
        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
579
            case bcs_Simple:
304
579
                switch(pdev->params.ColorConversionStrategy) {
305
579
                    case ccs_LeaveColorUnchanged:
306
579
                        code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
307
579
                        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
579
                }
325
579
                break;
326
579
        }
327
579
    }
328
2.70k
    if (code < 0)
329
0
        return code;
330
2.70k
    group_dict = NULL; /* The next line invalidates it. */
331
2.70k
    code = pdf_substitute_resource(pdev, &pres_group, resourceGroup, NULL, false);
332
2.70k
    if (code < 0)
333
0
        return code;
334
2.70k
    pres_group->where_used |= pdev->used_mask;
335
2.70k
    *pdict = (cos_dict_t *)pres_group->object;
336
2.70k
    return 0;
337
2.70k
}
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
1.14k
{
344
1.14k
    cos_array_t *bbox_array;
345
1.14k
    float bbox[4];
346
1.14k
    gs_rect bbox_rect;
347
1.14k
    int code;
348
349
1.14k
    code = gs_bbox_transform(&pparams->bbox, &ctm_only(pgs), &bbox_rect);
350
1.14k
    if (code < 0)
351
0
        return code;
352
1.14k
    bbox[0] = bbox_rect.p.x;
353
1.14k
    bbox[1] = bbox_rect.p.y;
354
1.14k
    bbox[2] = bbox_rect.q.x;
355
1.14k
    bbox[3] = bbox_rect.q.y;
356
1.14k
    code = cos_dict_put_c_key_string(form_dict, "/Type", (const byte *)"/XObject", 8);
357
1.14k
    if (code < 0)
358
0
        return code;
359
1.14k
    code = cos_dict_put_c_key_string(form_dict, "/Subtype", (const byte *)"/Form", 5);
360
1.14k
    if (code < 0)
361
0
        return code;
362
1.14k
    code = cos_dict_put_c_key_int(form_dict, "/FormType", 1);
363
1.14k
    if (code < 0)
364
0
        return code;
365
1.14k
    code = cos_dict_put_c_key_string(form_dict, "/Matrix", (const byte *)"[1 0 0 1 0 0]", 13);
366
1.14k
    if (code < 0)
367
0
        return code;
368
1.14k
    bbox_array = cos_array_from_floats(pdev, bbox, 4, "pdf_begin_transparency_group");
369
1.14k
    if (bbox_array == NULL)
370
0
        return_error(gs_error_VMerror);
371
1.14k
    code = cos_dict_put_c_key_object(form_dict, "/BBox", (cos_object_t *)bbox_array);
372
1.14k
    if (code < 0)
373
0
        return code;
374
1.14k
    if (pdev->PendingOC != 0) {
375
1
        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
1
        } else {
405
1
            char str[256];
406
1
            gs_param_string param;
407
1
            cos_object_t *pco = NULL;
408
409
1
            param.data = (const byte *)pdev->PendingOC;
410
1
            param.size = strlen(pdev->PendingOC);
411
1
            code = pdf_refer_named(pdev, &param, &pco);
412
1
            if(code < 0)
413
0
                return code;
414
415
1
            gs_snprintf(str, sizeof(str), "%"PRId64" 0 R", pco->id);
416
1
            code = cos_dict_put_string_copy(form_dict, "/OC", str);
417
1
            if (code < 0)
418
0
                return code;
419
420
1
            gs_free_object(pdev->memory->non_gc_memory, pdev->PendingOC, "");
421
1
            pdev->PendingOC = NULL;
422
1
        }
423
1
    }
424
1.14k
    return cos_dict_put_c_key_object(form_dict, "/Group", (cos_object_t *)group_dict);
425
1.14k
}
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
2.70k
{
431
2.70k
    cos_dict_t *group_dict;
432
2.70k
    int code;
433
434
2.70k
    if (pgs == NULL)
435
0
        return_error(gs_error_unregistered); /* Must not happen. */
436
2.70k
    code = pdf_make_group_dict(pdev, pparams, pgs, &group_dict);
437
2.70k
    if (code < 0)
438
0
        return code;
439
2.70k
    code = pdf_open_page(pdev, PDF_IN_STREAM);
440
2.70k
    if (code < 0)
441
0
        return code;
442
2.70k
    code = pdf_check_soft_mask(pdev, pgs);
443
2.70k
    if (code < 0)
444
0
        return code;
445
2.70k
    if (pdf_must_put_clip_path(pdev, pgs->clip_path)) {
446
313
        code = pdf_put_clip_path(pdev, pgs->clip_path);
447
313
        if (code < 0)
448
0
            return code;
449
313
    }
450
2.70k
    if (page_group)
451
255
        pdev->pages[pdev->next_page].group_id = group_dict->id;
452
2.44k
    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
1.30k
        pdev->image_with_SMask |= 1 << ++pdev->FormDepth;
457
1.30k
        pdev->PatternsSinceForm = 0;
458
1.30k
    } else {
459
1.14k
        pdf_resource_t *pres, *pres_gstate = NULL;
460
1.14k
        cos_dict_t *pcd = NULL, *pcd_Resources = NULL;
461
462
1.14k
        code = pdf_prepare_drawing(pdev, pgs, &pres_gstate, false);
463
1.14k
        if (code < 0)
464
0
            return code;
465
1.14k
        code = pdf_end_gstate(pdev, pres_gstate);
466
1.14k
        if (code < 0)
467
0
            return code;
468
1.14k
        code = pdf_enter_substream(pdev, resourceXObject,
469
1.14k
                gs_no_id, &pres, false, pdev->params.CompressPages);
470
1.14k
        if (code < 0)
471
0
            return code;
472
1.14k
        pdev->FormDepth++;
473
1.14k
        pdev->PatternsSinceForm = 0;
474
1.14k
        code = pdf_make_form_dict(pdev, pparams, pgs, group_dict, (cos_dict_t *)pres->object);
475
1.14k
        if (code < 0)
476
0
            return code;
477
478
        /* Create a Resources dictionary and add it to the form dictionary */
479
1.14k
        pcd = cos_stream_dict((cos_stream_t *)pres->object);
480
1.14k
        pcd_Resources = cos_dict_alloc(pdev, "pdf_group(Resources)");
481
1.14k
        if (pcd == NULL || pcd_Resources == NULL)
482
0
            return_error(gs_error_VMerror);
483
1.14k
        code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
484
1.14k
        pdev->substream_Resources = pcd_Resources;
485
1.14k
        return code;
486
1.14k
    }
487
1.56k
    return 0;
488
2.70k
}
489
490
static int
491
pdf_end_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev)
492
2.61k
{
493
2.61k
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
494
495
2.61k
    if (!is_in_page(pdev) && pdev->sbstack_depth == 0)
496
0
        return 0; /* A Group definition at the page level, handled separately. */
497
2.61k
    if (pdev->image_with_SMask & (1 << pdev->FormDepth)) {
498
        /* An internal group for the image implementation.
499
           See pdf_begin_transparency_group. */
500
1.30k
        pdev->image_with_SMask &= ~(1 << pdev->FormDepth--);
501
1.30k
        pdev->PatternsSinceForm = 0;
502
1.30k
        return 0;
503
1.30k
    } else if (pdev->sbstack_depth == bottom) {
504
        /* We're closing the page group. */
505
255
        if (pdev->pages[pdev->next_page].group_id == 0)
506
0
            return_error(gs_error_unregistered); /* Must not happen. */
507
255
        return 0;
508
1.05k
    } else {
509
1.05k
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
510
1.05k
        int code;
511
1.05k
        uint ignore;
512
513
1.05k
        if (pres == NULL)
514
0
            return_error(gs_error_unregistered);
515
1.05k
        pdev->FormDepth--;
516
1.05k
        pdev->PatternsSinceForm = 0;
517
1.05k
        code = pdf_exit_substream(pdev);
518
1.05k
        if (code < 0)
519
0
            return code;
520
1.05k
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
521
1.05k
        if (code < 0)
522
0
            return code;
523
        /* We need to update the 'where_used' field, in case we substituted a resource */
524
1.05k
        pres->where_used |= pdev->used_mask;
525
1.05k
        sputc(pdev->strm,'/');
526
1.05k
        sputs(pdev->strm, (const byte *)pres->rname, strlen(pres->rname), &ignore);
527
1.05k
        sputs(pdev->strm, (const byte *)" Do\n", 4, &ignore);
528
1.05k
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres);
529
1.05k
        return code;
530
1.05k
    }
531
2.61k
}
532
533
static int
534
pdf_begin_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
535
                                const gs_pdf14trans_params_t * pparams)
536
2.00k
{
537
2.00k
    if (pparams->subtype == TRANSPARENCY_MASK_None) {
538
1.92k
        int code;
539
1.92k
        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
1.92k
        pgs->soft_mask_id = 0;
546
1.92k
        code = pdf_prepare_drawing(pdev, pgs, &pres, false);
547
1.92k
        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
358
            pdf_end_gstate(pdev, pres);
557
358
            return 0;
558
358
        }
559
1.56k
        if (code < 0)
560
0
            return code;
561
1.56k
        code = pdf_end_gstate(pdev, pres);
562
1.56k
        if (code < 0)
563
0
            return code;
564
1.56k
        return 0;
565
1.56k
    }
566
87
    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
87
    } else {
596
87
        int code;
597
598
87
        pdev->smask_construction = true;
599
87
        code = pdf_make_soft_mask_dict(pdev, pparams);
600
87
        if (code < 0)
601
0
            return code;
602
87
        code = pdf_open_page(pdev, PDF_IN_STREAM);
603
87
        if (code < 0)
604
0
            return code;
605
87
        return pdf_begin_transparency_group(pgs, pdev, pparams, 0);
606
87
    }
607
87
}
608
609
static int
610
pdf_end_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
611
                                const gs_pdf14trans_params_t * pparams)
612
87
{
613
87
    pdev->smask_construction = false;
614
87
    if (pdev->image_mask_skip)
615
0
        pdev->image_mask_skip = false;
616
87
    else {
617
87
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
618
87
        int code;
619
87
        char buf[20];
620
621
87
        if (pres == NULL)
622
0
            return_error(gs_error_unregistered);
623
87
        code = pdf_exit_substream(pdev);
624
87
        if (code < 0)
625
0
            return code;
626
87
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
627
87
        if (code < 0)
628
0
            return 0;
629
        /* We need to update the 'where_used' field, in case we substituted a resource */
630
87
        pres->where_used |= pdev->used_mask;
631
87
        gs_snprintf(buf, sizeof(buf), "%"PRId64" 0 R", pdf_resource_id(pres));
632
87
        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
87
        code = cos_dict_put_c_key_string((cos_dict_t *)pdev->pres_soft_mask_dict->object,
639
87
                "/G", (const byte *)buf, strlen(buf));
640
87
        if (code < 0)
641
0
            return code;
642
87
        code = pdf_substitute_resource(pdev, &pdev->pres_soft_mask_dict,
643
87
                                        resourceSoftMaskDict, NULL, false);
644
87
        if (code < 0)
645
0
            return code;
646
87
        pdev->pres_soft_mask_dict->where_used |= pdev->used_mask;
647
87
        pgs->soft_mask_id = pdev->pres_soft_mask_dict->object->id;
648
87
        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
87
        pdev->FormDepth--;
654
87
        pdev->PatternsSinceForm = 0;
655
87
    }
656
87
    return 0;
657
87
}
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
178k
{
671
178k
    gx_device_pdf *pdev = (gx_device_pdf *)dev;
672
673
178k
    if (pdev->HaveTransparency && pdev->CompatibilityLevel >= 1.4 &&
674
165k
            pct->type->comp_id == GX_COMPOSITOR_PDF14_TRANS &&
675
29.2k
            pdev->PDFA != 1) {
676
29.2k
        gs_pdf14trans_t *pcte = (gs_pdf14trans_t *)pct;
677
29.2k
        gs_pdf14trans_params_t *params = &pcte->params;
678
679
29.2k
        *pcdev = dev;
680
29.2k
        switch(params->pdf14_op) {
681
451
            case PDF14_PUSH_DEVICE:
682
451
                return 0;
683
451
            case PDF14_POP_DEVICE:
684
451
                return 0;
685
0
            case PDF14_ABORT_DEVICE:
686
0
                return 0;
687
255
            case PDF14_BEGIN_TRANS_PAGE_GROUP:
688
255
                return pdf_begin_transparency_group(pgs, pdev, params, 1);
689
2.36k
            case PDF14_BEGIN_TRANS_GROUP:
690
2.36k
                return pdf_begin_transparency_group(pgs, pdev, params, 0);
691
2.61k
            case PDF14_END_TRANS_GROUP:
692
2.61k
                return pdf_end_transparency_group(pgs, pdev);
693
9.28k
            case PDF14_BEGIN_TRANS_TEXT_GROUP:
694
9.28k
                return 0;
695
11.4k
            case PDF14_END_TRANS_TEXT_GROUP:
696
11.4k
                return 0;
697
2.00k
            case PDF14_BEGIN_TRANS_MASK:
698
2.00k
                return pdf_begin_transparency_mask(pgs, pdev, params);
699
87
            case PDF14_END_TRANS_MASK:
700
87
                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
46
            case PDF14_POP_TRANS_STATE:
706
46
                return 0;
707
87
            case PDF14_PUSH_SMASK_COLOR:
708
87
                return 0;
709
87
            case PDF14_POP_SMASK_COLOR:
710
87
                return 0;
711
712
0
            default :
713
0
                return_error(gs_error_unregistered); /* Must not happen. */
714
29.2k
        }
715
0
        return 0;
716
29.2k
    }
717
148k
    return psdf_composite(dev, pcdev, pct, pgs, memory, cdev);
718
178k
}
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
}