Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gscdevn.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
/* DeviceN color space and operation definition */
18
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gscdevn.h"
24
#include "gsfunc.h"
25
#include "gsrefct.h"
26
#include "gsmatrix.h"   /* for gscolor2.h */
27
#include "gsstruct.h"
28
#include "gxcspace.h"
29
#include "gxcdevn.h"
30
#include "gxfarith.h"
31
#include "gxfrac.h"
32
#include "gxcmap.h"
33
#include "gxgstate.h"
34
#include "gscoord.h"
35
#include "gzstate.h"
36
#include "gxdevcli.h"
37
#include "gsovrc.h"
38
#include "stream.h"
39
#include "gsnamecl.h"  /* Custom color call back define */
40
#include "gsicc_manage.h"
41
#include "gsicc.h"
42
#include "gsicc_cache.h"
43
#include "gxdevice.h"
44
#include "gxcie.h"
45
#include "gxdevsop.h"
46
47
/* ---------------- Color space ---------------- */
48
49
/* GC descriptors */
50
gs_private_st_composite(st_color_space_DeviceN, gs_color_space,
51
     "gs_color_space_DeviceN", cs_DeviceN_enum_ptrs, cs_DeviceN_reloc_ptrs);
52
private_st_device_n_colorant();
53
private_st_device_n_map();
54
55
/* Define the DeviceN color space type. */
56
static cs_proc_num_components(gx_num_components_DeviceN);
57
static cs_proc_init_color(gx_init_DeviceN);
58
static cs_proc_restrict_color(gx_restrict_DeviceN);
59
static cs_proc_concrete_space(gx_concrete_space_DeviceN);
60
static cs_proc_concretize_color(gx_concretize_DeviceN);
61
static cs_proc_remap_concrete_color(gx_remap_concrete_DeviceN);
62
static cs_proc_remap_color(gx_remap_DeviceN);
63
static cs_proc_install_cspace(gx_install_DeviceN);
64
static cs_proc_set_overprint(gx_set_overprint_DeviceN);
65
static cs_proc_final(gx_final_DeviceN);
66
static cs_proc_serialize(gx_serialize_DeviceN);
67
static cs_proc_polarity(gx_polarity_DeviceN);
68
69
const gs_color_space_type gs_color_space_type_DeviceN = {
70
    gs_color_space_index_DeviceN, true, false,
71
    &st_color_space_DeviceN, gx_num_components_DeviceN,
72
    gx_init_DeviceN, gx_restrict_DeviceN,
73
    gx_concrete_space_DeviceN,
74
    gx_concretize_DeviceN, gx_remap_concrete_DeviceN,
75
    gx_remap_DeviceN, gx_install_DeviceN,
76
    gx_set_overprint_DeviceN,
77
    gx_final_DeviceN, gx_no_adjust_color_count,
78
    gx_serialize_DeviceN,
79
    gx_cspace_is_linear_default, gx_polarity_DeviceN
80
};
81
82
/* GC procedures */
83
84
static
85
0
ENUM_PTRS_BEGIN(cs_DeviceN_enum_ptrs)
86
0
    return 0;
87
0
ENUM_PTR(0, gs_color_space, params.device_n.map);
88
0
ENUM_PTR(1, gs_color_space, params.device_n.colorants);
89
0
ENUM_PTRS_END
90
0
static RELOC_PTRS_BEGIN(cs_DeviceN_reloc_ptrs)
91
0
{
92
0
    RELOC_PTR(gs_color_space, params.device_n.map);
93
0
    RELOC_PTR(gs_color_space, params.device_n.colorants);
94
0
}
95
0
RELOC_PTRS_END
96
97
/* ------ Public procedures ------ */
98
99
/*
100
 * Create a new DeviceN colorspace.
101
 */
102
int
103
gs_cspace_new_DeviceN(
104
    gs_color_space **ppcs,
105
    uint num_components,
106
    gs_color_space *palt_cspace,
107
    gs_memory_t *pmem
108
    )
109
4.74k
{
110
4.74k
    gs_color_space *pcs;
111
4.74k
    gs_device_n_params *pcsdevn;
112
4.74k
    char **pnames;
113
4.74k
    int i, code;
114
115
4.74k
    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
116
0
        return_error(gs_error_rangecheck);
117
118
4.74k
    pcs = gs_cspace_alloc(pmem, &gs_color_space_type_DeviceN);
119
4.74k
    if (pcs == NULL)
120
0
        return_error(gs_error_VMerror);
121
4.74k
    pcsdevn = &pcs->params.device_n;
122
4.74k
    pcsdevn->names = NULL;
123
4.74k
    pcsdevn->map = NULL;
124
4.74k
    pcsdevn->colorants = NULL;
125
4.74k
    pcsdevn->named_color_supported = false;
126
4.74k
    pcsdevn->num_process_names = 0;
127
4.74k
    pcsdevn->process_names = NULL;
128
4.74k
    pcsdevn->mem = pmem->non_gc_memory;
129
4.74k
    pcsdevn->all_none = false;
130
131
    /* Allocate space for color names list. */
132
4.74k
    code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
133
4.74k
    if (code < 0) {
134
0
        gs_free_object(pmem, pcs, "gs_cspace_new_DeviceN");
135
0
        return code;
136
0
    }
137
4.74k
    pnames = (char **)gs_alloc_bytes(pcsdevn->mem, (size_t)num_components * sizeof(char *), "gs_cspace_new_DeviceN");
138
4.74k
    if (pnames == 0) {
139
0
        gs_free_object(pmem, pcsdevn->map, ".gs_cspace_build_DeviceN(map)");
140
0
        gs_free_object(pmem, pcs, "gs_cspace_new_DeviceN");
141
0
        return_error(gs_error_VMerror);
142
0
    }
143
11.4k
    for (i=0; i<num_components; i++)
144
6.75k
        pnames[i] = NULL;   /* empty string for check_DeviceN_component_names */
145
4.74k
    pcs->base_space = palt_cspace;
146
4.74k
    rc_increment_cs(palt_cspace);
147
4.74k
    pcsdevn->names = pnames;
148
4.74k
    pcsdevn->num_components = num_components;
149
4.74k
    *ppcs = pcs;
150
4.74k
    return 0;
151
4.74k
}
152
153
/* Allocate and initialize a DeviceN map. */
154
int
155
alloc_device_n_map(gs_device_n_map ** ppmap, gs_memory_t * mem,
156
                   client_name_t cname)
157
39.7k
{
158
39.7k
    gs_device_n_map *pimap;
159
160
39.7k
    rc_alloc_struct_1(pimap, gs_device_n_map, &st_device_n_map, mem,
161
39.7k
                      return_error(gs_error_VMerror), cname);
162
39.7k
    pimap->tint_transform = 0;
163
39.7k
    pimap->tint_transform_data = 0;
164
39.7k
    pimap->cache_valid = false;
165
39.7k
    *ppmap = pimap;
166
39.7k
    return 0;
167
39.7k
}
168
169
/*
170
 * DeviceN and NChannel color spaces can have an attributes dict.  In the
171
 * attribute dict can be a Colorants dict which contains Separation color
172
 * spaces.  If the Colorant dict is present, the PS logic will build each of
173
 * the Separation color spaces in a temp gstate and then call this procedure
174
 * to attach the Separation color space to the DeviceN color space.
175
 * The parameter to this procedure is a colorant name.  The Separation
176
 * color space is in the current (temp) gstate.  The DeviceN color space is
177
 * in the next gstate down in the gstate list (pgs->saved).
178
 */
179
int
180
gs_attachcolorant(char *sep_name, gs_gstate * pgs)
181
0
{
182
0
    gs_color_space * pdevncs;
183
0
    gs_device_n_colorant * patt;
184
185
    /* Verify that we have a DeviceN color space */
186
0
    if (!pgs->saved)
187
0
        return_error(gs_error_rangecheck);
188
0
    pdevncs = gs_currentcolorspace_inline(pgs->saved);
189
0
    if (pdevncs->type != &gs_color_space_type_DeviceN)
190
0
        return_error(gs_error_rangecheck);
191
192
    /* Allocate an attribute list element for our linked list of colorants */
193
0
    rc_alloc_struct_1(patt, gs_device_n_colorant, &st_device_n_colorant,
194
0
                        pgs->memory, return_error(gs_error_VMerror),
195
0
                        "gs_attachattributrescolorspace");
196
197
    /* Point our attribute list entry to the attribute color space */
198
0
    patt->colorant_name = sep_name;
199
0
    patt->cspace = gs_currentcolorspace_inline(pgs);
200
0
    rc_increment_cs(patt->cspace);
201
202
    /* Link our new attribute color space to the DeviceN color space */
203
0
    patt->next = pdevncs->params.device_n.colorants;
204
0
    pdevncs->params.device_n.colorants = patt;
205
206
0
    return 0;
207
0
}
208
209
int
210
gs_attach_colorant_to_space(char *sep_name, gs_color_space *pcs, gs_color_space *colorant_space, gs_memory_t *mem)
211
0
{
212
0
    gs_device_n_colorant * patt;
213
214
0
    if (pcs->type != &gs_color_space_type_DeviceN)
215
0
        return_error(gs_error_rangecheck);
216
217
    /* Allocate an attribute list element for our linked list of colorants */
218
0
    rc_alloc_struct_1(patt, gs_device_n_colorant, &st_device_n_colorant,
219
0
                        mem, return_error(gs_error_VMerror),
220
0
                        "gs_attachattributrescolorspace");
221
222
    /* Point our attribute list entry to the attribute color space */
223
0
    patt->colorant_name = sep_name;
224
0
    patt->cspace = colorant_space;
225
0
    rc_increment_cs(patt->cspace);
226
227
    /* Link our new attribute color space to the DeviceN color space */
228
0
    patt->next = pcs->params.device_n.colorants;
229
0
    pcs->params.device_n.colorants = patt;
230
231
0
    return 0;
232
0
}
233
234
#if 0 /* Unused; Unsupported by gx_serialize_device_n_map. */
235
/*
236
 * Set the DeviceN tint transformation procedure.
237
 */
238
int
239
gs_cspace_set_devn_proc(gs_color_space * pcspace,
240
                        int (*proc)(const float *,
241
                                    float *,
242
                                    const gs_gstate *,
243
                                    void *
244
                                    ),
245
                        void *proc_data
246
                        )
247
{
248
    gs_device_n_map *pimap;
249
250
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN)
251
        return_error(gs_error_rangecheck);
252
    pimap = pcspace->params.device_n.map;
253
    pimap->tint_transform = proc;
254
    pimap->tint_transform_data = proc_data;
255
    pimap->cache_valid = false;
256
    return 0;
257
}
258
#endif
259
260
/*
261
 * Check if we are using the alternate color space.
262
 */
263
bool
264
using_alt_color_space(const gs_gstate * pgs)
265
42.8k
{
266
42.8k
    return (pgs->color_component_map.use_alt_cspace);
267
42.8k
}
268
269
/* Map a DeviceN color using a Function. */
270
int
271
map_devn_using_function(const float *in, float *out,
272
                        const gs_gstate *pgs, void *data)
273
274
5.53M
{
275
5.53M
    gs_function_t *const pfn = data;
276
277
5.53M
    return gs_function_evaluate(pfn, in, out);
278
5.53M
}
279
280
/*
281
 * Set the DeviceN tint transformation procedure to a Function.
282
 */
283
int
284
gs_cspace_set_devn_function(gs_color_space *pcspace, gs_function_t *pfn)
285
4.71k
{
286
4.71k
    gs_device_n_map *pimap;
287
288
4.71k
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN ||
289
4.71k
        pfn->params.m != pcspace->params.device_n.num_components ||
290
4.71k
        pfn->params.n != gs_color_space_num_components(pcspace->base_space)
291
4.71k
        )
292
0
        return_error(gs_error_rangecheck);
293
4.71k
    pimap = pcspace->params.device_n.map;
294
4.71k
    pimap->tint_transform = map_devn_using_function;
295
4.71k
    pimap->tint_transform_data = pfn;
296
4.71k
    pimap->cache_valid = false;
297
4.71k
    return 0;
298
4.71k
}
299
300
/*
301
 * If the DeviceN tint transformation procedure is a Function,
302
 * return the function object, otherwise return 0.
303
 */
304
gs_function_t *
305
gs_cspace_get_devn_function(const gs_color_space *pcspace)
306
4.74k
{
307
4.74k
    if (gs_color_space_get_index(pcspace) == gs_color_space_index_DeviceN &&
308
4.74k
        pcspace->params.device_n.map->tint_transform ==
309
4.74k
          map_devn_using_function)
310
4.74k
        return pcspace->params.device_n.map->tint_transform_data;
311
0
    return 0;
312
4.74k
}
313
314
/* ------ Color space implementation ------ */
315
316
/* Return the number of components of a DeviceN space. */
317
static int
318
gx_num_components_DeviceN(const gs_color_space * pcs)
319
7.31M
{
320
7.31M
    return pcs->params.device_n.num_components;
321
7.31M
}
322
323
/* Determine best guess of polarity */
324
static gx_color_polarity_t
325
gx_polarity_DeviceN(const gs_color_space * pcs)
326
0
{
327
    /* DeviceN initializes to 1.0 like a separation so
328
       for now, treat this as subtractive.  It is possible
329
       that we may have to do a special test for Red, Green
330
       and Blue but for now, I believe the following is
331
       correct */
332
0
    return GX_CINFO_POLARITY_SUBTRACTIVE;
333
0
}
334
335
/* Initialize a DeviceN color. */
336
static void
337
gx_init_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
338
20.0k
{
339
20.0k
    uint i;
340
341
65.6k
    for (i = 0; i < pcs->params.device_n.num_components; ++i)
342
45.6k
        pcc->paint.values[i] = 1.0;
343
20.0k
}
344
345
/* Force a DeviceN color into legal range. */
346
static void
347
gx_restrict_DeviceN(gs_client_color * pcc, const gs_color_space * pcs)
348
1.21M
{
349
1.21M
    uint i;
350
351
2.84M
    for (i = 0; i < pcs->params.device_n.num_components; ++i) {
352
1.63M
        double value = pcc->paint.values[i];
353
1.63M
        pcc->paint.values[i] = (value <= 0 ? 0 : value >= 1 ? 1 : value);
354
1.63M
    }
355
1.21M
}
356
357
/* Remap a DeviceN color. */
358
static const gs_color_space *
359
gx_concrete_space_DeviceN(const gs_color_space * pcs,
360
                          const gs_gstate * pgs)
361
7.04M
{
362
7.04M
    bool is_lab = false;
363
#ifdef DEBUG
364
    /*
365
     * Verify that the color space and gs_gstate info match.
366
     */
367
    if (pcs->id != pgs->color_component_map.cspace_id)
368
        dmprintf(pgs->memory, "gx_concrete_space_DeviceN: color space id mismatch");
369
#endif
370
    /*
371
     * Check if we are using the alternate color space.
372
     */
373
7.04M
    if (pgs->color_component_map.use_alt_cspace) {
374
        /* Need to handle PS CIE space */
375
5.38M
        if (gs_color_space_is_PSCIE(pcs->base_space)) {
376
0
            if (pcs->base_space->icc_equivalent == NULL) {
377
0
                (void)gs_colorspace_set_icc_equivalent(pcs->base_space,
378
0
                                                    &is_lab, pgs->memory);
379
0
            }
380
0
            return (pcs->base_space->icc_equivalent);
381
0
        }
382
5.38M
        return cs_concrete_space(pcs->base_space, pgs);
383
5.38M
    }
384
    /*
385
     * DeviceN color spaces are concrete (when not using alt. color space).
386
     */
387
1.65M
    return pcs;
388
7.04M
}
389
390
static int
391
gx_remap_DeviceN(const gs_client_color * pcc, const gs_color_space * pcs,
392
        gx_device_color * pdc, const gs_gstate * pgs, gx_device * dev,
393
                       gs_color_select_t select)
394
4.77M
{
395
4.77M
    frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
396
4.77M
    const gs_color_space *pconcs;
397
4.77M
    int i = pcs->type->num_components(pcs),k;
398
4.77M
    int code = 0;
399
4.77M
    const gs_color_space *pacs = pcs->base_space;
400
4.77M
    gs_client_color temp;
401
4.77M
    bool mapped = false;
402
403
4.77M
    if ( pcs->cmm_icc_profile_data != NULL && pgs->color_component_map.use_alt_cspace) {
404
        /* This is the case where we have placed a N-CLR source profile for
405
           this color space */
406
0
        if (pcs->cmm_icc_profile_data->devicen_permute_needed) {
407
0
            for ( k = 0; k < i; k++) {
408
0
                temp.paint.values[k] = pcc->paint.values[pcs->cmm_icc_profile_data->devicen_permute[k]];
409
0
            }
410
0
            code = pacs->type->remap_color(&temp, pacs, pdc, pgs, dev, select);
411
0
        } else {
412
0
            code = pacs->type->remap_color(pcc, pacs, pdc, pgs, dev, select);
413
0
        }
414
0
        return(code);
415
4.77M
    } else {
416
        /* Check if we are doing any named color management.  This check happens
417
           regardless if we are doing the alternate tint transform or not.  If
418
           desired, that check could be made in gsicc_transform_named_color and
419
           a decision made to return true or false */
420
4.77M
        if (pgs->icc_manager->device_named != NULL) {
421
            /* Try to apply the direct replacement */
422
0
            mapped = gx_remap_named_color(pcc, pcs, pdc, pgs, dev, select);
423
0
        }
424
4.77M
        if (!mapped) {
425
4.77M
            cmm_dev_profile_t *dev_profile;
426
4.77M
            code = dev_proc(dev, get_profile)(dev, &dev_profile);
427
4.77M
            if (code < 0)
428
0
                return code;
429
4.77M
            code = (*pcs->type->concretize_color)(pcc, pcs, conc, pgs, dev);
430
4.77M
            if (code < 0)
431
107
                return code;
432
4.77M
            pconcs = cs_concrete_space(pcs, pgs);
433
4.77M
            code = (*pconcs->type->remap_concrete_color)(pconcs, conc, pdc, pgs, dev, select, dev_profile);
434
4.77M
        }
435
        /* Save original color space and color info into dev color */
436
4.77M
        i = any_abs(i);
437
16.6M
        for (i--; i >= 0; i--)
438
11.9M
            pdc->ccolor.paint.values[i] = pcc->paint.values[i];
439
4.77M
        pdc->ccolor_valid = true;
440
4.77M
        return code;
441
4.77M
    }
442
4.77M
}
443
444
static int
445
gx_concretize_DeviceN(const gs_client_color * pc, const gs_color_space * pcs,
446
                      frac * pconc, const gs_gstate * pgs, gx_device *dev)
447
7.04M
{
448
7.04M
    int code, tcode = 0;
449
7.04M
    gs_client_color cc;
450
7.04M
    gs_color_space *pacs = (gs_color_space*) (pcs->base_space);
451
7.04M
    gs_device_n_map *map = pcs->params.device_n.map;
452
7.04M
    bool is_lab;
453
7.04M
    int num_src_comps = pcs->params.device_n.num_components;
454
455
#ifdef DEBUG
456
    /*
457
     * Verify that the color space and gs_gstate info match.
458
     */
459
    if (pcs->id != pgs->color_component_map.cspace_id)
460
        dmprintf(dev->memory, "gx_concretize_DeviceN: color space id mismatch");
461
#endif
462
463
    /*
464
     * Check if we need to map into the alternate color space.
465
     * We must preserve tcode for implementing a semi-hack in the interpreter.
466
     */
467
468
7.04M
    if (pgs->color_component_map.use_alt_cspace) {
469
        /* Check the 1-element cache first. */
470
5.38M
        if (map->cache_valid) {
471
0
            int i;
472
473
0
            for (i = pcs->params.device_n.num_components; --i >= 0;) {
474
0
                if (map->tint[i] != pc->paint.values[i])
475
0
                    break;
476
0
            }
477
0
            if (i < 0) {
478
0
                int num_out = gs_color_space_num_components(pacs);
479
480
0
                for (i = 0; i < num_out; ++i)
481
0
                    pconc[i] = map->conc[i];
482
0
                return 0;
483
0
            }
484
0
        }
485
5.38M
        tcode = (*pcs->params.device_n.map->tint_transform)
486
5.38M
             (pc->paint.values, &cc.paint.values[0],
487
5.38M
             pgs, pcs->params.device_n.map->tint_transform_data);
488
5.38M
        if (tcode < 0)
489
1
            return tcode;
490
5.38M
        (*pacs->type->restrict_color)(&cc, pacs);
491
        /* First check if this was PS based. */
492
5.38M
        if (gs_color_space_is_PSCIE(pacs)) {
493
            /* We may have to rescale data to 0 to 1 range */
494
0
            rescale_cie_colors(pacs, &cc);
495
            /* If we have not yet created the profile do that now */
496
0
            if (pacs->icc_equivalent == NULL) {
497
0
                code = gs_colorspace_set_icc_equivalent(pacs, &(is_lab), pgs->memory);
498
0
                if (code < 0)
499
0
                   return code;
500
0
            }
501
            /* Use the ICC equivalent color space */
502
0
            pacs = pacs->icc_equivalent;
503
0
        }
504
5.38M
        if (pacs->cmm_icc_profile_data &&
505
5.38M
            (pacs->cmm_icc_profile_data->data_cs == gsCIELAB ||
506
5.38M
            pacs->cmm_icc_profile_data->islab)) {
507
            /* Get the data in a form that is concrete for the CMM */
508
0
            cc.paint.values[0] /= 100.0;
509
0
            cc.paint.values[1] = (cc.paint.values[1]+128)/255.0;
510
0
            cc.paint.values[2] = (cc.paint.values[2]+128)/255.0;
511
0
        }
512
5.38M
        code = cs_concretize_color(&cc, pacs, pconc, pgs, dev);
513
5.38M
    }
514
1.65M
    else {
515
1.65M
        int i;
516
517
4.35M
        for (i = num_src_comps; --i >= 0;)
518
2.70M
            pconc[i] = gx_unit_frac(pc->paint.values[i]);
519
1.65M
        return 0;
520
1.65M
    }
521
5.38M
    return (code < 0 || tcode == 0 ? code : tcode);
522
7.04M
}
523
524
static int
525
gx_remap_concrete_DeviceN(const gs_color_space * pcs, const frac * pconc,
526
                          gx_device_color * pdc, const gs_gstate * pgs,
527
                          gx_device * dev, gs_color_select_t select,
528
                          const cmm_dev_profile_t *dev_profile)
529
1.65M
{
530
1.65M
    int code = 0;
531
532
#ifdef DEBUG
533
    /*
534
     * Verify that the color space and gs_gstate info match.
535
     */
536
    if (pcs->id != pgs->color_component_map.cspace_id)
537
        dmprintf(pgs->memory, "gx_remap_concrete_DeviceN: color space id mismatch");
538
#endif
539
1.65M
    if (pgs->color_component_map.use_alt_cspace) {
540
0
        const gs_color_space *pacs = pcs->base_space;
541
0
        return (*pacs->type->remap_concrete_color)
542
0
                                (pacs, pconc, pdc, pgs, dev, select, dev_profile);
543
1.65M
    } else {
544
    /* If we are going DeviceN out to real sep device that understands these,
545
       and if the destination profile is DeviceN, we print the colors directly.
546
       Make sure to disable the DeviceN profile color map so that is does not
547
       get used in gx_remap_concrete_devicen.  We probably should pass something
548
       through here but it is a pain due to the change in the proc. */
549
1.65M
        bool temp_val;
550
551
1.65M
        if (dev_profile->spotnames != NULL && code >= 0) {
552
0
            temp_val = dev_profile->spotnames->equiv_cmyk_set;
553
0
            dev_profile->spotnames->equiv_cmyk_set = false;
554
0
            gx_remap_concrete_devicen(pconc, pdc, pgs, dev, select, pcs);
555
0
            dev_profile->spotnames->equiv_cmyk_set = temp_val;
556
1.65M
        } else {
557
1.65M
            gx_remap_concrete_devicen(pconc, pdc, pgs, dev, select, pcs);
558
1.65M
        }
559
1.65M
        return 0;
560
1.65M
    }
561
1.65M
}
562
563
/*
564
 * Check that the color component names for a DeviceN color space
565
 * match the device colorant names.  Also build a gs_devicen_color_map
566
 * structure.
567
 */
568
static int
569
check_DeviceN_component_names(const gs_color_space * pcs, gs_gstate * pgs)
570
4.85k
{
571
4.85k
    char **names = pcs->params.device_n.names;
572
4.85k
    int num_comp = pcs->params.device_n.num_components;
573
4.85k
    int i;
574
4.85k
    int colorant_number;
575
4.85k
    const char *pname;
576
4.85k
    uint name_size;
577
4.85k
    gs_devicen_color_map * pcolor_component_map
578
4.85k
        = &pgs->color_component_map;
579
4.85k
    gx_device * dev = pgs->device;
580
4.85k
    bool non_match = false;
581
4.85k
    int none_count = 0;
582
583
4.85k
    pcolor_component_map->num_components = num_comp;
584
4.85k
    pcolor_component_map->cspace_id = pcs->id;
585
4.85k
    pcolor_component_map->num_colorants = dev->color_info.num_components;
586
4.85k
    pcolor_component_map->sep_type = SEP_OTHER;
587
588
    /* If the named color profile supports the components, don't use
589
       the alternate tint transform. */
590
4.85k
    if (gsicc_support_named_color(pcs, pgs)) {
591
0
        pcolor_component_map->use_alt_cspace = false;
592
0
        return 0;
593
0
    }
594
595
    /* If our device is using an additive color model, then we need to
596
     * consider using the alternative color space, as separations are
597
     * generally only used with a subtractive color model. There are
598
     * exceptions, however.
599
     *
600
     * If we don't support devn, then we will certainly have to use the
601
     * alternative color space.
602
     *
603
     * If we are a pdf14 device, and we are doing transparency blending
604
     * in an additive space, we need to keep the spots separated and
605
     * blend them individually as per the PDF specification. Note
606
     * however, if the spot is a CMYK process color and we are doing
607
     * the blend in an additive color space the alternate color space
608
     * is used.  This matches AR.
609
     *
610
     * Otherwise, we will always use the alternate colorspace, unless
611
     * our device specifically claims to be a separation-supporting
612
     * additive device. Possibly all additive devn devices should
613
     * support this now, but I lack to confidence to make this change
614
     * globally. Instead we'll just enable it on a device by device
615
     * basis for now.
616
     *
617
     * This matches logic in check_Separation_component_name.
618
     */
619
4.85k
    if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
620
1.63k
        if (dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0) == 0 ||
621
0
            (dev_proc(dev, dev_spec_op)(dev, gxdso_is_pdf14_device, NULL, 0) == 0 &&
622
1.63k
             dev_proc(dev, dev_spec_op)(dev, gxdso_is_sep_supporting_additive_device, NULL, 0) == 0)) {
623
1.63k
            pcolor_component_map->use_alt_cspace = true;
624
1.63k
            return 0;
625
1.63k
        }
626
1.63k
    }
627
628
    /*
629
     * Now check the names of the color components.  If any of the colorants
630
     * come back as process type (i.e. CMYK) and we are drawing in a pdf14
631
     * additive color space then use the alternate tint transform.
632
     */
633
634
7.29k
    for(i = 0; i < num_comp; i++ ) {
635
        /*
636
         * Get the character string and length for the component name.
637
         */
638
4.07k
        pname = names[i];
639
4.07k
        if (pname == NULL)
640
24
            pname = "";
641
4.07k
        name_size = strlen(pname);
642
        /*
643
         * Compare the colorant name to the device's.  If the device's
644
         * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
645
         * colorant is in the SeparationNames list but not in the
646
         * SeparationOrder list.
647
         */
648
4.07k
        colorant_number = (*dev_proc(dev, get_color_comp_index))
649
4.07k
                                   (dev, pname, name_size, SEPARATION_NAME);
650
4.07k
        if (colorant_number >= 0) {   /* If valid colorant name */
651
4.04k
            pcolor_component_map->color_map[i] =
652
4.04k
            (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
653
4.04k
                                                   : colorant_number;
654
4.04k
        } else {
655
36
            if (strncmp(pname, "None", name_size) != 0) {
656
0
                    non_match = true;
657
36
            } else {
658
                /* Device N includes one or more None Entries. We can't reduce
659
                   the number of components in the list count, since the None Name(s)
660
                   are present in the list and GCd and we may need the None
661
                   entries in the alternate tint trasform calcuation.
662
                   So we will detect the presence of them by setting
663
                   pcolor_component_map->color_map[i] = -1 and watching
664
                   for this case later during the remap operation. */
665
36
                pcolor_component_map->color_map[i] = -1;
666
36
                none_count++;
667
36
            }
668
36
        }
669
4.07k
    }
670
3.21k
    pcolor_component_map->use_alt_cspace = non_match;
671
672
3.21k
    if (none_count == num_comp)
673
0
        return 1;
674
675
3.21k
    return 0;
676
3.21k
}
677
678
/* Check if the colorants are all process colorants and of the same type */
679
static separation_colors
680
gx_check_process_names_DeviceN(gs_color_space * pcs, gs_gstate * pgs)
681
4.85k
{
682
4.85k
    int i, num_comp, num_spots = 0, num_rgb_process = 0;
683
4.85k
    int num_cmyk_process = 0;
684
4.85k
    char **names;
685
4.85k
    const char *pname;
686
4.85k
    uint name_size;
687
688
4.85k
    names = pcs->params.device_n.names;
689
4.85k
    num_comp = pcs->params.device_n.num_components;
690
691
    /* Step through the color space colorants */
692
11.9k
    for (i = 0; i < num_comp; i++) {
693
7.13k
        pname = names[i];
694
7.13k
        if (pname == NULL)
695
24
            pname = "";
696
7.13k
        name_size = strlen(pname);
697
698
        /* Classify */
699
7.13k
        if (strncmp(pname, "None", name_size) == 0) {
700
224
            continue;
701
6.91k
        } else {
702
6.91k
            if (strncmp(pname, "Cyan", name_size) == 0 ||
703
6.75k
                strncmp(pname, "Magenta", name_size) == 0 ||
704
6.18k
                strncmp(pname, "Yellow", name_size) == 0 ||
705
5.75k
                strncmp(pname, "Black", name_size) == 0) {
706
5.75k
                num_cmyk_process++;
707
5.75k
            } else if (strncmp(pname, "Red", name_size) == 0 ||
708
962
                strncmp(pname, "Green", name_size) == 0 ||
709
779
                strncmp(pname, "Blue", name_size) == 0) {
710
558
                num_rgb_process++;
711
601
            } else {
712
601
                num_spots++;
713
601
            }
714
6.91k
        }
715
7.13k
    }
716
717
4.85k
    if (num_cmyk_process > 0 && num_rgb_process == 0 && num_spots == 0)
718
4.33k
        return SEP_PURE_CMYK;
719
521
    if (num_rgb_process > 0 && num_cmyk_process == 0 && num_spots == 0)
720
162
        return SEP_PURE_RGB;
721
359
    if (num_spots > 0 && num_cmyk_process == 0 && num_rgb_process == 0)
722
66
        return SEP_PURE_SPOT;
723
293
    return SEP_MIX;
724
359
}
725
726
/* Install a DeviceN color space. */
727
static int
728
gx_install_DeviceN(gs_color_space * pcs, gs_gstate * pgs)
729
4.85k
{
730
4.85k
    int code;
731
4.85k
    code = check_DeviceN_component_names(pcs, pgs);
732
4.85k
    if (code < 0)
733
0
       return code;
734
735
    /* Indicates all colorants are /None */
736
4.85k
    if (code > 0)
737
0
        pcs->params.device_n.all_none = true;
738
739
4.85k
    if (pgs->icc_manager->device_named != NULL) {
740
0
        pcs->params.device_n.named_color_supported =
741
0
            gsicc_support_named_color(pcs, pgs);
742
0
    }
743
4.85k
    pcs->params.device_n.color_type = gx_check_process_names_DeviceN(pcs, pgs);
744
745
    /* See if we have an ICC profile that we can associate with
746
       this DeviceN color space */
747
4.85k
    if (pgs->icc_manager->device_n != NULL) {
748
        /* An nclr profile is in the manager.  Grab one that matches. */
749
0
        cmm_profile_t *profdata = gsicc_finddevicen(pcs, pgs->icc_manager);
750
0
        if (profdata != NULL)
751
0
            gsicc_adjust_profile_rc(profdata, 1, "gx_install_DeviceN");
752
0
        if (pcs->cmm_icc_profile_data != NULL)
753
0
            gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, -1, "gx_install_DeviceN");
754
0
        pcs->cmm_icc_profile_data = profdata;
755
0
    }
756
    /* {csrc} was pgs->color_space->params.device_n.use_alt_cspace */
757
4.85k
    ((gs_color_space *)pcs)->params.device_n.use_alt_cspace =
758
4.85k
        using_alt_color_space(pgs);
759
4.85k
    if (pcs->params.device_n.use_alt_cspace && pcs->cmm_icc_profile_data == NULL ) {
760
        /* No nclr ICC profile */
761
1.63k
        code = (pcs->base_space->type->install_cspace)
762
1.63k
            (pcs->base_space, pgs);
763
3.21k
    } else if (pcs->params.device_n.use_alt_cspace) {
764
0
        gs_color_space *nclr_pcs;
765
        /* Need to install the nclr cspace */
766
0
        code = gs_cspace_build_ICC(&nclr_pcs, NULL, pgs->memory);
767
0
        nclr_pcs->cmm_icc_profile_data = pcs->cmm_icc_profile_data;
768
0
        gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, 1, "gx_install_DeviceN");
769
0
        rc_increment(nclr_pcs);       /* FIXME: Suspicious - RJW */
770
0
        rc_decrement(pcs->base_space, "gx_install_DeviceN");
771
0
        pcs->base_space = nclr_pcs;
772
0
    }
773
    /*
774
     * Give the device an opportunity to capture equivalent colors for any
775
     * spot colors which might be present in the color space.
776
     */
777
4.85k
    if (code >= 0) {
778
4.85k
        if (dev_proc(pgs->device, update_spot_equivalent_colors))
779
4.85k
            code = dev_proc(pgs->device, update_spot_equivalent_colors)
780
4.85k
                                                        (pgs->device, pgs, pcs);
781
4.85k
    }
782
4.85k
    return code;
783
4.85k
}
784
785
/* Set overprint information for a DeviceN color space */
786
static int
787
gx_set_overprint_DeviceN(const gs_color_space * pcs, gs_gstate * pgs)
788
0
{
789
0
    gs_devicen_color_map *  pcmap = &pgs->color_component_map;
790
0
    int code;
791
792
    /* It is possible that the color map information in the graphic state
793
       is not current due to save/restore and or if we are coming from
794
       a color space that is inside a PatternType 2 */
795
0
    code = check_DeviceN_component_names(pcs, pgs);
796
0
    if (code < 0)
797
0
       return code;
798
0
    if (pcmap->use_alt_cspace) {
799
0
        const gs_color_space_type* base_type = pcs->base_space->type;
800
801
        /* If the base space is DeviceCMYK, handle overprint as DeviceCMYK */
802
0
        if ( base_type->index == gs_color_space_index_DeviceCMYK )
803
0
            return base_type->set_overprint( pcs->base_space, pgs );
804
0
        else
805
0
            return gx_set_no_overprint(pgs);
806
0
    } else {
807
0
        gs_overprint_params_t   params = { 0 };
808
809
0
        params.retain_any_comps = (pgs->overprint && pgs->is_fill_color) ||
810
0
                                  (pgs->stroke_overprint && !pgs->is_fill_color);
811
812
0
        params.drawn_comps = 0;
813
0
        if (params.retain_any_comps) {
814
0
            int     i, ncomps = pcs->params.device_n.num_components;
815
816
0
            params.is_fill_color = pgs->is_fill_color;  /* for fill_stroke */
817
0
            if (pcs->params.device_n.named_color_supported) {
818
                /* This color will not actually be the device_n color any more.
819
                 * It will have been substituted with the named color replacement.
820
                 * Therefore the drawn comps will be different. */
821
                /* FIXME: For now, we assume the replacement color uses
822
                 * C,M,Y and K. To do better, we'd either need to look at the
823
                 * device color (but this is problematic, as we may have scaled light
824
                 * components to 0), or we'd need to get this from the named color
825
                 * code itself. Possibly by another entry in color_component_map. */
826
0
                params.drawn_comps = 15;
827
0
            } else {
828
0
                for (i = 0; i < ncomps; i++) {
829
0
                    int mcomp = pcmap->color_map[i];
830
0
                    if (mcomp >= 0)
831
0
                        gs_overprint_set_drawn_comp( params.drawn_comps, mcomp);
832
0
                }
833
0
            }
834
0
        }
835
836
        /* Only DeviceCMYK can use overprint mode */
837
0
        params.effective_opm = pgs->color[0].effective_opm = 0;
838
0
        params.op_state = GS_OP_STATE_NONE;
839
0
        params.is_fill_color =pgs->is_fill_color;
840
0
        return gs_gstate_update_overprint(pgs, &params);
841
0
    }
842
0
}
843
844
/* Finalize contents of a DeviceN color space. */
845
static void
846
gx_final_DeviceN(gs_color_space * pcs)
847
4.74k
{
848
4.74k
    gs_device_n_colorant * pnextatt, * patt = pcs->params.device_n.colorants;
849
4.74k
    uint num_proc_names = pcs->params.device_n.num_process_names;
850
4.74k
    gs_memory_t *mem = pcs->params.device_n.mem->non_gc_memory;
851
4.74k
    char **proc_names = pcs->params.device_n.process_names;
852
4.74k
    int k;
853
854
11.4k
    for (k = 0; k < pcs->params.device_n.num_components; k++)
855
6.75k
        gs_free_object(mem, pcs->params.device_n.names[k], "gx_final_DeviceN");
856
4.74k
    gs_free_object(mem, pcs->params.device_n.names, "gx_final_DeviceN");
857
858
4.74k
    if (num_proc_names > 0 && proc_names != NULL) {
859
21.3k
        for (k = 0; k < num_proc_names; k++) {
860
17.0k
            gs_free_object(mem, proc_names[k], "gx_final_DeviceN");
861
17.0k
        }
862
4.25k
        gs_free_object(mem, proc_names, "gx_final_DeviceN");
863
4.25k
    }
864
865
4.74k
    rc_decrement_only(pcs->params.device_n.map, "gx_adjust_DeviceN");
866
4.74k
    while (patt != NULL) {
867
0
        pnextatt = patt->next;
868
0
        gs_free_object(mem, patt->colorant_name, "gx_final_DeviceN");
869
0
        rc_decrement_cs(patt->cspace, "gx_final_DeviceN");
870
0
        rc_decrement(patt, "gx_adjust_DeviceN");
871
0
        patt = pnextatt;
872
0
    }
873
4.74k
    if (pcs->params.device_n.devn_process_space)
874
4.74k
        rc_decrement_only(pcs->params.device_n.devn_process_space, "gx_final_DeviceN");
875
    /* Ensure idempotency */
876
4.74k
    memset(&pcs->params.device_n, 0, sizeof(pcs->params.device_n));
877
4.74k
}
878
879
/* ---------------- Serialization. -------------------------------- */
880
881
int
882
gx_serialize_device_n_map(const gs_color_space * pcs, gs_device_n_map * m, stream * s)
883
31.0k
{
884
31.0k
    const gs_function_t *pfn;
885
886
31.0k
    if (m->tint_transform != map_devn_using_function)
887
0
        return_error(gs_error_unregistered); /* Unimplemented. */
888
31.0k
    pfn = (const gs_function_t *)m->tint_transform_data;
889
31.0k
    return gs_function_serialize(pfn, s);
890
31.0k
}
891
892
static int
893
gx_serialize_DeviceN(const gs_color_space * pcs, stream * s)
894
1.82k
{
895
1.82k
    const gs_device_n_params * p = &pcs->params.device_n;
896
1.82k
    uint n, m;
897
1.82k
    int code = gx_serialize_cspace_type(pcs, s);
898
899
1.82k
    if (code < 0)
900
0
        return code;
901
1.82k
    code = sputs(s, (const byte *)&p->num_components, sizeof(p->num_components), &n);
902
1.82k
    if (code < 0)
903
0
        return code;
904
4.26k
    for (n=0;n < p->num_components;n++) {
905
2.44k
        const char *name = p->names[n];
906
2.44k
        if (name == NULL)
907
0
            name = "";
908
2.44k
        code = sputs(s, (const byte *)name, strlen(name) + 1, &m);
909
2.44k
        if (code < 0)
910
0
            return code;
911
2.44k
    }
912
1.82k
    code = cs_serialize(pcs->base_space, s);
913
1.82k
    if (code < 0)
914
0
        return code;
915
1.82k
    return gx_serialize_device_n_map(pcs, p->map, s);
916
    /* p->use_alt_cspace isn't a property of the space. */
917
1.82k
}