Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gscrd.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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 rendering dictionary creation */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gscdefs.h"    /* for gs_lib_device_list */
23
#include "gsdevice.h"
24
#include "gserrors.h"
25
#include "gsmatrix.h"   /* for gscolor2.h */
26
#include "gsparam.h"
27
#include "gsstruct.h"
28
#include "gsutil.h"
29
#include "gxcspace.h"
30
#include "gscolor2.h"   /* for gs_set/currentcolorrendering */
31
#include "gscrd.h"
32
33
/* Import gs_lib_device_list() */
34
extern_gs_lib_device_list();
35
36
/* Allocator structure type */
37
public_st_cie_render1();
38
static
39
1.01M
ENUM_PTRS_WITH(cie_render1_enum_ptrs, gs_cie_render *pcrd) return 0;
40
339k
case 0: return ENUM_OBJ(pcrd->client_data);
41
339k
case 1: return ENUM_OBJ(pcrd->RenderTable.lookup.table);
42
339k
case 2: return (pcrd->RenderTable.lookup.table ?
43
339k
                ENUM_CONST_STRING(&pcrd->TransformPQR.proc_data) :
44
339k
                0);
45
1.01M
ENUM_PTRS_END
46
339k
static RELOC_PTRS_WITH(cie_render1_reloc_ptrs, gs_cie_render *pcrd);
47
339k
RELOC_OBJ_VAR(pcrd->client_data);
48
339k
if (pcrd->RenderTable.lookup.table)
49
0
{
50
0
RELOC_OBJ_VAR(pcrd->RenderTable.lookup.table);
51
0
RELOC_CONST_STRING_VAR(pcrd->TransformPQR.proc_data);
52
0
}
53
339k
RELOC_PTRS_END
54
55
/* Default CRD procedures. */
56
57
static int
58
tpqr_identity(int index, double in, const gs_cie_wbsd * pwbsd,
59
              gs_cie_render * pcrd, float *out)
60
0
{
61
0
    *out = in;
62
0
    return 0;
63
0
}
64
65
static int
66
tpqr_from_cache(int index, double in, const gs_cie_wbsd * pwbsd,
67
                gs_cie_render * pcrd, float *out)
68
0
{
69
    /*
70
     * Since the TransformPQR cache is in the joint caches, not in the
71
     * CRD cache, we can't actually implement this procedure.
72
     * Instead, the place that calls it checks for it specially.
73
     */
74
0
    *out = in;
75
0
    return 0;
76
0
}
77
78
static float
79
render_identity(double in, const gs_cie_render * pcrd)
80
499M
{
81
499M
    return in;
82
499M
}
83
static frac
84
render_table_identity(byte in, const gs_cie_render * pcrd)
85
0
{
86
0
    return byte2frac(in);
87
0
}
88
89
/* Transformation procedures that just consult the cache. */
90
91
static float
92
EncodeABC_cached_A(double in, const gs_cie_render * pcrd)
93
0
{
94
0
    return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[0].floats);
95
0
}
96
static float
97
EncodeABC_cached_B(double in, const gs_cie_render * pcrd)
98
0
{
99
0
    return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[1].floats);
100
0
}
101
static float
102
EncodeABC_cached_C(double in, const gs_cie_render * pcrd)
103
0
{
104
0
    return gs_cie_cached_value(in, &pcrd->caches.EncodeABC[2].floats);
105
0
}
106
static float
107
EncodeLMN_cached_L(double in, const gs_cie_render * pcrd)
108
0
{
109
0
    return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[0].floats);
110
0
}
111
static float
112
EncodeLMN_cached_M(double in, const gs_cie_render * pcrd)
113
0
{
114
0
    return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[1].floats);
115
0
}
116
static float
117
EncodeLMN_cached_N(double in, const gs_cie_render * pcrd)
118
0
{
119
0
    return gs_cie_cached_value(in, &pcrd->caches.EncodeLMN.caches[2].floats);
120
0
}
121
122
static frac
123
RTT_cached(byte in, const gs_cie_render * pcrd, int i)
124
0
{
125
0
    return pcrd->caches.RenderTableT[i].fracs.values[
126
0
        in * (gx_cie_cache_size - 1) / 255
127
0
    ];
128
0
}
129
static frac
130
RTT_cached_0(byte in, const gs_cie_render * pcrd)
131
0
{
132
0
    return RTT_cached(in, pcrd, 0);
133
0
}
134
static frac
135
RTT_cached_1(byte in, const gs_cie_render * pcrd)
136
0
{
137
0
    return RTT_cached(in, pcrd, 1);
138
0
}
139
static frac
140
RTT_cached_2(byte in, const gs_cie_render * pcrd)
141
0
{
142
0
    return RTT_cached(in, pcrd, 2);
143
0
}
144
static frac
145
RTT_cached_3(byte in, const gs_cie_render * pcrd)
146
0
{
147
0
    return RTT_cached(in, pcrd, 3);
148
0
}
149
150
/* Define the TransformPQR trampoline procedure that looks up proc_name. */
151
152
static int
153
tpqr_do_lookup(gs_cie_render *pcrd, const gx_device *dev_proto)
154
0
{
155
0
    gx_device *dev;
156
0
    gs_memory_t *mem = pcrd->rc.memory;
157
0
    gs_c_param_list list;
158
0
    gs_param_string proc_addr;
159
0
    int code;
160
161
    /* Device prototypes are const, so we must create a copy. */
162
0
    code = gs_copydevice(&dev, dev_proto, mem);
163
0
    if (code < 0)
164
0
        return code;
165
0
    gs_c_param_list_write(&list, mem);
166
0
    code = param_request((gs_param_list *)&list,
167
0
                         pcrd->TransformPQR.proc_name);
168
0
    if (code >= 0) {
169
0
        code = gs_getdeviceparams(dev, (gs_param_list *)&list);
170
0
        if (code >= 0) {
171
0
            gs_c_param_list_read(&list);
172
0
            code = param_read_string((gs_param_list *)&list,
173
0
                                     pcrd->TransformPQR.proc_name,
174
0
                                     &proc_addr);
175
0
            if (code == 0 && proc_addr.size == sizeof(gs_cie_transform_proc)) {
176
0
                memcpy(&pcrd->TransformPQR.proc, proc_addr.data,
177
0
                       sizeof(gs_cie_transform_proc));
178
0
            } else
179
0
                code = gs_note_error(gs_error_rangecheck);
180
0
        }
181
0
    }
182
0
    gs_c_param_list_release(&list);
183
0
    gs_free_object(mem, dev, "tpqr_do_lookup(device)");
184
0
    return code;
185
0
}
186
static int
187
tpqr_lookup(int index, double in, const gs_cie_wbsd * pwbsd,
188
            gs_cie_render * pcrd, float *out)
189
0
{
190
0
    const gx_device *const *dev_list;
191
0
    int count = gs_lib_device_list(&dev_list, NULL);
192
0
    int i;
193
0
    int code;
194
195
0
    for (i = 0; i < count; ++i)
196
0
        if (!strcmp(gs_devicename(dev_list[i]),
197
0
                    pcrd->TransformPQR.driver_name))
198
0
            break;
199
0
    if (i < count)
200
0
        code = tpqr_do_lookup(pcrd, dev_list[i]);
201
0
    else
202
0
        code = gs_note_error(gs_error_undefined);
203
0
    if (code < 0)
204
0
        return code;
205
0
    return pcrd->TransformPQR.proc(index, in, pwbsd, pcrd, out);
206
0
}
207
208
/* Default vectors. */
209
const gs_cie_transform_proc3 TransformPQR_default = {
210
    tpqr_identity,
211
    0,        /* proc_name */
212
    {0, 0},     /* proc_data */
213
    0       /* driver_name */
214
};
215
const gs_cie_transform_proc3 TransformPQR_from_cache = {
216
    tpqr_from_cache,
217
    0,        /* proc_name */
218
    {0, 0},     /* proc_data */
219
    0       /* driver_name */
220
};
221
const gs_cie_transform_proc TransformPQR_lookup_proc_name = tpqr_lookup;
222
const gs_cie_render_proc3 Encode_default = {
223
    {render_identity, render_identity, render_identity}
224
};
225
const gs_cie_render_proc3 EncodeLMN_from_cache = {
226
    {EncodeLMN_cached_L, EncodeLMN_cached_M, EncodeLMN_cached_N}
227
};
228
const gs_cie_render_proc3 EncodeABC_from_cache = {
229
    {EncodeABC_cached_A, EncodeABC_cached_B, EncodeABC_cached_C}
230
};
231
const gs_cie_render_table_procs RenderTableT_default = {
232
    {render_table_identity, render_table_identity, render_table_identity,
233
     render_table_identity
234
    }
235
};
236
const gs_cie_render_table_procs RenderTableT_from_cache = {
237
    {RTT_cached_0, RTT_cached_1, RTT_cached_2, RTT_cached_3}
238
};
239
240
/*
241
 * Allocate and minimally initialize a CRD.  Note that this procedure sets
242
 * the reference count of the structure to 1, not 0.  gs_setcolorrendering
243
 * will increment the reference count again, so unless you want the
244
 * structure to stay allocated permanently (or until a garbage collection),
245
 * you should call rc_decrement(pcrd, "client name") *after* calling
246
 * gs_setcolorrendering.
247
 */
248
int
249
gs_cie_render1_build(gs_cie_render ** ppcrd, gs_memory_t * mem,
250
                     client_name_t cname)
251
162k
{
252
162k
    gs_cie_render *pcrd;
253
254
162k
    rc_alloc_struct_1(pcrd, gs_cie_render, &st_cie_render1, mem,
255
162k
                      return_error(gs_error_VMerror), cname);
256
162k
    pcrd->id = gs_next_ids(mem, 1);
257
    /* Initialize pointers for the GC. */
258
162k
    pcrd->client_data = 0;
259
162k
    pcrd->RenderTable.lookup.table = 0;
260
162k
    pcrd->status = CIE_RENDER_STATUS_BUILT;
261
162k
    *ppcrd = pcrd;
262
162k
    return 0;
263
162k
}
264
265
static bool render_proc3_equal(const gs_cie_render_proc3 *p1, const gs_cie_render_proc3 *p2)
266
0
{
267
0
    int k;
268
269
0
    for (k = 0; k < 3; k++) {
270
0
        if (p1->procs[k] != p2->procs[k])
271
0
            return false;
272
0
    }
273
0
    return true;
274
0
}
275
276
static bool render_table_procs_equal(const gs_cie_render_table_procs *p1,
277
    const gs_cie_render_table_procs *p2)
278
0
{
279
0
    int k;
280
281
0
    for (k = 0; k < 4; k++) {
282
0
        if (p1->procs[k] != p2->procs[k])
283
0
            return false;
284
0
    }
285
0
    return true;
286
0
}
287
288
/*
289
 * Initialize a CRD given all of the relevant parameters.
290
 * Any of the pointers except WhitePoint may be zero, meaning
291
 * use the default values.
292
 *
293
 * The actual point, matrix, range, and procedure values are copied into the
294
 * CRD, but only the pointer to the color lookup table is copied.
295
 *
296
 * If pfrom_crd is not NULL, then if the EncodeLMN, EncodeABC, or
297
 * RenderTable.T procedures indicate that the values exist only in the
298
 * cache, the corresponding values will be copied from pfrom_crd.
299
 * Note that NULL values for the individual pointers still represent
300
 * default values.
301
 */
302
int
303
gs_cie_render1_init_from(const gs_memory_t *mem,
304
                         gs_cie_render * pcrd,
305
                         void *client_data,
306
                         const gs_cie_render * pfrom_crd,
307
                         const gs_vector3 * WhitePoint,
308
                         const gs_vector3 * BlackPoint,
309
                         const gs_matrix3 * MatrixPQR,
310
                         const gs_range3 * RangePQR,
311
                         const gs_cie_transform_proc3 * TransformPQR,
312
                         const gs_matrix3 * MatrixLMN,
313
                         const gs_cie_render_proc3 * EncodeLMN,
314
                         const gs_range3 * RangeLMN,
315
                         const gs_matrix3 * MatrixABC,
316
                         const gs_cie_render_proc3 * EncodeABC,
317
                         const gs_range3 * RangeABC,
318
                         const gs_cie_render_table_t * RenderTable)
319
0
{
320
0
    pcrd->id = gs_next_ids(mem, 1);
321
0
    pcrd->client_data = client_data;
322
0
    pcrd->points.WhitePoint = *WhitePoint;
323
0
    pcrd->points.BlackPoint =
324
0
        *(BlackPoint ? BlackPoint : &BlackPoint_default);
325
0
    pcrd->MatrixPQR = *(MatrixPQR ? MatrixPQR : &Matrix3_default);
326
0
    pcrd->RangePQR = *(RangePQR ? RangePQR : &Range3_default);
327
0
    pcrd->TransformPQR =
328
0
        *(TransformPQR ? TransformPQR : &TransformPQR_default);
329
0
    pcrd->MatrixLMN = *(MatrixLMN ? MatrixLMN : &Matrix3_default);
330
0
    pcrd->EncodeLMN = *(EncodeLMN ? EncodeLMN : &Encode_default);
331
0
    if (pfrom_crd && render_proc3_equal(&pcrd->EncodeLMN, &EncodeLMN_from_cache))
332
0
        memcpy(&pcrd->caches.EncodeLMN, &pfrom_crd->caches.EncodeLMN,
333
0
               sizeof(pcrd->caches.EncodeLMN));
334
0
    pcrd->RangeLMN = *(RangeLMN ? RangeLMN : &Range3_default);
335
0
    pcrd->MatrixABC = *(MatrixABC ? MatrixABC : &Matrix3_default);
336
0
    pcrd->EncodeABC = *(EncodeABC ? EncodeABC : &Encode_default);
337
0
    if (pfrom_crd && render_proc3_equal(&pcrd->EncodeABC, &EncodeABC_from_cache))
338
0
        memcpy(pcrd->caches.EncodeABC, pfrom_crd->caches.EncodeABC,
339
0
               sizeof(pcrd->caches.EncodeABC));
340
0
    pcrd->RangeABC = *(RangeABC ? RangeABC : &Range3_default);
341
0
    if (RenderTable) {
342
0
        pcrd->RenderTable = *RenderTable;
343
0
        if (pfrom_crd && render_table_procs_equal(&pcrd->RenderTable.T,
344
0
            &RenderTableT_from_cache)) {
345
0
            memcpy(pcrd->caches.RenderTableT, pfrom_crd->caches.RenderTableT,
346
0
                   sizeof(pcrd->caches.RenderTableT));
347
0
            pcrd->caches.RenderTableT_is_identity =
348
0
                pfrom_crd->caches.RenderTableT_is_identity;
349
0
        }
350
0
    } else {
351
0
        pcrd->RenderTable.lookup.table = 0;
352
0
        pcrd->RenderTable.T = RenderTableT_default;
353
0
    }
354
0
    pcrd->status = CIE_RENDER_STATUS_BUILT;
355
0
    return 0;
356
0
}
357
/*
358
 * Initialize a CRD without the option of copying cached values.
359
 */
360
int
361
gs_cie_render1_initialize(const gs_memory_t *mem,
362
                          gs_cie_render * pcrd, void *client_data,
363
                          const gs_vector3 * WhitePoint,
364
                          const gs_vector3 * BlackPoint,
365
                          const gs_matrix3 * MatrixPQR,
366
                          const gs_range3 * RangePQR,
367
                          const gs_cie_transform_proc3 * TransformPQR,
368
                          const gs_matrix3 * MatrixLMN,
369
                          const gs_cie_render_proc3 * EncodeLMN,
370
                          const gs_range3 * RangeLMN,
371
                          const gs_matrix3 * MatrixABC,
372
                          const gs_cie_render_proc3 * EncodeABC,
373
                          const gs_range3 * RangeABC,
374
                          const gs_cie_render_table_t * RenderTable)
375
0
{
376
0
    return gs_cie_render1_init_from(mem, pcrd, client_data, NULL,
377
0
                                    WhitePoint, BlackPoint,
378
0
                                    MatrixPQR, RangePQR, TransformPQR,
379
0
                                    MatrixLMN, EncodeLMN, RangeLMN,
380
0
                                    MatrixABC, EncodeABC, RangeABC,
381
0
                                    RenderTable);
382
0
}