xref: /plan9/sys/src/cmd/gs/src/gscie.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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
cache_is_linear(cie_linear_params_t * params,const cie_cache_floats * pcf)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
cache_set_linear(cie_cache_floats * pcf)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
cache3_set_linear(gx_cie_vector_cache3_t * pvc)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
if_debug_vector3(const char * str,const gs_vector3 * vec)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
if_debug_matrix3(const char * str,const gs_matrix3 * mat)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
a_identity(floatp in,const gs_cie_a * pcie)182 a_identity(floatp in, const gs_cie_a * pcie)
183 {
184     return in;
185 }
186 private float
a_from_cache(floatp in,const gs_cie_a * pcie)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
abc_identity(floatp in,const gs_cie_abc * pcie)193 abc_identity(floatp in, const gs_cie_abc * pcie)
194 {
195     return in;
196 }
197 private float
abc_from_cache_0(floatp in,const gs_cie_abc * pcie)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
abc_from_cache_1(floatp in,const gs_cie_abc * pcie)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
abc_from_cache_2(floatp in,const gs_cie_abc * pcie)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
def_identity(floatp in,const gs_cie_def * pcie)214 def_identity(floatp in, const gs_cie_def * pcie)
215 {
216     return in;
217 }
218 private float
def_from_cache_0(floatp in,const gs_cie_def * pcie)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
def_from_cache_1(floatp in,const gs_cie_def * pcie)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
def_from_cache_2(floatp in,const gs_cie_def * pcie)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
defg_identity(floatp in,const gs_cie_defg * pcie)235 defg_identity(floatp in, const gs_cie_defg * pcie)
236 {
237     return in;
238 }
239 private float
defg_from_cache_0(floatp in,const gs_cie_defg * pcie)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
defg_from_cache_1(floatp in,const gs_cie_defg * pcie)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
defg_from_cache_2(floatp in,const gs_cie_defg * pcie)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
defg_from_cache_3(floatp in,const gs_cie_defg * pcie)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
common_identity(floatp in,const gs_cie_common * pcie)261 common_identity(floatp in, const gs_cie_common * pcie)
262 {
263     return in;
264 }
265 private float
lmn_from_cache_0(floatp in,const gs_cie_common * pcie)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
lmn_from_cache_1(floatp in,const gs_cie_common * pcie)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
lmn_from_cache_2(floatp in,const gs_cie_common * pcie)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
gs_cie_cached_value(floatp in,const cie_cache_floats * pcache)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
gx_init_CIE(gs_client_color * pcc,const gs_color_space * pcs)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
cie_restrict(float * pv,const gs_range * range)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
gx_restrict_CIEDEFG(gs_client_color * pcc,const gs_color_space * pcs)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
gx_restrict_CIEDEF(gs_client_color * pcc,const gs_color_space * pcs)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
gx_restrict_CIEABC(gs_client_color * pcc,const gs_color_space * pcs)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
gx_restrict_CIEA(gs_client_color * pcc,const gs_color_space * pcs)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
gx_install_cie_abc(gs_cie_abc * pcie,gs_state * pgs)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
gx_install_CIEDEFG(const gs_color_space * pcs,gs_state * pgs)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
gx_install_CIEDEF(const gs_color_space * pcs,gs_state * pgs)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
gx_install_CIEABC(const gs_color_space * pcs,gs_state * pgs)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
gx_install_CIEA(const gs_color_space * pcs,gs_state * pgs)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
gx_cie_load_common_cache(gs_cie_common * pcie,gs_state * pgs)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
gx_cie_common_complete(gs_cie_common * pcie)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
gs_cie_defx_scale(float * values,const gs_range * range,int dim)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
gs_cie_defg_complete(gs_cie_defg * pcie)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
gs_cie_def_complete(gs_cie_def * pcie)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
gs_cie_abc_complete(gs_cie_abc * pcie)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
gs_cie_a_complete(gs_cie_a * pcie)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
check_interpolation_required(cie_cache_range_temp_t * pccr,cie_cached_value cur,int i,floatp threshold)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
cie_cache_set_interpolation(gx_cie_vector_cache * pcache,floatp threshold)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
cie_cache_mult(gx_cie_vector_cache * pcache,const gs_vector3 * pvec,const cie_cache_floats * pcf,floatp threshold)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
cie_cache3_set_interpolation(gx_cie_vector_cache3_t * pvc)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
cie_cache_mult3(gx_cie_vector_cache3_t * pvc,const gs_matrix3 * pmat,floatp threshold)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
gs_setcolorrendering(gs_state * pgs,gs_cie_render * pcrd)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 *
gs_currentcolorrendering(const gs_state * pgs)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 *
gx_currentciecaches(gs_state * pgs)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
gs_cie_cache_init(cie_cache_params * pcache,gs_sample_loop_params_t * pslp,const gs_range * domain,client_name_t cname)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
gs_cie_render_init(gs_cie_render * pcrd)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
gs_cie_render_sample(gs_cie_render * pcrd)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
cie_transform_range(const gs_range3 * in,floatp mu,floatp mv,floatp mw,gs_range * out)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
cie_transform_range3(const gs_range3 * in,const gs_matrix3 * mat,gs_range3 * out)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
gs_cie_render_complete(gs_cie_render * pcrd)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
cie_cache_restrict(cie_cache_floats * pcache,const gs_range * prange)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
gs_cie_cache_to_fracs(const cie_cache_floats * pfloats,cie_cache_fracs * pfracs)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 *
cie_cs_common_abc(const gs_color_space * pcs_orig,const gs_cie_abc ** ppabc)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 *
gs_cie_cs_common(const gs_state * pgs)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
gs_cie_cs_complete(gs_state * pgs,bool init)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
gs_cie_jc_complete(const gs_imager_state * pis,const gs_color_space * pcs)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
gs_cie_compute_points_sd(gx_cie_joint_caches * pjc,const gs_cie_common * pcie,const gs_cie_render * pcrd)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
cie_joint_caches_init(gx_cie_joint_caches * pjc,const gs_cie_common * pcie,gs_cie_render * pcrd)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
cie_joint_caches_complete(gx_cie_joint_caches * pjc,const gs_cie_common * pcie,const gs_cie_abc * pabc,const gs_cie_render * pcrd)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
gx_cie_to_xyz_alloc(gs_imager_state ** ppis,const gs_color_space * pcs,gs_memory_t * mem)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
gx_cie_to_xyz_free(gs_imager_state * pis)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
cie_mult3(const gs_vector3 * in,register const gs_matrix3 * mat,gs_vector3 * out)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
cie_matrix_mult3(const gs_matrix3 * ma,const gs_matrix3 * mb,gs_matrix3 * mc)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
cie_invert3(const gs_matrix3 * in,gs_matrix3 * out)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
cie_matrix_init(register gs_matrix3 * mat)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 }
1542