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