Coverage Report

Created: 2026-09-14 07:34

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
441k
{
71
441k
    int code = dict_floats_param(mem, pdref, kstr, count * 2,
72
441k
                                 (float *)prange, NULL);
73
74
441k
    if (code < 0)
75
0
        return code;
76
441k
    else if (code == 0)
77
294k
        memcpy(prange, Range4_default.ranges, count * sizeof(gs_range));
78
441k
    return 0;
79
441k
}
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
883k
{
88
883k
    ref *pvalue;
89
90
883k
    if (dict_find_string(pdict, kstr, &pvalue) > 0) {
91
589k
        uint i;
92
93
589k
        check_array_only(*pvalue);
94
589k
        if (r_size(pvalue) != count)
95
0
            return_error(gs_error_rangecheck);
96
2.35M
        for (i = 0; i < count; i++) {
97
1.76M
            ref proc;
98
99
1.76M
            array_get(mem, pvalue, (long)i, &proc);
100
1.76M
            check_proc_only(proc);
101
1.76M
        }
102
589k
        *pparray = *pvalue;
103
589k
        return 0;
104
589k
    } else {
105
294k
        make_const_array(pparray, a_readonly | avm_foreign,
106
294k
                         count, &empty_procs[0]);
107
294k
        return 1;
108
294k
    }
109
883k
}
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
441k
{
117
441k
    return dict_ranges_param(mem, pdref, kstr, 3, prange3->ranges);
118
441k
}
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
441k
{
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
441k
    float values[9], defaults[9];
132
441k
    int code;
133
134
441k
    memcpy(&defaults[0], &Matrix3_default.cu, 3 * sizeof(float));
135
441k
    memcpy(&defaults[3], &Matrix3_default.cv, 3 * sizeof(float));
136
441k
    memcpy(&defaults[6], &Matrix3_default.cw, 3 * sizeof(float));
137
441k
    code = dict_floats_param(mem, pdref, kstr, 9, values, defaults);
138
441k
    if (code < 0)
139
0
        return code;
140
441k
    memcpy(&pmat3->cu, &values[0], 3 * sizeof(float));
141
441k
    memcpy(&pmat3->cv, &values[3], 3 * sizeof(float));
142
441k
    memcpy(&pmat3->cw, &values[6], 3 * sizeof(float));
143
441k
    return 0;
144
441k
}
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
883k
{
150
883k
    return dict_proc_array_param(mem, pdref, kstr, 3, proc3);
151
883k
}
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
147k
{
158
147k
    int code;
159
160
147k
    if ((code = dict_floats_param(mem, pdref, "WhitePoint", 3,
161
147k
        (float *)&pwb->WhitePoint, NULL)) < 0 ||
162
147k
        (code = dict_floats_param(mem, pdref, "BlackPoint", 3,
163
147k
        (float *)&pwb->BlackPoint, (const float *)&BlackPoint_default)) < 0
164
147k
        )
165
0
        return code;
166
147k
    if (pwb->WhitePoint.u <= 0 ||
167
147k
        pwb->WhitePoint.v != 1 ||
168
147k
        pwb->WhitePoint.w <= 0 ||
169
147k
        pwb->BlackPoint.u < 0 ||
170
147k
        pwb->BlackPoint.v < 0 ||
171
147k
        pwb->BlackPoint.w < 0
172
147k
        )
173
0
        return_error(gs_error_rangecheck);
174
147k
    return 0;
175
147k
}
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
30
{
278
30
    int code;
279
280
30
    if ((code = dict_range3_param(mem, pdref, "RangeLMN", &pcie->RangeLMN)) < 0 ||
281
30
        (code = dict_matrix3_param(mem, pdref, "MatrixLMN", &pcie->MatrixLMN)) < 0 ||
282
30
        (code = cie_points_param(mem, pdref, &pcie->points)) < 0
283
30
        )
284
0
        return code;
285
30
    code = dict_proc3_param(mem, pdref, "DecodeLMN", &pcprocs->DecodeLMN);
286
30
    if (code < 0)
287
0
        return code;
288
30
    *has_lmn_procs = !code;  /* Need to know for efficient creation of ICC profile */
289
30
    pcie->DecodeLMN = DecodeLMN_default;
290
30
    return 0;
291
30
}
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
15
{
298
15
    int code;
299
300
15
    code = dict_floats_param(mem, pdref, "RangeA", 2, (float *)&pcie->RangeA,
301
15
                            (const float *)&RangeA_default);
302
15
    if (code < 0)
303
0
        return code;
304
15
    code = dict_floats_param(mem, pdref, "MatrixA", 3, (float *)&pcie->MatrixA,
305
15
                            (const float *)&MatrixA_default);
306
15
    if (code < 0)
307
0
        return code;
308
15
    code = cie_lmnp_param(mem, pdref, &pcie->common, pcprocs, has_lmn_procs);
309
15
    if (code < 0)
310
0
        return code;
311
15
    if ((code = dict_proc_param(pdref, "DecodeA", &(pcprocs->Decode.A), true)) < 0)
312
0
        return code;
313
15
    *has_a_procs = !code;
314
15
    return 0;
315
15
}
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
15
{
323
15
    int code;
324
15
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
325
326
15
    if ((code = dict_range3_param(mem, pdref, "RangeABC", &pcie->RangeABC)) < 0 ||
327
15
        (code = dict_matrix3_param(mem, pdref, "MatrixABC", &pcie->MatrixABC)) < 0 ||
328
15
        (code = cie_lmnp_param(mem, pdref, &pcie->common, pcprocs, has_lmn_procs)) < 0
329
15
        )
330
0
        return code;
331
15
    code = dict_proc3_param(mem, pdref, "DecodeABC", &pcprocs->Decode.ABC);
332
15
    if (code < 0)
333
0
        return code;
334
15
    *has_abc_procs = !code;
335
15
    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
15
    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
15
    } else {
355
15
        pcie->caches.DecodeABC.caches->floats.params.is_identity = true;
356
15
        (pcie->caches.DecodeABC.caches)[1].floats.params.is_identity = true;
357
15
        (pcie->caches.DecodeABC.caches)[2].floats.params.is_identity = true;
358
15
    }
359
15
    if (*has_lmn_procs) {
360
15
        cieicc_prepare_caches(i_ctx_p, (&pcie->common.RangeLMN)->ranges,
361
15
                    pcprocs->DecodeLMN.value.const_refs,
362
15
                    &(pcie->common.caches.DecodeLMN)->floats,
363
15
                    &(pcie->common.caches.DecodeLMN)[1].floats,
364
15
                    &(pcie->common.caches.DecodeLMN)[2].floats,
365
15
                    NULL, pcie, imem, "Decode.LMN(ICC)");
366
15
    } 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
15
    return 0;
372
15
}
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
41
{
379
41
    if (code >= 0)
380
41
        code = gs_setcolorspace(igs, pcs);
381
    /* Delete the extra reference to the parameter tables. */
382
41
    rc_decrement_only_cs(pcs, "cie_set_finish");
383
41
    if (code < 0) {
384
0
        ref_stack_pop_to(&e_stack, edepth);
385
0
        return code;
386
0
    }
387
41
    istate->colorspace[0].procs.cie = *pcprocs;
388
41
    pop(1);
389
41
    return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);
390
41
}
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
15
{
660
15
    os_ptr op = osp;
661
15
    int edepth = ref_stack_count(&e_stack);
662
15
    gs_memory_t *mem = gs_gstate_memory(igs);
663
15
    gs_color_space *pcs;
664
15
    ref_cie_procs procs;
665
15
    gs_cie_abc *pcie = NULL;
666
15
    int code = 0;
667
15
    bool has_lmn_procs, has_abc_procs;
668
15
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
669
670
/* See if the color space is in the profile cache */
671
15
    if (dictkey != 0) {
672
15
        pcs = gsicc_find_cs(dictkey, igs);
673
15
        if (pcs && gs_color_space_num_components(pcs) != 3)
674
0
            pcs = NULL;
675
15
    }
676
0
    else
677
0
        pcs = NULL;
678
679
15
    push(1); /* Sacrificial */
680
15
    procs = istate->colorspace[0].procs.cie;
681
15
    if (pcs == NULL ) {
682
        /* Stable memory due to current caching of color space */
683
15
        code = gs_cspace_build_CIEABC(&pcs, NULL, mem->stable_memory);
684
15
        if (code < 0)
685
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
686
15
        pcie = pcs->params.abc;
687
15
        code = cie_cache_push_finish(i_ctx_p, cie_abc_finish, imem, pcie);
688
15
        if (code < 0)
689
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
690
15
        rc_increment(pcie); /* cie_cache_push_finish stored a ref on the exec stack, see bug #709468 */
691
15
        code = cie_abc_param(i_ctx_p, imemory, CIEDict, pcie, &procs,
692
15
            &has_abc_procs, &has_lmn_procs);
693
15
        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
15
        code = gsicc_add_cs(igs, pcs,dictkey);
705
15
        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
15
    } else {
710
0
        rc_increment(pcs);
711
0
    }
712
15
    code = cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
713
15
    if (code < 0)
714
15
        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
15
    return code;
716
15
}
717
718
static int
719
cie_abc_finish(i_ctx_t *i_ctx_p)
720
15
{
721
15
    os_ptr op = osp;
722
15
    gs_cie_abc *pcie;
723
15
    gs_color_space *pcs = gs_currentcolorspace_inline(igs);
724
725
15
    if (!r_is_struct(op))
726
0
        return_error(gs_error_typecheck);
727
15
    pcie = r_ptr(op, gs_cie_abc);
728
15
    rc_decrement(pcie, "cie_abc_finish");
729
15
    pop(1);
730
15
    if (gs_color_space_get_index(pcs) != gs_color_space_index_CIEABC)
731
0
        return_error(gs_error_typecheck);
732
15
    pcie->DecodeABC = DecodeABC_from_cache;
733
15
    pcie->common.DecodeLMN = DecodeLMN_from_cache;
734
15
    gs_cie_abc_complete(pcie);
735
15
    return 0;
736
15
}
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
26
{
743
26
    os_ptr op = osp;
744
26
    int edepth = ref_stack_count(&e_stack);
745
26
    gs_memory_t *mem = gs_gstate_memory(igs);
746
26
    const gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
747
26
    gs_color_space *pcs;
748
26
    ref_cie_procs procs;
749
26
    gs_cie_a *pcie = NULL;
750
26
    int code = 0;
751
26
    bool has_a_procs = false;
752
26
    bool has_lmn_procs;
753
754
/* See if the color space is in the profile cache */
755
26
    if (dictkey != 0) {
756
26
        pcs = gsicc_find_cs(dictkey, igs);
757
26
        if (pcs && gs_color_space_num_components(pcs) != 1)
758
0
            pcs = NULL;
759
26
    }
760
0
    else
761
0
        pcs = NULL;
762
26
    push(1); /* Sacrificial */
763
26
    procs = istate->colorspace[0].procs.cie;
764
26
    if (pcs == NULL ) {
765
        /* Stable memory due to current caching of color space */
766
15
        code = gs_cspace_build_CIEA(&pcs, NULL, mem->stable_memory);
767
15
    if (code < 0)
768
0
        return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
769
15
    pcie = pcs->params.a;
770
15
        code = cie_a_param(imemory, CIEdict, pcie, &procs, &has_a_procs,
771
15
                                &has_lmn_procs);
772
15
        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
15
        code = cie_cache_push_finish(i_ctx_p, cie_a_finish, (gs_ref_memory_t *)imem, pcie);
776
15
        if (code < 0)
777
0
            return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
778
15
        rc_increment(pcie);
779
15
        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
15
        } else {
786
15
            if (has_a_procs) {
787
8
                code = cie_prepare_iccproc(i_ctx_p, &pcie->RangeA,
788
8
                    &procs.Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A");
789
8
                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
8
            } else {
794
7
                pcie->caches.DecodeA.floats.params.is_identity = true;
795
7
            }
796
15
            if (has_lmn_procs) {
797
7
                cieicc_prepare_caches(i_ctx_p, (&pcie->common.RangeLMN)->ranges,
798
7
                         procs.DecodeLMN.value.const_refs,
799
7
                         &(pcie->common.caches.DecodeLMN)->floats,
800
7
                         &(pcie->common.caches.DecodeLMN)[1].floats,
801
7
                         &(pcie->common.caches.DecodeLMN)[2].floats,
802
7
                         NULL, pcie, imem, "Decode.LMN(ICC)");
803
8
            } else {
804
8
                pcie->common.caches.DecodeLMN->floats.params.is_identity = true;
805
8
                (pcie->common.caches.DecodeLMN)[1].floats.params.is_identity = true;
806
8
                (pcie->common.caches.DecodeLMN)[2].floats.params.is_identity = true;
807
8
            }
808
15
        }
809
        /* Add the color space to the profile cache */
810
15
        code = gsicc_add_cs(igs, pcs,dictkey);
811
15
        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
15
    } 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
26
    code = cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
821
26
    if (code < 0)
822
26
        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
26
    return code;
824
26
}
825
826
static int
827
cie_a_finish(i_ctx_t *i_ctx_p)
828
15
{
829
15
    os_ptr op = osp;
830
15
    gs_cie_a *pcie;
831
15
    gs_color_space *pcs = gs_currentcolorspace_inline(igs);
832
833
15
    if (!r_is_struct(op))
834
0
        return_error(gs_error_typecheck);
835
15
    pcie = r_ptr(op, gs_cie_a);
836
15
    rc_decrement(pcie, "cie_a_finish");
837
15
    pop(1);
838
15
    if (gs_color_space_get_index(pcs) != gs_color_space_index_CIEA)
839
0
        return_error(gs_error_typecheck);
840
15
    pcie->DecodeA = DecodeA_from_cache;
841
15
    pcie->common.DecodeLMN = DecodeLMN_from_cache;
842
15
    gs_cie_a_complete(pcie);
843
15
    return 0;
844
15
}
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
30
{
977
30
    check_estack(2);
978
30
    push_op_estack(finish_proc);
979
30
    ++esp;
980
30
    make_struct(esp, imemory_space(imem), data);
981
30
    return o_push_estack;
982
30
}
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
74
{
998
74
    int space = imemory_space(imem);
999
74
    gs_sample_loop_params_t lp;
1000
74
    es_ptr ep;
1001
1002
74
    gs_cie_cache_init(&pcache->params, &lp, domain, cname);
1003
74
    pcache->params.is_identity = r_size(proc) == 0;
1004
74
    check_estack(9);
1005
74
    ep = esp;
1006
74
    make_real(ep + 9, lp.A);
1007
74
    make_int(ep + 8, lp.N);
1008
74
    make_real(ep + 7, lp.B);
1009
74
    ep[6] = *proc;
1010
74
    r_clear_attrs(ep + 6, a_executable);
1011
74
    make_op_estack(ep + 5, zcvx);
1012
74
    make_op_estack(ep + 4, zfor_samples);
1013
74
    make_op_estack(ep + 3, cie_create_icc);
1014
74
    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
74
    make_int(ep + 2, (char *)pcache - (char *)container);
1021
74
    make_struct(ep + 1, space, container);
1022
74
    return o_push_estack;
1023
74
}
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
22
{
1033
22
    cie_cache_floats *pcn[4];
1034
22
    int i, n, code = 0;
1035
1036
22
    pcn[0] = pc0, pcn[1] = pc1, pcn[2] = pc2;
1037
22
    if (pc3 == 0)
1038
22
        n = 3;
1039
0
    else
1040
0
        pcn[3] = pc3, n = 4;
1041
88
    for (i = 0; i < n && code >= 0; ++i)
1042
66
        code = cie_prepare_iccproc(i_ctx_p, domains + i, procs + i, pcn[i],
1043
66
                                 container, imem, cname);
1044
22
    return code;
1045
22
}
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
74
{
1051
74
    os_ptr op = osp;
1052
74
    cie_cache_floats *pcache;
1053
74
    int code;
1054
1055
74
    check_esp(2);
1056
    /* See above for the container + offset representation of */
1057
    /* the pointer to the cache. */
1058
74
    pcache = (cie_cache_floats *) (r_ptr(esp - 1, char) + esp->value.intval);
1059
1060
74
    pcache->params.is_identity = false; /* cache_set_linear computes this */
1061
74
    if_debug3m('c', imemory, "[c]icc_sample_proc "PRI_INTPTR" base=%g, factor=%g:\n",
1062
74
               (intptr_t) pcache, pcache->params.base, pcache->params.factor);
1063
74
    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
74
    ref_stack_pop(&o_stack, gx_cie_cache_size);
1090
74
    esp -= 2;      /* pop pointer to cache */
1091
74
    return o_pop_estack;
1092
74
}