Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gscdevn.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, 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
2.46k
{
110
2.46k
    gs_color_space *pcs;
111
2.46k
    gs_device_n_params *pcsdevn;
112
2.46k
    char **pnames;
113
2.46k
    int i, code;
114
115
2.46k
    if (palt_cspace == 0 || !palt_cspace->type->can_be_alt_space)
116
0
        return_error(gs_error_rangecheck);
117
118
2.46k
    pcs = gs_cspace_alloc(pmem, &gs_color_space_type_DeviceN);
119
2.46k
    if (pcs == NULL)
120
0
        return_error(gs_error_VMerror);
121
2.46k
    pcsdevn = &pcs->params.device_n;
122
2.46k
    pcsdevn->names = NULL;
123
2.46k
    pcsdevn->map = NULL;
124
2.46k
    pcsdevn->colorants = NULL;
125
2.46k
    pcsdevn->named_color_supported = false;
126
2.46k
    pcsdevn->num_process_names = 0;
127
2.46k
    pcsdevn->process_names = NULL;
128
2.46k
    pcsdevn->mem = pmem->non_gc_memory;
129
2.46k
    pcsdevn->all_none = false;
130
131
    /* Allocate space for color names list. */
132
2.46k
    code = alloc_device_n_map(&pcsdevn->map, pmem, "gs_cspace_build_DeviceN");
133
2.46k
    if (code < 0) {
134
0
        gs_free_object(pmem, pcs, "gs_cspace_new_DeviceN");
135
0
        return code;
136
0
    }
137
2.46k
    pnames = (char **)gs_alloc_bytes(pcsdevn->mem, num_components * sizeof(char *), "gs_cspace_new_DeviceN");
138
2.46k
    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
5.79k
    for (i=0; i<num_components; i++)
144
3.33k
        pnames[i] = NULL;   /* empty string for check_DeviceN_component_names */
145
2.46k
    pcs->base_space = palt_cspace;
146
2.46k
    rc_increment_cs(palt_cspace);
147
2.46k
    pcsdevn->names = pnames;
148
2.46k
    pcsdevn->num_components = num_components;
149
2.46k
    *ppcs = pcs;
150
2.46k
    return 0;
151
2.46k
}
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
16.4k
{
158
16.4k
    gs_device_n_map *pimap;
159
160
16.4k
    rc_alloc_struct_1(pimap, gs_device_n_map, &st_device_n_map, mem,
161
16.4k
                      return_error(gs_error_VMerror), cname);
162
16.4k
    pimap->tint_transform = 0;
163
16.4k
    pimap->tint_transform_data = 0;
164
16.4k
    pimap->cache_valid = false;
165
16.4k
    *ppmap = pimap;
166
16.4k
    return 0;
167
16.4k
}
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
19.4k
{
266
19.4k
    return (pgs->color_component_map.use_alt_cspace);
267
19.4k
}
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
88.8k
{
275
88.8k
    gs_function_t *const pfn = data;
276
277
88.8k
    return gs_function_evaluate(pfn, in, out);
278
88.8k
}
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
2.46k
{
286
2.46k
    gs_device_n_map *pimap;
287
288
2.46k
    if (gs_color_space_get_index(pcspace) != gs_color_space_index_DeviceN ||
289
2.46k
        pfn->params.m != pcspace->params.device_n.num_components ||
290
2.46k
        pfn->params.n != gs_color_space_num_components(pcspace->base_space)
291
2.46k
        )
292
3
        return_error(gs_error_rangecheck);
293
2.45k
    pimap = pcspace->params.device_n.map;
294
2.45k
    pimap->tint_transform = map_devn_using_function;
295
2.45k
    pimap->tint_transform_data = pfn;
296
2.45k
    pimap->cache_valid = false;
297
2.45k
    return 0;
298
2.46k
}
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
2.47k
{
307
2.47k
    if (gs_color_space_get_index(pcspace) == gs_color_space_index_DeviceN &&
308
2.47k
        pcspace->params.device_n.map->tint_transform ==
309
2.47k
          map_devn_using_function)
310
2.47k
        return pcspace->params.device_n.map->tint_transform_data;
311
0
    return 0;
312
2.47k
}
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
269k
{
320
269k
    return pcs->params.device_n.num_components;
321
269k
}
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
4.81k
{
339
4.81k
    uint i;
340
341
11.1k
    for (i = 0; i < pcs->params.device_n.num_components; ++i)
342
6.30k
        pcc->paint.values[i] = 1.0;
343
4.81k
}
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
493k
{
349
493k
    uint i;
350
351
1.10M
    for (i = 0; i < pcs->params.device_n.num_components; ++i) {
352
614k
        double value = pcc->paint.values[i];
353
614k
        pcc->paint.values[i] = (value <= 0 ? 0 : value >= 1 ? 1 : value);
354
614k
    }
355
493k
}
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
237k
{
362
237k
    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
237k
    if (pgs->color_component_map.use_alt_cspace) {
374
        /* Need to handle PS CIE space */
375
3.29k
        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
3.29k
        return cs_concrete_space(pcs->base_space, pgs);
383
3.29k
    }
384
    /*
385
     * DeviceN color spaces are concrete (when not using alt. color space).
386
     */
387
234k
    return pcs;
388
237k
}
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
235k
{
395
235k
    frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
396
235k
    const gs_color_space *pconcs;
397
235k
    int i = pcs->type->num_components(pcs),k;
398
235k
    int code = 0;
399
235k
    const gs_color_space *pacs = pcs->base_space;
400
235k
    gs_client_color temp;
401
235k
    bool mapped = false;
402
403
235k
    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
235k
    } 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
235k
        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
235k
        if (!mapped) {
425
235k
            cmm_dev_profile_t *dev_profile;
426
235k
            code = dev_proc(dev, get_profile)(dev, &dev_profile);
427
235k
            if (code < 0)
428
0
                return code;
429
235k
            code = (*pcs->type->concretize_color)(pcc, pcs, conc, pgs, dev);
430
235k
            if (code < 0)
431
38
                return code;
432
235k
            pconcs = cs_concrete_space(pcs, pgs);
433
235k
            code = (*pconcs->type->remap_concrete_color)(pconcs, conc, pdc, pgs, dev, select, dev_profile);
434
235k
        }
435
        /* Save original color space and color info into dev color */
436
235k
        i = any_abs(i);
437
482k
        for (i--; i >= 0; i--)
438
247k
            pdc->ccolor.paint.values[i] = pcc->paint.values[i];
439
235k
        pdc->ccolor_valid = true;
440
235k
        return code;
441
235k
    }
442
235k
}
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
237k
{
448
237k
    int code, tcode = 0;
449
237k
    gs_client_color cc;
450
237k
    gs_color_space *pacs = (gs_color_space*) (pcs->base_space);
451
237k
    gs_device_n_map *map = pcs->params.device_n.map;
452
237k
    bool is_lab;
453
237k
    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
237k
    if (pgs->color_component_map.use_alt_cspace) {
469
        /* Check the 1-element cache first. */
470
3.32k
        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
3.32k
        tcode = (*pcs->params.device_n.map->tint_transform)
486
3.32k
             (pc->paint.values, &cc.paint.values[0],
487
3.32k
             pgs, pcs->params.device_n.map->tint_transform_data);
488
3.32k
        (*pacs->type->restrict_color)(&cc, pacs);
489
3.32k
        if (tcode < 0)
490
1
            return tcode;
491
        /* First check if this was PS based. */
492
3.31k
        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
3.31k
        if (pacs->cmm_icc_profile_data &&
505
3.31k
            (pacs->cmm_icc_profile_data->data_cs == gsCIELAB ||
506
3.31k
            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
3.31k
        code = cs_concretize_color(&cc, pacs, pconc, pgs, dev);
513
3.31k
    }
514
234k
    else {
515
234k
        int i;
516
517
481k
        for (i = num_src_comps; --i >= 0;)
518
247k
            pconc[i] = gx_unit_frac(pc->paint.values[i]);
519
234k
        return 0;
520
234k
    }
521
3.31k
    return (code < 0 || tcode == 0 ? code : tcode);
522
237k
}
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
234k
{
530
234k
    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
234k
    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
234k
    } 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
234k
        bool temp_val;
550
551
234k
        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
234k
        } else {
557
234k
            gx_remap_concrete_devicen(pconc, pdc, pgs, dev, select, pcs);
558
234k
        }
559
234k
        return 0;
560
234k
    }
561
234k
}
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
2.47k
{
571
2.47k
    char **names = pcs->params.device_n.names;
572
2.47k
    int num_comp = pcs->params.device_n.num_components;
573
2.47k
    int i;
574
2.47k
    int colorant_number;
575
2.47k
    const char *pname;
576
2.47k
    uint name_size;
577
2.47k
    gs_devicen_color_map * pcolor_component_map
578
2.47k
        = &pgs->color_component_map;
579
2.47k
    gx_device * dev = pgs->device;
580
2.47k
    bool non_match = false;
581
2.47k
    int none_count = 0;
582
583
2.47k
    pcolor_component_map->num_components = num_comp;
584
2.47k
    pcolor_component_map->cspace_id = pcs->id;
585
2.47k
    pcolor_component_map->num_colorants = dev->color_info.num_components;
586
2.47k
    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
2.47k
    if (gsicc_support_named_color(pcs, pgs)) {
591
0
        pcolor_component_map->use_alt_cspace = false;
592
0
        return 0;
593
0
    }
594
595
    /*
596
     * Always use the alternate color space if the current device is
597
     * using an additive color model. The exception is if we have a separation
598
     * device and we are doing transparency blending in an additive color
599
     * space.  In that case, the spots are kept separated and blended
600
     * individually per the PDF specification.  However, if any of the spots are
601
     * CMYK process colors, we use the alternate color space.  This matches AR.
602
     */
603
2.47k
    if (!(dev_proc(dev, dev_spec_op)(dev, gxdso_supports_devn, NULL, 0) &&
604
2.47k
        dev_proc(dev, dev_spec_op)(dev, gxdso_is_pdf14_device, NULL, 0)) &&
605
2.47k
        dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE) {
606
345
        pcolor_component_map->use_alt_cspace = true;
607
345
        return 0;
608
345
    }
609
    /*
610
     * Now check the names of the color components.  If any of the colorants
611
     * come back as process type (i.e. CMYK) and we are drawing in a pdf14
612
     * additive color space then use the alternate tint transform.
613
     */
614
615
4.81k
    for(i = 0; i < num_comp; i++ ) {
616
        /*
617
         * Get the character string and length for the component name.
618
         */
619
2.68k
        pname = names[i];
620
2.68k
        if (pname == NULL)
621
0
            pname = "";
622
2.68k
        name_size = strlen(pname);
623
        /*
624
         * Compare the colorant name to the device's.  If the device's
625
         * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
626
         * colorant is in the SeparationNames list but not in the
627
         * SeparationOrder list.
628
         */
629
2.68k
        colorant_number = (*dev_proc(dev, get_color_comp_index))
630
2.68k
                                   (dev, pname, name_size, SEPARATION_NAME);
631
2.68k
        if (colorant_number >= 0) {   /* If valid colorant name */
632
2.66k
            pcolor_component_map->color_map[i] =
633
2.66k
            (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) ? -1
634
2.66k
                                                   : colorant_number;
635
2.66k
        } else {
636
24
            if (strncmp(pname, "None", name_size) != 0) {
637
0
                    non_match = true;
638
24
            } else {
639
                /* Device N includes one or more None Entries. We can't reduce
640
                   the number of components in the list count, since the None Name(s)
641
                   are present in the list and GCd and we may need the None
642
                   entries in the alternate tint trasform calcuation.
643
                   So we will detect the presence of them by setting
644
                   pcolor_component_map->color_map[i] = -1 and watching
645
                   for this case later during the remap operation. */
646
24
                pcolor_component_map->color_map[i] = -1;
647
24
                none_count++;
648
24
            }
649
24
        }
650
2.68k
    }
651
2.12k
    pcolor_component_map->use_alt_cspace = non_match;
652
653
2.12k
    if (none_count == num_comp)
654
0
        return 1;
655
656
2.12k
    return 0;
657
2.12k
}
658
659
/* Check if the colorants are all process colorants and of the same type */
660
static separation_colors
661
gx_check_process_names_DeviceN(gs_color_space * pcs, gs_gstate * pgs)
662
2.47k
{
663
2.47k
    int i, num_comp, num_spots = 0, num_rgb_process = 0;
664
2.47k
    int num_cmyk_process = 0, num_other = 0;
665
2.47k
    char **names;
666
2.47k
    const char *pname;
667
2.47k
    uint name_size;
668
669
2.47k
    names = pcs->params.device_n.names;
670
2.47k
    num_comp = pcs->params.device_n.num_components;
671
672
    /* Step through the color space colorants */
673
5.85k
    for (i = 0; i < num_comp; i++) {
674
3.38k
        pname = names[i];
675
3.38k
        if (pname == NULL)
676
0
            pname = "";
677
3.38k
        name_size = strlen(pname);
678
679
        /* Classify */
680
3.38k
        if (strncmp(pname, "None", name_size) == 0) {
681
96
            num_other++;
682
3.28k
        } else {
683
3.28k
            if (strncmp(pname, "Cyan", name_size) == 0 ||
684
3.28k
                strncmp(pname, "Magenta", name_size) == 0 ||
685
3.28k
                strncmp(pname, "Yellow", name_size) == 0 ||
686
3.28k
                strncmp(pname, "Black", name_size) == 0) {
687
3.11k
                num_cmyk_process++;
688
3.11k
            } else if (strncmp(pname, "Red", name_size) == 0 ||
689
169
                strncmp(pname, "Green", name_size) == 0 ||
690
169
                strncmp(pname, "Blue", name_size) == 0) {
691
130
                num_rgb_process++;
692
130
            } else {
693
39
                num_spots++;
694
39
            }
695
3.28k
        }
696
3.38k
    }
697
698
2.47k
    if (num_cmyk_process > 0 && num_rgb_process == 0 && num_spots == 0)
699
2.39k
        return SEP_PURE_CMYK;
700
79
    if (num_rgb_process > 0 && num_cmyk_process == 0 && num_spots == 0)
701
40
        return SEP_PURE_RGB;
702
39
    if (num_spots > 0 && num_cmyk_process == 0 && num_rgb_process == 0)
703
32
        return SEP_PURE_SPOT;
704
7
    return SEP_MIX;
705
39
}
706
707
/* Install a DeviceN color space. */
708
static int
709
gx_install_DeviceN(gs_color_space * pcs, gs_gstate * pgs)
710
2.47k
{
711
2.47k
    int code;
712
2.47k
    code = check_DeviceN_component_names(pcs, pgs);
713
2.47k
    if (code < 0)
714
0
       return code;
715
716
    /* Indicates all colorants are /None */
717
2.47k
    if (code > 0)
718
0
        pcs->params.device_n.all_none = true;
719
720
2.47k
    if (pgs->icc_manager->device_named != NULL) {
721
0
        pcs->params.device_n.named_color_supported =
722
0
            gsicc_support_named_color(pcs, pgs);
723
0
    }
724
2.47k
    pcs->params.device_n.color_type = gx_check_process_names_DeviceN(pcs, pgs);
725
726
    /* See if we have an ICC profile that we can associate with
727
       this DeviceN color space */
728
2.47k
    if (pgs->icc_manager->device_n != NULL) {
729
        /* An nclr profile is in the manager.  Grab one that matches. */
730
0
        cmm_profile_t *profdata = gsicc_finddevicen(pcs, pgs->icc_manager);
731
0
        if (profdata != NULL)
732
0
            gsicc_adjust_profile_rc(profdata, 1, "gx_install_DeviceN");
733
0
        if (pcs->cmm_icc_profile_data != NULL)
734
0
            gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, -1, "gx_install_DeviceN");
735
0
        pcs->cmm_icc_profile_data = profdata;
736
0
    }
737
    /* {csrc} was pgs->color_space->params.device_n.use_alt_cspace */
738
2.47k
    ((gs_color_space *)pcs)->params.device_n.use_alt_cspace =
739
2.47k
        using_alt_color_space(pgs);
740
2.47k
    if (pcs->params.device_n.use_alt_cspace && pcs->cmm_icc_profile_data == NULL ) {
741
        /* No nclr ICC profile */
742
345
        code = (pcs->base_space->type->install_cspace)
743
345
            (pcs->base_space, pgs);
744
2.12k
    } else if (pcs->params.device_n.use_alt_cspace) {
745
0
        gs_color_space *nclr_pcs;
746
        /* Need to install the nclr cspace */
747
0
        code = gs_cspace_build_ICC(&nclr_pcs, NULL, pgs->memory);
748
0
        nclr_pcs->cmm_icc_profile_data = pcs->cmm_icc_profile_data;
749
0
        gsicc_adjust_profile_rc(pcs->cmm_icc_profile_data, 1, "gx_install_DeviceN");
750
0
        rc_increment(nclr_pcs);       /* FIXME: Suspicious - RJW */
751
0
        rc_decrement(pcs->base_space, "gx_install_DeviceN");
752
0
        pcs->base_space = nclr_pcs;
753
0
    }
754
    /*
755
     * Give the device an opportunity to capture equivalent colors for any
756
     * spot colors which might be present in the color space.
757
     */
758
2.47k
    if (code >= 0) {
759
2.47k
        if (dev_proc(pgs->device, update_spot_equivalent_colors))
760
2.47k
            code = dev_proc(pgs->device, update_spot_equivalent_colors)
761
2.47k
                                                        (pgs->device, pgs, pcs);
762
2.47k
    }
763
2.47k
    return code;
764
2.47k
}
765
766
/* Set overprint information for a DeviceN color space */
767
static int
768
gx_set_overprint_DeviceN(const gs_color_space * pcs, gs_gstate * pgs)
769
0
{
770
0
    gs_devicen_color_map *  pcmap = &pgs->color_component_map;
771
0
    int code;
772
773
    /* It is possible that the color map information in the graphic state
774
       is not current due to save/restore and or if we are coming from
775
       a color space that is inside a PatternType 2 */
776
0
    code = check_DeviceN_component_names(pcs, pgs);
777
0
    if (code < 0)
778
0
       return code;
779
0
    if (pcmap->use_alt_cspace) {
780
0
        const gs_color_space_type* base_type = pcs->base_space->type;
781
782
        /* If the base space is DeviceCMYK, handle overprint as DeviceCMYK */
783
0
        if ( base_type->index == gs_color_space_index_DeviceCMYK )
784
0
            return base_type->set_overprint( pcs->base_space, pgs );
785
0
        else
786
0
            return gx_set_no_overprint(pgs);
787
0
    } else {
788
0
        gs_overprint_params_t   params = { 0 };
789
790
0
        params.retain_any_comps = (pgs->overprint && pgs->is_fill_color) ||
791
0
                                  (pgs->stroke_overprint && !pgs->is_fill_color);
792
793
0
        params.drawn_comps = 0;
794
0
        if (params.retain_any_comps) {
795
0
            int     i, ncomps = pcs->params.device_n.num_components;
796
797
0
            params.is_fill_color = pgs->is_fill_color;  /* for fill_stroke */
798
0
            for (i = 0; i < ncomps; i++) {
799
0
                int mcomp = pcmap->color_map[i];
800
0
                if (mcomp >= 0)
801
0
                    gs_overprint_set_drawn_comp( params.drawn_comps, mcomp);
802
0
            }
803
0
        }
804
805
        /* Only DeviceCMYK can use overprint mode */
806
0
        params.effective_opm = pgs->color[0].effective_opm = 0;
807
0
        params.op_state = OP_STATE_NONE;
808
0
        params.is_fill_color =pgs->is_fill_color;
809
0
        return gs_gstate_update_overprint(pgs, &params);
810
0
    }
811
0
}
812
813
/* Finalize contents of a DeviceN color space. */
814
static void
815
gx_final_DeviceN(gs_color_space * pcs)
816
2.46k
{
817
2.46k
    gs_device_n_colorant * pnextatt, * patt = pcs->params.device_n.colorants;
818
2.46k
    uint num_proc_names = pcs->params.device_n.num_process_names;
819
2.46k
    gs_memory_t *mem = pcs->params.device_n.mem->non_gc_memory;
820
2.46k
    char **proc_names = pcs->params.device_n.process_names;
821
2.46k
    int k;
822
823
5.79k
    for (k = 0; k < pcs->params.device_n.num_components; k++)
824
3.33k
        gs_free_object(mem, pcs->params.device_n.names[k], "gx_final_DeviceN");
825
2.46k
    gs_free_object(mem, pcs->params.device_n.names, "gx_final_DeviceN");
826
827
2.46k
    if (num_proc_names > 0 && proc_names != NULL) {
828
11.3k
        for (k = 0; k < num_proc_names; k++) {
829
9.08k
            gs_free_object(mem, proc_names[k], "gx_final_DeviceN");
830
9.08k
        }
831
2.27k
        gs_free_object(mem, proc_names, "gx_final_DeviceN");
832
2.27k
    }
833
834
2.46k
    rc_decrement_only(pcs->params.device_n.map, "gx_adjust_DeviceN");
835
2.46k
    while (patt != NULL) {
836
0
        pnextatt = patt->next;
837
0
        gs_free_object(mem, patt->colorant_name, "gx_final_DeviceN");
838
0
        rc_decrement_cs(patt->cspace, "gx_final_DeviceN");
839
0
        rc_decrement(patt, "gx_adjust_DeviceN");
840
0
        patt = pnextatt;
841
0
    }
842
2.46k
    if (pcs->params.device_n.devn_process_space)
843
2.46k
        rc_decrement_only(pcs->params.device_n.devn_process_space, "gx_final_DeviceN");
844
    /* Ensure idempotency */
845
2.46k
    memset(&pcs->params.device_n, 0, sizeof(pcs->params.device_n));
846
2.46k
}
847
848
/* ---------------- Serialization. -------------------------------- */
849
850
int
851
gx_serialize_device_n_map(const gs_color_space * pcs, gs_device_n_map * m, stream * s)
852
15.1k
{
853
15.1k
    const gs_function_t *pfn;
854
855
15.1k
    if (m->tint_transform != map_devn_using_function)
856
0
        return_error(gs_error_unregistered); /* Unimplemented. */
857
15.1k
    pfn = (const gs_function_t *)m->tint_transform_data;
858
15.1k
    return gs_function_serialize(pfn, s);
859
15.1k
}
860
861
static int
862
gx_serialize_DeviceN(const gs_color_space * pcs, stream * s)
863
446
{
864
446
    const gs_device_n_params * p = &pcs->params.device_n;
865
446
    uint n, m;
866
446
    int code = gx_serialize_cspace_type(pcs, s);
867
868
446
    if (code < 0)
869
0
        return code;
870
446
    code = sputs(s, (const byte *)&p->num_components, sizeof(p->num_components), &n);
871
446
    if (code < 0)
872
0
        return code;
873
1.07k
    for (n=0;n < p->num_components;n++) {
874
630
        const char *name = p->names[n];
875
630
        if (name == NULL)
876
0
            name = "";
877
630
        code = sputs(s, (const byte *)name, strlen(name) + 1, &m);
878
630
        if (code < 0)
879
0
            return code;
880
630
    }
881
446
    code = cs_serialize(pcs->base_space, s);
882
446
    if (code < 0)
883
0
        return code;
884
446
    return gx_serialize_device_n_map(pcs, p->map, s);
885
    /* p->use_alt_cspace isn't a property of the space. */
886
446
}