Coverage Report

Created: 2026-10-28 08:05

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