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