Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zcrd.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* CIE color rendering operators */
18
#include "math_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "gsstruct.h"
22
#include "gscspace.h"
23
#include "gscolor2.h"
24
#include "gscrd.h"
25
#include "gscrdp.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 "iparam.h"
33
#include "ivmspace.h"
34
#include "store.h"    /* for make_null */
35
36
/* Forward references */
37
static int zcrd1_proc_params(const gs_memory_t *mem, os_ptr op, ref_cie_render_procs * pcprocs);
38
static int zcrd1_params(os_ptr op, gs_cie_render * pcrd,
39
                         ref_cie_render_procs * pcprocs, gs_memory_t * mem);
40
/* - currentcolorrendering <dict> */
41
static int
42
zcurrentcolorrendering(i_ctx_t *i_ctx_p)
43
89.2k
{
44
89.2k
    os_ptr op = osp;
45
46
89.2k
    push(1);
47
89.2k
    *op = istate->colorrendering.dict;
48
89.2k
    return 0;
49
89.2k
}
50
51
/* <dict> .buildcolorrendering1 <crd> */
52
static int
53
zbuildcolorrendering1(i_ctx_t *i_ctx_p)
54
89.2k
{
55
89.2k
    os_ptr op = osp;
56
89.2k
    gs_memory_t *mem = gs_gstate_memory(igs);
57
89.2k
    int code;
58
89.2k
    es_ptr ep = esp;
59
89.2k
    gs_cie_render *pcrd;
60
89.2k
    ref_cie_render_procs procs;
61
62
89.2k
    check_read_type(*op, t_dictionary);
63
89.2k
    check_dict_read(*op);
64
89.2k
    code = gs_cie_render1_build(&pcrd, mem, ".buildcolorrendering1");
65
89.2k
    if (code < 0)
66
0
        return code;
67
89.2k
    code = zcrd1_params(op, pcrd, &procs, mem);
68
89.2k
    if (code < 0 ) {
69
0
        rc_free_struct(pcrd, ".buildcolorrendering1");
70
0
        esp = ep;
71
0
        return code;
72
0
    }
73
    /****** FIX refct ******/
74
    /*rc_decrement(pcrd, ".buildcolorrendering1"); *//* build sets rc = 1 */
75
89.2k
    istate->colorrendering.dict = *op;
76
89.2k
    make_istruct_new(op, a_readonly, pcrd);
77
89.2k
    return (esp == ep ? 0 : o_push_estack);
78
89.2k
}
79
80
/* <dict> .builddevicecolorrendering1 <crd> */
81
static int
82
zbuilddevicecolorrendering1(i_ctx_t *i_ctx_p)
83
0
{
84
0
    os_ptr op = osp;
85
0
    gs_memory_t *mem = gs_gstate_memory(igs);
86
0
    dict_param_list list;
87
0
    gs_cie_render *pcrd = 0;
88
0
    int code;
89
90
0
    check_type(*op, t_dictionary);
91
0
    code = dict_param_list_read(&list, op, NULL, false, iimemory);
92
0
    if (code < 0)
93
0
        return code;
94
0
    code = gs_cie_render1_build(&pcrd, mem, ".builddevicecolorrendering1");
95
0
    if (code >= 0) {
96
0
        code = param_get_cie_render1(pcrd, (gs_param_list *) & list,
97
0
                                     gs_currentdevice(igs));
98
0
        if (code >= 0) {
99
            /****** FIX refct ******/
100
            /*rc_decrement(pcrd, ".builddevicecolorrendering1"); *//* build sets rc = 1 */
101
0
        }
102
0
    }
103
0
    iparam_list_release(&list);
104
0
    if (code < 0) {
105
0
        rc_free_struct(pcrd, ".builddevicecolorrendering1");
106
0
        return code;
107
0
    }
108
0
    istate->colorrendering.dict = *op;
109
0
    make_istruct_new(op, a_readonly, pcrd);
110
0
    return 0;
111
0
}
112
113
/* <dict> <crd> .setcolorrendering1 - */
114
static int
115
zsetcolorrendering1(i_ctx_t *i_ctx_p)
116
89.2k
{
117
89.2k
    os_ptr op = osp;
118
89.2k
    es_ptr ep = esp;
119
89.2k
    ref_cie_render_procs procs;
120
89.2k
    int code;
121
122
89.2k
    check_type(op[-1], t_dictionary);
123
89.2k
    check_stype(*op, st_cie_render1);
124
89.2k
    code = zcrd1_proc_params(imemory, op - 1, &procs);
125
89.2k
    if (code < 0)
126
0
        return code;
127
89.2k
    code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
128
89.2k
    if (code < 0)
129
0
        return code;
130
89.2k
    if (gs_cie_cs_common(igs) != 0 &&
131
89.2k
        (code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
132
89.2k
        )
133
0
        return code;
134
89.2k
    istate->colorrendering.dict = op[-1];
135
89.2k
    istate->colorrendering.procs = procs;
136
89.2k
    pop(2);
137
89.2k
    return (esp == ep ? 0 : o_push_estack);
138
89.2k
}
139
140
/* <dict> <crd> .setdevicecolorrendering1 - */
141
static int
142
zsetdevicecolorrendering1(i_ctx_t *i_ctx_p)
143
0
{
144
0
    os_ptr op = osp;
145
0
    int code;
146
0
    ref_cie_render_procs procs;
147
148
0
    check_type(op[-1], t_dictionary);
149
0
    check_stype(*op, st_cie_render1);
150
0
    code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
151
0
    if (code < 0)
152
0
        return code;
153
0
    refset_null((ref *)&procs, sizeof(procs) / sizeof(ref));
154
0
    if (gs_cie_cs_common(igs) != 0 &&
155
0
        (code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
156
0
        )
157
0
        return code;
158
0
    istate->colorrendering.dict = op[-1];
159
0
    refset_null((ref *)&istate->colorrendering.procs,
160
0
                sizeof(istate->colorrendering.procs) / sizeof(ref));
161
0
    pop(2);
162
0
    return 0;
163
0
}
164
165
/* Get ColorRenderingType 1 procedures from the PostScript dictionary. */
166
static int
167
zcrd1_proc_params(const gs_memory_t *mem,
168
                  os_ptr op, ref_cie_render_procs * pcprocs)
169
178k
{
170
178k
    int code;
171
178k
    ref *pRT;
172
173
178k
    code = dict_proc3_param(mem, op, "EncodeLMN", &pcprocs->EncodeLMN);
174
178k
    if (code < 0)
175
0
        return code;
176
178k
    code = dict_proc3_param(mem, op, "EncodeABC", &pcprocs->EncodeABC);
177
178k
    if (code < 0)
178
0
        return code;
179
178k
    code = dict_proc3_param(mem, op, "TransformPQR", &pcprocs->TransformPQR);
180
178k
    if (code < 0)
181
0
        return code;
182
178k
    if (code == 1)
183
0
        return gs_note_error(gs_error_undefined);
184
178k
    if (dict_find_string(op, "RenderTable", &pRT) > 0) {
185
0
        const ref *prte;
186
0
        int size;
187
0
        int i;
188
189
0
        check_read_type(*pRT, t_array);
190
0
        size = r_size(pRT);
191
0
        if (size < 5)
192
0
            return_error(gs_error_rangecheck);
193
0
        prte = pRT->value.const_refs;
194
0
        for (i = 5; i < size; i++)
195
0
            check_proc_only(prte[i]);
196
0
        make_const_array(&pcprocs->RenderTableT, a_readonly | r_space(pRT),
197
0
                         size - 5, prte + 5);
198
0
    } else
199
178k
        make_null(&pcprocs->RenderTableT);
200
178k
    return 0;
201
178k
}
202
203
/* Get ColorRenderingType 1 parameters from the PostScript dictionary. */
204
static int
205
zcrd1_params(os_ptr op, gs_cie_render * pcrd,
206
             ref_cie_render_procs * pcprocs, gs_memory_t * mem)
207
89.2k
{
208
89.2k
    int code;
209
89.2k
    int ignore;
210
89.2k
    gx_color_lookup_table *const prtl = &pcrd->RenderTable.lookup;
211
89.2k
    ref *pRT;
212
213
89.2k
    if ((code = dict_int_param(op, "ColorRenderingType", 1, 1, 0, &ignore)) < 0)
214
0
        return code;
215
89.2k
    if ((code = zcrd1_proc_params(mem, op, pcprocs)) < 0)
216
0
        return code;
217
218
89.2k
    if ((code = dict_matrix3_param(mem, op, "MatrixLMN", &pcrd->MatrixLMN)) < 0)
219
0
        return code;
220
89.2k
    if ((code = dict_range3_param(mem, op, "RangeLMN", &pcrd->RangeLMN)) < 0)
221
0
        return code;
222
89.2k
    if ((code = dict_matrix3_param(mem, op, "MatrixABC", &pcrd->MatrixABC)) < 0)
223
0
        return code;
224
89.2k
    if ((code = dict_range3_param(mem, op, "RangeABC", &pcrd->RangeABC)) < 0)
225
0
        return code;
226
89.2k
    if ((code = cie_points_param(mem, op, &pcrd->points)) < 0)
227
0
        return code;
228
89.2k
    if ((code = dict_matrix3_param(mem, op, "MatrixPQR", &pcrd->MatrixPQR)) < 0)
229
0
        return code;
230
89.2k
    if ((code = dict_range3_param(mem,op, "RangePQR", &pcrd->RangePQR)) < 0)
231
0
        return code;
232
233
89.2k
    if (dict_find_string(op, "RenderTable", &pRT) > 0) {
234
0
        const ref *prte;
235
236
0
        check_read_type(*pRT, t_array);
237
0
        prte = pRT->value.const_refs;
238
        /* Finish unpacking and checking the RenderTable parameter. */
239
0
        check_type_only(prte[4], t_integer);
240
0
        if (!(prte[4].value.intval == 3 || prte[4].value.intval == 4))
241
0
            return_error(gs_error_rangecheck);
242
0
        prtl->n = 3;
243
0
        prtl->m = prte[4].value.intval;
244
0
        if (r_size(pRT) != prtl->m + 5)
245
0
            return_error(gs_error_rangecheck);
246
0
        code = cie_table_param(pRT, prtl, mem);
247
0
        if (code < 0)
248
0
            return code;
249
89.2k
    } else {
250
89.2k
        prtl->table = 0;
251
89.2k
    }
252
89.2k
    pcrd->EncodeLMN = Encode_default;
253
89.2k
    pcrd->EncodeABC = Encode_default;
254
89.2k
    pcrd->TransformPQR = TransformPQR_default;
255
89.2k
    pcrd->RenderTable.T = RenderTableT_default;
256
89.2k
    return 0;
257
89.2k
}
258
259
/* ------ Internal procedures ------ */
260
261
/* Load the joint caches. */
262
static int
263
    cie_exec_tpqr(i_ctx_t *),
264
    cie_post_exec_tpqr(i_ctx_t *),
265
    cie_tpqr_finish(i_ctx_t *);
266
int
267
cie_cache_joint(i_ctx_t *i_ctx_p, const ref_cie_render_procs * pcrprocs,
268
                const gs_cie_common *pcie, gs_gstate * pgs)
269
0
{
270
0
    const gs_cie_render *pcrd = gs_currentcolorrendering(pgs);
271
0
    gx_cie_joint_caches *pjc = gx_unshare_cie_caches(pgs);
272
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_gstate_memory(pgs);
273
0
    ref pqr_procs;
274
0
    uint space;
275
0
    int code;
276
0
    int i;
277
278
0
    if (pcrd == 0)   /* cache is not set up yet */
279
0
        return 0;
280
0
    if (pjc == 0)   /* must already be allocated */
281
0
        return_error(gs_error_VMerror);
282
0
    if (r_has_type(&pcrprocs->TransformPQR, t_null)) {
283
        /*
284
         * This CRD came from a driver, not from a PostScript dictionary.
285
         * Resample TransformPQR in C code.
286
         */
287
0
        return gs_cie_cs_complete(pgs, true);
288
0
    }
289
0
    gs_cie_compute_points_sd(pjc, pcie, pcrd);
290
0
    code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
291
0
                            "cie_cache_common");
292
0
    if (code < 0)
293
0
        return code;
294
    /* When we're done, deallocate the procs and complete the caches. */
295
0
    check_estack(3);
296
0
    code = cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs);
297
0
    if (code < 0)
298
0
        return code;
299
300
0
    *++esp = pqr_procs;
301
0
    space = r_space(&pqr_procs);
302
0
    for (i = 0; i < 3; i++) {
303
0
        ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i;
304
0
        const float *ppt = (float *)&pjc->points_sd;
305
0
        int j;
306
307
0
        make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
308
0
                   4, p);
309
0
        make_array(p, a_readonly | space, 4 * 6, p + 4);
310
0
        p[1] = pcrprocs->TransformPQR.value.refs[i];
311
0
        make_oper(p + 2, 0, cie_exec_tpqr);
312
0
        make_oper(p + 3, 0, cie_post_exec_tpqr);
313
0
        for (j = 0, p += 4; j < 4 * 6; j++, p++, ppt++)
314
0
            make_real(p, *ppt);
315
0
    }
316
0
    return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR,
317
0
                              pqr_procs.value.const_refs,
318
0
                              pjc->TransformPQR.caches,
319
0
                              pjc, imem, "Transform.PQR");
320
0
}
321
322
/* Private operator to shuffle arguments for the TransformPQR procedure: */
323
/* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
324
static int
325
cie_exec_tpqr(i_ctx_t *i_ctx_p)
326
0
{
327
0
    os_ptr op = osp;
328
0
    const ref *ppt = op[-1].value.const_refs;
329
0
    uint space = r_space(op - 1);
330
0
    int i;
331
332
0
    check_op(3);
333
0
    push(4);
334
0
    *op = op[-4];   /* proc */
335
0
    op[-1] = op[-6];    /* v */
336
0
    for (i = 0; i < 4; i++)
337
0
        make_const_array(op - 5 + i, a_readonly | space,
338
0
                         6, ppt + i * 6);
339
0
    make_mark(op - 6);
340
0
    return zexec(i_ctx_p);
341
0
}
342
343
/* Remove extraneous values from the stack after executing */
344
/* the TransformPQR procedure.  -mark- ... v -> v */
345
static int
346
cie_post_exec_tpqr(i_ctx_t *i_ctx_p)
347
0
{
348
0
    os_ptr op = osp;
349
0
    uint count = ref_stack_counttomark(&o_stack);
350
0
    ref vref;
351
352
0
    if (count < 2)
353
0
        return_error(gs_error_unmatchedmark);
354
0
    vref = *op;
355
0
    ref_stack_pop(&o_stack, count - 1);
356
0
    *osp = vref;
357
0
    return 0;
358
0
}
359
360
/* Free the procs array and complete the joint caches. */
361
static int
362
cie_tpqr_finish(i_ctx_t *i_ctx_p)
363
0
{
364
0
    os_ptr op = osp;
365
0
    gs_gstate *pgs = r_ptr(op, gs_gstate);
366
0
    gs_cie_render *pcrd =
367
0
        (gs_cie_render *)gs_currentcolorrendering(pgs);  /* break const */
368
0
    int code;
369
370
0
    ifree_ref_array(op - 1, "cie_tpqr_finish");
371
0
    pcrd->TransformPQR = TransformPQR_from_cache;
372
0
    code = gs_cie_cs_complete(pgs, false);
373
0
    pop(2);
374
0
    return code;
375
0
}
376
377
/* Ws Bs Wd Bd Ps .transformPQR_scale_wb[012] Pd
378
379
   The default TransformPQR procedure is implemented in C, rather than
380
   PostScript, as a speed optimization.
381
382
   This TransformPQR implements a relative colorimetric intent by scaling
383
   the XYZ values relative to the white and black points.
384
*/
385
static int
386
ztpqr_scale_wb_common(i_ctx_t *i_ctx_p, int idx)
387
0
{
388
0
    os_ptr op = osp;
389
0
    double a[4], Ps; /* a[0] = ws, a[1] = bs, a[2] = wd, a[3] = bd */
390
0
    double result;
391
0
    int code;
392
0
    int i;
393
394
0
    code = real_param(op, &Ps);
395
0
    if (code < 0) return code;
396
397
0
    for (i = 0; i < 4; i++) {
398
0
        ref tmp;
399
400
0
        code = array_get(imemory, op - 4 + i, idx, &tmp);
401
0
        if (code >= 0)
402
0
            code = real_param(&tmp, &a[i]);
403
0
        if (code < 0) return code;
404
0
    }
405
406
0
    if (a[0] == a[1])
407
0
        return_error(gs_error_undefinedresult);
408
0
    result = a[3] + (a[2] - a[3]) * (Ps - a[1]) / (a[0] - a[1]);
409
0
    make_real(op - 4, result);
410
0
    pop(4);
411
0
    return 0;
412
0
}
413
414
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb0 Pd */
415
static int
416
ztpqr_scale_wb0(i_ctx_t *i_ctx_p)
417
0
{
418
0
    return ztpqr_scale_wb_common(i_ctx_p, 3);
419
0
}
420
421
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
422
static int
423
ztpqr_scale_wb1(i_ctx_t *i_ctx_p)
424
0
{
425
0
    return ztpqr_scale_wb_common(i_ctx_p, 4);
426
0
}
427
428
/* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
429
static int
430
ztpqr_scale_wb2(i_ctx_t *i_ctx_p)
431
0
{
432
0
    return ztpqr_scale_wb_common(i_ctx_p, 5);
433
0
}
434
435
/* ------ Initialization procedure ------ */
436
437
const op_def zcrd_l2_op_defs[] =
438
{
439
    op_def_begin_level2(),
440
    {"0currentcolorrendering", zcurrentcolorrendering},
441
    {"2.setcolorrendering1", zsetcolorrendering1},
442
    {"2.setdevicecolorrendering1", zsetdevicecolorrendering1},
443
    {"1.buildcolorrendering1", zbuildcolorrendering1},
444
    {"1.builddevicecolorrendering1", zbuilddevicecolorrendering1},
445
                /* Internal "operators" */
446
    {"3%cie_exec_tpqr", cie_exec_tpqr},
447
    {"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
448
    {"1%cie_tpqr_finish", cie_tpqr_finish},
449
    {"5.TransformPQR_scale_WB0", ztpqr_scale_wb0},
450
    {"5.TransformPQR_scale_WB1", ztpqr_scale_wb1},
451
    {"5.TransformPQR_scale_WB2", ztpqr_scale_wb2},
452
    op_def_end(0)
453
};