Coverage Report

Created: 2025-06-10 07:19

/src/ghostpdl/base/gscie.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 cache management */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsstruct.h"
23
#include "gsmatrix.h"   /* for gscolor2.h */
24
#include "gxcspace.h"   /* for gxcie.c */
25
#include "gscolor2.h"   /* for gs_set/currentcolorrendering */
26
#include "gxarith.h"
27
#include "gxcie.h"
28
#include "gxdevice.h"   /* for gxcmap.h */
29
#include "gxcmap.h"
30
#include "gzstate.h"
31
#include "gsicc.h"
32
33
/*
34
 * Define whether to optimize the CIE mapping process by combining steps.
35
 * This should only be disabled (commented out) for debugging.
36
 */
37
#define OPTIMIZE_CIE_MAPPING
38
39
/* Forward references */
40
static int cie_joint_caches_init(gx_cie_joint_caches *,
41
                                  const gs_cie_common *,
42
                                  gs_cie_render *);
43
static void cie_joint_caches_complete(gx_cie_joint_caches *,
44
                                       const gs_cie_common *,
45
                                       const gs_cie_abc *,
46
                                       const gs_cie_render *);
47
static void cie_cache_restrict(cie_cache_floats *, const gs_range *);
48
static void cie_invert3(const gs_matrix3 *, gs_matrix3 *);
49
static void cie_matrix_init(gs_matrix3 *);
50
51
/* Allocator structure types */
52
private_st_joint_caches();
53
extern_st(st_gs_gstate);
54
55
#define RESTRICTED_INDEX(v, n, itemp)\
56
0
  ((uint)(itemp = (int)(v)) >= (n) ?\
57
0
   (itemp < 0 ? 0 : (n) - 1) : itemp)
58
59
/* Define cache interpolation threshold values. */
60
#ifdef CIE_CACHE_INTERPOLATE
61
#  ifdef CIE_INTERPOLATE_THRESHOLD
62
9.57k
#    define CACHE_THRESHOLD CIE_INTERPOLATE_THRESHOLD
63
#  else
64
#    define CACHE_THRESHOLD 0 /* always interpolate */
65
#  endif
66
#else
67
#  define CACHE_THRESHOLD 1.0e6 /* never interpolate */
68
#endif
69
#ifdef CIE_RENDER_TABLE_INTERPOLATE
70
#  define RENDER_TABLE_THRESHOLD 0
71
#else
72
#  define RENDER_TABLE_THRESHOLD 1.0e6
73
#endif
74
75
/*
76
 * Determine whether a function is a linear transformation of the form
77
 * f(x) = scale * x + origin.
78
 */
79
static bool
80
cache_is_linear(cie_linear_params_t *params, const cie_cache_floats *pcf)
81
0
{
82
0
    double origin = pcf->values[0];
83
0
    double diff = pcf->values[countof(pcf->values) - 1] - origin;
84
0
    double scale = diff / (countof(pcf->values) - 1);
85
0
    int i;
86
0
    double test = origin + scale;
87
88
0
    for (i = 1; i < countof(pcf->values) - 1; ++i, test += scale)
89
0
        if (fabs(pcf->values[i] - test) >= 0.5 / countof(pcf->values))
90
0
            return (params->is_linear = false);
91
0
    params->origin = origin - pcf->params.base;
92
0
    params->scale =
93
0
        diff * pcf->params.factor / (countof(pcf->values) - 1);
94
0
    return (params->is_linear = true);
95
0
}
96
97
static void
98
cache_set_linear(cie_cache_floats *pcf)
99
28.7k
{
100
28.7k
        if (pcf->params.is_identity) {
101
28.7k
            if_debug1('c', "[c]is_linear("PRI_INTPTR") = true (is_identity)\n",
102
28.7k
                      (intptr_t)pcf);
103
28.7k
            pcf->params.linear.is_linear = true;
104
28.7k
            pcf->params.linear.origin = 0;
105
28.7k
            pcf->params.linear.scale = 1;
106
28.7k
        } else if (cache_is_linear(&pcf->params.linear, pcf)) {
107
0
            if (pcf->params.linear.origin == 0 &&
108
0
                fabs(pcf->params.linear.scale - 1) < 0.00001)
109
0
                pcf->params.is_identity = true;
110
0
            if_debug4('c',
111
0
                      "[c]is_linear("PRI_INTPTR") = true, origin = %g, scale = %g%s\n",
112
0
                      (intptr_t)pcf, pcf->params.linear.origin,
113
0
                      pcf->params.linear.scale,
114
0
                      (pcf->params.is_identity ? " (=> is_identity)" : ""));
115
0
        }
116
#ifdef DEBUG
117
        else
118
            if_debug1('c', "[c]linear("PRI_INTPTR") = false\n", (intptr_t)pcf);
119
#endif
120
28.7k
}
121
static void
122
cache3_set_linear(gx_cie_vector_cache3_t *pvc)
123
9.57k
{
124
9.57k
    cache_set_linear(&pvc->caches[0].floats);
125
9.57k
    cache_set_linear(&pvc->caches[1].floats);
126
9.57k
    cache_set_linear(&pvc->caches[2].floats);
127
9.57k
}
128
129
#ifdef DEBUG
130
static void
131
if_debug_vector3(const char *str, const gs_vector3 *vec)
132
{
133
    if_debug4('c', "%s[%g %g %g]\n", str, vec->u, vec->v, vec->w);
134
}
135
static void
136
if_debug_matrix3(const char *str, const gs_matrix3 *mat)
137
{
138
    if_debug10('c', "%s [%g %g %g] [%g %g %g] [%g %g %g]\n", str,
139
               mat->cu.u, mat->cu.v, mat->cu.w,
140
               mat->cv.u, mat->cv.v, mat->cv.w,
141
               mat->cw.u, mat->cw.v, mat->cw.w);
142
}
143
#else
144
95.7k
#  define if_debug_vector3(str, vec) DO_NOTHING
145
124k
#  define if_debug_matrix3(str, mat) DO_NOTHING
146
#endif
147
148
/* ------ Default values for CIE dictionary elements ------ */
149
150
/* Default transformation procedures. */
151
152
float
153
a_identity(double in, const gs_cie_a * pcie)
154
0
{
155
0
    return in;
156
0
}
157
static float
158
a_from_cache(double in, const gs_cie_a * pcie)
159
0
{
160
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeA.floats);
161
0
}
162
163
float
164
abc_identity(double in, const gs_cie_abc * pcie)
165
0
{
166
0
    return in;
167
0
}
168
static float
169
abc_from_cache_0(double in, const gs_cie_abc * pcie)
170
0
{
171
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeABC.caches[0].floats);
172
0
}
173
static float
174
abc_from_cache_1(double in, const gs_cie_abc * pcie)
175
0
{
176
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeABC.caches[1].floats);
177
0
}
178
static float
179
abc_from_cache_2(double in, const gs_cie_abc * pcie)
180
0
{
181
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeABC.caches[2].floats);
182
0
}
183
184
static float
185
def_identity(double in, const gs_cie_def * pcie)
186
0
{
187
0
    return in;
188
0
}
189
static float
190
def_from_cache_0(double in, const gs_cie_def * pcie)
191
0
{
192
0
    return gs_cie_cached_value(in, &pcie->caches_def.DecodeDEF[0].floats);
193
0
}
194
static float
195
def_from_cache_1(double in, const gs_cie_def * pcie)
196
0
{
197
0
    return gs_cie_cached_value(in, &pcie->caches_def.DecodeDEF[1].floats);
198
0
}
199
static float
200
def_from_cache_2(double in, const gs_cie_def * pcie)
201
0
{
202
0
    return gs_cie_cached_value(in, &pcie->caches_def.DecodeDEF[2].floats);
203
0
}
204
205
static float
206
defg_identity(double in, const gs_cie_defg * pcie)
207
0
{
208
0
    return in;
209
0
}
210
static float
211
defg_from_cache_0(double in, const gs_cie_defg * pcie)
212
0
{
213
0
    return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[0].floats);
214
0
}
215
static float
216
defg_from_cache_1(double in, const gs_cie_defg * pcie)
217
0
{
218
0
    return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[1].floats);
219
0
}
220
static float
221
defg_from_cache_2(double in, const gs_cie_defg * pcie)
222
0
{
223
0
    return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[2].floats);
224
0
}
225
static float
226
defg_from_cache_3(double in, const gs_cie_defg * pcie)
227
0
{
228
0
    return gs_cie_cached_value(in, &pcie->caches_defg.DecodeDEFG[3].floats);
229
0
}
230
231
float
232
common_identity(double in, const gs_cie_common * pcie)
233
0
{
234
0
    return in;
235
0
}
236
static float
237
lmn_from_cache_0(double in, const gs_cie_common * pcie)
238
0
{
239
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeLMN[0].floats);
240
0
}
241
static float
242
lmn_from_cache_1(double in, const gs_cie_common * pcie)
243
0
{
244
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeLMN[1].floats);
245
0
}
246
static float
247
lmn_from_cache_2(double in, const gs_cie_common * pcie)
248
0
{
249
0
    return gs_cie_cached_value(in, &pcie->caches.DecodeLMN[2].floats);
250
0
}
251
252
/* Transformation procedures for accessing an already-loaded cache. */
253
254
float
255
gs_cie_cached_value(double in, const cie_cache_floats *pcache)
256
0
{
257
    /*
258
     * We need to get the same results when we sample an already-loaded
259
     * cache, so we need to round the index just a tiny bit.
260
     */
261
0
    int index =
262
0
        (int)((in - pcache->params.base) * pcache->params.factor + 0.0001);
263
264
0
    CIE_CLAMP_INDEX(index);
265
0
    return pcache->values[index];
266
0
}
267
268
/* Default vectors and matrices. */
269
270
const gs_range3 Range3_default = {
271
    { {0, 1}, {0, 1}, {0, 1} }
272
};
273
const gs_range4 Range4_default = {
274
    { {0, 1}, {0, 1}, {0, 1}, {0, 1} }
275
};
276
const gs_cie_defg_proc4 DecodeDEFG_default = {
277
    {defg_identity, defg_identity, defg_identity, defg_identity}
278
};
279
const gs_cie_defg_proc4 DecodeDEFG_from_cache = {
280
    {defg_from_cache_0, defg_from_cache_1, defg_from_cache_2, defg_from_cache_3}
281
};
282
const gs_cie_def_proc3 DecodeDEF_default = {
283
    {def_identity, def_identity, def_identity}
284
};
285
const gs_cie_def_proc3 DecodeDEF_from_cache = {
286
    {def_from_cache_0, def_from_cache_1, def_from_cache_2}
287
};
288
const gs_cie_abc_proc3 DecodeABC_default = {
289
    {abc_identity, abc_identity, abc_identity}
290
};
291
const gs_cie_abc_proc3 DecodeABC_from_cache = {
292
    {abc_from_cache_0, abc_from_cache_1, abc_from_cache_2}
293
};
294
const gs_cie_common_proc3 DecodeLMN_default = {
295
    {common_identity, common_identity, common_identity}
296
};
297
const gs_cie_common_proc3 DecodeLMN_from_cache = {
298
    {lmn_from_cache_0, lmn_from_cache_1, lmn_from_cache_2}
299
};
300
const gs_matrix3 Matrix3_default = {
301
    {1, 0, 0},
302
    {0, 1, 0},
303
    {0, 0, 1},
304
    1 /*true */
305
};
306
const gs_range RangeA_default = {0, 1};
307
const gs_cie_a_proc DecodeA_default = a_identity;
308
const gs_cie_a_proc DecodeA_from_cache = a_from_cache;
309
const gs_vector3 MatrixA_default = {1, 1, 1};
310
const gs_vector3 BlackPoint_default = {0, 0, 0};
311
312
/* Initialize a CIE color. */
313
/* This only happens on setcolorspace. */
314
void
315
gx_init_CIE(gs_client_color * pcc, const gs_color_space * pcs)
316
0
{
317
0
    gx_init_paint_4(pcc, pcs);
318
    /* (0...) may not be within the range of allowable values. */
319
0
    (*pcs->type->restrict_color)(pcc, pcs);
320
0
}
321
322
/* Restrict CIE colors. */
323
324
static inline void
325
cie_restrict(float *pv, const gs_range *range)
326
0
{
327
0
    if (*pv <= range->rmin)
328
0
        *pv = range->rmin;
329
0
    else if (*pv >= range->rmax)
330
0
        *pv = range->rmax;
331
0
}
332
333
void
334
gx_restrict_CIEDEFG(gs_client_color * pcc, const gs_color_space * pcs)
335
0
{
336
0
    const gs_cie_defg *pcie = pcs->params.defg;
337
338
0
    cie_restrict(&pcc->paint.values[0], &pcie->RangeDEFG.ranges[0]);
339
0
    cie_restrict(&pcc->paint.values[1], &pcie->RangeDEFG.ranges[1]);
340
0
    cie_restrict(&pcc->paint.values[2], &pcie->RangeDEFG.ranges[2]);
341
0
    cie_restrict(&pcc->paint.values[3], &pcie->RangeDEFG.ranges[3]);
342
0
}
343
void
344
gx_restrict_CIEDEF(gs_client_color * pcc, const gs_color_space * pcs)
345
0
{
346
0
    const gs_cie_def *pcie = pcs->params.def;
347
348
0
    cie_restrict(&pcc->paint.values[0], &pcie->RangeDEF.ranges[0]);
349
0
    cie_restrict(&pcc->paint.values[1], &pcie->RangeDEF.ranges[1]);
350
0
    cie_restrict(&pcc->paint.values[2], &pcie->RangeDEF.ranges[2]);
351
0
}
352
void
353
gx_restrict_CIEABC(gs_client_color * pcc, const gs_color_space * pcs)
354
0
{
355
0
    const gs_cie_abc *pcie = pcs->params.abc;
356
357
0
    cie_restrict(&pcc->paint.values[0], &pcie->RangeABC.ranges[0]);
358
0
    cie_restrict(&pcc->paint.values[1], &pcie->RangeABC.ranges[1]);
359
0
    cie_restrict(&pcc->paint.values[2], &pcie->RangeABC.ranges[2]);
360
0
}
361
void
362
gx_restrict_CIEA(gs_client_color * pcc, const gs_color_space * pcs)
363
0
{
364
0
    const gs_cie_a *pcie = pcs->params.a;
365
366
0
    cie_restrict(&pcc->paint.values[0], &pcie->RangeA);
367
0
}
368
369
/* ================ Table setup ================ */
370
371
/* ------ Install a CIE color space ------ */
372
373
static void cie_cache_mult(gx_cie_vector_cache *, const gs_vector3 *,
374
                            const cie_cache_floats *, double);
375
static bool cie_cache_mult3(gx_cie_vector_cache3_t *,
376
                             const gs_matrix3 *, double);
377
378
int
379
gx_install_cie_abc(gs_cie_abc *pcie, gs_gstate * pgs)
380
0
{
381
0
    if_debug_matrix3("[c]CIE MatrixABC =", &pcie->MatrixABC);
382
0
    cie_matrix_init(&pcie->MatrixABC);
383
0
    CIE_LOAD_CACHE_BODY(pcie->caches.DecodeABC.caches, pcie->RangeABC.ranges,
384
0
                        &pcie->DecodeABC, DecodeABC_default, pcie,
385
0
                        "DecodeABC");
386
0
    gx_cie_load_common_cache(&pcie->common, pgs);
387
0
    gs_cie_abc_complete(pcie);
388
0
    return gs_cie_cs_complete(pgs, true);
389
0
}
390
391
int
392
gx_install_CIEDEFG(gs_color_space * pcs, gs_gstate * pgs)
393
0
{
394
0
    gs_cie_defg *pcie = pcs->params.defg;
395
396
0
    CIE_LOAD_CACHE_BODY(pcie->caches_defg.DecodeDEFG, pcie->RangeDEFG.ranges,
397
0
                        &pcie->DecodeDEFG, DecodeDEFG_default, pcie,
398
0
                        "DecodeDEFG");
399
0
    return gx_install_cie_abc((gs_cie_abc *)pcie, pgs);
400
0
}
401
402
int
403
gx_install_CIEDEF(gs_color_space * pcs, gs_gstate * pgs)
404
0
{
405
0
    gs_cie_def *pcie = pcs->params.def;
406
407
0
    CIE_LOAD_CACHE_BODY(pcie->caches_def.DecodeDEF, pcie->RangeDEF.ranges,
408
0
                        &pcie->DecodeDEF, DecodeDEF_default, pcie,
409
0
                        "DecodeDEF");
410
0
    return gx_install_cie_abc((gs_cie_abc *)pcie, pgs);
411
0
}
412
413
int
414
gx_install_CIEABC(gs_color_space * pcs, gs_gstate * pgs)
415
0
{
416
0
    return gx_install_cie_abc(pcs->params.abc, pgs);
417
0
}
418
419
int
420
gx_install_CIEA(gs_color_space * pcs, gs_gstate * pgs)
421
0
{
422
0
    gs_cie_a *pcie = pcs->params.a;
423
0
    gs_sample_loop_params_t lp;
424
0
    int i;
425
426
0
    gs_cie_cache_init(&pcie->caches.DecodeA.floats.params, &lp,
427
0
                      &pcie->RangeA, "DecodeA");
428
0
    for (i = 0; i <= lp.N; ++i) {
429
0
        float in = SAMPLE_LOOP_VALUE(i, lp);
430
431
0
        pcie->caches.DecodeA.floats.values[i] = (*pcie->DecodeA)(in, pcie);
432
0
        if_debug3m('C', pgs->memory, "[C]DecodeA[%d] = %g => %g\n",
433
0
                   i, in, pcie->caches.DecodeA.floats.values[i]);
434
0
    }
435
0
    gx_cie_load_common_cache(&pcie->common, pgs);
436
0
    gs_cie_a_complete(pcie);
437
0
    return gs_cie_cs_complete(pgs, true);
438
0
}
439
440
/* Load the common caches when installing the color space. */
441
/* This routine is exported for the benefit of gsicc.c */
442
void
443
gx_cie_load_common_cache(gs_cie_common * pcie, gs_gstate * pgs)
444
0
{
445
0
    if_debug_matrix3("[c]CIE MatrixLMN =", &pcie->MatrixLMN);
446
0
    cie_matrix_init(&pcie->MatrixLMN);
447
0
    CIE_LOAD_CACHE_BODY(pcie->caches.DecodeLMN, pcie->RangeLMN.ranges,
448
0
                        &pcie->DecodeLMN, DecodeLMN_default, pcie,
449
0
                        "DecodeLMN");
450
0
}
451
452
/* Complete loading the common caches. */
453
/* This routine is exported for the benefit of gsicc.c */
454
void
455
gx_cie_common_complete(gs_cie_common *pcie)
456
0
{
457
0
    int i;
458
459
0
    for (i = 0; i < 3; ++i)
460
0
        cache_set_linear(&pcie->caches.DecodeLMN[i].floats);
461
0
}
462
463
/*
464
 * Restrict the DecodeDEF[G] cache according to RangeHIJ[K], and scale to
465
 * the dimensions of Table.
466
 */
467
static void
468
gs_cie_defx_scale(float *values, const gs_range *range, int dim)
469
0
{
470
0
    double scale = (dim - 1.0) / (range->rmax - range->rmin);
471
0
    int i;
472
473
0
    for (i = 0; i < gx_cie_cache_size; ++i) {
474
0
        float value = values[i];
475
476
0
        values[i] =
477
0
            (value <= range->rmin ? 0 :
478
0
             value >= range->rmax ? dim - 1 :
479
0
             (value - range->rmin) * scale);
480
0
    }
481
0
}
482
483
/* Complete loading a CIEBasedDEFG color space. */
484
/* This routine is NOT idempotent. */
485
void
486
gs_cie_defg_complete(gs_cie_defg * pcie)
487
0
{
488
0
    int j;
489
490
0
    for (j = 0; j < 4; ++j)
491
0
        gs_cie_defx_scale(pcie->caches_defg.DecodeDEFG[j].floats.values,
492
0
                          &pcie->RangeHIJK.ranges[j], pcie->Table.dims[j]);
493
0
    gs_cie_abc_complete((gs_cie_abc *)pcie);
494
0
}
495
496
/* Complete loading a CIEBasedDEF color space. */
497
/* This routine is NOT idempotent. */
498
void
499
gs_cie_def_complete(gs_cie_def * pcie)
500
0
{
501
0
    int j;
502
503
0
    for (j = 0; j < 3; ++j)
504
0
        gs_cie_defx_scale(pcie->caches_def.DecodeDEF[j].floats.values,
505
0
                          &pcie->RangeHIJ.ranges[j], pcie->Table.dims[j]);
506
0
    gs_cie_abc_complete((gs_cie_abc *)pcie);
507
0
}
508
509
/* Complete loading a CIEBasedABC color space. */
510
/* This routine is idempotent. */
511
void
512
gs_cie_abc_complete(gs_cie_abc * pcie)
513
0
{
514
0
    cache3_set_linear(&pcie->caches.DecodeABC);
515
0
    pcie->caches.skipABC =
516
0
        cie_cache_mult3(&pcie->caches.DecodeABC, &pcie->MatrixABC,
517
0
                        CACHE_THRESHOLD);
518
0
    gx_cie_common_complete((gs_cie_common *)pcie);
519
0
}
520
521
/* Complete loading a CIEBasedA color space. */
522
/* This routine is idempotent. */
523
void
524
gs_cie_a_complete(gs_cie_a * pcie)
525
0
{
526
0
    cie_cache_mult(&pcie->caches.DecodeA, &pcie->MatrixA,
527
0
                   &pcie->caches.DecodeA.floats,
528
0
                   CACHE_THRESHOLD);
529
0
    cache_set_linear(&pcie->caches.DecodeA.floats);
530
0
    gx_cie_common_complete((gs_cie_common *)pcie);
531
0
}
532
533
/*
534
 * Set the ranges where interpolation is required in a vector cache.
535
 * This procedure is idempotent.
536
 */
537
typedef struct cie_cache_range_temp_s {
538
    cie_cached_value prev;
539
    int imin, imax;
540
} cie_cache_range_temp_t;
541
static inline void
542
check_interpolation_required(cie_cache_range_temp_t *pccr,
543
                             cie_cached_value cur, int i, double threshold)
544
44.1M
{
545
44.1M
    cie_cached_value prev = pccr->prev;
546
547
44.1M
    if (cie_cached_abs(cur - prev) > threshold * min(cie_cached_abs(prev), cie_cached_abs(cur))) {
548
3.75M
        if (i - 1 < pccr->imin)
549
28.7k
            pccr->imin = i - 1;
550
3.75M
        if (i > pccr->imax)
551
3.75M
            pccr->imax = i;
552
3.75M
    }
553
44.1M
    pccr->prev = cur;
554
44.1M
}
555
static void
556
cie_cache_set_interpolation(gx_cie_vector_cache *pcache, double threshold)
557
28.7k
{
558
28.7k
    cie_cached_value base = pcache->vecs.params.base;
559
28.7k
    cie_cached_value factor = pcache->vecs.params.factor;
560
28.7k
    cie_cache_range_temp_t temp[3];
561
28.7k
    int i, j;
562
563
114k
    for (j = 0; j < 3; ++j)
564
86.2k
        temp[j].imin = gx_cie_cache_size, temp[j].imax = -1;
565
28.7k
    temp[0].prev = pcache->vecs.values[0].u;
566
28.7k
    temp[1].prev = pcache->vecs.values[0].v;
567
28.7k
    temp[2].prev = pcache->vecs.values[0].w;
568
569
14.7M
    for (i = 0; i < gx_cie_cache_size; ++i) {
570
14.7M
        check_interpolation_required(&temp[0], pcache->vecs.values[i].u, i,
571
14.7M
                                     threshold);
572
14.7M
        check_interpolation_required(&temp[1], pcache->vecs.values[i].v, i,
573
14.7M
                                     threshold);
574
14.7M
        check_interpolation_required(&temp[2], pcache->vecs.values[i].w, i,
575
14.7M
                                     threshold);
576
14.7M
    }
577
578
114k
    for (j = 0; j < 3; ++j) {
579
86.2k
        pcache->vecs.params.interpolation_ranges[j].rmin =
580
86.2k
            base + (cie_cached_value)((double)temp[j].imin / factor);
581
86.2k
        pcache->vecs.params.interpolation_ranges[j].rmax =
582
86.2k
            base + (cie_cached_value)((double)temp[j].imax / factor);
583
86.2k
        if_debug3('c', "[c]interpolation_ranges[%d] = %g, %g\n", j,
584
86.2k
                  cie_cached2float(pcache->vecs.params.interpolation_ranges[j].rmin),
585
86.2k
                  cie_cached2float(pcache->vecs.params.interpolation_ranges[j].rmax));
586
86.2k
    }
587
588
28.7k
}
589
590
/*
591
 * Convert a scalar cache to a vector cache by multiplying the scalar
592
 * values by a vector.  Also set the range where interpolation is needed.
593
 * This procedure is idempotent.
594
 */
595
static void
596
cie_cache_mult(gx_cie_vector_cache * pcache, const gs_vector3 * pvec,
597
               const cie_cache_floats * pcf, double threshold)
598
28.7k
{
599
28.7k
    float u = pvec->u, v = pvec->v, w = pvec->w;
600
28.7k
    int i;
601
602
28.7k
    pcache->vecs.params.base = float2cie_cached(pcf->params.base);
603
28.7k
    pcache->vecs.params.factor = float2cie_cached(pcf->params.factor);
604
28.7k
    pcache->vecs.params.limit =
605
28.7k
        float2cie_cached((gx_cie_cache_size - 1) / pcf->params.factor +
606
28.7k
                         pcf->params.base);
607
14.7M
    for (i = 0; i < gx_cie_cache_size; ++i) {
608
14.7M
        float f = pcf->values[i];
609
610
14.7M
        pcache->vecs.values[i].u = float2cie_cached(f * u);
611
14.7M
        pcache->vecs.values[i].v = float2cie_cached(f * v);
612
14.7M
        pcache->vecs.values[i].w = float2cie_cached(f * w);
613
14.7M
    }
614
28.7k
    cie_cache_set_interpolation(pcache, threshold);
615
28.7k
}
616
617
/*
618
 * Set the interpolation ranges in a 3-vector cache, based on the ranges in
619
 * the individual vector caches.  This procedure is idempotent.
620
 */
621
static void
622
cie_cache3_set_interpolation(gx_cie_vector_cache3_t * pvc)
623
9.57k
{
624
9.57k
    int j, k;
625
626
    /* Iterate over output components. */
627
38.3k
    for (j = 0; j < 3; ++j) {
628
        /* Iterate over sub-caches. */
629
28.7k
        cie_interpolation_range_t *p =
630
28.7k
                &pvc->caches[0].vecs.params.interpolation_ranges[j];
631
28.7k
        cie_cached_value rmin = p->rmin, rmax = p->rmax;
632
633
86.2k
        for (k = 1; k < 3; ++k) {
634
57.4k
            p = &pvc->caches[k].vecs.params.interpolation_ranges[j];
635
57.4k
            rmin = min(rmin, p->rmin), rmax = max(rmax, p->rmax);
636
57.4k
        }
637
28.7k
        pvc->interpolation_ranges[j].rmin = rmin;
638
28.7k
        pvc->interpolation_ranges[j].rmax = rmax;
639
28.7k
        if_debug3('c', "[c]Merged interpolation_ranges[%d] = %g, %g\n",
640
28.7k
                  j, rmin, rmax);
641
28.7k
    }
642
9.57k
}
643
644
/*
645
 * Convert 3 scalar caches to vector caches by multiplying by a matrix.
646
 * Return true iff the resulting cache is an identity transformation.
647
 * This procedure is idempotent.
648
 */
649
static bool
650
cie_cache_mult3(gx_cie_vector_cache3_t * pvc, const gs_matrix3 * pmat,
651
                double threshold)
652
9.57k
{
653
9.57k
    cie_cache_mult(&pvc->caches[0], &pmat->cu, &pvc->caches[0].floats, threshold);
654
9.57k
    cie_cache_mult(&pvc->caches[1], &pmat->cv, &pvc->caches[1].floats, threshold);
655
9.57k
    cie_cache_mult(&pvc->caches[2], &pmat->cw, &pvc->caches[2].floats, threshold);
656
9.57k
    cie_cache3_set_interpolation(pvc);
657
9.57k
    return pmat->is_identity & pvc->caches[0].floats.params.is_identity &
658
9.57k
        pvc->caches[1].floats.params.is_identity &
659
9.57k
        pvc->caches[2].floats.params.is_identity;
660
9.57k
}
661
662
/* ------ Install a rendering dictionary ------ */
663
664
bool
665
vector_equal(const gs_vector3 *p1, const gs_vector3 *p2)
666
0
{
667
0
    if (p1->u != p2->u)
668
0
        return false;
669
0
    if (p1->v != p2->v)
670
0
        return false;
671
0
    if (p1->w != p2->w)
672
0
        return false;
673
0
    return true;
674
0
}
675
676
bool
677
matrix_equal(const gs_matrix3 *p1, const gs_matrix3 *p2)
678
0
{
679
0
    if (p1->is_identity != p2->is_identity)
680
0
        return false;
681
0
    if (!vector_equal(&(p1->cu), &(p2->cu)))
682
0
        return false;
683
0
    if (!vector_equal(&(p1->cv), &(p2->cv)))
684
0
        return false;
685
0
    if (!vector_equal(&(p1->cw), &(p2->cw)))
686
0
        return false;
687
0
    return true;
688
0
}
689
690
static bool
691
transform_equal(const gs_cie_transform_proc3 *p1, const gs_cie_transform_proc3 *p2)
692
0
{
693
0
    if (p1->proc != p2->proc)
694
0
        return false;
695
0
    if (p1->proc_data.size != p2->proc_data.size)
696
0
        return false;
697
0
    if (memcmp(p1->proc_data.data, p2->proc_data.data, p1->proc_data.size) != 0)
698
0
        return false;
699
0
    if (p1->driver_name != p2->driver_name)
700
0
        return false;
701
0
    if (p1->proc_name != p2->proc_name)
702
0
        return false;
703
0
    return true;
704
0
}
705
706
bool
707
range_equal(const gs_range3 *p1, const gs_range3 *p2)
708
0
{
709
0
    int k;
710
711
0
    for (k = 0; k < 3; k++) {
712
0
        if (p1->ranges[k].rmax != p2->ranges[k].rmax)
713
0
            return false;
714
0
        if (p1->ranges[k].rmin != p2->ranges[k].rmin)
715
0
            return false;
716
0
    }
717
0
    return true;
718
0
}
719
720
/* setcolorrendering */
721
int
722
gs_setcolorrendering(gs_gstate * pgs, gs_cie_render * pcrd)
723
9.57k
{
724
9.57k
    int code = gs_cie_render_complete(pcrd);
725
9.57k
    const gs_cie_render *pcrd_old = pgs->cie_render;
726
9.57k
    bool joint_ok;
727
728
9.57k
    if (code < 0)
729
0
        return code;
730
9.57k
    if (pcrd_old != 0 && pcrd->id == pcrd_old->id)
731
0
        return 0;   /* detect needless reselecting */
732
9.57k
    joint_ok =
733
9.57k
        pcrd_old != 0 &&
734
9.57k
        vector_equal(&pcrd->points.WhitePoint, &pcrd_old->points.WhitePoint) &&
735
9.57k
        vector_equal(&pcrd->points.BlackPoint, &pcrd_old->points.BlackPoint) &&
736
9.57k
        matrix_equal(&pcrd->MatrixPQR, &pcrd_old->MatrixPQR) &&
737
9.57k
        range_equal(&pcrd->RangePQR, &pcrd_old->RangePQR) &&
738
9.57k
        transform_equal(&pcrd->TransformPQR, &pcrd_old->TransformPQR);
739
9.57k
    rc_assign(pgs->cie_render, pcrd, "gs_setcolorrendering");
740
    /* Initialize the joint caches if needed. */
741
9.57k
    if (!joint_ok)
742
9.57k
        code = gs_cie_cs_complete(pgs, true);
743
9.57k
    gx_unset_dev_color(pgs);
744
9.57k
    return code;
745
9.57k
}
746
747
/* currentcolorrendering */
748
const gs_cie_render *
749
gs_currentcolorrendering(const gs_gstate * pgs)
750
0
{
751
0
    return pgs->cie_render;
752
0
}
753
754
/* Unshare (allocating if necessary) the joint caches. */
755
gx_cie_joint_caches *
756
gx_unshare_cie_caches(gs_gstate * pgs)
757
9.57k
{
758
9.57k
    gx_cie_joint_caches *pjc = pgs->cie_joint_caches;
759
760
9.57k
    rc_unshare_struct(pgs->cie_joint_caches, gx_cie_joint_caches,
761
9.57k
                      &st_joint_caches, pgs->memory,
762
9.57k
                      return 0, "gx_unshare_cie_caches");
763
9.57k
    if (pgs->cie_joint_caches != pjc) {
764
9.57k
        pjc = pgs->cie_joint_caches;
765
9.57k
        pjc->cspace_id = pjc->render_id = gs_no_id;
766
9.57k
        pjc->id_status = pjc->status = CIE_JC_STATUS_BUILT;
767
9.57k
    }
768
9.57k
    return pjc;
769
9.57k
}
770
771
gx_cie_joint_caches *
772
gx_get_cie_caches_ref(gs_gstate * pgs, gs_memory_t * mem)
773
0
{
774
0
    gx_cie_joint_caches *pjc = pgs->cie_joint_caches;
775
776
    /* Take a reference here, to allow for the one that
777
     * rc_unshare_struct might drop if it has to copy it.
778
     * Whatever happens we will have taken 1 net new
779
     * reference which we return to the caller. */
780
0
    rc_increment(pgs->cie_joint_caches);
781
0
    rc_unshare_struct(pjc, gx_cie_joint_caches,
782
0
                      &st_joint_caches, mem,
783
0
                      return NULL, "gx_unshare_cie_caches");
784
0
    return pjc;
785
0
}
786
787
/* Compute the parameters for loading a cache, setting base and factor. */
788
/* This procedure is idempotent. */
789
void
790
gs_cie_cache_init(cie_cache_params * pcache, gs_sample_loop_params_t * pslp,
791
                  const gs_range * domain, client_name_t cname)
792
57.4k
{
793
    /*
794
      We need to map the values in the range [domain->rmin..domain->rmax].
795
      However, if rmin < 0 < rmax and the function is non-linear, this can
796
      lead to anomalies at zero, which is the default value for CIE colors.
797
      The "correct" way to approach this is to run the mapping functions on
798
      demand, but we don't want to deal with the complexities of the
799
      callbacks this would involve (especially in the middle of rendering
800
      images); instead, we adjust the range so that zero maps precisely to a
801
      cache slot.  Define:
802
803
      A = domain->rmin;
804
      B = domain->rmax;
805
      N = gx_cie_cache_size - 1;
806
807
      R = B - A;
808
      h(v) = N * (v - A) / R;   // the index of v in the cache
809
      X = h(0).
810
811
      If X is not an integer, we can decrease A and/increase B to make it
812
      one.  Let A' and B' be the adjusted values of A and B respectively,
813
      and let K be the integer derived from X (either floor(X) or ceil(X)).
814
      Define
815
816
      f(K) = (K * B' + (N - K) * A') / N).
817
818
      We want f(K) = 0.  This occurs precisely when, for any real number
819
      C != 0,
820
821
      A' = -K * C;
822
      B' = (N - K) * C.
823
824
      In order to ensure A' <= A and B' >= B, we require
825
826
      C >= -A / K;
827
      C >= B / (N - K).
828
829
      Since A' and B' must be exactly representable as floats, we round C
830
      upward to ensure that it has no more than M mantissa bits, where
831
832
      M = ARCH_FLOAT_MANTISSA_BITS - ceil(log2(N)).
833
    */
834
57.4k
    float A = domain->rmin, B = domain->rmax;
835
57.4k
    double R = B - A, delta;
836
287k
#define NN (gx_cie_cache_size - 1) /* 'N' is a member name, see end of proc */
837
229k
#define N NN
838
57.4k
#define CEIL_LOG2_N CIE_LOG2_CACHE_SIZE
839
840
    /* Adjust the range if necessary. */
841
57.4k
    if (A < 0 && B >= 0) {
842
28.7k
        const double X = -N * A / R; /* know X > 0 */
843
        /* Choose K to minimize range expansion. */
844
28.7k
        const int K = (int)(A + B < 0 ? floor(X) : ceil(X)); /* know 0 < K < N */
845
28.7k
        const int M = ARCH_FLOAT_MANTISSA_BITS - CEIL_LOG2_N;
846
28.7k
        int cexp;
847
848
28.7k
        double Ca, Cb;
849
28.7k
        double C;
850
28.7k
        double cfrac;
851
852
28.7k
        if (K != 0)
853
28.7k
            Ca = -A / K;
854
0
        else
855
0
            Ca = 0;
856
857
28.7k
        if (N != K)
858
28.7k
            Cb = B / (N - K); /* know Ca, Cb > 0 */
859
0
        else
860
0
            Cb = 0;
861
862
28.7k
        C = max(Ca, Cb); /* know C > 0 */
863
28.7k
        cfrac = frexp(C, &cexp);
864
865
28.7k
        if_debug4('c', "[c]adjusting cache_init(%8g, %8g), X = %8g, K = %d:\n",
866
28.7k
                  A, B, X, K);
867
        /* Round C to no more than M significant bits.  See above. */
868
28.7k
        C = ldexp(ceil(ldexp(cfrac, M)), cexp - M);
869
        /* Finally, compute A' and B'. */
870
28.7k
        A = -K * C;
871
28.7k
        B = (N - K) * C;
872
28.7k
        if_debug2('c', "[c]  => %8g, %8g\n", A, B);
873
28.7k
        R = B - A;
874
28.7k
    }
875
57.4k
    delta = R / N;
876
57.4k
#ifdef CIE_CACHE_INTERPOLATE
877
57.4k
    pcache->base = A;   /* no rounding */
878
#else
879
    pcache->base = A - delta / 2; /* so lookup will round */
880
#endif
881
    /*
882
     * If size of the domain is zero, then use 1.0 as the scaling
883
     * factor.  This prevents divide by zero errors in later calculations.
884
     * This should only occurs with zero matrices.  It does occur with
885
     * Genoa test file 050-01.ps.
886
     */
887
57.4k
    pcache->factor = (any_abs(delta) < 1e-30 ? 1.0 : N / R);
888
57.4k
    if_debug4('c', "[c]cache %s "PRI_INTPTR" base=%g, factor=%g\n",
889
57.4k
              (const char *)cname, (intptr_t)pcache,
890
57.4k
              pcache->base, pcache->factor);
891
57.4k
    pslp->A = A;
892
57.4k
    pslp->B = B;
893
57.4k
#undef N
894
57.4k
    pslp->N = NN;
895
57.4k
#undef NN
896
57.4k
}
897
898
/* ------ Complete a rendering structure ------ */
899
900
/*
901
 * Compute the derived values in a CRD that don't involve the cached
902
 * procedure values.  This procedure is idempotent.
903
 */
904
static void cie_transform_range3(const gs_range3 *, const gs_matrix3 *,
905
                                  gs_range3 *);
906
int
907
gs_cie_render_init(gs_cie_render * pcrd)
908
9.57k
{
909
9.57k
    gs_matrix3 PQR_inverse;
910
911
9.57k
    if (pcrd->status >= CIE_RENDER_STATUS_INITED)
912
0
        return 0;   /* init already done */
913
9.57k
    if_debug_matrix3("[c]CRD MatrixLMN =", &pcrd->MatrixLMN);
914
9.57k
    cie_matrix_init(&pcrd->MatrixLMN);
915
9.57k
    if_debug_matrix3("[c]CRD MatrixABC =", &pcrd->MatrixABC);
916
9.57k
    cie_matrix_init(&pcrd->MatrixABC);
917
9.57k
    if_debug_matrix3("[c]CRD MatrixPQR =", &pcrd->MatrixPQR);
918
9.57k
    cie_matrix_init(&pcrd->MatrixPQR);
919
9.57k
    cie_invert3(&pcrd->MatrixPQR, &PQR_inverse);
920
9.57k
    cie_matrix_mult3(&pcrd->MatrixLMN, &PQR_inverse,
921
9.57k
                     &pcrd->MatrixPQR_inverse_LMN);
922
9.57k
    cie_transform_range3(&pcrd->RangePQR, &pcrd->MatrixPQR_inverse_LMN,
923
9.57k
                         &pcrd->DomainLMN);
924
9.57k
    cie_transform_range3(&pcrd->RangeLMN, &pcrd->MatrixABC,
925
9.57k
                         &pcrd->DomainABC);
926
9.57k
    cie_mult3(&pcrd->points.WhitePoint, &pcrd->MatrixPQR, &pcrd->wdpqr);
927
9.57k
    cie_mult3(&pcrd->points.BlackPoint, &pcrd->MatrixPQR, &pcrd->bdpqr);
928
9.57k
    pcrd->status = CIE_RENDER_STATUS_INITED;
929
9.57k
    return 0;
930
9.57k
}
931
932
/*
933
 * Sample the EncodeLMN, EncodeABC, and RenderTableT CRD procedures, and
934
 * load the caches.  This procedure is idempotent.
935
 */
936
int
937
gs_cie_render_sample(gs_cie_render * pcrd)
938
9.57k
{
939
9.57k
    int code;
940
941
9.57k
    if (pcrd->status >= CIE_RENDER_STATUS_SAMPLED)
942
0
        return 0;   /* sampling already done */
943
9.57k
    code = gs_cie_render_init(pcrd);
944
9.57k
    if (code < 0)
945
0
        return code;
946
9.57k
    CIE_LOAD_CACHE_BODY(pcrd->caches.EncodeLMN.caches, pcrd->DomainLMN.ranges,
947
9.57k
                        &pcrd->EncodeLMN, Encode_default, pcrd, "EncodeLMN");
948
9.57k
    cache3_set_linear(&pcrd->caches.EncodeLMN);
949
9.57k
    CIE_LOAD_CACHE_BODY(pcrd->caches.EncodeABC, pcrd->DomainABC.ranges,
950
9.57k
                        &pcrd->EncodeABC, Encode_default, pcrd, "EncodeABC");
951
9.57k
    if (pcrd->RenderTable.lookup.table != 0) {
952
0
        int i, j, m = pcrd->RenderTable.lookup.m;
953
0
        gs_sample_loop_params_t lp;
954
0
        bool is_identity = true;
955
956
0
        for (j = 0; j < m; j++) {
957
0
            gs_cie_cache_init(&pcrd->caches.RenderTableT[j].fracs.params,
958
0
                              &lp, &Range3_default.ranges[0],
959
0
                              "RenderTableT");
960
0
            is_identity &= pcrd->RenderTable.T.procs[j] ==
961
0
                RenderTableT_default.procs[j];
962
0
        }
963
0
        pcrd->caches.RenderTableT_is_identity = is_identity;
964
        /*
965
         * Unfortunately, we defined the first argument of the RenderTable
966
         * T procedures as being a byte, limiting the number of distinct
967
         * cache entries to 256 rather than gx_cie_cache_size.
968
         * We confine this decision to this loop, rather than propagating
969
         * it to the procedures that use the cached data, so that we can
970
         * change it more easily at some future time.
971
         */
972
0
        for (i = 0; i < gx_cie_cache_size; i++) {
973
0
#if gx_cie_log2_cache_size >= 8
974
0
            byte value = i >> (gx_cie_log2_cache_size - 8);
975
#else
976
            byte value = (i << (8 - gx_cie_log2_cache_size)) +
977
                (i >> (gx_cie_log2_cache_size * 2 - 8));
978
#endif
979
0
            for (j = 0; j < m; j++) {
980
0
                pcrd->caches.RenderTableT[j].fracs.values[i] =
981
0
                    (*pcrd->RenderTable.T.procs[j])(value, pcrd);
982
0
                if_debug3('C', "[C]RenderTableT[%d,%d] = %g\n",
983
0
                          i, j,
984
0
                          frac2float(pcrd->caches.RenderTableT[j].fracs.values[i]));
985
0
            }
986
0
        }
987
0
    }
988
9.57k
    pcrd->status = CIE_RENDER_STATUS_SAMPLED;
989
9.57k
    return 0;
990
9.57k
}
991
992
/* Transform a set of ranges. */
993
static void
994
cie_transform_range(const gs_range3 * in, double mu, double mv, double mw,
995
                    gs_range * out)
996
57.4k
{
997
57.4k
    float umin = mu * in->ranges[0].rmin, umax = mu * in->ranges[0].rmax;
998
57.4k
    float vmin = mv * in->ranges[1].rmin, vmax = mv * in->ranges[1].rmax;
999
57.4k
    float wmin = mw * in->ranges[2].rmin, wmax = mw * in->ranges[2].rmax;
1000
57.4k
    float temp;
1001
1002
57.4k
    if (umin > umax)
1003
19.1k
        temp = umin, umin = umax, umax = temp;
1004
57.4k
    if (vmin > vmax)
1005
19.1k
        temp = vmin, vmin = vmax, vmax = temp;
1006
57.4k
    if (wmin > wmax)
1007
19.1k
        temp = wmin, wmin = wmax, wmax = temp;
1008
57.4k
    out->rmin = umin + vmin + wmin;
1009
57.4k
    out->rmax = umax + vmax + wmax;
1010
57.4k
}
1011
static void
1012
cie_transform_range3(const gs_range3 * in, const gs_matrix3 * mat,
1013
                     gs_range3 * out)
1014
19.1k
{
1015
19.1k
    cie_transform_range(in, mat->cu.u, mat->cv.u, mat->cw.u,
1016
19.1k
                        &out->ranges[0]);
1017
19.1k
    cie_transform_range(in, mat->cu.v, mat->cv.v, mat->cw.v,
1018
19.1k
                        &out->ranges[1]);
1019
19.1k
    cie_transform_range(in, mat->cu.w, mat->cv.w, mat->cw.w,
1020
19.1k
                        &out->ranges[2]);
1021
19.1k
}
1022
1023
/*
1024
 * Finish preparing a CRD for installation, by restricting and/or
1025
 * transforming the cached procedure values.
1026
 * This procedure is idempotent.
1027
 */
1028
int
1029
gs_cie_render_complete(gs_cie_render * pcrd)
1030
9.57k
{
1031
9.57k
    int code;
1032
1033
9.57k
    if (pcrd->status >= CIE_RENDER_STATUS_COMPLETED)
1034
0
        return 0;   /* completion already done */
1035
9.57k
    code = gs_cie_render_sample(pcrd);
1036
9.57k
    if (code < 0)
1037
0
        return code;
1038
    /*
1039
     * Since range restriction happens immediately after
1040
     * the cache lookup, we can save a step by restricting
1041
     * the values in the cache entries.
1042
     *
1043
     * If there is no lookup table, we want the final ABC values
1044
     * to be fracs; if there is a table, we want them to be
1045
     * appropriately scaled ints.
1046
     */
1047
9.57k
    pcrd->MatrixABCEncode = pcrd->MatrixABC;
1048
9.57k
    {
1049
9.57k
        int c;
1050
9.57k
        double f;
1051
1052
38.3k
        for (c = 0; c < 3; c++) {
1053
28.7k
            gx_cie_float_fixed_cache *pcache = &pcrd->caches.EncodeABC[c];
1054
1055
28.7k
            cie_cache_restrict(&pcrd->caches.EncodeLMN.caches[c].floats,
1056
28.7k
                               &pcrd->RangeLMN.ranges[c]);
1057
28.7k
            cie_cache_restrict(&pcrd->caches.EncodeABC[c].floats,
1058
28.7k
                               &pcrd->RangeABC.ranges[c]);
1059
28.7k
            if (pcrd->RenderTable.lookup.table == 0) {
1060
28.7k
                cie_cache_restrict(&pcache->floats,
1061
28.7k
                                   &Range3_default.ranges[0]);
1062
28.7k
                gs_cie_cache_to_fracs(&pcache->floats, &pcache->fixeds.fracs);
1063
28.7k
                pcache->fixeds.fracs.params.is_identity = false;
1064
28.7k
            } else {
1065
0
                int i;
1066
0
                int n = pcrd->RenderTable.lookup.dims[c];
1067
1068
0
#ifdef CIE_RENDER_TABLE_INTERPOLATE
1069
0
#  define SCALED_INDEX(f, n, itemp)\
1070
0
     RESTRICTED_INDEX(f * (1 << _cie_interpolate_bits),\
1071
0
                      (n) << _cie_interpolate_bits, itemp)
1072
#else
1073
                int m = pcrd->RenderTable.lookup.m;
1074
                int k =
1075
                    (c == 0 ? 1 : c == 1 ?
1076
                     m * pcrd->RenderTable.lookup.dims[2] : m);
1077
#  define SCALED_INDEX(f, n, itemp)\
1078
     (RESTRICTED_INDEX(f, n, itemp) * k)
1079
#endif
1080
0
                const gs_range *prange = pcrd->RangeABC.ranges + c;
1081
0
                double scale = (n - 1) / (prange->rmax - prange->rmin);
1082
1083
0
                for (i = 0; i < gx_cie_cache_size; ++i) {
1084
0
                    float v =
1085
0
                        (pcache->floats.values[i] - prange->rmin) * scale
1086
#ifndef CIE_RENDER_TABLE_INTERPOLATE
1087
                        + 0.5
1088
#endif
1089
0
                        ;
1090
0
                    int itemp;
1091
1092
0
                    if_debug5('c',
1093
0
                              "[c]cache[%d][%d] = %g => %g => %d\n",
1094
0
                              c, i, pcache->floats.values[i], v,
1095
0
                              SCALED_INDEX(v, n, itemp));
1096
0
                    pcache->fixeds.ints.values[i] =
1097
0
                        SCALED_INDEX(v, n, itemp);
1098
0
                }
1099
0
                pcache->fixeds.ints.params = pcache->floats.params;
1100
0
                pcache->fixeds.ints.params.is_identity = false;
1101
0
#undef SCALED_INDEX
1102
0
            }
1103
28.7k
        }
1104
        /* Fold the scaling of the EncodeABC cache index */
1105
        /* into MatrixABC. */
1106
9.57k
#define MABC(i, t)\
1107
28.7k
  f = pcrd->caches.EncodeABC[i].floats.params.factor;\
1108
28.7k
  pcrd->MatrixABCEncode.cu.t *= f;\
1109
28.7k
  pcrd->MatrixABCEncode.cv.t *= f;\
1110
28.7k
  pcrd->MatrixABCEncode.cw.t *= f;\
1111
28.7k
  pcrd->EncodeABC_base[i] =\
1112
28.7k
    float2cie_cached(pcrd->caches.EncodeABC[i].floats.params.base * f)
1113
9.57k
        MABC(0, u);
1114
9.57k
        MABC(1, v);
1115
9.57k
        MABC(2, w);
1116
9.57k
#undef MABC
1117
9.57k
        pcrd->MatrixABCEncode.is_identity = 0;
1118
9.57k
    }
1119
9.57k
    cie_cache_mult3(&pcrd->caches.EncodeLMN, &pcrd->MatrixABCEncode,
1120
9.57k
                    CACHE_THRESHOLD);
1121
9.57k
    pcrd->status = CIE_RENDER_STATUS_COMPLETED;
1122
9.57k
    return 0;
1123
9.57k
}
1124
1125
/* Apply a range restriction to a cache. */
1126
static void
1127
cie_cache_restrict(cie_cache_floats * pcache, const gs_range * prange)
1128
86.2k
{
1129
86.2k
    int i;
1130
1131
44.2M
    for (i = 0; i < gx_cie_cache_size; i++) {
1132
44.1M
        float v = pcache->values[i];
1133
1134
44.1M
        if (v < prange->rmin)
1135
4.63M
            pcache->values[i] = prange->rmin;
1136
39.4M
        else if (v > prange->rmax)
1137
6.32M
            pcache->values[i] = prange->rmax;
1138
44.1M
    }
1139
86.2k
}
1140
1141
/* Convert a cache from floats to fracs. */
1142
/* Note that the two may be aliased. */
1143
void
1144
gs_cie_cache_to_fracs(const cie_cache_floats *pfloats, cie_cache_fracs *pfracs)
1145
28.7k
{
1146
28.7k
    int i;
1147
1148
    /* Loop from bottom to top so that we don't */
1149
    /* overwrite elements before they're used. */
1150
14.7M
    for (i = 0; i < gx_cie_cache_size; ++i)
1151
14.7M
        pfracs->values[i] = float2frac(pfloats->values[i]);
1152
28.7k
    pfracs->params = pfloats->params;
1153
28.7k
}
1154
1155
/* ------ Fill in the joint cache ------ */
1156
1157
/* If the current color space is a CIE space, or has a CIE base space, */
1158
/* return a pointer to the common part of the space; otherwise return 0. */
1159
static const gs_cie_common *
1160
cie_cs_common_abc(const gs_color_space *pcs_orig, const gs_cie_abc **ppabc)
1161
9.57k
{
1162
9.57k
    const gs_color_space *pcs = pcs_orig;
1163
1164
9.57k
    *ppabc = 0;
1165
9.57k
    do {
1166
9.57k
        switch (pcs->type->index) {
1167
0
        case gs_color_space_index_CIEDEF:
1168
0
            *ppabc = (const gs_cie_abc *)pcs->params.def;
1169
0
            return &pcs->params.def->common;
1170
0
        case gs_color_space_index_CIEDEFG:
1171
0
            *ppabc = (const gs_cie_abc *)pcs->params.defg;
1172
0
            return &pcs->params.defg->common;
1173
0
        case gs_color_space_index_CIEABC:
1174
0
            *ppabc = pcs->params.abc;
1175
0
            return &pcs->params.abc->common;
1176
0
        case gs_color_space_index_CIEA:
1177
0
            return &pcs->params.a->common;
1178
9.57k
        default:
1179
9.57k
            pcs = gs_cspace_base_space(pcs);
1180
9.57k
            break;
1181
9.57k
        }
1182
9.57k
    } while (pcs != 0);
1183
1184
9.57k
    return 0;
1185
9.57k
}
1186
const gs_cie_common *
1187
gs_cie_cs_common(const gs_gstate * pgs)
1188
9.57k
{
1189
9.57k
    const gs_cie_abc *ignore_pabc;
1190
1191
9.57k
    return cie_cs_common_abc(gs_currentcolorspace_inline(pgs), &ignore_pabc);
1192
9.57k
}
1193
1194
/*
1195
 * Mark the joint caches as needing completion.  This is done lazily,
1196
 * when a color is being mapped.  However, make sure the joint caches
1197
 * exist now.
1198
 */
1199
int
1200
gs_cie_cs_complete(gs_gstate * pgs, bool init)
1201
9.57k
{
1202
9.57k
    gx_cie_joint_caches *pjc = gx_unshare_cie_caches(pgs);
1203
1204
9.57k
    if (pjc == 0)
1205
0
        return_error(gs_error_VMerror);
1206
9.57k
    pjc->status = (init ? CIE_JC_STATUS_BUILT : CIE_JC_STATUS_INITED);
1207
9.57k
    return 0;
1208
9.57k
}
1209
/* Actually complete the joint caches. */
1210
int
1211
gs_cie_jc_complete(const gs_gstate *pgs, const gs_color_space *pcs)
1212
0
{
1213
0
    const gs_cie_abc *pabc;
1214
0
    const gs_cie_common *common = cie_cs_common_abc(pcs, &pabc);
1215
0
    gs_cie_render *pcrd = pgs->cie_render;
1216
0
    gx_cie_joint_caches *pjc = pgs->cie_joint_caches;
1217
1218
0
    if (pjc->cspace_id == pcs->id &&
1219
0
        pjc->render_id == pcrd->id)
1220
0
        pjc->status = pjc->id_status;
1221
0
    switch (pjc->status) {
1222
0
    case CIE_JC_STATUS_BUILT: {
1223
0
        int code = cie_joint_caches_init(pjc, common, pcrd);
1224
1225
0
        if (code < 0)
1226
0
            return code;
1227
0
    }
1228
        /* falls through */
1229
0
    case CIE_JC_STATUS_INITED:
1230
0
        cie_joint_caches_complete(pjc, common, pabc, pcrd);
1231
0
        pjc->cspace_id = pcs->id;
1232
0
        pjc->render_id = pcrd->id;
1233
0
        pjc->id_status = pjc->status = CIE_JC_STATUS_COMPLETED;
1234
        /* falls through */
1235
0
    case CIE_JC_STATUS_COMPLETED:
1236
0
        break;
1237
0
    }
1238
0
    return 0;
1239
0
}
1240
1241
/*
1242
 * Compute the source and destination WhitePoint and BlackPoint for
1243
 * the TransformPQR procedure.
1244
 */
1245
int
1246
gs_cie_compute_points_sd(gx_cie_joint_caches *pjc,
1247
                         const gs_cie_common * pcie,
1248
                         const gs_cie_render * pcrd)
1249
0
{
1250
0
    gs_cie_wbsd *pwbsd = &pjc->points_sd;
1251
1252
0
    pwbsd->ws.xyz = pcie->points.WhitePoint;
1253
0
    cie_mult3(&pwbsd->ws.xyz, &pcrd->MatrixPQR, &pwbsd->ws.pqr);
1254
0
    pwbsd->bs.xyz = pcie->points.BlackPoint;
1255
0
    cie_mult3(&pwbsd->bs.xyz, &pcrd->MatrixPQR, &pwbsd->bs.pqr);
1256
0
    pwbsd->wd.xyz = pcrd->points.WhitePoint;
1257
0
    pwbsd->wd.pqr = pcrd->wdpqr;
1258
0
    pwbsd->bd.xyz = pcrd->points.BlackPoint;
1259
0
    pwbsd->bd.pqr = pcrd->bdpqr;
1260
0
    return 0;
1261
0
}
1262
1263
/*
1264
 * Sample the TransformPQR procedure for the joint caches.
1265
 * This routine is idempotent.
1266
 */
1267
static int
1268
cie_joint_caches_init(gx_cie_joint_caches * pjc,
1269
                      const gs_cie_common * pcie,
1270
                      gs_cie_render * pcrd)
1271
0
{
1272
0
    bool is_identity;
1273
0
    int j;
1274
1275
0
    gs_cie_compute_points_sd(pjc, pcie, pcrd);
1276
    /*
1277
     * If a client pre-loaded the cache, we can't adjust the range.
1278
     * ****** WRONG ******
1279
     */
1280
0
    if (pcrd->TransformPQR.proc == TransformPQR_from_cache.proc)
1281
0
        return 0;
1282
0
    is_identity = pcrd->TransformPQR.proc == TransformPQR_default.proc;
1283
0
    for (j = 0; j < 3; j++) {
1284
0
        int i;
1285
0
        gs_sample_loop_params_t lp;
1286
1287
0
        gs_cie_cache_init(&pjc->TransformPQR.caches[j].floats.params, &lp,
1288
0
                          &pcrd->RangePQR.ranges[j], "TransformPQR");
1289
0
        for (i = 0; i <= lp.N; ++i) {
1290
0
            float in = SAMPLE_LOOP_VALUE(i, lp);
1291
0
            float out;
1292
0
            int code = (*pcrd->TransformPQR.proc)(j, in, &pjc->points_sd,
1293
0
                                                  pcrd, &out);
1294
1295
0
            if (code < 0)
1296
0
                return code;
1297
0
            pjc->TransformPQR.caches[j].floats.values[i] = out;
1298
0
            if_debug4('C', "[C]TransformPQR[%d,%d] = %g => %g\n",
1299
0
                      j, i, in, out);
1300
0
        }
1301
0
        pjc->TransformPQR.caches[j].floats.params.is_identity = is_identity;
1302
0
    }
1303
0
    return 0;
1304
0
}
1305
1306
/*
1307
 * Complete the loading of the joint caches.
1308
 * This routine is idempotent.
1309
 */
1310
static void
1311
cie_joint_caches_complete(gx_cie_joint_caches * pjc,
1312
                          const gs_cie_common * pcie,
1313
                          const gs_cie_abc * pabc /* NULL if CIEA */,
1314
                          const gs_cie_render * pcrd)
1315
0
{
1316
0
    gs_matrix3 mat3, mat2;
1317
0
    gs_matrix3 MatrixLMN_PQR;
1318
0
    int j;
1319
1320
0
    pjc->remap_finish = gx_cie_real_remap_finish;
1321
1322
    /*
1323
     * We number the pipeline steps as follows:
1324
     *   1 - DecodeABC/MatrixABC
1325
     *   2 - DecodeLMN/MatrixLMN/MatrixPQR
1326
     *   3 - TransformPQR/MatrixPQR'/MatrixLMN
1327
     *   4 - EncodeLMN/MatrixABC
1328
     *   5 - EncodeABC, RenderTable (we don't do anything with this here)
1329
     * We work from back to front, combining steps where possible.
1330
     * Currently we only combine steps if a procedure is the identity
1331
     * transform, but we could do it whenever the procedure is linear.
1332
     * A project for another day....
1333
     */
1334
1335
        /* Step 4 */
1336
1337
0
#ifdef OPTIMIZE_CIE_MAPPING
1338
0
    if (pcrd->caches.EncodeLMN.caches[0].floats.params.is_identity &&
1339
0
        pcrd->caches.EncodeLMN.caches[1].floats.params.is_identity &&
1340
0
        pcrd->caches.EncodeLMN.caches[2].floats.params.is_identity
1341
0
        ) {
1342
        /* Fold step 4 into step 3. */
1343
0
        if_debug0('c', "[c]EncodeLMN is identity, folding MatrixABC(Encode) into MatrixPQR'+LMN.\n");
1344
0
        cie_matrix_mult3(&pcrd->MatrixABCEncode, &pcrd->MatrixPQR_inverse_LMN,
1345
0
                         &mat3);
1346
0
        pjc->skipEncodeLMN = true;
1347
0
    } else
1348
0
#endif /* OPTIMIZE_CIE_MAPPING */
1349
0
    {
1350
0
        if_debug0('c', "[c]EncodeLMN is not identity.\n");
1351
0
        mat3 = pcrd->MatrixPQR_inverse_LMN;
1352
0
        pjc->skipEncodeLMN = false;
1353
0
    }
1354
1355
        /* Step 3 */
1356
1357
0
    cache3_set_linear(&pjc->TransformPQR);
1358
0
    cie_matrix_mult3(&pcrd->MatrixPQR, &pcie->MatrixLMN,
1359
0
                     &MatrixLMN_PQR);
1360
1361
0
#ifdef OPTIMIZE_CIE_MAPPING
1362
0
    if (pjc->TransformPQR.caches[0].floats.params.is_identity &
1363
0
        pjc->TransformPQR.caches[1].floats.params.is_identity &
1364
0
        pjc->TransformPQR.caches[2].floats.params.is_identity
1365
0
        ) {
1366
        /* Fold step 3 into step 2. */
1367
0
        if_debug0('c', "[c]TransformPQR is identity, folding MatrixPQR'+LMN into MatrixLMN+PQR.\n");
1368
0
        cie_matrix_mult3(&mat3, &MatrixLMN_PQR, &mat2);
1369
0
        pjc->skipPQR = true;
1370
0
    } else
1371
0
#endif /* OPTIMIZE_CIE_MAPPING */
1372
0
    {
1373
0
        if_debug0('c', "[c]TransformPQR is not identity.\n");
1374
0
        mat2 = MatrixLMN_PQR;
1375
0
        for (j = 0; j < 3; j++) {
1376
0
            cie_cache_restrict(&pjc->TransformPQR.caches[j].floats,
1377
0
                               &pcrd->RangePQR.ranges[j]);
1378
0
        }
1379
0
        cie_cache_mult3(&pjc->TransformPQR, &mat3, CACHE_THRESHOLD);
1380
0
        pjc->skipPQR = false;
1381
0
    }
1382
1383
        /* Steps 2 & 1 */
1384
1385
0
#ifdef OPTIMIZE_CIE_MAPPING
1386
0
    if (pcie->caches.DecodeLMN[0].floats.params.is_identity &
1387
0
        pcie->caches.DecodeLMN[1].floats.params.is_identity &
1388
0
        pcie->caches.DecodeLMN[2].floats.params.is_identity
1389
0
        ) {
1390
0
        if_debug0('c', "[c]DecodeLMN is identity, folding MatrixLMN+PQR into MatrixABC.\n");
1391
0
        if (!pabc) {
1392
0
            pjc->skipDecodeLMN = mat2.is_identity;
1393
0
            pjc->skipDecodeABC = false;
1394
0
            if (!pjc->skipDecodeLMN) {
1395
0
                for (j = 0; j < 3; j++) {
1396
0
                    cie_cache_mult(&pjc->DecodeLMN.caches[j], &mat2.cu + j,
1397
0
                                   &pcie->caches.DecodeLMN[j].floats,
1398
0
                                   CACHE_THRESHOLD);
1399
0
                }
1400
0
                cie_cache3_set_interpolation(&pjc->DecodeLMN);
1401
0
            }
1402
0
        } else {
1403
            /*
1404
             * Fold step 2 into step 1.  This is a little different because
1405
             * the data for step 1 are in the color space structure.
1406
             */
1407
0
            gs_matrix3 mat1;
1408
1409
0
            cie_matrix_mult3(&mat2, &pabc->MatrixABC, &mat1);
1410
0
            for (j = 0; j < 3; j++) {
1411
0
                cie_cache_mult(&pjc->DecodeLMN.caches[j], &mat1.cu + j,
1412
0
                               &pabc->caches.DecodeABC.caches[j].floats,
1413
0
                               CACHE_THRESHOLD);
1414
0
            }
1415
0
            cie_cache3_set_interpolation(&pjc->DecodeLMN);
1416
0
            pjc->skipDecodeLMN = false;
1417
0
            pjc->skipDecodeABC = true;
1418
0
        }
1419
0
    } else
1420
0
#endif /* OPTIMIZE_CIE_MAPPING */
1421
0
    {
1422
0
        if_debug0('c', "[c]DecodeLMN is not identity.\n");
1423
0
        for (j = 0; j < 3; j++) {
1424
0
            cie_cache_mult(&pjc->DecodeLMN.caches[j], &mat2.cu + j,
1425
0
                           &pcie->caches.DecodeLMN[j].floats,
1426
0
                           CACHE_THRESHOLD);
1427
0
        }
1428
0
        cie_cache3_set_interpolation(&pjc->DecodeLMN);
1429
0
        pjc->skipDecodeLMN = false;
1430
0
        pjc->skipDecodeABC = pabc != 0 && pabc->caches.skipABC;
1431
0
    }
1432
1433
0
}
1434
1435
/*
1436
 * Initialize (just enough of) an gs_gstate so that "concretizing" colors
1437
 * using this gs_gstate will do only the CIE->XYZ mapping.  This is a
1438
 * semi-hack for the PDF writer.
1439
 */
1440
int
1441
gx_cie_to_xyz_alloc(gs_gstate **ppgs, const gs_color_space *pcs,
1442
                    gs_memory_t *mem)
1443
0
{
1444
    /*
1445
     * In addition to the gs_gstate itself, we need the joint caches.
1446
     */
1447
0
    gs_gstate *pgs =
1448
0
        gs_alloc_struct(mem, gs_gstate, &st_gs_gstate,
1449
0
                        "gx_cie_to_xyz_alloc(gs_gstate)");
1450
0
    gx_cie_joint_caches *pjc;
1451
0
    const gs_cie_abc *pabc;
1452
0
    const gs_cie_common *pcie = cie_cs_common_abc(pcs, &pabc);
1453
0
    int j;
1454
1455
0
    if (pgs == 0)
1456
0
        return_error(gs_error_VMerror);
1457
0
    memset(pgs, 0, sizeof(*pgs)); /* mostly paranoia */
1458
0
    pgs->memory = mem;
1459
0
    GS_STATE_INIT_VALUES(pgs, 1.0);
1460
0
    gs_gstate_initialize(pgs, mem);
1461
1462
0
    pjc = gs_alloc_struct(mem, gx_cie_joint_caches, &st_joint_caches,
1463
0
                          "gx_cie_to_xyz_free(joint caches)");
1464
0
    if (pjc == 0) {
1465
0
        gs_free_object(mem, pgs, "gx_cie_to_xyz_alloc(gs_gstate)");
1466
0
        return_error(gs_error_VMerror);
1467
0
    }
1468
0
    rc_init(pjc, mem, 1);
1469
1470
    /*
1471
     * Perform an abbreviated version of cie_joint_caches_complete.
1472
     * Don't bother with any optimizations.
1473
     */
1474
0
    for (j = 0; j < 3; j++) {
1475
0
        cie_cache_mult(&pjc->DecodeLMN.caches[j], &pcie->MatrixLMN.cu + j,
1476
0
                       &pcie->caches.DecodeLMN[j].floats,
1477
0
                       CACHE_THRESHOLD);
1478
0
    }
1479
0
    cie_cache3_set_interpolation(&pjc->DecodeLMN);
1480
0
    pjc->skipDecodeLMN = false;
1481
0
    pjc->skipDecodeABC = pabc != 0 && pabc->caches.skipABC;
1482
    /* Mark the joint caches as completed. */
1483
0
    pjc->remap_finish = gx_cie_xyz_remap_finish;
1484
0
    pjc->cspace_id = pcs->id;
1485
0
    pjc->status = CIE_JC_STATUS_COMPLETED;
1486
0
    pgs->cie_joint_caches = pjc;
1487
0
    pgs->cie_to_xyz = true;
1488
0
    *ppgs = pgs;
1489
0
    return 0;
1490
0
}
1491
void
1492
gx_cie_to_xyz_free(gs_gstate *pgs)
1493
0
{
1494
0
    gs_memory_t *mem = pgs->memory;
1495
1496
0
    rc_decrement(pgs->cie_joint_caches,"gx_cie_to_xyz_free");
1497
1498
    /* Free up the ICC objects if created */    /* FIXME: does this need to be thread safe */
1499
0
    if (pgs->icc_link_cache != NULL) {
1500
0
        rc_decrement(pgs->icc_link_cache,"gx_cie_to_xyz_free");
1501
0
    }
1502
0
    if (pgs->icc_manager != NULL) {
1503
0
        rc_decrement(pgs->icc_manager,"gx_cie_to_xyz_free");
1504
0
    }
1505
0
    if (pgs->icc_profile_cache != NULL) {
1506
0
        rc_decrement(pgs->icc_profile_cache,"gx_cie_to_xyz_free");
1507
0
    }
1508
0
    gs_free_object(mem, pgs, "gx_cie_to_xyz_free(gs_gstate)");
1509
0
}
1510
1511
/* ================ Utilities ================ */
1512
1513
/* Multiply a vector by a matrix. */
1514
/* Note that we are computing M * V where v is a column vector. */
1515
void
1516
cie_mult3(const gs_vector3 * in, register const gs_matrix3 * mat,
1517
          gs_vector3 * out)
1518
47.8k
{
1519
47.8k
    if_debug_vector3("[c]mult", in);
1520
47.8k
    if_debug_matrix3("  *", mat);
1521
47.8k
    {
1522
47.8k
        float u = in->u, v = in->v, w = in->w;
1523
1524
47.8k
        out->u = (u * mat->cu.u) + (v * mat->cv.u) + (w * mat->cw.u);
1525
47.8k
        out->v = (u * mat->cu.v) + (v * mat->cv.v) + (w * mat->cw.v);
1526
47.8k
        out->w = (u * mat->cu.w) + (v * mat->cv.w) + (w * mat->cw.w);
1527
47.8k
    }
1528
47.8k
    if_debug_vector3("  =", out);
1529
47.8k
}
1530
1531
/*
1532
 * Multiply two matrices.  Note that the composition of the transformations
1533
 * M1 followed by M2 is M2 * M1, not M1 * M2.  (See gscie.h for details.)
1534
 */
1535
void
1536
cie_matrix_mult3(const gs_matrix3 *ma, const gs_matrix3 *mb, gs_matrix3 *mc)
1537
9.57k
{
1538
9.57k
    gs_matrix3 mprod;
1539
9.57k
    gs_matrix3 *mp = (mc == ma || mc == mb ? &mprod : mc);
1540
1541
9.57k
    if_debug_matrix3("[c]matrix_mult", ma);
1542
9.57k
    if_debug_matrix3("             *", mb);
1543
9.57k
    cie_mult3(&mb->cu, ma, &mp->cu);
1544
9.57k
    cie_mult3(&mb->cv, ma, &mp->cv);
1545
9.57k
    cie_mult3(&mb->cw, ma, &mp->cw);
1546
9.57k
    cie_matrix_init(mp);
1547
9.57k
    if_debug_matrix3("             =", mp);
1548
9.57k
    if (mp != mc)
1549
0
        *mc = *mp;
1550
9.57k
}
1551
1552
/*
1553
 * Transpose a 3x3 matrix. In and out can not be the same
1554
 */
1555
void
1556
cie_matrix_transpose3(const gs_matrix3 *in, gs_matrix3 *out)
1557
0
{
1558
0
    out->cu.u = in->cu.u;
1559
0
    out->cu.v = in->cv.u;
1560
0
    out->cu.w = in->cw.u;
1561
1562
0
    out->cv.u = in->cu.v;
1563
0
    out->cv.v = in->cv.v;
1564
0
    out->cv.w = in->cw.v;
1565
1566
0
    out->cw.u = in->cu.w;
1567
0
    out->cw.v = in->cv.w;
1568
0
    out->cw.w = in->cw.w;
1569
0
}
1570
1571
/* Invert a matrix. */
1572
/* The output must not be an alias for the input. */
1573
static void
1574
cie_invert3(const gs_matrix3 *in, gs_matrix3 *out)
1575
9.57k
{ /* This is a brute force algorithm; maybe there are better. */
1576
    /* We label the array elements */
1577
    /*   [ A B C ]   */
1578
    /*   [ D E F ]   */
1579
    /*   [ G H I ]   */
1580
57.4k
#define A cu.u
1581
57.4k
#define B cv.u
1582
57.4k
#define C cw.u
1583
47.8k
#define D cu.v
1584
47.8k
#define E cv.v
1585
47.8k
#define F cw.v
1586
47.8k
#define G cu.w
1587
47.8k
#define H cv.w
1588
47.8k
#define I cw.w
1589
9.57k
    double coA = in->E * in->I - in->F * in->H;
1590
9.57k
    double coB = in->F * in->G - in->D * in->I;
1591
9.57k
    double coC = in->D * in->H - in->E * in->G;
1592
9.57k
    double det = in->A * coA + in->B * coB + in->C * coC;
1593
1594
9.57k
    if_debug_matrix3("[c]invert", in);
1595
9.57k
    out->A = coA / det;
1596
9.57k
    out->D = coB / det;
1597
9.57k
    out->G = coC / det;
1598
9.57k
    out->B = (in->C * in->H - in->B * in->I) / det;
1599
9.57k
    out->E = (in->A * in->I - in->C * in->G) / det;
1600
9.57k
    out->H = (in->B * in->G - in->A * in->H) / det;
1601
9.57k
    out->C = (in->B * in->F - in->C * in->E) / det;
1602
9.57k
    out->F = (in->C * in->D - in->A * in->F) / det;
1603
9.57k
    out->I = (in->A * in->E - in->B * in->D) / det;
1604
9.57k
    if_debug_matrix3("        =", out);
1605
9.57k
#undef A
1606
9.57k
#undef B
1607
9.57k
#undef C
1608
9.57k
#undef D
1609
9.57k
#undef E
1610
9.57k
#undef F
1611
9.57k
#undef G
1612
9.57k
#undef H
1613
9.57k
#undef I
1614
9.57k
    out->is_identity = in->is_identity;
1615
9.57k
}
1616
1617
/* Set the is_identity flag that accelerates multiplication. */
1618
static void
1619
cie_matrix_init(register gs_matrix3 * mat)
1620
38.3k
{
1621
38.3k
    mat->is_identity =
1622
38.3k
        mat->cu.u == 1.0 && is_fzero2(mat->cu.v, mat->cu.w) &&
1623
38.3k
        mat->cv.v == 1.0 && is_fzero2(mat->cv.u, mat->cv.w) &&
1624
38.3k
        mat->cw.w == 1.0 && is_fzero2(mat->cw.u, mat->cw.v);
1625
38.3k
}
1626
1627
bool
1628
gx_color_space_needs_cie_caches(const gs_color_space * pcs)
1629
0
{
1630
0
    switch (pcs->type->index) {
1631
0
        case gs_color_space_index_CIEDEFG:
1632
0
        case gs_color_space_index_CIEDEF:
1633
0
        case gs_color_space_index_CIEABC:
1634
0
        case gs_color_space_index_CIEA:
1635
0
            return true;
1636
0
        case gs_color_space_index_ICC:
1637
0
            return false;
1638
0
        case gs_color_space_index_DevicePixel:
1639
0
        case gs_color_space_index_DeviceN:
1640
0
        case gs_color_space_index_Separation:
1641
0
        case gs_color_space_index_Indexed:
1642
0
        case gs_color_space_index_Pattern:
1643
0
            return gx_color_space_needs_cie_caches(pcs->base_space);
1644
0
        default:
1645
0
            return false;
1646
0
    }
1647
0
}