Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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