]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/gs/src/zcrd.c
gs: fix /undefined in --setcolor-- errors on amd64
[plan9front.git] / sys / src / cmd / gs / src / zcrd.c
1 /* Copyright (C) 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: zcrd.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18 /* CIE color rendering operators */
19 #include "math_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gsstruct.h"
23 #include "gscspace.h"
24 #include "gscolor2.h"
25 #include "gscrd.h"
26 #include "gscrdp.h"
27 #include "estack.h"
28 #include "ialloc.h"
29 #include "idict.h"
30 #include "idparam.h"
31 #include "igstate.h"
32 #include "icie.h"
33 #include "iparam.h"
34 #include "ivmspace.h"
35 #include "store.h"              /* for make_null */
36
37 /* Forward references */
38 private int zcrd1_proc_params(const gs_memory_t *mem, os_ptr op, ref_cie_render_procs * pcprocs);
39 private int zcrd1_params(os_ptr op, gs_cie_render * pcrd,
40                          ref_cie_render_procs * pcprocs, gs_memory_t * mem);
41 private int cache_colorrendering1(i_ctx_t *i_ctx_p, gs_cie_render * pcrd,
42                                   const ref_cie_render_procs * pcprocs,
43                                   gs_ref_memory_t * imem);
44
45 /* - currentcolorrendering <dict> */
46 private int
47 zcurrentcolorrendering(i_ctx_t *i_ctx_p)
48 {
49     os_ptr op = osp;
50
51     push(1);
52     *op = istate->colorrendering.dict;
53     return 0;
54 }
55
56 /* <dict> .buildcolorrendering1 <crd> */
57 private int
58 zbuildcolorrendering1(i_ctx_t *i_ctx_p)
59 {
60     os_ptr op = osp;
61     gs_memory_t *mem = gs_state_memory(igs);
62     int code;
63     es_ptr ep = esp;
64     gs_cie_render *pcrd;
65     ref_cie_render_procs procs;
66
67     check_read_type(*op, t_dictionary);
68     check_dict_read(*op);
69     code = gs_cie_render1_build(&pcrd, mem, ".buildcolorrendering1");
70     if (code < 0)
71         return code;
72     code = zcrd1_params(op, pcrd, &procs, mem);
73     if (code < 0 ||
74     (code = cache_colorrendering1(i_ctx_p, pcrd, &procs,
75                                   (gs_ref_memory_t *) mem)) < 0
76         ) {
77         rc_free_struct(pcrd, ".buildcolorrendering1");
78         esp = ep;
79         return code;
80     }
81     /****** FIX refct ******/
82     /*rc_decrement(pcrd, ".buildcolorrendering1"); *//* build sets rc = 1 */
83     istate->colorrendering.dict = *op;
84     make_istruct_new(op, a_readonly, pcrd);
85     return (esp == ep ? 0 : o_push_estack);
86 }
87
88 /* <dict> .builddevicecolorrendering1 <crd> */
89 private int
90 zbuilddevicecolorrendering1(i_ctx_t *i_ctx_p)
91 {
92     os_ptr op = osp;
93     gs_memory_t *mem = gs_state_memory(igs);
94     dict_param_list list;
95     gs_cie_render *pcrd = 0;
96     int code;
97
98     check_type(*op, t_dictionary);
99     code = dict_param_list_read(&list, op, NULL, false, iimemory);
100     if (code < 0)
101         return code;
102     code = gs_cie_render1_build(&pcrd, mem, ".builddevicecolorrendering1");
103     if (code >= 0) {
104         code = param_get_cie_render1(pcrd, (gs_param_list *) & list,
105                                      gs_currentdevice(igs));
106         if (code >= 0) {
107             /****** FIX refct ******/
108             /*rc_decrement(pcrd, ".builddevicecolorrendering1"); *//* build sets rc = 1 */
109         }
110     }
111     iparam_list_release(&list);
112     if (code < 0) {
113         rc_free_struct(pcrd, ".builddevicecolorrendering1");
114         return code;
115     }
116     istate->colorrendering.dict = *op;
117     make_istruct_new(op, a_readonly, pcrd);
118     return 0;
119 }
120
121 /* <dict> <crd> .setcolorrendering1 - */
122 private int
123 zsetcolorrendering1(i_ctx_t *i_ctx_p)
124 {
125     os_ptr op = osp;
126     es_ptr ep = esp;
127     ref_cie_render_procs procs;
128     int code;
129
130     check_type(op[-1], t_dictionary);
131     check_stype(*op, st_cie_render1);
132     code = zcrd1_proc_params(imemory, op - 1, &procs);
133     if (code < 0)
134         return code;
135     code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
136     if (code < 0)
137         return code;
138     if (gs_cie_cs_common(igs) != 0 &&
139         (code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
140         )
141         return code;
142     istate->colorrendering.dict = op[-1];
143     istate->colorrendering.procs = procs;
144     pop(2);
145     return (esp == ep ? 0 : o_push_estack);
146 }
147
148 /* <dict> <crd> .setdevicecolorrendering1 - */
149 private int
150 zsetdevicecolorrendering1(i_ctx_t *i_ctx_p)
151 {
152     os_ptr op = osp;
153     int code;
154     ref_cie_render_procs procs;
155
156     check_type(op[-1], t_dictionary);
157     check_stype(*op, st_cie_render1);
158     code = gs_setcolorrendering(igs, r_ptr(op, gs_cie_render));
159     if (code < 0)
160         return code;
161     refset_null((ref *)&procs, sizeof(procs) / sizeof(ref));
162     if (gs_cie_cs_common(igs) != 0 &&
163         (code = cie_cache_joint(i_ctx_p, &procs, gs_cie_cs_common(igs), igs)) < 0
164         )
165         return code;
166     istate->colorrendering.dict = op[-1];
167     refset_null((ref *)&istate->colorrendering.procs,
168                 sizeof(istate->colorrendering.procs) / sizeof(ref));
169     pop(2);
170     return 0;
171 }
172
173 /* Get ColorRenderingType 1 procedures from the PostScript dictionary. */
174 private int
175 zcrd1_proc_params(const gs_memory_t *mem, 
176                   os_ptr op, ref_cie_render_procs * pcprocs)
177 {
178     int code;
179     ref *pRT;
180
181     if ((code = dict_proc3_param(mem, op, "EncodeLMN", &pcprocs->EncodeLMN)) < 0 ||
182       (code = dict_proc3_param(mem, op, "EncodeABC", &pcprocs->EncodeABC)) < 0 ||
183     (code = dict_proc3_param(mem, op, "TransformPQR", &pcprocs->TransformPQR)) < 0
184         )
185         return (code < 0 ? code : gs_note_error(e_rangecheck));
186     if (dict_find_string(op, "RenderTable", &pRT) > 0) {
187         const ref *prte;
188         int size;
189         int i;
190
191         check_read_type(*pRT, t_array);
192         size = r_size(pRT);
193         if (size < 5)
194             return_error(e_rangecheck);
195         prte = pRT->value.const_refs;
196         for (i = 5; i < size; i++)
197             check_proc_only(prte[i]);
198         make_const_array(&pcprocs->RenderTableT, a_readonly | r_space(pRT),
199                          size - 5, prte + 5);
200     } else
201         make_null(&pcprocs->RenderTableT);
202     return 0;
203 }
204
205 /* Get ColorRenderingType 1 parameters from the PostScript dictionary. */
206 private int
207 zcrd1_params(os_ptr op, gs_cie_render * pcrd,
208              ref_cie_render_procs * pcprocs, gs_memory_t * mem)
209 {
210     int code;
211     int ignore;
212     gx_color_lookup_table *const prtl = &pcrd->RenderTable.lookup;
213     ref *pRT;
214
215     if ((code = dict_int_param(op, "ColorRenderingType", 1, 1, 0, &ignore)) < 0 ||
216         (code = zcrd1_proc_params(mem, op, pcprocs)) < 0 ||
217         (code = dict_matrix3_param(mem, op, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
218         (code = dict_range3_param(mem, op, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
219         (code = dict_matrix3_param(mem, op, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
220         (code = dict_range3_param(mem, op, "RangeABC", &pcrd->RangeABC)) < 0 ||
221         (code = cie_points_param(mem, op, &pcrd->points)) < 0 ||
222         (code = dict_matrix3_param(mem, op, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
223         (code = dict_range3_param(mem,op, "RangePQR", &pcrd->RangePQR)) < 0
224         )
225         return code;
226     if (dict_find_string(op, "RenderTable", &pRT) > 0) {
227         const ref *prte = pRT->value.const_refs;
228
229         /* Finish unpacking and checking the RenderTable parameter. */
230         check_type_only(prte[4], t_integer);
231         if (!(prte[4].value.intval == 3 || prte[4].value.intval == 4))
232             return_error(e_rangecheck);
233         prtl->n = 3;
234         prtl->m = prte[4].value.intval;
235         if (r_size(pRT) != prtl->m + 5)
236             return_error(e_rangecheck);
237         code = cie_table_param(pRT, prtl, mem);
238         if (code < 0)
239             return code;
240     } else {
241         prtl->table = 0;
242     }
243     pcrd->EncodeLMN = Encode_default;
244     pcrd->EncodeABC = Encode_default;
245     pcrd->TransformPQR = TransformPQR_default;
246     pcrd->RenderTable.T = RenderTableT_default;
247     return 0;
248 }
249
250 /* Cache the results of the color rendering procedures. */
251 private int cie_cache_render_finish(i_ctx_t *);
252 private int
253 cache_colorrendering1(i_ctx_t *i_ctx_p, gs_cie_render * pcrd,
254                       const ref_cie_render_procs * pcrprocs,
255                       gs_ref_memory_t * imem)
256 {
257     es_ptr ep = esp;
258     int code = gs_cie_render_init(pcrd);        /* sets Domain values */
259     int i;
260
261     if (code < 0 ||
262         (code = cie_cache_push_finish(i_ctx_p, cie_cache_render_finish, imem, pcrd)) < 0 ||
263         (code = cie_prepare_cache3(i_ctx_p, &pcrd->DomainLMN, pcrprocs->EncodeLMN.value.const_refs, pcrd->caches.EncodeLMN.caches, pcrd, imem, "Encode.LMN")) < 0 ||
264         (code = cie_prepare_cache3(i_ctx_p, &pcrd->DomainABC, pcrprocs->EncodeABC.value.const_refs, &pcrd->caches.EncodeABC[0], pcrd, imem, "Encode.ABC")) < 0
265         ) {
266         esp = ep;
267         return code;
268     }
269     if (pcrd->RenderTable.lookup.table != 0) {
270         bool is_identity = true;
271
272         for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
273             if (r_size(pcrprocs->RenderTableT.value.const_refs + i) != 0) {
274                 is_identity = false;
275                 break;
276             }
277         pcrd->caches.RenderTableT_is_identity = is_identity;
278         if (!is_identity)
279             for (i = 0; i < pcrd->RenderTable.lookup.m; i++)
280                 if ((code =
281                      cie_prepare_cache(i_ctx_p, Range4_default.ranges,
282                                 pcrprocs->RenderTableT.value.const_refs + i,
283                                        &pcrd->caches.RenderTableT[i].floats,
284                                        pcrd, imem, "RenderTable.T")) < 0
285                     ) {
286                     esp = ep;
287                     return code;
288                 }
289     }
290     return o_push_estack;
291 }
292
293 /* Finish up after loading the rendering caches. */
294 private int
295 cie_cache_render_finish(i_ctx_t *i_ctx_p)
296 {
297     os_ptr op = osp;
298     gs_cie_render *pcrd = r_ptr(op, gs_cie_render);
299     int code;
300
301     if (pcrd->RenderTable.lookup.table != 0 &&
302         !pcrd->caches.RenderTableT_is_identity
303         ) {
304         /* Convert the RenderTableT cache from floats to fracs. */
305         int j;
306
307         for (j = 0; j < pcrd->RenderTable.lookup.m; j++)
308             gs_cie_cache_to_fracs(&pcrd->caches.RenderTableT[j].floats,
309                                   &pcrd->caches.RenderTableT[j].fracs);
310     }
311     pcrd->status = CIE_RENDER_STATUS_SAMPLED;
312     pcrd->EncodeLMN = EncodeLMN_from_cache;
313     pcrd->EncodeABC = EncodeABC_from_cache;
314     pcrd->RenderTable.T = RenderTableT_from_cache;
315     code = gs_cie_render_complete(pcrd);
316     if (code < 0)
317         return code;
318     pop(1);
319     return 0;
320 }
321
322 /* ------ Internal procedures ------ */
323
324 /* Load the joint caches. */
325 private int
326     cie_exec_tpqr(i_ctx_t *),
327     cie_post_exec_tpqr(i_ctx_t *),
328     cie_tpqr_finish(i_ctx_t *);
329 int
330 cie_cache_joint(i_ctx_t *i_ctx_p, const ref_cie_render_procs * pcrprocs,
331                 const gs_cie_common *pcie, gs_state * pgs)
332 {
333     const gs_cie_render *pcrd = gs_currentcolorrendering(pgs);
334     gx_cie_joint_caches *pjc = gx_currentciecaches(pgs);
335     gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
336     ref pqr_procs;
337     uint space;
338     int code;
339     int i;
340
341     if (pcrd == 0)              /* cache is not set up yet */
342         return 0;
343     if (pjc == 0)               /* must already be allocated */
344         return_error(e_VMerror);
345     if (r_has_type(&pcrprocs->TransformPQR, t_null)) {
346         /*
347          * This CRD came from a driver, not from a PostScript dictionary.
348          * Resample TransformPQR in C code.
349          */
350         return gs_cie_cs_complete(pgs, true);
351     }
352     gs_cie_compute_points_sd(pjc, pcie, pcrd);
353     code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
354                             "cie_cache_common");
355     if (code < 0)
356         return code;
357     /* When we're done, deallocate the procs and complete the caches. */
358     check_estack(3);
359     cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs);
360     *++esp = pqr_procs;
361     space = r_space(&pqr_procs);
362     for (i = 0; i < 3; i++) {
363         ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i;
364
365         make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
366                    4, p);
367         make_array(p, a_readonly | space, 4 * 6, p + 4);
368         p[1] = pcrprocs->TransformPQR.value.refs[i];
369         make_oper(p + 2, 0, cie_exec_tpqr);
370         make_oper(p + 3, 0, cie_post_exec_tpqr);
371         p += 4;
372
373         /* cant use array due to structure alignment */
374         make_real(p, pjc->points_sd.ws.xyz.u); p++;
375         make_real(p, pjc->points_sd.ws.xyz.v); p++;
376         make_real(p, pjc->points_sd.ws.xyz.w); p++;
377         make_real(p, pjc->points_sd.ws.pqr.u); p++;
378         make_real(p, pjc->points_sd.ws.pqr.v); p++;
379         make_real(p, pjc->points_sd.ws.pqr.w); p++;
380
381         make_real(p, pjc->points_sd.bs.xyz.u); p++;
382         make_real(p, pjc->points_sd.bs.xyz.v); p++;
383         make_real(p, pjc->points_sd.bs.xyz.w); p++;
384         make_real(p, pjc->points_sd.bs.pqr.u); p++;
385         make_real(p, pjc->points_sd.bs.pqr.v); p++;
386         make_real(p, pjc->points_sd.bs.pqr.w); p++;
387
388         make_real(p, pjc->points_sd.wd.xyz.u); p++;
389         make_real(p, pjc->points_sd.wd.xyz.v); p++;
390         make_real(p, pjc->points_sd.wd.xyz.w); p++;
391         make_real(p, pjc->points_sd.wd.pqr.u); p++;
392         make_real(p, pjc->points_sd.wd.pqr.v); p++;
393         make_real(p, pjc->points_sd.wd.pqr.w); p++;
394
395         make_real(p, pjc->points_sd.bd.xyz.u); p++;
396         make_real(p, pjc->points_sd.bd.xyz.v); p++;
397         make_real(p, pjc->points_sd.bd.xyz.w); p++;
398         make_real(p, pjc->points_sd.bd.pqr.u); p++;
399         make_real(p, pjc->points_sd.bd.pqr.v); p++;
400         make_real(p, pjc->points_sd.bd.pqr.w); p++;
401    }
402     return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR,
403                               pqr_procs.value.const_refs,
404                               pjc->TransformPQR.caches,
405                               pjc, imem, "Transform.PQR");
406 }
407
408 /* Private operator to shuffle arguments for the TransformPQR procedure: */
409 /* v [ws wd bs bd] proc -> -mark- ws wd bs bd v proc + exec */
410 private int
411 cie_exec_tpqr(i_ctx_t *i_ctx_p)
412 {
413     os_ptr op = osp;
414     const ref *ppt = op[-1].value.const_refs;
415     uint space = r_space(op - 1);
416     int i;
417
418     check_op(3);
419     push(4);
420     *op = op[-4];               /* proc */
421     op[-1] = op[-6];            /* v */
422     for (i = 0; i < 4; i++)
423         make_const_array(op - 5 + i, a_readonly | space,
424                          6, ppt + i * 6);
425     make_mark(op - 6);
426     return zexec(i_ctx_p);
427 }
428
429 /* Remove extraneous values from the stack after executing */
430 /* the TransformPQR procedure.  -mark- ... v -> v */
431 private int
432 cie_post_exec_tpqr(i_ctx_t *i_ctx_p)
433 {
434     os_ptr op = osp;
435     uint count = ref_stack_counttomark(&o_stack);
436     ref vref;
437
438     if (count < 2)
439         return_error(e_unmatchedmark);
440     vref = *op;
441     ref_stack_pop(&o_stack, count - 1);
442     *osp = vref;
443     return 0;
444 }
445
446 /* Free the procs array and complete the joint caches. */
447 private int
448 cie_tpqr_finish(i_ctx_t *i_ctx_p)
449 {
450     os_ptr op = osp;
451     gs_state *pgs = r_ptr(op, gs_state);
452     gs_cie_render *pcrd =
453         (gs_cie_render *)gs_currentcolorrendering(pgs);  /* break const */
454     int code;
455
456     ifree_ref_array(op - 1, "cie_tpqr_finish");
457     pcrd->TransformPQR = TransformPQR_from_cache;
458     code = gs_cie_cs_complete(pgs, false);
459     pop(2);
460     return code;
461 }
462
463 /* Ws Bs Wd Bd Ps .transformPQR_scale_wb[012] Pd
464
465    The default TransformPQR procedure is implemented in C, rather than
466    PostScript, as a speed optimization.
467
468    This TransformPQR implements a relative colorimetric intent by scaling
469    the XYZ values relative to the white and black points.
470 */
471 private int
472 ztpqr_scale_wb_common(i_ctx_t *i_ctx_p, int idx)
473 {
474     os_ptr op = osp;
475     double a[4], Ps; /* a[0] = ws, a[1] = bs, a[2] = wd, a[3] = bd */
476     double result;
477     int code;
478     int i;
479
480     code = real_param(op, &Ps);
481     if (code < 0) return code;
482
483     for (i = 0; i < 4; i++) {
484         ref tmp;
485
486         code = array_get(imemory, op - 4 + i, idx, &tmp);
487         if (code >= 0)
488             code = real_param(&tmp, &a[i]);
489         if (code < 0) return code;
490     }
491
492     if (a[0] == a[1])
493         return_error(e_undefinedresult);
494     result = a[3] + (a[2] - a[3]) * (Ps - a[1]) / (a[0] - a[1]);
495     make_real(op - 4, result);
496     pop(4);
497     return 0;
498 }
499
500 /* Ws Bs Wd Bd Ps .TransformPQR_scale_wb0 Pd */
501 private int
502 ztpqr_scale_wb0(i_ctx_t *i_ctx_p)
503 {
504     return ztpqr_scale_wb_common(i_ctx_p, 3);
505 }
506
507 /* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
508 private int
509 ztpqr_scale_wb1(i_ctx_t *i_ctx_p)
510 {
511     return ztpqr_scale_wb_common(i_ctx_p, 4);
512 }
513
514 /* Ws Bs Wd Bd Ps .TransformPQR_scale_wb2 Pd */
515 private int
516 ztpqr_scale_wb2(i_ctx_t *i_ctx_p)
517 {
518     return ztpqr_scale_wb_common(i_ctx_p, 5);
519 }
520
521 /* ------ Initialization procedure ------ */
522
523 const op_def zcrd_l2_op_defs[] =
524 {
525     op_def_begin_level2(),
526     {"0currentcolorrendering", zcurrentcolorrendering},
527     {"2.setcolorrendering1", zsetcolorrendering1},
528     {"2.setdevicecolorrendering1", zsetdevicecolorrendering1},
529     {"1.buildcolorrendering1", zbuildcolorrendering1},
530     {"1.builddevicecolorrendering1", zbuilddevicecolorrendering1},
531                 /* Internal "operators" */
532     {"1%cie_render_finish", cie_cache_render_finish},
533     {"3%cie_exec_tpqr", cie_exec_tpqr},
534     {"2%cie_post_exec_tpqr", cie_post_exec_tpqr},
535     {"1%cie_tpqr_finish", cie_tpqr_finish},
536     {"5.TransformPQR_scale_WB0", ztpqr_scale_wb0},
537     {"5.TransformPQR_scale_WB1", ztpqr_scale_wb1},
538     {"5.TransformPQR_scale_WB2", ztpqr_scale_wb2},
539     op_def_end(0)
540 };