Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zcie.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
/* CIE color operators */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "ghost.h"
21
#include "oper.h"
22
#include "gsstruct.h"
23
#include "gxcspace.h"   /* gscolor2.h requires gscspace.h */
24
#include "gscolor2.h"
25
#include "gscie.h"
26
#include "estack.h"
27
#include "ialloc.h"
28
#include "idict.h"
29
#include "idparam.h"
30
#include "igstate.h"
31
#include "icie.h"
32
#include "isave.h"
33
#include "ivmspace.h"
34
#include "store.h"    /* for make_null */
35
#include "zcie.h"
36
#include "gsicc_create.h"
37
#include "gsicc_manage.h"
38
#include "gsicc_profilecache.h"
39
40
/* Prototype */
41
int cieicc_prepare_caches(i_ctx_t *i_ctx_p, const gs_range * domains,
42
                     const ref * procs,
43
                     cie_cache_floats * pc0, cie_cache_floats * pc1,
44
                     cie_cache_floats * pc2, cie_cache_floats * pc3,
45
                     void *container,
46
                     const gs_ref_memory_t * imem, client_name_t cname);
47
static int
48
cie_prepare_iccproc(i_ctx_t *i_ctx_p, const gs_range * domain, const ref * proc,
49
                  cie_cache_floats * pcache, void *container,
50
                  const gs_ref_memory_t * imem, client_name_t cname);
51
52
/* Empty procedures */
53
static const ref empty_procs[4] =
54
{
55
    empty_ref_data(t_array, a_readonly | a_executable),
56
    empty_ref_data(t_array, a_readonly | a_executable),
57
    empty_ref_data(t_array, a_readonly | a_executable),
58
    empty_ref_data(t_array, a_readonly | a_executable)
59
};
60
61
/* ------ Parameter extraction utilities ------ */
62
63
/* Get a range array parameter from a dictionary. */
64
/* We know that count <= 4. */
65
int
66
dict_ranges_param(const gs_memory_t *mem,
67
                  const ref * pdref, const char *kstr, int count,
68
                  gs_range * prange)
69
267k
{
70
267k
    int code = dict_floats_param(mem, pdref, kstr, count * 2,
71
267k
                                 (float *)prange, NULL);
72
73
267k
    if (code < 0)
74
0
        return code;
75
267k
    else if (code == 0)
76
178k
        memcpy(prange, Range4_default.ranges, count * sizeof(gs_range));
77
267k
    return 0;
78
267k
}
79
80
/* Get an array of procedures from a dictionary. */
81
/* We know count <= countof(empty_procs). */
82
int
83
dict_proc_array_param(const gs_memory_t *mem,
84
                      const ref *pdict, const char *kstr,
85
                      uint count, ref *pparray)
86
535k
{
87
535k
    ref *pvalue;
88
89
535k
    if (dict_find_string(pdict, kstr, &pvalue) > 0) {
90
357k
        uint i;
91
92
357k
        check_array_only(*pvalue);
93
357k
        if (r_size(pvalue) != count)
94
0
            return_error(gs_error_rangecheck);
95
1.42M
        for (i = 0; i < count; i++) {
96
1.07M
            ref proc;
97
98
1.07M
            array_get(mem, pvalue, (long)i, &proc);
99
1.07M
            check_proc_only(proc);
100
1.07M
        }
101
357k
        *pparray = *pvalue;
102
357k
        return 0;
103
357k
    } else {
104
178k
        make_const_array(pparray, a_readonly | avm_foreign,
105
178k
                         count, &empty_procs[0]);
106
178k
        return 1;
107
178k
    }
108
535k
}
109
110
/* Get 3 ranges from a dictionary. */
111
int
112
dict_range3_param(const gs_memory_t *mem,
113
                  const ref *pdref, const char *kstr,
114
                  gs_range3 *prange3)
115
267k
{
116
267k
    return dict_ranges_param(mem, pdref, kstr, 3, prange3->ranges);
117
267k
}
118
119
/* Get a 3x3 matrix from a dictionary. */
120
int
121
dict_matrix3_param(const gs_memory_t *mem,
122
                   const ref *pdref, const char *kstr, gs_matrix3 *pmat3)
123
267k
{
124
    /*
125
     * We can't simply call dict_float_array_param with the matrix
126
     * cast to a 9-element float array, because compilers may insert
127
     * padding elements after each of the vectors.  However, we can be
128
     * confident that there is no padding within a single vector.
129
     */
130
267k
    float values[9], defaults[9];
131
267k
    int code;
132
133
267k
    memcpy(&defaults[0], &Matrix3_default.cu, 3 * sizeof(float));
134
267k
    memcpy(&defaults[3], &Matrix3_default.cv, 3 * sizeof(float));
135
267k
    memcpy(&defaults[6], &Matrix3_default.cw, 3 * sizeof(float));
136
267k
    code = dict_floats_param(mem, pdref, kstr, 9, values, defaults);
137
267k
    if (code < 0)
138
0
        return code;
139
267k
    memcpy(&pmat3->cu, &values[0], 3 * sizeof(float));
140
267k
    memcpy(&pmat3->cv, &values[3], 3 * sizeof(float));
141
267k
    memcpy(&pmat3->cw, &values[6], 3 * sizeof(float));
142
267k
    return 0;
143
267k
}
144
145
/* Get 3 procedures from a dictionary. */
146
int
147
dict_proc3_param(const gs_memory_t *mem, const ref *pdref, const char *kstr, ref *proc3)
148
535k
{
149
535k
    return dict_proc_array_param(mem, pdref, kstr, 3, proc3);
150
535k
}
151
152
/* Get WhitePoint and BlackPoint values. */
153
int
154
cie_points_param(const gs_memory_t *mem,
155
                 const ref * pdref, gs_cie_wb * pwb)
156
89.2k
{
157
89.2k
    int code;
158
159
89.2k
    if ((code = dict_floats_param(mem, pdref, "WhitePoint", 3,
160
89.2k
        (float *)&pwb->WhitePoint, NULL)) < 0 ||
161
89.2k
        (code = dict_floats_param(mem, pdref, "BlackPoint", 3,
162
89.2k
        (float *)&pwb->BlackPoint, (const float *)&BlackPoint_default)) < 0
163
89.2k
        )
164
0
        return code;
165
89.2k
    if (pwb->WhitePoint.u <= 0 ||
166
89.2k
        pwb->WhitePoint.v != 1 ||
167
89.2k
        pwb->WhitePoint.w <= 0 ||
168
89.2k
        pwb->BlackPoint.u < 0 ||
169
89.2k
        pwb->BlackPoint.v < 0 ||
170
89.2k
        pwb->BlackPoint.w < 0
171
89.2k
        )
172
0
        return_error(gs_error_rangecheck);
173
89.2k
    return 0;
174
89.2k
}
175
176
/* Process a 3- or 4-dimensional lookup table from a dictionary. */
177
/* The caller has set pclt->n and pclt->m. */
178
/* ptref is known to be a readable array of size at least n+1. */
179
static int cie_3d_table_param(const ref * ptable, uint count, uint nbytes,
180
                               gs_const_string * strings, const gs_memory_t *mem);
181
int
182
cie_table_param(const ref * ptref, gx_color_lookup_table * pclt,
183
                const gs_memory_t * mem)
184
0
{
185
0
    int n = pclt->n, m = pclt->m;
186
0
    const ref *pta = ptref->value.const_refs;
187
0
    int i;
188
0
    uint nbytes;
189
0
    int code;
190
0
    gs_const_string *table;
191
192
0
    for (i = 0; i < n; ++i) {
193
0
        check_type_only(pta[i], t_integer);
194
0
        if (pta[i].value.intval <= 1 || pta[i].value.intval > max_ushort)
195
0
            return_error(gs_error_rangecheck);
196
0
        pclt->dims[i] = (int)pta[i].value.intval;
197
0
    }
198
0
    nbytes = m * pclt->dims[n - 2] * pclt->dims[n - 1];
199
0
    if (n == 3) {
200
0
        table =
201
0
            gs_alloc_struct_array(mem->stable_memory, pclt->dims[0], gs_const_string,
202
0
                                  &st_const_string_element, "cie_table_param");
203
0
        if (table == 0)
204
0
            return_error(gs_error_VMerror);
205
0
        code = cie_3d_table_param(pta + 3, pclt->dims[0], nbytes, table, mem);
206
0
    } else {     /* n == 4 */
207
0
        int d0 = pclt->dims[0], d1 = pclt->dims[1];
208
0
        uint ntables = d0 * d1;
209
0
        const ref *psuba;
210
211
0
        check_read_type(pta[4], t_array);
212
0
        if (r_size(pta + 4) != d0)
213
0
            return_error(gs_error_rangecheck);
214
0
        table =
215
0
            gs_alloc_struct_array(mem->stable_memory, ntables, gs_const_string,
216
0
                                  &st_const_string_element, "cie_table_param");
217
0
        if (table == 0)
218
0
            return_error(gs_error_VMerror);
219
0
        psuba = pta[4].value.const_refs;
220
        /*
221
         * We know that d0 > 0, so code will always be set in the loop:
222
         * we initialize code to 0 here solely to pacify stupid compilers.
223
         */
224
0
        for (code = 0, i = 0; i < d0; ++i) {
225
0
            code = cie_3d_table_param(psuba + i, d1, nbytes, table + d1 * i, mem);
226
0
            if (code < 0)
227
0
                break;
228
0
        }
229
0
    }
230
0
    if (code < 0) {
231
0
        gs_free_object((gs_memory_t *)mem, table, "cie_table_param");
232
0
        return code;
233
0
    }
234
0
    pclt->table = table;
235
0
    return 0;
236
0
}
237
static int
238
cie_3d_table_param(const ref * ptable, uint count, uint nbytes,
239
                   gs_const_string * strings, const gs_memory_t *mem)
240
0
{
241
0
    const ref *rstrings;
242
0
    uint i;
243
244
0
    check_read_type(*ptable, t_array);
245
0
    if (r_size(ptable) != count)
246
0
        return_error(gs_error_rangecheck);
247
0
    rstrings = ptable->value.const_refs;
248
0
    for (i = 0; i < count; ++i) {
249
0
        const ref *const prt2 = rstrings + i;
250
0
        byte *tmpstr;
251
252
0
        check_read_type(*prt2, t_string);
253
0
        if (r_size(prt2) != nbytes)
254
0
            return_error(gs_error_rangecheck);
255
        /* Here we need to get a string in stable_memory (like the rest of the CIEDEF(G)
256
        * structure). It _may_ already be in global or stable memory, but we don't know
257
        * that, so just allocate and copy it so we don't end up with stale pointers after
258
        * a "restore" that frees localVM. Rely on GC to collect the strings.
259
        */
260
0
        tmpstr = gs_alloc_string(mem->stable_memory, nbytes, "cie_3d_table_param");
261
0
        if (tmpstr == NULL)
262
0
            return_error(gs_error_VMerror);
263
0
        memcpy(tmpstr, prt2->value.const_bytes, nbytes);
264
0
        strings[i].data = tmpstr;
265
0
        strings[i].size = nbytes;
266
0
    }
267
0
    return 0;
268
0
}
269
270
/* ------ CIE setcolorspace ------ */
271
272
/* Common code for the CIEBased* cases of setcolorspace. */
273
static int
274
cie_lmnp_param(const gs_memory_t *mem, const ref * pdref, gs_cie_common * pcie,
275
               ref_cie_procs * pcprocs, bool *has_lmn_procs)
276
0
{
277
0
    int code;
278
279
0
    if ((code = dict_range3_param(mem, pdref, "RangeLMN", &pcie->RangeLMN)) < 0 ||
280
0
        (code = dict_matrix3_param(mem, pdref, "MatrixLMN", &pcie->MatrixLMN)) < 0 ||
281
0
        (code = cie_points_param(mem, pdref, &pcie->points)) < 0
282
0
        )
283
0
        return code;
284
0
    code = dict_proc3_param(mem, pdref, "DecodeLMN", &pcprocs->DecodeLMN);
285
0
    if (code < 0)
286
0
        return code;
287
0
    *has_lmn_procs = !code;  /* Need to know for efficient creation of ICC profile */
288
0
    pcie->DecodeLMN = DecodeLMN_default;
289
0
    return 0;
290
0
}
291
292
/* Get objects associated with cie color space */
293
static int
294
cie_a_param(const gs_memory_t *mem, const ref * pdref, gs_cie_a * pcie,
295
            ref_cie_procs * pcprocs, bool *has_a_procs, bool *has_lmn_procs)
296
0
{
297
0
    int code;
298
299
0
    code = dict_floats_param(mem, pdref, "RangeA", 2, (float *)&pcie->RangeA,
300
0
                            (const float *)&RangeA_default);
301
0
    if (code < 0)
302
0
        return code;
303
0
    code = dict_floats_param(mem, pdref, "MatrixA", 3, (float *)&pcie->MatrixA,
304
0
                            (const float *)&MatrixA_default);
305
0
    if (code < 0)
306
0
        return code;
307
0
    code = cie_lmnp_param(mem, pdref, &pcie->common, pcprocs, has_lmn_procs);
308
0
    if (code < 0)
309
0
        return code;
310
0
    if ((code = dict_proc_param(pdref, "DecodeA", &(pcprocs->Decode.A), true)) < 0)
311
0
        return code;
312
0
    *has_a_procs = !code;
313
0
    return 0;
314
0
}
315
316
/* Common code for the CIEBasedABC/DEF[G] cases of setcolorspace. */
317
static int
318
cie_abc_param(i_ctx_t *i_ctx_p, const gs_memory_t *mem, const ref * pdref,
319
               gs_cie_abc * pcie, ref_cie_procs * pcprocs,
320
              bool *has_abc_procs, bool *has_lmn_procs)
321
0
{
322
0
    int code;
323
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
324
325
0
    if ((code = dict_range3_param(mem, pdref, "RangeABC", &pcie->RangeABC)) < 0 ||
326
0
        (code = dict_matrix3_param(mem, pdref, "MatrixABC", &pcie->MatrixABC)) < 0 ||
327
0
        (code = cie_lmnp_param(mem, pdref, &pcie->common, pcprocs, has_lmn_procs)) < 0
328
0
        )
329
0
        return code;
330
0
    code = dict_proc3_param(mem, pdref, "DecodeABC", &pcprocs->Decode.ABC);
331
0
    if (code < 0)
332
0
        return code;
333
0
    *has_abc_procs = !code;
334
0
    pcie->DecodeABC = DecodeABC_default;
335
   /* At this point, we have all the parameters in pcie including knowing if
336
    there
337
       are procedures present.  If there are no procedures, life is simple for us.
338
       If there are procedures, we can not create the ICC profile until we have the procedures
339
       sampled, which requires pushing the appropriate commands upon the postscript execution stack
340
       to create the sampled procs and then having a follow up operation to create the ICC profile.
341
       Because the procs may have to be merged with other operators and/or packed
342
       in a particular form, we will have the PS operators stuff them in the already
343
       existing static buffers that already exist for this purpose in the cie structures
344
       e.g. gx_cie_vector_cache3_t that are in the common (params.abc.common.caches.DecodeLMN)
345
       and unique entries (e.g. params.abc.caches.DecodeABC.caches) */
346
0
    if (*has_abc_procs) {
347
0
        cieicc_prepare_caches(i_ctx_p, (&pcie->RangeABC)->ranges,
348
0
                 pcprocs->Decode.ABC.value.const_refs,
349
0
                 &(pcie->caches.DecodeABC.caches)->floats,
350
0
                 &(pcie->caches.DecodeABC.caches)[1].floats,
351
0
                 &(pcie->caches.DecodeABC.caches)[2].floats,
352
0
                 NULL, pcie, imem, "Decode.ABC(ICC)");
353
0
    } else {
354
0
        pcie->caches.DecodeABC.caches->floats.params.is_identity = true;
355
0
        (pcie->caches.DecodeABC.caches)[1].floats.params.is_identity = true;
356
0
        (pcie->caches.DecodeABC.caches)[2].floats.params.is_identity = true;
357
0
    }
358
0
    if (*has_lmn_procs) {
359
0
        cieicc_prepare_caches(i_ctx_p, (&pcie->common.RangeLMN)->ranges,
360
0
                    pcprocs->DecodeLMN.value.const_refs,
361
0
                    &(pcie->common.caches.DecodeLMN)->floats,
362
0
                    &(pcie->common.caches.DecodeLMN)[1].floats,
363
0
                    &(pcie->common.caches.DecodeLMN)[2].floats,
364
0
                    NULL, pcie, imem, "Decode.LMN(ICC)");
365
0
    } else {
366
0
        pcie->common.caches.DecodeLMN->floats.params.is_identity = true;
367
0
        (pcie->common.caches.DecodeLMN)[1].floats.params.is_identity = true;
368
0
        (pcie->common.caches.DecodeLMN)[2].floats.params.is_identity = true;
369
0
    }
370
0
    return 0;
371
0
}
372
373
/* Finish setting a CIE space (successful or not). */
374
int
375
cie_set_finish(i_ctx_t *i_ctx_p, gs_color_space * pcs,
376
               const ref_cie_procs * pcprocs, int edepth, int code)
377
0
{
378
0
    if (code >= 0)
379
0
        code = gs_setcolorspace(igs, pcs);
380
    /* Delete the extra reference to the parameter tables. */
381
0
    rc_decrement_only_cs(pcs, "cie_set_finish");
382
0
    if (code < 0) {
383
0
        ref_stack_pop_to(&e_stack, edepth);
384
0
        return code;
385
0
    }
386
0
    istate->colorspace[0].procs.cie = *pcprocs;
387
0
    pop(1);
388
0
    return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);
389
0
}
390
391
/* Forward references */
392
static int cie_defg_finish(i_ctx_t *);
393
394
static int
395
cie_defg_param(i_ctx_t *i_ctx_p, const gs_memory_t *mem, const ref * pdref,
396
               gs_cie_defg * pcie, ref_cie_procs * pcprocs, bool *has_abc_procs,
397
               bool *has_lmn_procs, bool *has_defg_procs, ref *ptref)
398
0
{
399
0
    int code;
400
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
401
402
    /* First get all the ABC and LMN information related to this space */
403
0
    code = cie_abc_param(i_ctx_p, mem, pdref, (gs_cie_abc *) pcie, pcprocs,
404
0
                            has_abc_procs, has_lmn_procs);
405
0
    if (code < 0)
406
0
        return code;
407
0
    code = dict_ranges_param(mem, pdref, "RangeDEFG", 4, pcie->RangeDEFG.ranges);
408
0
    if (code < 0)
409
0
        return code;
410
0
    code = dict_ranges_param(mem, pdref, "RangeHIJK", 4, pcie->RangeHIJK.ranges);
411
0
    if (code < 0)
412
0
        return code;
413
0
    code = cie_table_param(ptref, &pcie->Table, mem);
414
0
    if (code < 0)
415
0
        return code;
416
0
    code = dict_proc_array_param(mem, pdref, "DecodeDEFG", 4,
417
0
                                    &(pcprocs->PreDecode.DEFG));
418
0
    if (code < 0)
419
0
        return code;
420
0
    *has_defg_procs = !code;
421
0
    if (*has_defg_procs) {
422
0
        cieicc_prepare_caches(i_ctx_p, (&pcie->RangeDEFG)->ranges,
423
0
                 pcprocs->PreDecode.DEFG.value.const_refs,
424
0
                 &(pcie->caches_defg.DecodeDEFG)->floats,
425
0
                 &(pcie->caches_defg.DecodeDEFG)[1].floats,
426
0
                 &(pcie->caches_defg.DecodeDEFG)[2].floats,
427
0
                 &(pcie->caches_defg.DecodeDEFG)[3].floats,
428
0
                    pcie, imem, "Decode.DEFG(ICC)");
429
0
    } else {
430
0
         pcie->caches_defg.DecodeDEFG->floats.params.is_identity = true;
431
0
        (pcie->caches_defg.DecodeDEFG)[1].floats.params.is_identity = true;
432
0
        (pcie->caches_defg.DecodeDEFG)[2].floats.params.is_identity = true;
433
0
        (pcie->caches_defg.DecodeDEFG)[3].floats.params.is_identity = true;
434
0
    }
435
0
    return(0);
436
0
}
437
int
438
ciedefgspace(i_ctx_t *i_ctx_p, ref *CIEDict, uint64_t dictkey)
439
0
{
440
0
    os_ptr op = osp;
441
0
    int edepth = ref_stack_count(&e_stack);
442
0
    gs_memory_t *mem = gs_gstate_memory(igs);
443
0
    gs_color_space *pcs;
444
0
    ref_cie_procs procs;
445
0
    gs_cie_defg *pcie;
446
0
    int code = 0;
447
0
    ref *ptref;
448
0
    bool has_defg_procs, has_abc_procs, has_lmn_procs;
449
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
450
451
0
    if (dictkey != 0) {
452
0
        pcs = gsicc_find_cs(dictkey, igs);
453
0
        if (pcs && gs_color_space_num_components(pcs) != 4)
454
0
            pcs = NULL;
455
0
    }
456
0
    else
457
0
        pcs = NULL;
458
0
    push(1); /* Sacrificial */
459
0
    procs = istate->colorspace[0].procs.cie;
460
0
    if (pcs == NULL ) {
461
0
        if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0) {
462
0
            if (code == 0)
463
0
                gs_note_error(cie_set_finish(i_ctx_p, pcs, &procs, edepth, gs_error_rangecheck));
464
0
            else
465
0
                return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
466
0
        }
467
0
        check_read_type(*ptref, t_array);
468
0
        if (r_size(ptref) != 5)
469
0
            return_error(gs_error_rangecheck);
470
        /* Stable memory due to current caching of color space */
471
0
        code = gs_cspace_build_CIEDEFG(&pcs, NULL, mem->stable_memory);
472
0
        if (code < 0)
473
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
474
0
        pcie = pcs->params.defg;
475
0
        pcie->Table.n = 4;
476
0
        pcie->Table.m = 3;
477
0
        code = cie_cache_push_finish(i_ctx_p, cie_defg_finish, imem, pcie);
478
0
        if (code < 0)
479
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
480
0
        code = cie_defg_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
481
0
            &has_abc_procs, &has_lmn_procs, &has_defg_procs,ptref);
482
0
        if (code < 0)
483
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
484
        /* Add the color space to the profile cache */
485
0
        gsicc_add_cs(igs, pcs,dictkey);
486
0
    } else {
487
0
        rc_increment(pcs);
488
0
    }
489
0
    return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
490
0
}
491
492
static int
493
cie_defg_finish(i_ctx_t *i_ctx_p)
494
0
{
495
0
    os_ptr op = osp;
496
0
    gs_cie_defg *pcie = r_ptr(op, gs_cie_defg);
497
498
0
    pcie->DecodeDEFG = DecodeDEFG_from_cache;
499
0
    pcie->DecodeABC = DecodeABC_from_cache;
500
0
    pcie->common.DecodeLMN = DecodeLMN_from_cache;
501
0
    gs_cie_defg_complete(pcie);
502
0
    pop(1);
503
0
    return 0;
504
0
}
505
506
static int
507
cie_def_param(i_ctx_t *i_ctx_p, const gs_memory_t *mem, const ref * pdref,
508
              gs_cie_def * pcie, ref_cie_procs * pcprocs,
509
              bool *has_abc_procs, bool *has_lmn_procs,
510
              bool *has_def_procs, ref *ptref)
511
0
{
512
0
    int code;
513
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
514
515
    /* First get all the ABC and LMN information related to this space */
516
0
    code = cie_abc_param(i_ctx_p, mem, pdref, (gs_cie_abc *) pcie, pcprocs,
517
0
                            has_abc_procs, has_lmn_procs);
518
0
    if (code < 0)
519
0
        return code;
520
0
    code = dict_range3_param(mem, pdref, "RangeDEF", &pcie->RangeDEF);
521
0
    if (code < 0)
522
0
        return code;
523
0
    code = dict_range3_param(mem, pdref, "RangeHIJ", &pcie->RangeHIJ);
524
0
    if (code < 0)
525
0
        return code;
526
0
    code = cie_table_param(ptref, &pcie->Table, mem);
527
0
    if (code < 0)
528
0
        return code;
529
    /* The DEF procs */
530
0
    code = dict_proc3_param(mem, pdref, "DecodeDEF", &(pcprocs->PreDecode.DEF));
531
0
    if (code < 0)
532
0
        return code;
533
0
    *has_def_procs = !code;
534
0
    if (*has_def_procs) {
535
0
        cieicc_prepare_caches(i_ctx_p, (&pcie->RangeDEF)->ranges,
536
0
                 pcprocs->PreDecode.DEF.value.const_refs,
537
0
                 &(pcie->caches_def.DecodeDEF)->floats,
538
0
                 &(pcie->caches_def.DecodeDEF)[1].floats,
539
0
                 &(pcie->caches_def.DecodeDEF)[2].floats,
540
0
                 NULL, pcie, imem, "Decode.DEF(ICC)");
541
0
    } else {
542
0
         pcie->caches_def.DecodeDEF->floats.params.is_identity = true;
543
0
        (pcie->caches_def.DecodeDEF)[1].floats.params.is_identity = true;
544
0
        (pcie->caches_def.DecodeDEF)[2].floats.params.is_identity = true;
545
0
    }
546
0
    return(0);
547
0
}
548
549
static int cie_def_finish(i_ctx_t *);
550
int
551
ciedefspace(i_ctx_t *i_ctx_p, ref *CIEDict, uint64_t dictkey)
552
0
{
553
0
    os_ptr op = osp;
554
0
    int edepth = ref_stack_count(&e_stack);
555
0
    gs_memory_t *mem = gs_gstate_memory(igs);
556
0
    gs_color_space *pcs;
557
0
    ref_cie_procs procs;
558
0
    gs_cie_def *pcie;
559
0
    int code = 0;
560
0
    ref *ptref;
561
0
    bool has_def_procs, has_lmn_procs, has_abc_procs;
562
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
563
564
0
    if (dictkey != 0) {
565
0
        pcs = gsicc_find_cs(dictkey, igs);
566
0
        if (pcs && gs_color_space_num_components(pcs) != 3)
567
0
            pcs = NULL;
568
0
    }
569
0
    else
570
0
        pcs = NULL;
571
0
    push(1); /* Sacrificial */
572
0
    procs = istate->colorspace[0].procs.cie;
573
0
    if (pcs == NULL ) {
574
0
        if ((code = dict_find_string(CIEDict, "Table", &ptref)) <= 0) {
575
0
            if (code == 0)
576
0
                gs_note_error(cie_set_finish(i_ctx_p, pcs, &procs, edepth, gs_error_rangecheck));
577
0
            else
578
0
                return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
579
0
        }
580
0
        check_read_type(*ptref, t_array);
581
0
        if (r_size(ptref) != 4)
582
0
            return_error(gs_error_rangecheck);
583
       /* Stable memory due to current caching of color space */
584
0
        code = gs_cspace_build_CIEDEF(&pcs, NULL, mem->stable_memory);
585
0
        if (code < 0)
586
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
587
0
        pcie = pcs->params.def;
588
0
        pcie->Table.n = 3;
589
0
        pcie->Table.m = 3;
590
0
        code = cie_cache_push_finish(i_ctx_p, cie_def_finish, imem, pcie);
591
0
        if (code < 0)
592
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
593
0
        code = cie_def_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
594
0
            &has_abc_procs, &has_lmn_procs, &has_def_procs, ptref);
595
0
        if (code < 0)
596
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
597
        /* Add the color space to the profile cache */
598
0
        gsicc_add_cs(igs, pcs,dictkey);
599
0
    } else {
600
0
        rc_increment(pcs);
601
0
    }
602
0
    return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
603
0
}
604
605
static int
606
cie_def_finish(i_ctx_t *i_ctx_p)
607
0
{
608
0
    os_ptr op = osp;
609
0
    gs_cie_def *pcie = r_ptr(op, gs_cie_def);
610
611
0
    pcie->DecodeDEF = DecodeDEF_from_cache;
612
0
    pcie->DecodeABC = DecodeABC_from_cache;
613
0
    pcie->common.DecodeLMN = DecodeLMN_from_cache;
614
0
    gs_cie_def_complete(pcie);
615
0
    pop(1);
616
0
    return 0;
617
0
}
618
619
static int cie_abc_finish(i_ctx_t *);
620
621
int
622
cieabcspace(i_ctx_t *i_ctx_p, ref *CIEDict, uint64_t dictkey)
623
0
{
624
0
    os_ptr op = osp;
625
0
    int edepth = ref_stack_count(&e_stack);
626
0
    gs_memory_t *mem = gs_gstate_memory(igs);
627
0
    gs_color_space *pcs;
628
0
    ref_cie_procs procs;
629
0
    gs_cie_abc *pcie;
630
0
    int code = 0;
631
0
    bool has_lmn_procs, has_abc_procs;
632
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
633
634
/* See if the color space is in the profile cache */
635
0
    if (dictkey != 0) {
636
0
        pcs = gsicc_find_cs(dictkey, igs);
637
0
        if (pcs && gs_color_space_num_components(pcs) != 3)
638
0
            pcs = NULL;
639
0
    }
640
0
    else
641
0
        pcs = NULL;
642
643
0
    push(1); /* Sacrificial */
644
0
    procs = istate->colorspace[0].procs.cie;
645
0
    if (pcs == NULL ) {
646
        /* Stable memory due to current caching of color space */
647
0
        code = gs_cspace_build_CIEABC(&pcs, NULL, mem->stable_memory);
648
0
    if (code < 0)
649
0
        return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
650
0
    pcie = pcs->params.abc;
651
0
        code = cie_cache_push_finish(i_ctx_p, cie_abc_finish, imem, pcie);
652
0
        if (code < 0)
653
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
654
0
        code = cie_abc_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
655
0
            &has_abc_procs, &has_lmn_procs);
656
0
        if (code < 0)
657
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
658
        /* Set the color space in the graphic state.  The ICC profile
659
            will be set later if we actually use the space.  Procs will be
660
            sampled now though. Also, the finish procedure is on the stack
661
            since that is where the vector cache is completed from the scalar
662
            caches.  We may need the vector cache if we are going to go
663
            ahead and create an MLUT for this thing */
664
        /* Add the color space to the profile cache */
665
0
        gsicc_add_cs(igs, pcs,dictkey);
666
0
    } else {
667
0
        rc_increment(pcs);
668
0
    }
669
0
    return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
670
0
}
671
672
static int
673
cie_abc_finish(i_ctx_t *i_ctx_p)
674
0
{
675
0
    os_ptr op = osp;
676
0
    gs_cie_abc *pcie = r_ptr(op, gs_cie_abc);
677
678
0
    pcie->DecodeABC = DecodeABC_from_cache;
679
0
    pcie->common.DecodeLMN = DecodeLMN_from_cache;
680
0
    gs_cie_abc_complete(pcie);
681
0
    pop(1);
682
0
    return 0;
683
0
}
684
685
static int cie_a_finish(i_ctx_t *);
686
687
int
688
cieaspace(i_ctx_t *i_ctx_p, ref *CIEdict, uint64_t dictkey)
689
0
{
690
0
    os_ptr op = osp;
691
0
    int edepth = ref_stack_count(&e_stack);
692
0
    gs_memory_t *mem = gs_gstate_memory(igs);
693
0
    const gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
694
0
    gs_color_space *pcs;
695
0
    ref_cie_procs procs;
696
0
    gs_cie_a *pcie;
697
0
    int code = 0;
698
0
    bool has_a_procs = false;
699
0
    bool has_lmn_procs;
700
701
/* See if the color space is in the profile cache */
702
0
    if (dictkey != 0) {
703
0
        pcs = gsicc_find_cs(dictkey, igs);
704
0
        if (pcs && gs_color_space_num_components(pcs) != 1)
705
0
            pcs = NULL;
706
0
    }
707
0
    else
708
0
        pcs = NULL;
709
0
    push(1); /* Sacrificial */
710
0
    procs = istate->colorspace[0].procs.cie;
711
0
    if (pcs == NULL ) {
712
        /* Stable memory due to current caching of color space */
713
0
        code = gs_cspace_build_CIEA(&pcs, NULL, mem->stable_memory);
714
0
    if (code < 0)
715
0
        return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
716
0
    pcie = pcs->params.a;
717
0
        code = cie_a_param(imemory, CIEdict, pcie, &procs, &has_a_procs,
718
0
                                &has_lmn_procs);
719
0
        if (code < 0)
720
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
721
        /* Push finalize procedure on the execution stack */
722
0
        code = cie_cache_push_finish(i_ctx_p, cie_a_finish, (gs_ref_memory_t *)imem, pcie);
723
0
        if (code < 0)
724
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
725
0
        if (!has_a_procs && !has_lmn_procs) {
726
0
            pcie->common.caches.DecodeLMN->floats
727
0
                .params.is_identity = true;
728
0
            (pcie->common.caches.DecodeLMN)[1].floats.params.is_identity = true;
729
0
            (pcie->common.caches.DecodeLMN)[2].floats.params.is_identity = true;
730
0
            pcie->caches.DecodeA.floats.params.is_identity = true;
731
0
        } else {
732
0
            if (has_a_procs) {
733
0
                code = cie_prepare_iccproc(i_ctx_p, &pcie->RangeA,
734
0
                    &procs.Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A");
735
0
                if (code < 0)
736
0
                    return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
737
0
            } else {
738
0
                pcie->caches.DecodeA.floats.params.is_identity = true;
739
0
            }
740
0
            if (has_lmn_procs) {
741
0
                cieicc_prepare_caches(i_ctx_p, (&pcie->common.RangeLMN)->ranges,
742
0
                         procs.DecodeLMN.value.const_refs,
743
0
                         &(pcie->common.caches.DecodeLMN)->floats,
744
0
                         &(pcie->common.caches.DecodeLMN)[1].floats,
745
0
                         &(pcie->common.caches.DecodeLMN)[2].floats,
746
0
                         NULL, pcie, imem, "Decode.LMN(ICC)");
747
0
            } else {
748
0
                pcie->common.caches.DecodeLMN->floats.params.is_identity = true;
749
0
                (pcie->common.caches.DecodeLMN)[1].floats.params.is_identity = true;
750
0
                (pcie->common.caches.DecodeLMN)[2].floats.params.is_identity = true;
751
0
            }
752
0
        }
753
        /* Add the color space to the profile cache */
754
0
        gsicc_add_cs(igs, pcs,dictkey);
755
0
    } else {
756
0
        rc_increment(pcs);
757
0
    }
758
    /* Set the color space in the graphic state.  The ICC profile may be set after this
759
           due to the needed sampled procs */
760
0
    return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
761
0
}
762
763
static int
764
cie_a_finish(i_ctx_t *i_ctx_p)
765
0
{
766
0
    os_ptr op = osp;
767
0
    gs_cie_a *pcie = r_ptr(op, gs_cie_a);
768
769
0
    pcie->DecodeA = DecodeA_from_cache;
770
0
    pcie->common.DecodeLMN = DecodeLMN_from_cache;
771
0
    gs_cie_a_complete(pcie);
772
0
    pop(1);
773
0
    return 0;
774
0
}
775
776
/* ------ Internal routines ------ */
777
778
/* Prepare to cache the values for one or more procedures. */
779
/* RJW: No longer used, but keeping it around in case it becomes useful
780
 * again in future.
781
 * static int cie_cache_finish1(i_ctx_t *);
782
 */
783
static int cie_cache_finish(i_ctx_t *);
784
int
785
cie_prepare_cache(i_ctx_t *i_ctx_p, const gs_range * domain, const ref * proc,
786
                  cie_cache_floats * pcache, void *container,
787
                  gs_ref_memory_t * imem, client_name_t cname)
788
0
{
789
0
    int space = imemory_space(imem);
790
0
    gs_sample_loop_params_t lp;
791
0
    es_ptr ep;
792
793
0
    gs_cie_cache_init(&pcache->params, &lp, domain, cname);
794
0
    pcache->params.is_identity = r_size(proc) == 0;
795
0
    check_estack(9);
796
0
    ep = esp;
797
0
    make_real(ep + 9, lp.A);
798
0
    make_int(ep + 8, lp.N);
799
0
    make_real(ep + 7, lp.B);
800
0
    ep[6] = *proc;
801
0
    r_clear_attrs(ep + 6, a_executable);
802
0
    make_op_estack(ep + 5, zcvx);
803
0
    make_op_estack(ep + 4, zfor_samples);
804
0
    make_op_estack(ep + 3, cie_cache_finish);
805
0
    esp += 9;
806
    /*
807
     * The caches are embedded in the middle of other
808
     * structures, so we represent the pointer to the cache
809
     * as a pointer to the container plus an offset.
810
     */
811
0
    make_int(ep + 2, (char *)pcache - (char *)container);
812
0
    make_struct(ep + 1, space, container);
813
0
    return o_push_estack;
814
0
}
815
/* Note that pc3 may be 0, indicating that there are only 3 caches to load. */
816
int
817
cie_prepare_caches_4(i_ctx_t *i_ctx_p, const gs_range * domains,
818
                     const ref * procs,
819
                     cie_cache_floats * pc0, cie_cache_floats * pc1,
820
                     cie_cache_floats * pc2, cie_cache_floats * pc3,
821
                     void *container,
822
                     gs_ref_memory_t * imem, client_name_t cname)
823
0
{
824
0
    cie_cache_floats *pcn[4];
825
0
    int i, n, code = 0;
826
827
0
    pcn[0] = pc0, pcn[1] = pc1, pcn[2] = pc2;
828
0
    if (pc3 == 0)
829
0
        n = 3;
830
0
    else
831
0
        pcn[3] = pc3, n = 4;
832
0
    for (i = 0; i < n && code >= 0; ++i)
833
0
        code = cie_prepare_cache(i_ctx_p, domains + i, procs + i, pcn[i],
834
0
                                 container, imem, cname);
835
0
    return code;
836
0
}
837
838
/* Store the result of caching one procedure. */
839
static int
840
cie_cache_finish_store(i_ctx_t *i_ctx_p, bool replicate)
841
0
{
842
0
    os_ptr op = osp;
843
0
    cie_cache_floats *pcache;
844
0
    int code;
845
846
0
    check_esp(2);
847
    /* See above for the container + offset representation of */
848
    /* the pointer to the cache. */
849
0
    pcache = (cie_cache_floats *) (r_ptr(esp - 1, char) + esp->value.intval);
850
851
0
    pcache->params.is_identity = false; /* cache_set_linear computes this */
852
0
    if_debug3m('c', imemory, "[c]cache "PRI_INTPTR" base=%g, factor=%g:\n",
853
0
               (intptr_t) pcache, pcache->params.base, pcache->params.factor);
854
0
    if (replicate ||
855
0
        (code = float_params(op, gx_cie_cache_size, &pcache->values[0])) < 0
856
0
        ) {
857
        /* We might have underflowed the current stack block. */
858
        /* Handle the parameters one-by-one. */
859
0
        uint i;
860
861
0
        for (i = 0; i < gx_cie_cache_size; i++) {
862
0
            code = float_param(ref_stack_index(&o_stack,
863
0
                               (replicate ? 0 : gx_cie_cache_size - 1 - i)),
864
0
                               &pcache->values[i]);
865
0
            if (code < 0) {
866
0
                esp -= 2;      /* pop pointer to cache */
867
0
                return code;
868
0
            }
869
0
        }
870
0
    }
871
#ifdef DEBUG
872
    if (gs_debug_c('c')) {
873
        int i;
874
875
        for (i = 0; i < gx_cie_cache_size; i += 4)
876
            dmlprintf5(imemory, "[c]  cache[%3d]=%g, %g, %g, %g\n", i,
877
                       pcache->values[i], pcache->values[i + 1],
878
                       pcache->values[i + 2], pcache->values[i + 3]);
879
    }
880
#endif
881
0
    ref_stack_pop(&o_stack, (replicate ? 1 : gx_cie_cache_size));
882
0
    esp -= 2;      /* pop pointer to cache */
883
0
    return o_pop_estack;
884
0
}
885
static int
886
cie_cache_finish(i_ctx_t *i_ctx_p)
887
0
{
888
0
    return cie_cache_finish_store(i_ctx_p, false);
889
0
}
890
#if 0
891
/* RJW: No longer used, but might be useful in future. */
892
static int
893
cie_cache_finish1(i_ctx_t *i_ctx_p)
894
{
895
    return cie_cache_finish_store(i_ctx_p, true);
896
}
897
#endif
898
899
/* Push a finishing procedure on the e-stack. */
900
/* ptr will be the top element of the o-stack. */
901
int
902
cie_cache_push_finish(i_ctx_t *i_ctx_p, op_proc_t finish_proc,
903
                      gs_ref_memory_t * imem, void *data)
904
0
{
905
0
    check_estack(2);
906
0
    push_op_estack(finish_proc);
907
0
    ++esp;
908
0
    make_struct(esp, imemory_space(imem), data);
909
0
    return o_push_estack;
910
0
}
911
912
/* Special functions related to the creation of ICC profiles
913
   from the PS CIE color management objects.  These basically
914
   make use of the existing objects in the CIE stuctures to
915
   store the sampled procs.  These sampled procs are then
916
   used in the creation of the ICC profiles */
917
918
/* Push the sequence of commands onto the execution stack
919
   so that we sample the procs */
920
static int cie_create_icc(i_ctx_t *);
921
static int
922
cie_prepare_iccproc(i_ctx_t *i_ctx_p, const gs_range * domain, const ref * proc,
923
                  cie_cache_floats * pcache, void *container,
924
                  const gs_ref_memory_t * imem, client_name_t cname)
925
0
{
926
0
    int space = imemory_space(imem);
927
0
    gs_sample_loop_params_t lp;
928
0
    es_ptr ep;
929
930
0
    gs_cie_cache_init(&pcache->params, &lp, domain, cname);
931
0
    pcache->params.is_identity = r_size(proc) == 0;
932
0
    check_estack(9);
933
0
    ep = esp;
934
0
    make_real(ep + 9, lp.A);
935
0
    make_int(ep + 8, lp.N);
936
0
    make_real(ep + 7, lp.B);
937
0
    ep[6] = *proc;
938
0
    r_clear_attrs(ep + 6, a_executable);
939
0
    make_op_estack(ep + 5, zcvx);
940
0
    make_op_estack(ep + 4, zfor_samples);
941
0
    make_op_estack(ep + 3, cie_create_icc);
942
0
    esp += 9;
943
    /*
944
     * The caches are embedded in the middle of other
945
     * structures, so we represent the pointer to the cache
946
     * as a pointer to the container plus an offset.
947
     */
948
0
    make_int(ep + 2, (char *)pcache - (char *)container);
949
0
    make_struct(ep + 1, space, container);
950
0
    return o_push_estack;
951
0
}
952
953
int
954
cieicc_prepare_caches(i_ctx_t *i_ctx_p, const gs_range * domains,
955
                     const ref * procs,
956
                     cie_cache_floats * pc0, cie_cache_floats * pc1,
957
                     cie_cache_floats * pc2, cie_cache_floats * pc3,
958
                     void *container,
959
                     const gs_ref_memory_t * imem, client_name_t cname)
960
0
{
961
0
    cie_cache_floats *pcn[4];
962
0
    int i, n, code = 0;
963
964
0
    pcn[0] = pc0, pcn[1] = pc1, pcn[2] = pc2;
965
0
    if (pc3 == 0)
966
0
        n = 3;
967
0
    else
968
0
        pcn[3] = pc3, n = 4;
969
0
    for (i = 0; i < n && code >= 0; ++i)
970
0
        code = cie_prepare_iccproc(i_ctx_p, domains + i, procs + i, pcn[i],
971
0
                                 container, imem, cname);
972
0
    return code;
973
0
}
974
975
/* We have sampled the procs. Go ahead and create the ICC profile.  */
976
static int
977
cie_create_icc(i_ctx_t *i_ctx_p)
978
0
{
979
0
    os_ptr op = osp;
980
0
    cie_cache_floats *pcache;
981
0
    int code;
982
983
0
    check_esp(2);
984
    /* See above for the container + offset representation of */
985
    /* the pointer to the cache. */
986
0
    pcache = (cie_cache_floats *) (r_ptr(esp - 1, char) + esp->value.intval);
987
988
0
    pcache->params.is_identity = false; /* cache_set_linear computes this */
989
0
    if_debug3m('c', imemory, "[c]icc_sample_proc "PRI_INTPTR" base=%g, factor=%g:\n",
990
0
               (intptr_t) pcache, pcache->params.base, pcache->params.factor);
991
0
    if ((code = float_params(op, gx_cie_cache_size, &pcache->values[0])) < 0) {
992
        /* We might have underflowed the current stack block. */
993
        /* Handle the parameters one-by-one. */
994
0
        uint i;
995
996
0
        for (i = 0; i < gx_cie_cache_size; i++) {
997
0
            code = float_param(ref_stack_index(&o_stack,gx_cie_cache_size - 1 - i),
998
0
                               &pcache->values[i]);
999
0
            if (code < 0)
1000
0
                return code;
1001
0
        }
1002
0
    }
1003
#ifdef DEBUG
1004
    if (gs_debug_c('c')) {
1005
        int i;
1006
1007
        for (i = 0; i < gx_cie_cache_size; i += 4)
1008
            dmlprintf5(imemory, "[c]  icc_sample_proc[%3d]=%g, %g, %g, %g\n", i,
1009
                       pcache->values[i], pcache->values[i + 1],
1010
                       pcache->values[i + 2], pcache->values[i + 3]);
1011
    }
1012
#endif
1013
0
    ref_stack_pop(&o_stack, gx_cie_cache_size);
1014
0
    esp -= 2;      /* pop pointer to cache */
1015
0
    return o_pop_estack;
1016
0
}