Coverage Report

Created: 2026-10-28 08:05

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