1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Color operators */
18 #include "memory_.h"
19 #include "math_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "dstack.h" /* for systemdict */
23 #include "estack.h"
24 #include "ialloc.h"
25 #include "igstate.h"
26 #include "iutil.h"
27 #include "store.h"
28 #include "gscolor.h" /* for gs_setgray and gs_setrgbcolor */
29 #include "gscsepr.h" /* For declarartion of Separation functions */
30 #include "gscdevn.h" /* For declarartion of DeviceN functions */
31 #include "gscpixel.h" /* For declarartion of DevicePixel functions */
32 #include "gxfixed.h"
33 #include "gxmatrix.h"
34 #include "gzstate.h"
35 #include "gxdcolor.h" /* for gxpcolor.h */
36 #include "gxdevice.h"
37 #include "gxdevmem.h" /* for gxpcolor.h */
38 #include "gxcmap.h"
39 #include "gxcspace.h"
40 #include "gxcolor2.h"
41 #include "gxpcolor.h"
42 #include "idict.h"
43 #include "icolor.h"
44 #include "idparam.h"
45 #include "iname.h"
46 #include "iutil.h"
47 #include "ifunc.h" /* For declaration of buildfunction */
48 #include "icsmap.h"
49 #include "ifunc.h"
50 #include "zht2.h"
51 #include "zcolor.h" /* For the PS_colour_space_t structure */
52 #include "zcie.h" /* For CIE space function declarations */
53 #include "zicc.h" /* For declaration of seticc */
54 #include "gscspace.h" /* Needed for checking if current pgs colorspace is CIE */
55 #include "iddict.h" /* for idict_put_string */
56 #include "zfrsd.h" /* for make_rss() */
57
58 /* imported from gsht.c */
59 extern void gx_set_effective_transfer(gs_state *);
60
61 /* Essential forward declarations */
62 static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth);
63 static int setcolorspace_cont(i_ctx_t *i_ctx_p);
64 static int setcolor_cont(i_ctx_t *i_ctx_p);
65
66 /* define the number of stack slots needed for zcolor_remap_one */
67 const int zcolor_remap_one_ostack = 4;
68 const int zcolor_remap_one_estack = 3;
69
70 /* utility to test whether a Pattern instance uses a base space */
71 static inline bool
pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)72 pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)
73 {
74 return pinst->type->procs.uses_base_space(
75 pinst->type->procs.get_pattern(pinst) );
76 }
77
78 /*
79 * - currentcolor <param1> ... <paramN>
80 *
81 * Return the current color. <paramN> may be a dictionary or a null
82 * object, if the current color space is a pattern color space. The
83 * other parameters will be numeric.
84 *
85 * Note that the results of this operator differ slightly from those of
86 * most currentcolor implementations. If a color component value is
87 * integral (e.g.: 0, 1), it will be pushed on the stack as an integer.
88 * Most currentcolor implementations, including the earlier
89 * implementation in Ghostscript, would push real objects for all
90 * color spaces except indexed color space. The approach taken here is
91 * equally legitimate, and avoids special handling of indexed color
92 * spaces.
93 */
94 static int
zcurrentcolor(i_ctx_t * i_ctx_p)95 zcurrentcolor(i_ctx_t * i_ctx_p)
96 {
97 os_ptr op = osp;
98 const gs_color_space * pcs = gs_currentcolorspace(igs);
99 const gs_client_color * pcc = gs_currentcolor(igs);
100 int i, n = cs_num_components(pcs);
101 bool push_pattern = n < 0;
102
103 /* check for pattern */
104 if (push_pattern) {
105 gs_pattern_instance_t * pinst = pcc->pattern;
106
107 if (pinst == 0 || !pattern_instance_uses_base_space(pinst))
108 n = 1;
109 else
110 n = -n;
111 }
112
113 /* check for sufficient space on the stack */
114 push(n);
115 op -= n - 1;
116
117 /* push the numeric operands, if any */
118 if (push_pattern)
119 --n;
120 for (i = 0; i < n; i++, op++) {
121 float rval = pcc->paint.values[i];
122 int ival = (int)rval;
123
124 /* the following handles indexed color spaces */
125 if (rval == ival && pcs->type->index == gs_color_space_index_Indexed)
126 make_int(op, ival);
127 else
128 make_real(op, rval);
129 }
130
131 /* push the pattern dictionary or null object, if appropriate */
132 if (push_pattern)
133 *op = istate->pattern[0];
134
135 return 0;
136 }
137
138 /*
139 * - .currentcolorspace <array>
140 *
141 * Return the current color space. Unlike the prior implementation, the
142 * istate->color_space.array field will now always have a legitimate
143 * (array) value.
144 */
145 static int
zcurrentcolorspace(i_ctx_t * i_ctx_p)146 zcurrentcolorspace(i_ctx_t * i_ctx_p)
147 {
148 os_ptr op = osp; /* required by "push" macro */
149 int code;
150 ref namestr,stref;
151 byte *body;
152
153 /* Adobe applications expect that the Device spaces (DeviceGray
154 * DeviceRGB and DeviceCMYK) will always return the same array.
155 * Not merely the same content but the same actual array. To do
156 * this we define the arrays at startup (see gs_cspace.ps), and
157 * recover them here by executing PostScript.
158 */
159 if (r_has_type(&istate->colorspace[0].array, t_name)) {
160 name_string_ref(imemory, &istate->colorspace[0].array, &namestr);
161 if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceGray", 10)) {
162 body = ialloc_string(32, "string");
163 if (body == 0)
164 return_error(e_VMerror);
165 memcpy(body, "systemdict /DeviceGray_array get", 32);
166 make_string(&stref, a_all | icurrent_space, 32, body);
167 } else {
168 if (r_size(&namestr) == 9 && !memcmp(namestr.value.bytes, "DeviceRGB", 9)) {
169 body = ialloc_string(31, "string");
170 if (body == 0)
171 return_error(e_VMerror);
172 memcpy(body, "systemdict /DeviceRGB_array get", 31);
173 make_string(&stref, a_all | icurrent_space, 31, body);
174 } else {
175 if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceCMYK", 10)) {
176 body = ialloc_string(32, "string");
177 if (body == 0)
178 return_error(e_VMerror);
179 memcpy(body, "systemdict /DeviceCMYK_array get", 32);
180 make_string(&stref, a_all | icurrent_space, 32, body);
181 } else {
182 /* Not one of the Device spaces, but still just a name. Give
183 * up and return the name on the stack.
184 */
185 push(1);
186 code = ialloc_ref_array(op, a_all, 1, "currentcolorspace");
187 if (code < 0)
188 return code;
189 refset_null(op->value.refs, 1);
190 ref_assign_old(op, op->value.refs,
191 &istate->colorspace[0].array,
192 "currentcolorspace");
193 return 0;
194 }
195 }
196 }
197 r_set_attrs(&stref, a_executable);
198 esp++;
199 ref_assign(esp, &stref);
200 return o_push_estack;
201 } else {
202 /* If the space isn't a simple name, then we don't need any special
203 * action and can simply use it.
204 */
205 push(1);
206 *op = istate->colorspace[0].array;
207 }
208 return 0;
209 }
210
211 /*
212 * - .getuseciecolor <bool>
213 *
214 * Return the current setting of the use_cie_color graphic state parameter,
215 * which tracks the UseCIEColor page device parameter. This parameter may be
216 * read (via this operator) at all language leves, but may only be set (via
217 * the .setuseciecolor operator; see zcolor3.c) only in language level 3.
218 *
219 * We handle this parameter separately from the page device primarily for
220 * performance reasons (the parameter may be queried frequently), but as a
221 * side effect achieve proper behavior relative to the language level. The
222 * interpreter is always initialized with this parameter set to false, and
223 * it can only be updated (via setpagedevice) in language level 3.
224 */
225 static int
zgetuseciecolor(i_ctx_t * i_ctx_p)226 zgetuseciecolor(i_ctx_t * i_ctx_p)
227 {
228 os_ptr op = osp;
229
230 push(1);
231 *op = istate->use_cie_color;
232 return 0;
233 }
234
235 /* Clean up when unwinding the stack on an error. (No action needed.) */
236 static int
colour_cleanup(i_ctx_t * i_ctx_p)237 colour_cleanup(i_ctx_t *i_ctx_p)
238 {
239 return 0;
240 }
241
242 /*
243 * <param1> ... <paramN> setcolor -
244 *
245 * Set the current color. All of the parameters except the topmost (paramN) are
246 * numbers; the topmost (and possibly only) entry may be pattern dictionary or
247 * a null object.
248 *
249 * The use of one operator to set both patterns and "normal" colors is
250 * consistent with Adobe's documentation, but primarily reflects the use of
251 * gs_setcolor for both purposes in the graphic library. An alternate
252 * implementation would use a .setpattern operator, which would interface with
253 * gs_setpattern.
254 *
255 * This operator is hidden by a pseudo-operator of the same name, so it will
256 * only be invoked under controlled situations. Hence, it does no operand
257 * checking.
258 */
259 static int
zsetcolor(i_ctx_t * i_ctx_p)260 zsetcolor(i_ctx_t * i_ctx_p)
261 {
262 os_ptr op = osp;
263 es_ptr ep = esp;
264 const gs_color_space * pcs = gs_currentcolorspace(igs);
265 gs_client_color cc;
266 int n_comps, n_numeric_comps, num_offset = 0, code, depth;
267 bool is_ptype2 = 0;
268 PS_colour_space_t *space;
269
270 /* initialize the client color pattern pointer for GC */
271 cc.pattern = 0;
272
273 /* check for a pattern color space */
274 if ((n_comps = cs_num_components(pcs)) < 0) {
275 n_comps = -n_comps;
276 if (r_has_type(op, t_dictionary)) {
277 ref *pImpl, pPatInst;
278 int ptype;
279
280 code = dict_find_string(op, "Implementation", &pImpl);
281 if (code < 0)
282 return code;
283 code = array_get(imemory, pImpl, 0, &pPatInst);
284 if (code < 0)
285 return code;
286 cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
287 n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern)
288 ? n_comps - 1
289 : 0 );
290 (void)dict_int_param(op, "PatternType", 1, 2, 1, &ptype);
291 is_ptype2 = ptype == 2;
292 } else
293 n_numeric_comps = 0;
294 num_offset = 1;
295 } else
296 n_numeric_comps = n_comps;
297
298 /* gather the numeric operands */
299 code = float_params(op - num_offset, n_numeric_comps, cc.paint.values);
300 if (code < 0)
301 return code;
302
303 code = get_space_object(i_ctx_p, &istate->colorspace[0].array, &space);
304 if (code < 0)
305 return code;
306 if (space->validatecomponents) {
307 code = space->validatecomponents(i_ctx_p,
308 &istate->colorspace[0].array,
309 cc.paint.values, n_numeric_comps);
310 if (code < 0)
311 return code;
312 }
313
314 /* pass the color to the graphic library */
315 if ((code = gs_setcolor(igs, &cc)) >= 0) {
316
317 if (n_comps > n_numeric_comps) {
318 istate->pattern[0] = *op; /* save pattern dict or null */
319 n_comps = n_numeric_comps + 1;
320 }
321 }
322
323 /* Check the color spaces, to see if we need to run any tint transform
324 * procedures. Some Adobe applications *eg Photoshop) expect that the
325 * tint transform will be run and use this to set up duotone DeviceN
326 * spaces.
327 */
328 code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
329 if (code < 0)
330 return code;
331 /* Set up for the continuation procedure which will do the work */
332 /* Make sure the exec stack has enough space */
333 check_estack(5);
334 /* A place holder for data potentially used by transform functions */
335 ep = esp += 1;
336 make_int(ep, 0);
337 /* Store the 'depth' of the space returned during checking above */
338 ep = esp += 1;
339 make_int(ep, 0);
340 /* Store the 'stage' of processing (initially 0) */
341 ep = esp += 1;
342 make_int(ep, 0);
343 /* Store a pointer to the color space stored on the operand stack
344 * as the stack may grow unpredictably making further access
345 * to the space difficult
346 */
347 ep = esp += 1;
348 *ep = istate->colorspace[0].array;
349 /* Finally, the actual continuation routine */
350 push_op_estack(setcolor_cont);
351 return o_push_estack;
352 }
353
354 /* This is used to detect color space changes due
355 to the changing of UseCIEColor during transparency
356 soft mask processing */
357
name_is_device_color(char * cs_name)358 static bool name_is_device_color( char *cs_name )
359 {
360
361 return( strcmp(cs_name, "DeviceGray") == 0 ||
362 strcmp(cs_name, "DeviceRGB") == 0 ||
363 strcmp(cs_name, "DeviceCMYK") == 0);
364
365 }
366
367 /*
368 * Given two color space arrays, attempts to determine if they are the
369 * same space by comparing their contents recursively. For some spaces,
370 * especially CIE based color spaces, it can significantly improve
371 * performance if the same space is frequently re-used.
372 */
is_same_colorspace(i_ctx_t * i_ctx_p,ref * space1,ref * space2,bool isCIE)373 static int is_same_colorspace(i_ctx_t * i_ctx_p, ref *space1, ref *space2, bool isCIE)
374 {
375 PS_colour_space_t *oldcspace = 0, *newcspace = 0;
376 ref oldspace, *poldspace = &oldspace, newspace, *pnewspace = &newspace;
377 int code, CIESubst;
378
379 /* Silence compiler warnings */
380 oldspace.tas.type_attrs = 0;
381 oldspace.tas.type_attrs = 0;
382
383 ref_assign(pnewspace, space1);
384 ref_assign(poldspace, space2);
385
386 do {
387 if (r_type(poldspace) != r_type(pnewspace))
388 return 0;
389
390 code = get_space_object(i_ctx_p, poldspace, &oldcspace);
391 if (code < 0)
392 return 0;
393
394 code = get_space_object(i_ctx_p, pnewspace, &newcspace);
395 if (code < 0)
396 return 0;
397
398 /* Check the two color space types are the same
399 * (Indexed, Separation, DeviceCMYK etc).
400 */
401 if (strcmp(oldcspace->name, newcspace->name) != 0)
402 return 0;
403
404 /* Call the space-specific comparison routine */
405 if (!oldcspace->compareproc(i_ctx_p, poldspace, pnewspace))
406 return 0;
407
408 /* See if current space is CIE based (which could happen
409 if UseCIE had been true previously), but UseCIE is false
410 and incoming space is device based. This can occur
411 when we are now processing a soft mask, which should not
412 use the UseCIEColor option.
413
414 Need to detect this case at both transitions
415
416 Device Color UseCIEColor true
417 Soft mask
418 Device color UseCIEColor false
419 Soft mask
420 Device color UseCIEColor true
421 */
422
423 if ( name_is_device_color(newcspace->name) ){
424 if ( gs_color_space_is_CIE(gs_currentcolorspace_inline(i_ctx_p->pgs)) ){
425 if ( !isCIE ) return 0; /* The color spaces will be different */
426 } else {
427 if ( isCIE ) return 0; /* The color spaces will be different */
428 }
429 }
430
431 /* The current space is OK, if there is no alternate, then that's
432 * good enough.
433 */
434 if (!oldcspace->alternateproc)
435 break;
436
437 /* Otherwise, retrieve the alternate space for each, and continue
438 * round the loop, checking those.
439 */
440 code = oldcspace->alternateproc(i_ctx_p, poldspace, &poldspace, &CIESubst);
441 if (code < 0)
442 return 0;
443
444 code = newcspace->alternateproc(i_ctx_p, pnewspace, &pnewspace, &CIESubst);
445 if (code < 0)
446 return 0;
447 }
448 while(1);
449
450 return 1;
451 }
452
453 /*
454 * <array> setcolorspace -
455 *
456 * Set the nominal color space. This color space will be pushd by the
457 * currentcolorspace operator, but is not directly used to pass color
458 * space information to the graphic library.
459 *
460 */
461 static int
zsetcolorspace(i_ctx_t * i_ctx_p)462 zsetcolorspace(i_ctx_t * i_ctx_p)
463 {
464 os_ptr op = osp;
465 es_ptr ep = esp;
466 int code, depth;
467 bool is_CIE;
468
469 /* Make sure we have an operand... */
470 check_op(1);
471 /* Check its either a name (base space) or an array */
472 if (!r_has_type(op, t_name))
473 if (!r_is_array(op))
474 return_error(e_typecheck);
475
476 code = validate_spaces(i_ctx_p, op, &depth);
477 if (code < 0)
478 return code;
479
480 is_CIE = istate->use_cie_color.value.boolval;
481
482 /* See if its the same as the current space */
483 if (is_same_colorspace(i_ctx_p, op, &istate->colorspace[0].array, is_CIE)) {
484 PS_colour_space_t *cspace;
485
486 /* Even if its the same space, we still need to set the correct
487 * initial color value.
488 */
489 code = get_space_object(i_ctx_p, &istate->colorspace[0].array, &cspace);
490 if (code < 0)
491 return 0;
492 if (cspace->initialcolorproc) {
493 cspace->initialcolorproc(i_ctx_p, &istate->colorspace[0].array);
494 }
495 /* Pop the space off the stack */
496 pop(1);
497 return 0;
498 }
499 /* Set up for the continuation procedure which will do the work */
500 /* Make sure the exec stack has enough space */
501 check_estack(5);
502 /* Store the initial value of CIE substitution (not substituting) */
503 ep = esp += 1;
504 make_int(ep, 0);
505 /* Store the 'depth' of the space returned during checking above */
506 ep = esp += 1;
507 make_int(ep, depth);
508 /* Store the 'stage' of processing (initially 0) */
509 ep = esp += 1;
510 make_int(ep, 0);
511 /* Store a pointer to the color space stored on the operand stack
512 * as the stack may grow unpredictably making further access
513 * to the space difficult
514 */
515 ep = esp += 1;
516 *ep = *op;
517 /* Finally, the actual continuation routine */
518 push_op_estack(setcolorspace_cont);
519 return o_push_estack;
520 }
521
522 /*
523 * A special version of the setcolorspace operation above. This sets the
524 * CIE substitution flag to true before starting, which prevents any further
525 * CIE substitution taking place.
526 */
527 static int
setcolorspace_nosubst(i_ctx_t * i_ctx_p)528 setcolorspace_nosubst(i_ctx_t * i_ctx_p)
529 {
530 os_ptr op = osp;
531 es_ptr ep = esp;
532 int code, depth;
533
534 /* Make sure we have an operand... */
535 check_op(1);
536 /* Check its either a name (base space) or an array */
537 if (!r_has_type(op, t_name))
538 if (!r_is_array(op))
539 return_error(e_typecheck);
540
541 code = validate_spaces(i_ctx_p, op, &depth);
542 if (code < 0)
543 return code;
544
545 /* Set up for the continuation procedure which will do the work */
546 /* Make sure the exec stack has enough space */
547 check_estack(5);
548 /* Store the initial value of CIE substitution (substituting) */
549 ep = esp += 1;
550 make_int(ep, 1);
551 /* Store the 'depth' of the space returned during checking above */
552 ep = esp += 1;
553 make_int(ep, depth);
554 /* Store the 'stage' of processing (initially 0) */
555 ep = esp += 1;
556 make_int(ep, 0);
557 /* Store a pointer to the color space stored on the operand stack
558 * as the stack may grow unpredictably making further access
559 * to the space difficult
560 */
561 ep = esp += 1;
562 *ep = *op;
563 /* Finally, the actual continuation routine */
564 push_op_estack(setcolorspace_cont);
565 return o_push_estack;
566 }
567
568 /*
569 * <name> .includecolorspace -
570 *
571 * See the comment for gs_includecolorspace in gscolor2.c .
572 */
573 static int
zincludecolorspace(i_ctx_t * i_ctx_p)574 zincludecolorspace(i_ctx_t * i_ctx_p)
575 {
576 os_ptr op = osp;
577 ref nsref;
578 int code;
579
580 check_type(*op, t_name);
581 name_string_ref(imemory, op, &nsref);
582 code = gs_includecolorspace(igs, nsref.value.const_bytes, r_size(&nsref));
583 if (!code)
584 pop(1);
585 return code;
586 }
587
588 /* - currenttransfer <proc> */
589 static int
zcurrenttransfer(i_ctx_t * i_ctx_p)590 zcurrenttransfer(i_ctx_t *i_ctx_p)
591 {
592 os_ptr op = osp;
593
594 push(1);
595 *op = istate->transfer_procs.gray;
596 return 0;
597 }
598
599 /*
600 * - processcolors <int> -
601 *
602 * Note: this is an undocumented operator that is not supported
603 * in Level 2.
604 */
605 static int
zprocesscolors(i_ctx_t * i_ctx_p)606 zprocesscolors(i_ctx_t * i_ctx_p)
607 {
608 os_ptr op = osp;
609
610 push(1);
611 make_int(op, gs_currentdevice(igs)->color_info.num_components);
612 return 0;
613 }
614
615 /* <proc> settransfer - */
616 static int
zsettransfer(i_ctx_t * i_ctx_p)617 zsettransfer(i_ctx_t * i_ctx_p)
618 {
619 os_ptr op = osp;
620 int code;
621
622 check_proc(*op);
623 check_ostack(zcolor_remap_one_ostack - 1);
624 check_estack(1 + zcolor_remap_one_estack);
625 istate->transfer_procs.red =
626 istate->transfer_procs.green =
627 istate->transfer_procs.blue =
628 istate->transfer_procs.gray = *op;
629 if ((code = gs_settransfer_remap(igs, gs_mapped_transfer, false)) < 0)
630 return code;
631 push_op_estack(zcolor_reset_transfer);
632 pop(1);
633 return zcolor_remap_one( i_ctx_p,
634 &istate->transfer_procs.gray,
635 igs->set_transfer.gray,
636 igs,
637 zcolor_remap_one_finish );
638 }
639
640 /*
641 * Internal routines
642 */
643
644 /*
645 * Prepare to remap one color component (also used for black generation
646 * and undercolor removal). Use the 'for' operator to gather the values.
647 * The caller must have done the necessary check_ostack and check_estack.
648 */
649 int
zcolor_remap_one(i_ctx_t * i_ctx_p,const ref * pproc,gx_transfer_map * pmap,const gs_state * pgs,op_proc_t finish_proc)650 zcolor_remap_one(
651 i_ctx_t * i_ctx_p,
652 const ref * pproc,
653 gx_transfer_map * pmap,
654 const gs_state * pgs,
655 op_proc_t finish_proc )
656 {
657 os_ptr op;
658
659 /*
660 * Detect the identity function, which is a common value for one or
661 * more of these functions.
662 */
663 if (r_size(pproc) == 0) {
664 gx_set_identity_transfer(pmap);
665 /*
666 * Even though we don't actually push anything on the e-stack, all
667 * clients do, so we return o_push_estack in this case. This is
668 * needed so that clients' finishing procedures will get run.
669 */
670 return o_push_estack;
671 }
672 op = osp += 4;
673 make_real(op - 3, 0);
674 make_int(op - 2, transfer_map_size - 1);
675 make_real(op - 1, 1);
676 *op = *pproc;
677 ++esp;
678 make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory),
679 pmap);
680 push_op_estack(finish_proc);
681 push_op_estack(zfor_samples);
682 return o_push_estack;
683 }
684
685 /* Store the result of remapping a component. */
686 static int
zcolor_remap_one_store(i_ctx_t * i_ctx_p,floatp min_value)687 zcolor_remap_one_store(i_ctx_t *i_ctx_p, floatp min_value)
688 {
689 int i;
690 gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map);
691
692 if (ref_stack_count(&o_stack) < transfer_map_size)
693 return_error(e_stackunderflow);
694 for (i = 0; i < transfer_map_size; i++) {
695 double v;
696 int code =
697 real_param(ref_stack_index(&o_stack, transfer_map_size - 1 - i),
698 &v);
699
700 if (code < 0)
701 return code;
702 pmap->values[i] =
703 (v < min_value ? float2frac(min_value) :
704 v >= 1.0 ? frac_1 :
705 float2frac(v));
706 }
707 ref_stack_pop(&o_stack, transfer_map_size);
708 esp--; /* pop pointer to transfer map */
709 return o_pop_estack;
710 }
711 int
zcolor_remap_one_finish(i_ctx_t * i_ctx_p)712 zcolor_remap_one_finish(i_ctx_t *i_ctx_p)
713 {
714 return zcolor_remap_one_store(i_ctx_p, 0.0);
715 }
716 int
zcolor_remap_one_signed_finish(i_ctx_t * i_ctx_p)717 zcolor_remap_one_signed_finish(i_ctx_t *i_ctx_p)
718 {
719 return zcolor_remap_one_store(i_ctx_p, -1.0);
720 }
721
722 /* Finally, reset the effective transfer functions and */
723 /* invalidate the current color. */
724 int
zcolor_reset_transfer(i_ctx_t * i_ctx_p)725 zcolor_reset_transfer(i_ctx_t *i_ctx_p)
726 {
727 gx_set_effective_transfer(igs);
728 return zcolor_remap_color(i_ctx_p);
729 }
730 int
zcolor_remap_color(i_ctx_t * i_ctx_p)731 zcolor_remap_color(i_ctx_t *i_ctx_p)
732 {
733 /* Remap both colors. This should never hurt. */
734 gs_swapcolors(igs);
735 gx_unset_dev_color(igs);
736 gs_swapcolors(igs);
737 gx_unset_dev_color(igs);
738 return 0;
739 }
740
741 /*
742 * <param1> ... <paramN> .color_test <param1> ... <paramN>
743 *
744 * encode and decode color to allow mapping to be tested.
745 */
746 static int
zcolor_test(i_ctx_t * i_ctx_p)747 zcolor_test(i_ctx_t *i_ctx_p)
748 {
749 gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
750 gx_device *dev = gs_currentdevice(igs);
751 int ncomp = dev->color_info.num_components;
752 gx_color_index color;
753 os_ptr op = osp - (ncomp-1);
754 int i;
755 if (ref_stack_count(&o_stack) < ncomp)
756 return_error(e_stackunderflow);
757 for (i = 0; i < ncomp; i++) {
758 if (r_has_type(op+i, t_real))
759 cv[i] = (gx_color_value)
760 (op[i].value.realval * gx_max_color_value);
761 else if (r_has_type(op+i, t_integer))
762 cv[i] = (gx_color_value)
763 (op[i].value.intval * gx_max_color_value);
764 else
765 return_error(e_typecheck);
766 }
767 color = (*dev_proc(dev, encode_color)) (dev, cv);
768 (*dev_proc(dev, decode_color)) (dev, color, cv);
769 for (i = 0; i < ncomp; i++)
770 make_real(op+i, (float)cv[i] / (float)gx_max_color_value);
771 return 0;
772 }
773
774 /*
775 * <levels> .color_test_all <value0> ... <valueN>
776 *
777 * Test encode/decode color procedures for a range of values.
778 * Return value with the worst error in a single component.
779 */
780 static int
zcolor_test_all(i_ctx_t * i_ctx_p)781 zcolor_test_all(i_ctx_t *i_ctx_p)
782 {
783 os_ptr op = osp;
784 gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
785 gx_color_value cvout[GX_DEVICE_COLOR_MAX_COMPONENTS];
786 gx_color_value cvbad[GX_DEVICE_COLOR_MAX_COMPONENTS];
787 int counter[GX_DEVICE_COLOR_MAX_COMPONENTS];
788 gx_device *dev = gs_currentdevice(igs);
789 int ncomp = dev->color_info.num_components;
790 int steps;
791 int maxerror = 0;
792 int err;
793 int acceptable_error;
794 int linsep = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN;
795 int linsepfailed = 0;
796 int lsmaxerror = 0;
797 gx_color_index color, lscolor;
798 int i, j, k;
799 int finished = 0;
800
801 if (ncomp == 1)
802 acceptable_error = gx_max_color_value / dev->color_info.max_gray + 1;
803 else
804 acceptable_error = gx_max_color_value / dev->color_info.max_color + 1;
805
806 if (ref_stack_count(&o_stack) < 1)
807 return_error(e_stackunderflow);
808 if (!r_has_type(&osp[0], t_integer))
809 return_error(e_typecheck);
810 steps = osp[0].value.intval;
811 for (i = 0; i < ncomp; i++) {
812 counter[i] = 0;
813 cvbad[i] = 0;
814 }
815
816 dprintf1("Number of components = %d\n", ncomp);
817 dprintf1("Depth = %d\n", dev->color_info.depth);
818 dprintf2("max_gray = %d dither_grays = %d\n",
819 dev->color_info.max_gray, dev->color_info.dither_grays);
820 dprintf2("max_color = %d dither_colors = %d\n",
821 dev->color_info.max_color, dev->color_info.dither_colors);
822 dprintf1("polarity = %s\n",
823 dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE ? "Additive" :
824 dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE ?"Subtractive":
825 "Unknown");
826 /* Indicate color index value with all colorants = zero */
827 for (i = 0; i < ncomp; i++)
828 cv[i] = 0;
829 color = (*dev_proc(dev, encode_color)) (dev, cv);
830 if (sizeof(color) <= sizeof(ulong))
831 dprintf1("Zero color index: %8lx\n", (ulong)color);
832 else
833 dprintf2("Zero color index: %8lx%08lx\n",
834 (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color);
835
836 dprintf1("separable_and_linear = %s\n",
837 linsep == GX_CINFO_SEP_LIN_NONE ? "No" :
838 linsep == GX_CINFO_SEP_LIN ? "Yes" :
839 "Unknown");
840 if (dev->color_info.gray_index == GX_CINFO_COMP_INDEX_UNKNOWN)
841 dprintf("gray_index is unknown\n");
842 else
843 dprintf1("gray_index = %d\n", dev->color_info.gray_index);
844 if (linsep) {
845 dprintf(" Shift Mask Bits\n");
846 for (i = 0; i < ncomp; i++) {
847 dprintf3(" %5d %8x %4d\n",
848 (int)(dev->color_info.comp_shift[i]),
849 (int)(dev->color_info.comp_mask[i]),
850 (int)(dev->color_info.comp_bits[i]));
851 }
852 }
853
854 while (!finished) {
855 for (j = 0; j <= steps; j++) {
856 for (i = 0; i < ncomp; i++)
857 cv[i] = counter[i] * gx_max_color_value / steps;
858 color = (*dev_proc(dev, encode_color)) (dev, cv);
859 if (linsep) {
860 /* Derive it the other way */
861 lscolor = gx_default_encode_color(dev, cv);
862 if ((color != lscolor) && (linsepfailed < 5)) {
863 linsepfailed++;
864 dprintf("Failed separable_and_linear for");
865 for (i = 0; i < ncomp; i++)
866 dprintf1(" %d", cv[i]);
867 dprintf("\n");
868 dprintf2("encode_color=%x gx_default_encode_color=%x\n",
869 (int)color, (int)lscolor);
870 }
871 }
872 (*dev_proc(dev, decode_color)) (dev, color, cvout);
873 for (i = 0; i < ncomp; i++) {
874 err = (int)cvout[i] - (int)cv[i];
875 if (err < 0)
876 err = -err;
877 if (err > maxerror) {
878 maxerror = err;
879 for (k=0; k < ncomp; k++)
880 cvbad[k] = cv[k];
881 }
882 }
883 if (linsep) {
884 gx_default_decode_color(dev, color, cvout);
885 for (i = 0; i < ncomp; i++) {
886 err = (int)cvout[i] - (int)cv[i];
887 if (err < 0)
888 err = -err;
889 if (err > lsmaxerror) {
890 lsmaxerror = err;
891 }
892 }
893 }
894 counter[0] += 1;
895 }
896 counter[0] = 0;
897 i = 1;
898 while (i < ncomp) {
899 counter[i] += 1;
900 if (counter[i] > steps) {
901 counter[i] = 0;
902 i++;
903 }
904 else
905 break;
906 }
907 if (i >= ncomp)
908 finished = 1;
909 }
910
911 dprintf2("Maximum error %g %s\n",
912 (float)maxerror / (float)gx_max_color_value,
913 maxerror <= acceptable_error ? "is Ok" :
914 maxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
915
916 if (linsep)
917 dprintf2("Maximum linear_and_separable error %g %s\n",
918 (float)lsmaxerror / (float)gx_max_color_value,
919 lsmaxerror <= acceptable_error ? "is Ok" :
920 lsmaxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
921
922 /* push worst value */
923 push(ncomp-1);
924 op -= ncomp - 1;
925 for (i = 0; i < ncomp; i++)
926 make_real(op+i, (float)cvbad[i] / (float)gx_max_color_value);
927
928 return 0;
929 }
930
931 /* Convert between RGB and HSB colors, using the hexcone approach (see
932 * Rogers, David, "Procedureal Elements For Computer Graphics",
933 * (McGraw-Hill, 1985), pp. 402 - 3).
934 *
935 * The rgb ==> hsb calculation is:
936 *
937 * br = max(r, g, b)
938 *
939 * if (br == 0)
940 * h = 0, s = 0;
941 * else {
942 * v = min(r, g, b)
943 * diff = br - v;
944 * sat = diff / br;
945 * if (r == br)
946 * h = (g - b) / (6 * diff) + (b > g ? 1 : 0);
947 * else if (g == br)
948 * h = 1/3 + (b - r) / (6 * diff);
949 * else
950 * h = 2/3 + (r - g) / (6 * diff);
951 * }
952 */
rgb2hsb(float * RGB)953 static int rgb2hsb(float *RGB)
954 {
955 float HSB[3], v, diff;
956 int i, j=0;
957
958 v = 1.0;
959 for (i=0;i<3;i++)
960 HSB[i] = 0.0;
961 for (i=0;i<3;i++) {
962 if (RGB[i] > HSB[2]) {
963 HSB[2] = RGB[i];
964 j = i;
965 }
966 if (RGB[i] < v)
967 v = RGB[i];
968 }
969 if (HSB[2] != 0) {
970 diff = HSB[2] - v;
971 HSB[1] = diff / HSB[2];
972 switch (j) {
973 case 0 : /* R == Brightness */
974 /* diff can only be zero if r == br, so we need to make sure here we
975 * don't divide by zero
976 */
977 if (diff)
978 HSB[0] = ((RGB[1] - RGB[2]) / (6.0 * diff)) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
979 else
980 HSB[0] = (RGB[1] - RGB[2]) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
981 break;
982 case 1 : /* G == Brightness */
983 HSB[0] = (1.0 / 3.0) + (RGB[2] - RGB[0]) / (6.0 * diff);
984 break;
985 case 2 : /* B == Brightness */
986 HSB[0] = (2.0 / 3.0) + (RGB[0] - RGB[1]) / (6.0 * diff);
987 break;
988 }
989 }
990 for (i=0;i<3;i++) {
991 if (HSB[i] < 0)
992 HSB[i] = 0;
993 if (RGB[i] > 1)
994 HSB[i] = 1;
995 RGB[i] = HSB[i];
996 }
997 return 0;
998 }
999 /* The hsb ==> rgb conversion is:
1000 *
1001 * mn = (1 - s) * br, md = 6 * s * br;
1002 *
1003 * switch ((int)floor(6 * h)) {
1004 * case 0: %% r >= g >= b
1005 * r = br;
1006 * g = mn + h * md;
1007 * b = mn;
1008 * break;
1009 *
1010 * case 1: %% g >= r >= b
1011 * r = mn + md * (1/3 - h);
1012 * g = br;
1013 * b = mn;
1014 * break;
1015 *
1016 * case 2: %% g >= b >= r
1017 * r = mn;
1018 * g = br;
1019 * b = mn + (h - 1/3) * md;
1020 * break;
1021 *
1022 * case 3: %% b >= g >= r
1023 * r = mn;
1024 * g = mn + (2/3 - h) * md;
1025 * b = br;
1026 * break;
1027 *
1028 * case 4: %% b >= r >= g
1029 * r = mn + (h - 2/3) * md;
1030 * g = mn;
1031 * b = br;
1032 * break;
1033 *
1034 * case 5: %% r >= b >= g
1035 * r = br;
1036 * g = mn;
1037 * b = mn + (1 - h) * md;
1038 * break;
1039 *
1040 * case 6: %% We have wrapped around the hexcone. Thus this case is
1041 * the same as case 0 with h = 0
1042 * h = 0;
1043 * r = br;
1044 * g = mn + h * md = mn;
1045 * b = mn;
1046 * break;
1047 * }
1048 */
hsb2rgb(float * HSB)1049 static int hsb2rgb(float *HSB)
1050 {
1051 float RGB[3], mn, md;
1052 int i;
1053
1054 mn = (1.0 - HSB[1]) * HSB[2];
1055 md = 6.0 * HSB[1] * HSB[2];
1056
1057 switch ((int)floor(6.0 * HSB[0])) {
1058 case 6:
1059 HSB[0] = (float)0;
1060 default: /* Shuts up compiler warning about RGB being uninited */
1061 case 0:
1062 RGB[0] = HSB[2];
1063 RGB[1] = mn + (HSB[0] * md);
1064 RGB[2] = mn;
1065 break;
1066 case 1:
1067 RGB[0] = mn + (md * ((1.0 / 3.0) - HSB[0]));
1068 RGB[1] = HSB[2];
1069 RGB[2] = mn;
1070 break;
1071 case 2:
1072 RGB[0] = mn;
1073 RGB[1] = HSB[2];
1074 RGB[2] = mn + ((HSB[0] - (1.0 / 3.0)) * md);
1075 break;
1076 case 3:
1077 RGB[0] = mn;
1078 RGB[1] = mn + (((2.0 / 3.0f) - HSB[0]) * md);
1079 RGB[2] = HSB[2];
1080 break;
1081 case 4:
1082 RGB[0] = mn + ((HSB[0] - (2.0 / 3.0)) * md);
1083 RGB[1] = mn;
1084 RGB[2] = HSB[2];
1085 break;
1086 case 5:
1087 RGB[0] = HSB[2];
1088 RGB[1] = mn;
1089 RGB[2] = mn + ((1.0 - HSB[0]) * md);
1090 break;
1091 }
1092 for (i=0;i<3;i++) {
1093 if (RGB[i] < 0)
1094 RGB[i] = 0;
1095 if (RGB[i] > 1)
1096 RGB[i] = 1;
1097 HSB[i] = RGB[i];
1098 }
1099 return 0;
1100 }
1101
1102 /* The routines for handling colors and color spaces, moved from
1103 * PostScript to C, start here.
1104 */
1105
1106 /* DeviceGray */
setgrayspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)1107 static int setgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1108 {
1109 os_ptr op = osp;
1110 gs_color_space *pcs;
1111 int code=0;
1112 ref stref;
1113
1114 do {
1115 switch (*stage) {
1116 case 0:
1117 if (istate->use_cie_color.value.boolval && !CIESubst) {
1118 byte *body;
1119 ref *nosubst;
1120
1121 code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1122 if (code < 0)
1123 return code;
1124 if (!r_has_type(nosubst, t_boolean))
1125 return_error(e_typecheck);
1126 if (nosubst->value.boolval) {
1127 *stage = 4;
1128 *cont = 1;
1129 body = ialloc_string(32, "string");
1130 if (body == 0)
1131 return_error(e_VMerror);
1132 memcpy(body, "/DefaultGray ..nosubstdevicetest",32);
1133 make_string(&stref, a_all | icurrent_space, 32, body);
1134 r_set_attrs(&stref, a_executable);
1135 esp++;
1136 ref_assign(esp, &stref);
1137 return o_push_estack;
1138 } else {
1139 *stage = 2;
1140 *cont = 1;
1141 body = ialloc_string(47, "string");
1142 if (body == 0)
1143 return_error(e_VMerror);
1144 memcpy(body, "{/DefaultGray /ColorSpace findresource} stopped",47);
1145 make_string(&stref, a_all | icurrent_space, 47, body);
1146 r_set_attrs(&stref, a_executable);
1147 esp++;
1148 ref_assign(esp, &stref);
1149 return o_push_estack;
1150 }
1151 break;
1152 }
1153 /* fall through */
1154 case 1:
1155 pcs = gs_cspace_new_DeviceGray(imemory);
1156 if (pcs == NULL)
1157 return_error(e_VMerror);
1158 code = gs_setcolorspace(igs, pcs);
1159 if (code >= 0) {
1160 gs_client_color *pcc = gs_currentcolor_inline(igs);
1161
1162 cs_adjust_color_count(igs, -1); /* not strictly necessary */
1163 pcc->paint.values[0] = (0);
1164 pcc->pattern = 0; /* for GC */
1165 gx_unset_dev_color(igs);
1166 }
1167 rc_decrement_only_cs(pcs, "zsetdevcspace");
1168 *cont = 0;
1169 *stage = 0;
1170 break;
1171 case 2:
1172 if (!r_has_type(op, t_boolean))
1173 return_error(e_typecheck);
1174 if (op->value.boolval) {
1175 /* Failed to find the /DefaultGray CSA, so give up and
1176 * just use DeviceGray
1177 */
1178 pop(1);
1179 *stage = 1;
1180 break;
1181 }
1182 pop(1);
1183 *cont = 1;
1184 *stage = 3;
1185 code = setcolorspace_nosubst(i_ctx_p);
1186 if (code != 0)
1187 return code;
1188 break;
1189 case 3:
1190 /* We end up here after setting the DefaultGray space
1191 * We've finished setting the gray color space, so we
1192 * just exit now
1193 */
1194 *cont = 0;
1195 *stage = 0;
1196 break;
1197 case 4:
1198 /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1199 * is also true. We will have a boolean on the stack, if its true
1200 * then we need to set the space (also on the stack), invoke
1201 * .includecolorspace, and set /DeviceGray, otherwise we just need
1202 * to set DeviceGray. See gs_cspace.ps.
1203 */
1204 if (!r_has_type(op, t_boolean))
1205 return_error(e_typecheck);
1206 pop(1);
1207 *stage = 1;
1208 *cont = 1;
1209 if (op->value.boolval) {
1210 *stage = 5;
1211 code = setcolorspace_nosubst(i_ctx_p);
1212 if (code != 0)
1213 return code;
1214 }
1215 break;
1216 case 5:
1217 /* After stage 4 above, if we had to set a color space, we come
1218 * here. Now we need to use .includecolorspace to register the space
1219 * with any high-level devices which want it.
1220 */
1221 *stage = 1;
1222 *cont = 1;
1223 code = zincludecolorspace(i_ctx_p);
1224 if (code != 0)
1225 return code;
1226 break;
1227 }
1228 } while (*stage);
1229 return code;
1230 }
graydomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)1231 static int graydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1232 {
1233 ptr[0] = 0;
1234 ptr[1] = 1;
1235 return 0;
1236 }
grayrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)1237 static int grayrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1238 {
1239 ptr[0] = 0;
1240 ptr[1] = 1;
1241 return 0;
1242 }
1243 /* This routine converts a Gray value into its equivalent in a different
1244 * device space, required by currentgray, currentrgb, currenthsb and
1245 * currentcmyk. The actual color value will have been processed through
1246 * the tint transform(s) of the parent space(s) until it reaches a device
1247 * space. This converts that final value into the requested space.
1248 */
graybasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)1249 static int graybasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1250 {
1251 os_ptr op = osp;
1252 float Gray, RGB[3];
1253
1254 *cont = 0;
1255 *stage = 0;
1256 check_op(1);
1257 if (!r_has_type(op, t_integer)) {
1258 if (r_has_type(op, t_real)) {
1259 Gray = op->value.realval;
1260 } else
1261 return_error(e_typecheck);
1262 } else
1263 Gray = (float)op->value.intval;
1264
1265 if (Gray < 0 || Gray > 1)
1266 return_error(e_rangecheck);
1267
1268 switch (base) {
1269 case 0:
1270 /* Requested space is DeviceGray, just use the value */
1271 make_real(op, Gray);
1272 break;
1273 case 1:
1274 /* Requested space is HSB */
1275 case 2:
1276 /* Requested space is RGB, set all the components
1277 * to the gray value
1278 */
1279 push(2);
1280 RGB[0] = RGB[1] = RGB[2] = Gray;
1281 if (base == 1)
1282 /* If the requested space is HSB, convert the RGB to HSB */
1283 rgb2hsb((float *)&RGB);
1284 make_real(&op[-2], RGB[0]);
1285 make_real(&op[-1], RGB[1]);
1286 make_real(op, RGB[2]);
1287 break;
1288 case 3:
1289 /* Requested space is CMYK, use the gray value to set the
1290 * black channel.
1291 */
1292 push(3);
1293 make_real(&op[-3], (float)0);
1294 make_real(&op[-2], (float)0);
1295 make_real(&op[-1], (float)0);
1296 make_real(op, (float)1.0 - Gray);
1297 break;
1298 default:
1299 return_error(e_undefined);
1300 }
1301 return 0;
1302 }
grayvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)1303 static int grayvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1304 {
1305 os_ptr op = osp;
1306
1307 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1308 return_error(e_typecheck);
1309
1310 if (num_comps < 1)
1311 return_error(e_stackunderflow);
1312
1313 if (*values > 1.0)
1314 *values = 1.0;
1315
1316 if ( *values < 0.0)
1317 *values = 0.0;
1318
1319 return 0;
1320 }
grayinitialproc(i_ctx_t * i_ctx_p,ref * space)1321 static int grayinitialproc(i_ctx_t *i_ctx_p, ref *space)
1322 {
1323 gs_client_color cc;
1324
1325 cc.pattern = 0x00;
1326 cc.paint.values[0] = 0;
1327 return gs_setcolor(igs, &cc);
1328 }
1329
1330 /* DeviceRGB */
setrgbspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)1331 static int setrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1332 {
1333 os_ptr op = osp;
1334 gs_color_space *pcs;
1335 int code=0;
1336 ref stref;
1337
1338 do {
1339 switch (*stage) {
1340 case 0:
1341 if (istate->use_cie_color.value.boolval && !CIESubst) {
1342 byte *body;
1343 ref *nosubst;
1344
1345 code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1346 if (code < 0)
1347 return code;
1348 if (!r_has_type(nosubst, t_boolean))
1349 return_error(e_typecheck);
1350 if (nosubst->value.boolval) {
1351 *stage = 4;
1352 *cont = 1;
1353 body = ialloc_string(31, "string");
1354 if (body == 0)
1355 return_error(e_VMerror);
1356 memcpy(body, "/DefaultRGB ..nosubstdevicetest",31);
1357 make_string(&stref, a_all | icurrent_space, 31, body);
1358 r_set_attrs(&stref, a_executable);
1359 esp++;
1360 ref_assign(esp, &stref);
1361 return o_push_estack;
1362 } else {
1363 *stage = 2;
1364 *cont = 1;
1365 body = ialloc_string(46, "string");
1366 if (body == 0)
1367 return_error(e_VMerror);
1368 memcpy(body, "{/DefaultRGB /ColorSpace findresource} stopped", 46);
1369 make_string(&stref, a_all | icurrent_space, 46, body);
1370 r_set_attrs(&stref, a_executable);
1371 esp++;
1372 ref_assign(esp, &stref);
1373 return o_push_estack;
1374 }
1375 }
1376 /* fall through */
1377 case 1:
1378 pcs = gs_cspace_new_DeviceRGB(imemory);
1379 if (pcs == NULL)
1380 return_error(e_VMerror);
1381 code = gs_setcolorspace(igs, pcs);
1382 if (code >= 0) {
1383 gs_client_color *pcc = gs_currentcolor_inline(igs);
1384
1385 cs_adjust_color_count(igs, -1); /* not strictly necessary */
1386 pcc->paint.values[0] = 0;
1387 pcc->paint.values[1] = 0;
1388 pcc->paint.values[2] = 0;
1389 pcc->pattern = 0; /* for GC */
1390 gx_unset_dev_color(igs);
1391 }
1392 rc_decrement_only_cs(pcs, "zsetdevcspace");
1393 *cont = 0;
1394 *stage = 0;
1395 break;
1396 case 2:
1397 if (!r_has_type(op, t_boolean))
1398 return_error(e_typecheck);
1399 if (op->value.boolval) {
1400 /* Failed to find the /DefaultRGB CSA, so give up and
1401 * just use DeviceRGB
1402 */
1403 pop(1);
1404 *stage = 1;
1405 break;
1406 }
1407 pop(1);
1408 *stage = 3;
1409 code = setcolorspace_nosubst(i_ctx_p);
1410 if (code != 0)
1411 return code;
1412 break;
1413 case 3:
1414 /* We end up here after setting the DefaultGray CIE space
1415 * We've finished setting the gray color space, so we
1416 * just exit now
1417 */
1418 *cont = 0;
1419 *stage = 0;
1420 break;
1421 case 4:
1422 /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1423 * is also true. We will have a boolean on the stack, if its true
1424 * then we need to set the space (also on the stack), invoke
1425 * .includecolorspace, and set /DeviceGray, otherwise we just need
1426 * to set DeviceGray. See gs-cspace.ps.
1427 */
1428 if (!r_has_type(op, t_boolean))
1429 return_error(e_typecheck);
1430 pop(1);
1431 *stage = 1;
1432 *cont = 1;
1433 if (op->value.boolval) {
1434 *stage = 5;
1435 code = setcolorspace_nosubst(i_ctx_p);
1436 if (code != 0)
1437 return code;
1438 }
1439 break;
1440 case 5:
1441 /* After stage 4 above, if we had to set a color space, we come
1442 * here. Now we need to use .includecolorspace to register the space
1443 * with any high-level devices which want it.
1444 */
1445 *stage = 1;
1446 *cont = 1;
1447 code = zincludecolorspace(i_ctx_p);
1448 if (code != 0)
1449 return code;
1450 break;
1451 }
1452 } while (*stage);
1453 return code;
1454 }
rgbdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)1455 static int rgbdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1456 {
1457 int i;
1458
1459 for (i = 0;i < 6;i+=2) {
1460 ptr[i] = 0;
1461 ptr[i+1] = 1;
1462 }
1463 return 0;
1464 }
rgbrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)1465 static int rgbrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1466 {
1467 int i;
1468
1469 for (i = 0;i < 6;i+=2) {
1470 ptr[i] = 0;
1471 ptr[i+1] = 1;
1472 }
1473 return 0;
1474 }
1475 /* This routine converts an RGB value into its equivalent in a different
1476 * device space, required by currentgray, currentrgb, currenthsb and
1477 * currentcmyk. The actual color value will have been processed through
1478 * the tint transform(s) of the parent space(s) until it reaches a device
1479 * space. This converts that final value into the requested space.
1480 */
rgbbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)1481 static int rgbbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1482 {
1483 os_ptr op = osp;
1484 float RGB[3], CMYK[4], Gray, UCR, BG;
1485 int i;
1486 const gs_color_space * pcs = gs_currentcolorspace(igs);
1487
1488 if (pcs->id == cs_DeviceGray_id) {
1489 /* UGLY hack. Its possible for the graphics library to change the
1490 * colour space to DeviceGray (setcachedevice), but this does not
1491 * change the PostScript space. It can't, because the graphics library
1492 * doesn't know about the PostScript objects. If we get a current*
1493 * operation before the space has been restored, the colour space in
1494 * the graphics library and the PostScript stored space won't match.
1495 * If that happens then we need to pretend the PS colour space was
1496 * DeviceGray
1497 */
1498 return(graybasecolor(i_ctx_p, space, base, stage, cont, stack_depth));
1499 }
1500
1501 switch (*stage) {
1502 case 0:
1503 *cont = 0;
1504 check_op(3);
1505 op -= 2;
1506 for (i=0;i<3;i++) {
1507 if (!r_has_type(op, t_integer)) {
1508 if (r_has_type(op, t_real)) {
1509 RGB[i] = op->value.realval;
1510 } else
1511 return_error(e_typecheck);
1512 } else
1513 RGB[i] = (float)op->value.intval;
1514 if (RGB[i] < 0 || RGB[i] > 1)
1515 return_error(e_rangecheck);
1516 op++;
1517 }
1518 op = osp;
1519
1520 switch (base) {
1521 case 0:
1522 pop(2);
1523 op = osp;
1524 /* If R == G == B, then this is gray, so just use it. Avoids
1525 * rounding errors.
1526 */
1527 if (RGB[0] == RGB[1] && RGB[1] == RGB[2])
1528 Gray = RGB[0];
1529 else
1530 Gray = (0.3 * RGB[0]) + (0.59 * RGB[1]) + (0.11 * RGB[2]);
1531 make_real(op, Gray);
1532 return 0;
1533 break;
1534 case 1:
1535 rgb2hsb((float *)&RGB);
1536 make_real(&op[-2], RGB[0]);
1537 make_real(&op[-1], RGB[1]);
1538 make_real(op, RGB[2]);
1539 return 0;
1540 break;
1541 case 2:
1542 make_real(&op[-2], RGB[0]);
1543 make_real(&op[-1], RGB[1]);
1544 make_real(op, RGB[2]);
1545 return 0;
1546 break;
1547 case 3:
1548 *stage = 1;
1549 *cont = 1;
1550 for (i=0;i<3;i++)
1551 CMYK[i] = 1 - RGB[i];
1552 if (CMYK[0] < CMYK[1]) {
1553 if (CMYK[0] < CMYK[2])
1554 CMYK[3] = CMYK[0];
1555 else
1556 CMYK[3] = CMYK[2];
1557 } else {
1558 if (CMYK[1] < CMYK[2])
1559 CMYK[3] = CMYK[1];
1560 else
1561 CMYK[3] = CMYK[2];
1562 }
1563 check_estack(1);
1564 push(2);
1565 op = osp - 4;
1566 for (i=0;i<4;i++) {
1567 make_real(op, CMYK[i]);
1568 op++;
1569 }
1570 make_real(op, CMYK[3]);
1571 esp++;
1572 *esp = istate->undercolor_removal;
1573 return o_push_estack;
1574 break;
1575 default:
1576 return_error(e_undefined);
1577 break;
1578 }
1579 break;
1580 case 1:
1581 (*stage)++;
1582 *cont = 1;
1583 check_estack(1);
1584 check_op(5);
1585 op -= 4;
1586 for (i=0;i<4;i++) {
1587 if (!r_has_type(op, t_integer)) {
1588 if (r_has_type(op, t_real)) {
1589 CMYK[i] = op->value.realval;
1590 } else
1591 return_error(e_typecheck);
1592 } else
1593 CMYK[i] = (float)op->value.intval;
1594 op++;
1595 }
1596 if (!r_has_type(op, t_integer)) {
1597 if (r_has_type(op, t_real)) {
1598 UCR = op->value.realval;
1599 } else
1600 return_error(e_typecheck);
1601 } else
1602 UCR = (float)op->value.intval;
1603 for (i=0;i<3;i++) {
1604 CMYK[i] = CMYK[i] - UCR;
1605 if (CMYK[i] < 0)
1606 CMYK[i] = 0;
1607 if (CMYK[i] > 1)
1608 CMYK[i] = 1.0;
1609 }
1610 op -= 4;
1611 for (i=0;i<4;i++) {
1612 make_real(op, CMYK[i]);
1613 op++;
1614 }
1615 make_real(op, CMYK[3]);
1616 esp++;
1617 *esp = istate->black_generation;
1618 return o_push_estack;
1619 break;
1620 case 2:
1621 *stage = 0;
1622 *cont = 0;
1623 check_op(5);
1624 if (!r_has_type(op, t_integer)) {
1625 if (r_has_type(op, t_real)) {
1626 BG = op->value.realval;
1627 } else
1628 return_error(e_typecheck);
1629 } else
1630 BG = (float)op->value.intval;
1631 pop(1);
1632 op = osp;
1633 if (BG < 0)
1634 BG = 0;
1635 if (BG > 1)
1636 BG = 1;
1637 make_real(op, BG);
1638 break;
1639 }
1640 return 0;
1641 }
rgbvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)1642 static int rgbvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1643 {
1644 os_ptr op = osp;
1645 int i;
1646
1647 if (num_comps < 3)
1648 return_error(e_stackunderflow);
1649
1650 op -= 2;
1651 for (i=0;i<3;i++) {
1652 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1653 return_error(e_typecheck);
1654 op++;
1655 }
1656
1657 for (i=0;i < 3; i++) {
1658 if (values[i] > 1.0)
1659 values[i] = 1.0;
1660
1661 if (values[i] < 0.0)
1662 values[i] = 0.0;
1663 }
1664
1665 return 0;
1666 }
rgbinitialproc(i_ctx_t * i_ctx_p,ref * space)1667 static int rgbinitialproc(i_ctx_t *i_ctx_p, ref *space)
1668 {
1669 gs_client_color cc;
1670
1671 cc.pattern = 0x00;
1672 cc.paint.values[0] = 0;
1673 cc.paint.values[1] = 0;
1674 cc.paint.values[2] = 0;
1675 return gs_setcolor(igs, &cc);
1676 }
1677
1678 /* DeviceCMYK */
setcmykspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)1679 static int setcmykspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1680 {
1681 os_ptr op = osp;
1682 gs_color_space *pcs;
1683 int code=0;
1684 ref stref;
1685
1686 do {
1687 switch (*stage) {
1688 case 0:
1689 if (istate->use_cie_color.value.boolval && !CIESubst) {
1690 byte *body;
1691 ref *nosubst;
1692
1693 code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1694 if (code < 0)
1695 return code;
1696 if (!r_has_type(nosubst, t_boolean))
1697 return_error(e_typecheck);
1698 if (nosubst->value.boolval) {
1699 *stage = 4;
1700 *cont = 1;
1701 body = ialloc_string(32, "string");
1702 if (body == 0)
1703 return_error(e_VMerror);
1704 memcpy(body, "/DefaultCMYK ..nosubstdevicetest",32);
1705 make_string(&stref, a_all | icurrent_space, 32, body);
1706 r_set_attrs(&stref, a_executable);
1707 esp++;
1708 ref_assign(esp, &stref);
1709 return o_push_estack;
1710 } else {
1711 *stage = 2;
1712 *cont = 1;
1713 body = ialloc_string(47, "string");
1714 if (body == 0)
1715 return_error(e_VMerror);
1716 memcpy(body, "{/DefaultCMYK /ColorSpace findresource} stopped", 47);
1717 make_string(&stref, a_all | icurrent_space, 47, body);
1718 r_set_attrs(&stref, a_executable);
1719 esp++;
1720 ref_assign(esp, &stref);
1721 return o_push_estack;
1722 }
1723 }
1724 /* fall through */
1725 case 1:
1726 pcs = gs_cspace_new_DeviceCMYK(imemory);
1727 if (pcs == NULL)
1728 return_error(e_VMerror);
1729 code = gs_setcolorspace(igs, pcs);
1730 if (code >= 0) {
1731 gs_client_color *pcc = gs_currentcolor_inline(igs);
1732
1733 cs_adjust_color_count(igs, -1); /* not strictly necessary */
1734 pcc->paint.values[0] = 0;
1735 pcc->paint.values[1] = 0;
1736 pcc->paint.values[2] = 0;
1737 pcc->paint.values[3] = 1;
1738 pcc->pattern = 0; /* for GC */
1739 gx_unset_dev_color(igs);
1740 }
1741 rc_decrement_only_cs(pcs, "zsetdevcspace");
1742 *cont = 0;
1743 *stage = 0;
1744 break;
1745 case 2:
1746 if (!r_has_type(op, t_boolean))
1747 return_error(e_typecheck);
1748 if (op->value.boolval) {
1749 /* Failed to find the /DefaultCMYK CSA, so give up and
1750 * just use DeviceCMYK
1751 */
1752 pop(1);
1753 *stage = 1;
1754 break;
1755 }
1756 pop(1);
1757 *stage = 3;
1758 code = setcolorspace_nosubst(i_ctx_p);
1759 if (code != 0)
1760 return code;
1761 break;
1762 case 3:
1763 /* We end up here after setting the DefaultGray CIE space
1764 * We've finished setting the gray color space, so we
1765 * just exit now
1766 */
1767 *cont = 0;
1768 *stage = 0;
1769 break;
1770 case 4:
1771 /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1772 * is also true. We will have a boolean on the stack, if its true
1773 * then we need to set the space (also on the stack), invoke
1774 * .includecolorspace, and set /DeviceGray, otherwise we just need
1775 * to set DeviceGray. See gs-cspace.ps.
1776 */
1777 if (!r_has_type(op, t_boolean))
1778 return_error(e_typecheck);
1779 pop(1);
1780 *stage = 1;
1781 *cont = 1;
1782 if (op->value.boolval) {
1783 *stage = 5;
1784 code = setcolorspace_nosubst(i_ctx_p);
1785 if (code != 0)
1786 return code;
1787 }
1788 break;
1789 case 5:
1790 /* After stage 4 above, if we had to set a color space, we come
1791 * here. Now we need to use .includecolorspace to register the space
1792 * with any high-level devices which want it.
1793 */
1794 *stage = 1;
1795 *cont = 1;
1796 code = zincludecolorspace(i_ctx_p);
1797 if (code != 0)
1798 return code;
1799 break;
1800 }
1801 } while (*stage);
1802 return code;
1803 }
cmykdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)1804 static int cmykdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1805 {
1806 int i;
1807
1808 for (i = 0;i < 8;i+=2) {
1809 ptr[i] = 0;
1810 ptr[i+1] = 1;
1811 }
1812 return 0;
1813 }
cmykrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)1814 static int cmykrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1815 {
1816 int i;
1817
1818 for (i = 0;i < 8;i+=2) {
1819 ptr[i] = 0;
1820 ptr[i+1] = 1;
1821 }
1822 return 0;
1823 }
1824 /* This routine converts a CMYK value into its equivalent in a different
1825 * device space, required by currentgray, currentrgb, currenthsb and
1826 * currentcmyk. The actual color value will have been processed through
1827 * the tint transform(s) of the parent space(s) until it reaches a device
1828 * space. This converts that final value into the requested space.
1829 */
cmykbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)1830 static int cmykbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1831 {
1832 os_ptr op = osp;
1833 float CMYK[4], Gray, RGB[3];
1834 int i;
1835 const gs_color_space * pcs = gs_currentcolorspace(igs);
1836
1837 if (pcs->id == cs_DeviceGray_id) {
1838 /* UGLY hack. Its possible for the graphics library to change the
1839 * colour space to DeviceGray (setcachedevice), but this does not
1840 * change the PostScript space. It can't, because the graphics library
1841 * doesn't know about the PostScript objects. If we get a current*
1842 * operation before the space has been restored, the colour space in
1843 * the graphics library and the PostScript stored space won't match.
1844 * If that happens then we need to pretend the PS colour space was
1845 * DeviceGray
1846 */
1847 return(graybasecolor(i_ctx_p, space, base, stage, cont, stack_depth));
1848 }
1849
1850 *cont = 0;
1851 *stage = 0;
1852 check_op(4);
1853 op -= 3;
1854 for (i=0;i<4;i++) {
1855 if (!r_has_type(op, t_integer)) {
1856 if (r_has_type(op, t_real)) {
1857 CMYK[i] = op->value.realval;
1858 } else
1859 return_error(e_typecheck);
1860 } else
1861 CMYK[i] = (float)op->value.intval;
1862 if (CMYK[i] < 0 || CMYK[i] > 1)
1863 return_error(e_rangecheck);
1864 op++;
1865 }
1866
1867 switch (base) {
1868 case 0:
1869 pop(3);
1870 op = osp;
1871 Gray = (0.3 * CMYK[0]) + (0.59 * CMYK[1]) + (0.11 * CMYK[2]) + CMYK[3];
1872 if (Gray > 1.0)
1873 Gray = 0;
1874 else
1875 Gray = 1.0 - Gray;
1876 make_real(op, Gray);
1877 break;
1878 case 1:
1879 case 2:
1880 pop(1);
1881 op = osp;
1882 RGB[0] = 1.0 - (CMYK[0] + CMYK[3]);
1883 if (RGB[0] < 0)
1884 RGB[0] = 0;
1885 RGB[1] = 1.0 - (CMYK[1] + CMYK[3]);
1886 if (RGB[1] < 0)
1887 RGB[1] = 0;
1888 RGB[2] = 1.0 - (CMYK[2] + CMYK[3]);
1889 if (RGB[2] < 0)
1890 RGB[2] = 0;
1891 if (base == 1)
1892 rgb2hsb((float *)&RGB);
1893 make_real(&op[-2], RGB[0]);
1894 make_real(&op[-1], RGB[1]);
1895 make_real(op, RGB[2]);
1896 break;
1897 case 3:
1898 op = osp;
1899 make_real(&op[-3], CMYK[0]);
1900 make_real(&op[-2], CMYK[1]);
1901 make_real(&op[-1], CMYK[2]);
1902 make_real(op, CMYK[3]);
1903 break;
1904 default:
1905 return_error(e_undefined);
1906 }
1907 return 0;
1908 }
cmykvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)1909 static int cmykvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1910 {
1911 os_ptr op = osp;
1912 int i;
1913
1914 if (num_comps < 4)
1915 return_error(e_stackunderflow);
1916
1917 op -= 3;
1918 for (i=0;i < 4;i++) {
1919 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1920 return_error(e_typecheck);
1921 op++;
1922 }
1923
1924 for (i=0;i < 4; i++) {
1925 if (values[i] > 1.0)
1926 values[i] = 1.0;
1927
1928 if (values[i] < 0.0)
1929 values[i] = 0.0;
1930 }
1931
1932 return 0;
1933 }
cmykinitialproc(i_ctx_t * i_ctx_p,ref * space)1934 static int cmykinitialproc(i_ctx_t *i_ctx_p, ref *space)
1935 {
1936 gs_client_color cc;
1937
1938 cc.pattern = 0x00;
1939 cc.paint.values[0] = 0;
1940 cc.paint.values[1] = 0;
1941 cc.paint.values[2] = 0;
1942 cc.paint.values[3] = 1;
1943 return gs_setcolor(igs, &cc);
1944 }
1945
1946 /* CIEBased */
1947 /* A utility routine to check whether two arrays contain the same
1948 * contents. Used to check whether two color spaces are the same
1949 * Note that this can be recursive if the array contains arrays.
1950 */
comparearrays(i_ctx_t * i_ctx_p,ref * m1,ref * m2)1951 static int comparearrays(i_ctx_t * i_ctx_p, ref *m1, ref *m2)
1952 {
1953 int i, code;
1954 ref ref1, ref2;
1955
1956 if (r_size(m1) != r_size(m2))
1957 return 0;
1958
1959 for (i=0;i < r_size(m1);i++) {
1960 code = array_get(imemory, m1, i, &ref1);
1961 if (code < 0)
1962 return 0;
1963 code = array_get(imemory, m2, i, &ref2);
1964 if (code < 0)
1965 return 0;
1966
1967 if (r_type(&ref1) != r_type(&ref2))
1968 return 0;
1969
1970 code = r_type(&ref1);
1971 switch(r_type(&ref1)) {
1972 case t_null:
1973 break;
1974 case t_boolean:
1975 if (ref1.value.boolval != ref2.value.boolval)
1976 return 0;
1977 break;
1978 case t_integer:
1979 if (ref1.value.intval != ref2.value.intval)
1980 return 0;
1981 break;
1982 case t_real:
1983 if (ref1.value.realval != ref2.value.realval)
1984 return 0;
1985 break;
1986 case t_name:
1987 if (!name_eq(&ref1, &ref2))
1988 return 0;
1989 break;
1990 case t_string:
1991 if (r_size(&ref1) != r_size(&ref2))
1992 return 0;
1993 if (strncmp((const char *)ref1.value.const_bytes, (const char *)ref2.value.const_bytes, r_size(&ref1)) != 0)
1994 return 0;
1995 break;
1996 case t_array:
1997 case t_mixedarray:
1998 case t_shortarray:
1999 if (!comparearrays(i_ctx_p, &ref1, &ref2))
2000 return 0;
2001 break;
2002 case t_oparray:
2003 break;
2004 case t_operator:
2005 if (ref1.value.opproc != ref2.value.opproc)
2006 return 0;
2007 break;
2008 case t__invalid:
2009 case t_dictionary:
2010 case t_file:
2011 case t_unused_array_:
2012 case t_struct:
2013 case t_astruct:
2014 case t_fontID:
2015 case t_save:
2016 case t_mark:
2017 case t_device:
2018 return 0;
2019 default:
2020 /* Some high frequency operators are defined starting at t_next_index
2021 * I think as long as the 'type' of each is the same, we are OK
2022 */
2023 break;
2024 }
2025 }
2026 return 1;
2027 }
2028 /* A utility routine to check whether two dictionaries contain the same
2029 * arrays. This is a simple routine, unlike comparearrays above it is only
2030 * used by the CIE comparison code and expects only to check that the
2031 * dictionary contains an array, and checks the arrays.
2032 */
comparedictkey(i_ctx_t * i_ctx_p,ref * CIEdict1,ref * CIEdict2,char * key)2033 static int comparedictkey(i_ctx_t * i_ctx_p, ref *CIEdict1, ref *CIEdict2, char *key)
2034 {
2035 int code, code1;
2036 ref *tempref1, *tempref2;
2037
2038 code = dict_find_string(CIEdict1, key, &tempref1);
2039 code1 = dict_find_string(CIEdict2, key, &tempref2);
2040 if (code != code1)
2041 return 0;
2042
2043 if (code < 0)
2044 return 1;
2045
2046 if (r_type(tempref1) != r_type(tempref2))
2047 return 0;
2048
2049 if (r_type(tempref1) == t_null)
2050 return 1;
2051
2052 return comparearrays(i_ctx_p, tempref1, tempref2);
2053 }
2054
2055 /* Check that the WhitePoint of a CIE space is valid */
checkWhitePoint(i_ctx_t * i_ctx_p,ref * CIEdict)2056 static int checkWhitePoint(i_ctx_t * i_ctx_p, ref *CIEdict)
2057 {
2058 int code = 0, i;
2059 float value[3];
2060 ref *tempref, valref;
2061
2062 code = dict_find_string(CIEdict, "WhitePoint", &tempref);
2063 if (code < 0 || r_has_type(tempref, t_null))
2064 return code;
2065
2066 if (!r_is_array(tempref))
2067 return_error(e_typecheck);
2068 if (r_size(tempref) != 3)
2069 return_error(e_rangecheck);
2070
2071 for (i=0;i<3;i++) {
2072 code = array_get(imemory, tempref, i, &valref);
2073 if (code < 0)
2074 return code;
2075 if (r_has_type(&valref, t_integer))
2076 value[i] = (float)valref.value.intval;
2077 else if (r_has_type(&valref, t_real))
2078 value[i] = (float)valref.value.realval;
2079 else
2080 return_error(e_typecheck);
2081 }
2082 /* Xw and Zw must be positive and Yw must be 1 (3rd edition PLRM p230) */
2083 if (value[0] < 0 || value[1] != 1 || value[2] < 0 )
2084 return_error(e_rangecheck);
2085
2086 return 0;
2087 }
2088 /* Check that the BlackPoint of a CIE space is valid */
checkBlackPoint(i_ctx_t * i_ctx_p,ref * CIEdict)2089 static int checkBlackPoint(i_ctx_t * i_ctx_p, ref *CIEdict)
2090 {
2091 int code = 0, i;
2092 float value[3];
2093 ref *tempref, valref;
2094
2095 code = dict_find_string(CIEdict, "BlackPoint", &tempref);
2096 if (code >= 0 && !r_has_type(tempref, t_null)) {
2097 if (!r_is_array(tempref))
2098 return_error(e_typecheck);
2099 if (r_size(tempref) != 3)
2100 return_error(e_rangecheck);
2101
2102 for (i=0;i<3;i++) {
2103 code = array_get(imemory, tempref, i, &valref);
2104 if (code < 0)
2105 return code;
2106 if (r_has_type(&valref, t_integer))
2107 value[i] = (float)valref.value.intval;
2108 else if (r_has_type(&valref, t_real))
2109 value[i] = (float)valref.value.realval;
2110 else
2111 return_error(e_typecheck);
2112 }
2113 }
2114 return 0;
2115 }
2116 /* Check that the RangeLMN of a CIE space is valid */
checkRangeLMN(i_ctx_t * i_ctx_p,ref * CIEdict)2117 static int checkRangeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2118 {
2119 int code = 0, i;
2120 float value[6];
2121 ref *tempref, valref;
2122
2123 code = dict_find_string(CIEdict, "RangeLMN", &tempref);
2124 if (code >= 0 && !r_has_type(tempref, t_null)) {
2125 if (!r_is_array(tempref))
2126 return_error(e_typecheck);
2127 if (r_size(tempref) != 6)
2128 return_error(e_rangecheck);
2129
2130 for (i=0;i<6;i++) {
2131 code = array_get(imemory, tempref, i, &valref);
2132 if (code < 0)
2133 return code;
2134 if (r_has_type(&valref, t_integer))
2135 value[i] = (float)valref.value.intval;
2136 else if (r_has_type(&valref, t_real))
2137 value[i] = (float)valref.value.realval;
2138 else
2139 return_error(e_typecheck);
2140 }
2141 if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2142 return_error(e_rangecheck);
2143 }
2144 return 0;
2145 }
2146 /* Check that the DecodeLMN of a CIE space is valid */
checkDecodeLMN(i_ctx_t * i_ctx_p,ref * CIEdict)2147 static int checkDecodeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2148 {
2149 int code = 0, i;
2150 ref *tempref, valref;
2151
2152 code = dict_find_string(CIEdict, "DecodeLMN", &tempref);
2153 if (code >= 0 && !r_has_type(tempref, t_null)) {
2154 if (!r_is_array(tempref))
2155 return_error(e_typecheck);
2156 if (r_size(tempref) != 3)
2157 return_error(e_rangecheck);
2158
2159 for (i=0;i<3;i++) {
2160 code = array_get(imemory, tempref, i, &valref);
2161 if (code < 0)
2162 return code;
2163 check_proc(valref);
2164 }
2165 }
2166 return 0;
2167 }
2168 /* Check that the MatrixLMN of a CIE space is valid */
checkMatrixLMN(i_ctx_t * i_ctx_p,ref * CIEdict)2169 static int checkMatrixLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2170 {
2171 int code = 0, i;
2172 float value[9];
2173 ref *tempref, valref;
2174
2175 code = dict_find_string(CIEdict, "MatrixLMN", &tempref);
2176 if (code >= 0 && !r_has_type(tempref, t_null)) {
2177 if (!r_is_array(tempref))
2178 return_error(e_typecheck);
2179 if (r_size(tempref) != 9)
2180 return_error(e_rangecheck);
2181
2182 for (i=0;i<9;i++) {
2183 code = array_get(imemory, tempref, i, &valref);
2184 if (code < 0)
2185 return code;
2186 if (r_has_type(&valref, t_integer))
2187 value[i] = (float)valref.value.intval;
2188 else if (r_has_type(&valref, t_real))
2189 value[i] = (float)valref.value.realval;
2190 else
2191 return_error(e_typecheck);
2192 }
2193 }
2194 return 0;
2195 }
2196
2197 /* CIEBasedA */
setcieaspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2198 static int setcieaspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2199 {
2200 int code = 0;
2201 ref CIEDict, *nocie;
2202 ulong dictkey;
2203
2204 if (i_ctx_p->language_level < 2)
2205 return_error(e_undefined);
2206
2207 code = dict_find_string(systemdict, "NOCIE", &nocie);
2208 if (code < 0)
2209 return code;
2210 if (!r_has_type(nocie, t_boolean))
2211 return_error(e_typecheck);
2212 if (nocie->value.boolval)
2213 return setgrayspace(i_ctx_p, r, stage, cont, 1);
2214
2215 *cont = 0;
2216 code = array_get(imemory, r, 1, &CIEDict);
2217 if (code < 0)
2218 return code;
2219 if ((*stage) > 0) {
2220 gs_client_color cc;
2221
2222 cc.pattern = 0x00;
2223 cc.paint.values[0] = 0;
2224 code = gs_setcolor(igs, &cc);
2225 *stage = 0;
2226 return code;
2227 }
2228 dictkey = r->value.refs->value.saveid;
2229 code = cieaspace(i_ctx_p, &CIEDict, dictkey);
2230 (*stage)++;
2231 *cont = 1;
2232 return code;
2233 }
validatecieaspace(i_ctx_t * i_ctx_p,ref ** r)2234 static int validatecieaspace(i_ctx_t * i_ctx_p, ref **r)
2235 {
2236 int code = 0, i;
2237 float value[9];
2238 ref CIEdict, *CIEspace = *r, *tempref, valref;
2239
2240 if (!r_is_array(CIEspace))
2241 return_error(e_typecheck);
2242 /* Validate parameters, check we have enough operands */
2243 if (r_size(CIEspace) != 2)
2244 return_error(e_rangecheck);
2245
2246 code = array_get(imemory, CIEspace, 1, &CIEdict);
2247 if (code < 0)
2248 return code;
2249
2250 check_read_type(CIEdict, t_dictionary);
2251
2252 /* Check white point exists, and is an array of three numbers */
2253 code = checkWhitePoint(i_ctx_p, &CIEdict);
2254 if (code != 0)
2255 return code;
2256
2257 /* Remaining parameters are optional, but we must validate
2258 * them if they are present
2259 */
2260 code = dict_find_string(&CIEdict, "RangeA", &tempref);
2261 if (code >= 0 && !r_has_type(tempref, t_null)) {
2262 /* Array of two numbers A0 < A1 */
2263 if (!r_is_array(tempref))
2264 return_error(e_typecheck);
2265 if (r_size(tempref) != 2)
2266 return_error(e_rangecheck);
2267
2268 for (i=0;i<2;i++) {
2269 code = array_get(imemory, tempref, i, &valref);
2270 if (code < 0)
2271 return code;
2272 if (r_has_type(&valref, t_integer))
2273 value[i] = (float)valref.value.intval;
2274 else if (r_has_type(&valref, t_real))
2275 value[i] = (float)valref.value.realval;
2276 else
2277 return_error(e_typecheck);
2278 }
2279 if (value[1] < value[0])
2280 return_error(e_rangecheck);
2281 }
2282
2283 code = dict_find_string(&CIEdict, "DecodeA", &tempref);
2284 if (code >= 0 && !r_has_type(tempref, t_null)) {
2285 check_proc(*tempref);
2286 }
2287
2288 code = dict_find_string(&CIEdict, "MatrixA", &tempref);
2289 if (code >= 0 && !r_has_type(tempref, t_null)) {
2290 if (!r_is_array(tempref))
2291 return_error(e_typecheck);
2292 if (r_size(tempref) != 3)
2293 return_error(e_rangecheck);
2294
2295 for (i=0;i<3;i++) {
2296 code = array_get(imemory, tempref, i, &valref);
2297 if (code < 0)
2298 return code;
2299 if (r_has_type(&valref, t_integer))
2300 value[i] = (float)valref.value.intval;
2301 else if (r_has_type(&valref, t_real))
2302 value[i] = (float)valref.value.realval;
2303 else
2304 return_error(e_typecheck);
2305 }
2306 }
2307
2308 code = checkRangeLMN(i_ctx_p, &CIEdict);
2309 if (code != 0)
2310 return code;
2311
2312 code = checkDecodeLMN(i_ctx_p, &CIEdict);
2313 if (code != 0)
2314 return code;
2315
2316 code = checkMatrixLMN(i_ctx_p, &CIEdict);
2317 if (code != 0)
2318 return code;
2319
2320 code = checkBlackPoint(i_ctx_p, &CIEdict);
2321 if (code != 0)
2322 return code;
2323
2324 *r = 0;
2325 return 0;
2326 }
cieadomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)2327 static int cieadomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2328 {
2329 int i, code;
2330 ref CIEdict, *tempref, valref;
2331
2332 code = array_get(imemory, space, 1, &CIEdict);
2333 if (code < 0)
2334 return code;
2335
2336 /* If we have a RangeA entry in the dictionary, get the
2337 * values from that
2338 */
2339 code = dict_find_string(&CIEdict, "RangeA", &tempref);
2340 if (code >= 0 && !r_has_type(tempref, t_null)) {
2341 for (i=0;i<2;i++) {
2342 code = array_get(imemory, tempref, i, &valref);
2343 if (code < 0)
2344 return code;
2345 if (r_has_type(&valref, t_integer))
2346 ptr[i] = (float)valref.value.intval;
2347 else if (r_has_type(&valref, t_real))
2348 ptr[i] = (float)valref.value.realval;
2349 else
2350 return_error(e_typecheck);
2351 }
2352 } else {
2353 /* Default values for CIEBasedA */
2354 ptr[0] = 0;
2355 ptr[1] = 1;
2356 }
2357 return 0;
2358 }
ciearange(i_ctx_t * i_ctx_p,ref * space,float * ptr)2359 static int ciearange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2360 {
2361 int i, code;
2362 ref CIEdict, *tempref, valref;
2363
2364 code = array_get(imemory, space, 1, &CIEdict);
2365 if (code < 0)
2366 return code;
2367
2368 /* If we have a RangeA entry in the dictionary, get the
2369 * values from that
2370 */
2371 code = dict_find_string(&CIEdict, "RangeA", &tempref);
2372 if (code >= 0 && !r_has_type(tempref, t_null)) {
2373 for (i=0;i<2;i++) {
2374 code = array_get(imemory, tempref, i, &valref);
2375 if (code < 0)
2376 return code;
2377 if (r_has_type(&valref, t_integer))
2378 ptr[i] = (float)valref.value.intval;
2379 else if (r_has_type(&valref, t_real))
2380 ptr[i] = (float)valref.value.realval;
2381 else
2382 return_error(e_typecheck);
2383 }
2384 } else {
2385 /* Default values for CIEBasedA */
2386 ptr[0] = 0;
2387 ptr[1] = 1;
2388 }
2389 return 0;
2390 }
cieavalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)2391 static int cieavalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2392 {
2393 os_ptr op = osp;
2394
2395 if (num_comps < 1)
2396 return_error(e_stackunderflow);
2397
2398 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2399 return_error(e_typecheck);
2400
2401 return 0;
2402 }
cieacompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)2403 static int cieacompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2404 {
2405 int code = 0;
2406 ref CIEdict1, CIEdict2;
2407
2408 code = array_get(imemory, space, 1, &CIEdict1);
2409 if (code < 0)
2410 return 0;
2411 code = array_get(imemory, testspace, 1, &CIEdict2);
2412 if (code < 0)
2413 return 0;
2414 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2415 return 0;
2416 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2417 return 0;
2418 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeA"))
2419 return 0;
2420 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeA"))
2421 return 0;
2422 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixA"))
2423 return 0;
2424 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2425 return 0;
2426 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2427 return 0;
2428 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2429 return 0;
2430 return 1;
2431 }
2432
2433 /* CIEBasedABC */
setcieabcspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2434 static int setcieabcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2435 {
2436 int code = 0;
2437 ref CIEDict, *nocie;
2438 ulong dictkey;
2439
2440 if (i_ctx_p->language_level < 2)
2441 return_error(e_undefined);
2442
2443 code = dict_find_string(systemdict, "NOCIE", &nocie);
2444 if (code < 0)
2445 return code;
2446 if (!r_has_type(nocie, t_boolean))
2447 return_error(e_typecheck);
2448 if (nocie->value.boolval)
2449 return setrgbspace(i_ctx_p, r, stage, cont, 1);
2450
2451 *cont = 0;
2452 code = array_get(imemory, r, 1, &CIEDict);
2453 if (code < 0)
2454 return code;
2455
2456 if ((*stage) > 0) {
2457 gs_client_color cc;
2458 int i;
2459
2460 cc.pattern = 0x00;
2461 for (i=0;i<3;i++)
2462 cc.paint.values[i] = 0;
2463 code = gs_setcolor(igs, &cc);
2464 *stage = 0;
2465 return code;
2466 }
2467 dictkey = r->value.refs->value.saveid;
2468 code = cieabcspace(i_ctx_p, &CIEDict,dictkey);
2469 *cont = 1;
2470 (*stage)++;
2471 return code;
2472 }
validatecieabcspace(i_ctx_t * i_ctx_p,ref ** r)2473 static int validatecieabcspace(i_ctx_t * i_ctx_p, ref **r)
2474 {
2475 int code = 0, i;
2476 float value[9];
2477 ref CIEdict, *CIEspace = *r, *tempref, valref;
2478
2479 if (!r_is_array(CIEspace))
2480 return_error(e_typecheck);
2481 /* Validate parameters, check we have enough operands */
2482 if (r_size(CIEspace) != 2)
2483 return_error(e_rangecheck);
2484
2485 code = array_get(imemory, CIEspace, 1, &CIEdict);
2486 if (code < 0)
2487 return code;
2488 check_read_type(CIEdict, t_dictionary);
2489
2490 /* Check white point exists, and is an array of three numbers */
2491 code = checkWhitePoint(i_ctx_p, &CIEdict);
2492 if (code != 0)
2493 return code;
2494
2495 /* Remaining parameters are optional, but we must validate
2496 * them if they are present
2497 */
2498 code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2499 if (code >= 0 && !r_has_type(tempref, t_null)) {
2500 if (!r_is_array(tempref))
2501 return_error(e_typecheck);
2502 if (r_size(tempref) != 6)
2503 return_error(e_rangecheck);
2504
2505 for (i=0;i<6;i++) {
2506 code = array_get(imemory, tempref, i, &valref);
2507 if (code < 0)
2508 return code;
2509 if (r_has_type(&valref, t_integer))
2510 value[i] = (float)valref.value.intval;
2511 else if (r_has_type(&valref, t_real))
2512 value[i] = (float)valref.value.realval;
2513 else
2514 return_error(e_typecheck);
2515 }
2516 if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2517 return_error(e_rangecheck);
2518 }
2519
2520 code = dict_find_string(&CIEdict, "DecodeABC", &tempref);
2521 if (code >= 0 && !r_has_type(tempref, t_null)) {
2522 if (!r_is_array(tempref))
2523 return_error(e_typecheck);
2524 if (r_size(tempref) != 3)
2525 return_error(e_rangecheck);
2526
2527 for (i=0;i<3;i++) {
2528 code = array_get(imemory, tempref, i, &valref);
2529 if (code < 0)
2530 return code;
2531 check_proc(valref);
2532 }
2533 }
2534
2535 code = dict_find_string(&CIEdict, "MatrixABC", &tempref);
2536 if (code >= 0 && !r_has_type(tempref, t_null)) {
2537 if (!r_is_array(tempref))
2538 return_error(e_typecheck);
2539 if (r_size(tempref) != 9)
2540 return_error(e_rangecheck);
2541
2542 for (i=0;i<9;i++) {
2543 code = array_get(imemory, tempref, i, &valref);
2544 if (code < 0)
2545 return code;
2546 if (r_has_type(&valref, t_integer))
2547 value[i] = (float)valref.value.intval;
2548 else if (r_has_type(&valref, t_real))
2549 value[i] = (float)valref.value.realval;
2550 else
2551 return_error(e_typecheck);
2552 }
2553 }
2554
2555 code = checkRangeLMN(i_ctx_p, &CIEdict);
2556 if (code != 0)
2557 return code;
2558
2559 code = checkDecodeLMN(i_ctx_p, &CIEdict);
2560 if (code != 0)
2561 return code;
2562
2563 code = checkMatrixLMN(i_ctx_p, &CIEdict);
2564 if (code != 0)
2565 return code;
2566
2567 code = checkBlackPoint(i_ctx_p, &CIEdict);
2568 if (code != 0)
2569 return code;
2570
2571 *r = 0;
2572 return 0;
2573 }
cieabcdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)2574 static int cieabcdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2575 {
2576 int i, code;
2577 ref CIEdict, *tempref, valref;
2578
2579 code = array_get(imemory, space, 1, &CIEdict);
2580 if (code < 0)
2581 return code;
2582
2583 /* If we have a RangeABC, get the values from that */
2584 code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2585 if (code >= 0 && !r_has_type(tempref, t_null)) {
2586 for (i=0;i<6;i++) {
2587 code = array_get(imemory, tempref, i, &valref);
2588 if (code < 0)
2589 return code;
2590 if (r_has_type(&valref, t_integer))
2591 ptr[i] = (float)valref.value.intval;
2592 else if (r_has_type(&valref, t_real))
2593 ptr[i] = (float)valref.value.realval;
2594 else
2595 return_error(e_typecheck);
2596 }
2597 } else {
2598 /* Default values for CIEBasedABC */
2599 for (i=0;i<3;i++) {
2600 ptr[2 * i] = 0;
2601 ptr[(2 * i) + 1] = 1;
2602 }
2603 }
2604 return 0;
2605 }
cieabcrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)2606 static int cieabcrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2607 {
2608 int i, code;
2609 ref CIEdict, *tempref, valref;
2610
2611 code = array_get(imemory, space, 1, &CIEdict);
2612 if (code < 0)
2613 return code;
2614
2615 /* If we have a RangeABC, get the values from that */
2616 code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2617 if (code >= 0 && !r_has_type(tempref, t_null)) {
2618 for (i=0;i<6;i++) {
2619 code = array_get(imemory, tempref, i, &valref);
2620 if (code < 0)
2621 return code;
2622 if (r_has_type(&valref, t_integer))
2623 ptr[i] = (float)valref.value.intval;
2624 else if (r_has_type(&valref, t_real))
2625 ptr[i] = (float)valref.value.realval;
2626 else
2627 return_error(e_typecheck);
2628 }
2629 } else {
2630 /* Default values for CIEBasedABC */
2631 for (i=0;i<3;i++) {
2632 ptr[2 * i] = 0;
2633 ptr[(2 * i) + 1] = 1;
2634 }
2635 }
2636 return 0;
2637 }
cieabcvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)2638 static int cieabcvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2639 {
2640 os_ptr op = osp;
2641 int i;
2642
2643 if (num_comps < 3)
2644 return_error(e_stackunderflow);
2645
2646 op -= 2;
2647 for (i=0;i<3;i++) {
2648 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2649 return_error(e_typecheck);
2650 op++;
2651 }
2652
2653 return 0;
2654 }
cieabccompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)2655 static int cieabccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2656 {
2657 int code = 0;
2658 ref CIEdict1, CIEdict2;
2659
2660 code = array_get(imemory, space, 1, &CIEdict1);
2661 if (code < 0)
2662 return 0;
2663 code = array_get(imemory, testspace, 1, &CIEdict2);
2664 if (code < 0)
2665 return 0;
2666 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2667 return 0;
2668 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2669 return 0;
2670 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
2671 return 0;
2672 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
2673 return 0;
2674 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
2675 return 0;
2676 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2677 return 0;
2678 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2679 return 0;
2680 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2681 return 0;
2682 return 1;
2683 }
2684
2685 /* CIEBasedDEF */
setciedefspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2686 static int setciedefspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2687 {
2688 int code = 0;
2689 ref CIEDict, *nocie;
2690 ulong dictkey;
2691
2692 if (i_ctx_p->language_level < 3)
2693 return_error(e_undefined);
2694
2695 code = dict_find_string(systemdict, "NOCIE", &nocie);
2696 if (code < 0)
2697 return code;
2698 if (!r_has_type(nocie, t_boolean))
2699 return_error(e_typecheck);
2700 if (nocie->value.boolval)
2701 return setrgbspace(i_ctx_p, r, stage, cont, 1);
2702
2703 *cont = 0;
2704 code = array_get(imemory, r, 1, &CIEDict);
2705 if (code < 0)
2706 return code;
2707 if ((*stage) > 0) {
2708 gs_client_color cc;
2709 int i;
2710
2711 cc.pattern = 0x00;
2712 for (i=0;i<3;i++)
2713 cc.paint.values[i] = 0;
2714 code = gs_setcolor(igs, &cc);
2715 *stage = 0;
2716 return code;
2717 }
2718 dictkey = r->value.refs->value.saveid;
2719 code = ciedefspace(i_ctx_p, &CIEDict, dictkey);
2720 *cont = 1;
2721 (*stage)++;
2722 return code;
2723 }
validateciedefspace(i_ctx_t * i_ctx_p,ref ** r)2724 static int validateciedefspace(i_ctx_t * i_ctx_p, ref **r)
2725 {
2726 int code = 0, i;
2727 float value[6];
2728 ref CIEdict, *pref, *CIEspace = *r, tempref, valref;
2729
2730 if (!r_is_array(CIEspace))
2731 return_error(e_typecheck);
2732 /* Validate parameters, check we have enough operands */
2733 if (r_size(CIEspace) != 2)
2734 return_error(e_rangecheck);
2735
2736 code = array_get(imemory, CIEspace, 1, &CIEdict);
2737 if (code < 0)
2738 return code;
2739 check_read_type(CIEdict, t_dictionary);
2740
2741 code = validatecieabcspace(i_ctx_p, r);
2742 if (code != 0)
2743 return code;
2744
2745 pref = &tempref;
2746 code = dict_find_string(&CIEdict, "Table", &pref);
2747 if (code >= 0) {
2748 if (!r_is_array(pref))
2749 return_error(e_typecheck);
2750 if (r_size(pref) != 4)
2751 return_error(e_rangecheck);
2752
2753 for (i=0;i<3;i++) {
2754 code = array_get(imemory, pref, i, &valref);
2755 if (code < 0)
2756 return code;
2757 if (r_has_type(&valref, t_integer))
2758 value[i] = (float)valref.value.intval;
2759 else
2760 return_error(e_typecheck);
2761 }
2762 if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1)
2763 return_error(e_rangecheck);
2764
2765 code = array_get(imemory, pref, 3, &valref);
2766 if (code < 0)
2767 return code;
2768 if (!r_is_array(&valref))
2769 return_error(e_typecheck);
2770 if (r_size(&valref) != value[0])
2771 return_error(e_rangecheck);
2772
2773 for (i=0;i<value[0];i++) {
2774 code = array_get(imemory, &valref, i, &tempref);
2775 if (code < 0)
2776 return code;
2777 if (!r_has_type(&tempref, t_string))
2778 return_error(e_typecheck);
2779
2780 if (r_size(&tempref) != (3 * value[1] * value[2]))
2781 return_error(e_rangecheck);
2782 }
2783 } else {
2784 return_error(e_rangecheck);
2785 }
2786
2787 /* Remaining parameters are optional, but we must validate
2788 * them if they are present
2789 */
2790 code = dict_find_string(&CIEdict, "RangeDEF", &pref);
2791 if (code >= 0 && !r_has_type(&tempref, t_null)) {
2792 if (!r_is_array(pref))
2793 return_error(e_typecheck);
2794 if (r_size(pref) != 6)
2795 return_error(e_rangecheck);
2796
2797 for (i=0;i<6;i++) {
2798 code = array_get(imemory, pref, i, &valref);
2799 if (code < 0)
2800 return code;
2801 if (r_has_type(&valref, t_integer))
2802 value[i] = (float)valref.value.intval;
2803 else if (r_has_type(&valref, t_real))
2804 value[i] = (float)valref.value.realval;
2805 else
2806 return_error(e_typecheck);
2807 }
2808 if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2809 return_error(e_rangecheck);
2810 }
2811
2812 code = dict_find_string(&CIEdict, "DecodeDEF", &pref);
2813 if (code >= 0 && !r_has_type(pref, t_null)) {
2814 if (!r_is_array(pref))
2815 return_error(e_typecheck);
2816 if (r_size(pref) != 3)
2817 return_error(e_rangecheck);
2818
2819 for (i=0;i<3;i++) {
2820 code = array_get(imemory, pref, i, &valref);
2821 if (code < 0)
2822 return code;
2823 check_proc(valref);
2824 }
2825 }
2826
2827 code = dict_find_string(&CIEdict, "RangeHIJ", &pref);
2828 if (code >= 0 && !r_has_type(pref, t_null)) {
2829 if (!r_is_array(pref))
2830 return_error(e_typecheck);
2831 if (r_size(pref) != 6)
2832 return_error(e_rangecheck);
2833
2834 for (i=0;i<6;i++) {
2835 code = array_get(imemory, pref, i, &valref);
2836 if (code < 0)
2837 return code;
2838 if (r_has_type(&valref, t_integer))
2839 value[i] = (float)valref.value.intval;
2840 else if (r_has_type(&valref, t_real))
2841 value[i] = (float)valref.value.realval;
2842 else
2843 return_error(e_typecheck);
2844 }
2845 if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2846 return_error(e_rangecheck);
2847 }
2848
2849 *r = 0;
2850 return 0;
2851 }
ciedefdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)2852 static int ciedefdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2853 {
2854 int i, code;
2855 ref CIEdict, *tempref, valref;
2856
2857 code = array_get(imemory, space, 1, &CIEdict);
2858 if (code < 0)
2859 return code;
2860
2861 /* If we have a RangeDEF, get the values from that */
2862 code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
2863 if (code >= 0 && !r_has_type(tempref, t_null)) {
2864 for (i=0;i<6;i++) {
2865 code = array_get(imemory, tempref, i, &valref);
2866 if (code < 0)
2867 return code;
2868 if (r_has_type(&valref, t_integer))
2869 ptr[i] = (float)valref.value.intval;
2870 else if (r_has_type(&valref, t_real))
2871 ptr[i] = (float)valref.value.realval;
2872 else
2873 return_error(e_typecheck);
2874 }
2875 } else {
2876 /* Default values for a CIEBasedDEF */
2877 for (i=0;i<3;i++) {
2878 ptr[2 * i] = 0;
2879 ptr[(2 * i) + 1] = 1;
2880 }
2881 }
2882 return 0;
2883 }
ciedefrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)2884 static int ciedefrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2885 {
2886 int i, code;
2887 ref CIEdict, *tempref, valref;
2888
2889 code = array_get(imemory, space, 1, &CIEdict);
2890 if (code < 0)
2891 return code;
2892
2893 /* If we have a RangeDEF, get the values from that */
2894 code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
2895 if (code >= 0 && !r_has_type(tempref, t_null)) {
2896 for (i=0;i<6;i++) {
2897 code = array_get(imemory, tempref, i, &valref);
2898 if (code < 0)
2899 return code;
2900 if (r_has_type(&valref, t_integer))
2901 ptr[i] = (float)valref.value.intval;
2902 else if (r_has_type(&valref, t_real))
2903 ptr[i] = (float)valref.value.realval;
2904 else
2905 return_error(e_typecheck);
2906 }
2907 } else {
2908 /* Default values for a CIEBasedDEF */
2909 for (i=0;i<3;i++) {
2910 ptr[2 * i] = 0;
2911 ptr[(2 * i) + 1] = 1;
2912 }
2913 }
2914 return 0;
2915 }
ciedefvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)2916 static int ciedefvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2917 {
2918 os_ptr op = osp;
2919 int i;
2920
2921 if (num_comps < 3)
2922 return_error(e_stackunderflow);
2923
2924 op -= 2;
2925 for (i=0;i<3;i++) {
2926 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2927 return_error(e_typecheck);
2928 op++;
2929 }
2930
2931 return 0;
2932 }
ciedefcompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)2933 static int ciedefcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2934 {
2935 int code = 0;
2936 ref CIEdict1, CIEdict2;
2937
2938 code = array_get(imemory, space, 1, &CIEdict1);
2939 if (code < 0)
2940 return 0;
2941 code = array_get(imemory, testspace, 1, &CIEdict2);
2942 if (code < 0)
2943 return 0;
2944 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2945 return 0;
2946 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2947 return 0;
2948 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
2949 return 0;
2950 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
2951 return 0;
2952 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
2953 return 0;
2954 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2955 return 0;
2956 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2957 return 0;
2958 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2959 return 0;
2960 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEF"))
2961 return 0;
2962 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEF"))
2963 return 0;
2964 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJ"))
2965 return 0;
2966 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
2967 return 0;
2968 return 1;
2969 }
2970
2971 /* CIEBasedDEFG */
setciedefgspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2972 static int setciedefgspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2973 {
2974 int code = 0;
2975 ref CIEDict, *nocie;
2976 ulong dictkey;
2977
2978 if (i_ctx_p->language_level < 3)
2979 return_error(e_undefined);
2980
2981 code = dict_find_string(systemdict, "NOCIE", &nocie);
2982 if (code < 0)
2983 return code;
2984 if (!r_has_type(nocie, t_boolean))
2985 return_error(e_typecheck);
2986 if (nocie->value.boolval)
2987 return setcmykspace(i_ctx_p, r, stage, cont, 1);
2988
2989 *cont = 0;
2990 code = array_get(imemory, r, 1, &CIEDict);
2991 if (code < 0)
2992 return code;
2993 if ((*stage) > 0) {
2994 gs_client_color cc;
2995 int i;
2996
2997 cc.pattern = 0x00;
2998 for (i=0;i<4;i++)
2999 cc.paint.values[i] = 0;
3000 code = gs_setcolor(igs, &cc);
3001 *stage = 0;
3002 return code;
3003 }
3004 dictkey = r->value.refs->value.saveid;
3005 code = ciedefgspace(i_ctx_p, &CIEDict,dictkey);
3006 *cont = 1;
3007 (*stage)++;
3008 return code;
3009 }
validateciedefgspace(i_ctx_t * i_ctx_p,ref ** r)3010 static int validateciedefgspace(i_ctx_t * i_ctx_p, ref **r)
3011 {
3012 int code = 0, i, j;
3013 float value[8];
3014 ref CIEdict, *CIEspace = *r, tempref, arrayref, valref, *pref = &tempref;
3015
3016 if (!r_is_array(CIEspace))
3017 return_error(e_typecheck);
3018 /* Validate parameters, check we have enough operands */
3019 if (r_size(CIEspace) != 2)
3020 return_error(e_rangecheck);
3021
3022 code = array_get(imemory, CIEspace, 1, &CIEdict);
3023 if (code < 0)
3024 return code;
3025 check_read_type(CIEdict, t_dictionary);
3026
3027 code = validatecieabcspace(i_ctx_p, r);
3028 if (code != 0)
3029 return code;
3030
3031 code = dict_find_string(&CIEdict, "Table", &pref);
3032 if (code >= 0) {
3033 if (!r_is_array(pref))
3034 return_error(e_typecheck);
3035 if (r_size(pref) != 5)
3036 return_error(e_rangecheck);
3037
3038 for (i=0;i<4;i++) {
3039 code = array_get(imemory, pref, i, &valref);
3040 if (code < 0)
3041 return code;
3042 if (r_has_type(&valref, t_integer))
3043 value[i] = (float)valref.value.intval;
3044 else
3045 return_error(e_typecheck);
3046 }
3047 if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1 || value[3] <= 1)
3048 return_error(e_rangecheck);
3049
3050 code = array_get(imemory, pref, 4, &arrayref);
3051 if (code < 0)
3052 return code;
3053 if (!r_is_array(&arrayref))
3054 return_error(e_typecheck);
3055 if (r_size(&arrayref) != value[0])
3056 return_error(e_rangecheck);
3057
3058 for (i=0;i<value[0];i++) {
3059 code = array_get(imemory, &arrayref, i, &tempref);
3060 if (code < 0)
3061 return code;
3062 for (j=0;j<value[1];j++) {
3063 code = array_get(imemory, &tempref, i, &valref);
3064 if (code < 0)
3065 return code;
3066 if (!r_has_type(&valref, t_string))
3067 return_error(e_typecheck);
3068
3069 if (r_size(&valref) != (3 * value[2] * value[3]))
3070 return_error(e_rangecheck);
3071 }
3072 }
3073 } else {
3074 return_error(e_rangecheck);
3075 }
3076
3077 /* Remaining parameters are optional, but we must validate
3078 * them if they are present
3079 */
3080 code = dict_find_string(&CIEdict, "RangeDEFG", &pref);
3081 if (code >= 0 && !r_has_type(pref, t_null)) {
3082 if (!r_is_array(pref))
3083 return_error(e_typecheck);
3084 if (r_size(pref) != 8)
3085 return_error(e_rangecheck);
3086
3087 for (i=0;i<8;i++) {
3088 code = array_get(imemory, pref, i, &valref);
3089 if (code < 0)
3090 return code;
3091 if (r_has_type(&valref, t_integer))
3092 value[i] = (float)valref.value.intval;
3093 else if (r_has_type(&valref, t_real))
3094 value[i] = (float)valref.value.realval;
3095 else
3096 return_error(e_typecheck);
3097 }
3098 if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
3099 return_error(e_rangecheck);
3100 }
3101
3102 code = dict_find_string(&CIEdict, "DecodeDEFG", &pref);
3103 if (code >= 0 && !r_has_type(pref, t_null)) {
3104 if (!r_is_array(pref))
3105 return_error(e_typecheck);
3106 if (r_size(pref) != 4)
3107 return_error(e_rangecheck);
3108
3109 for (i=0;i<4;i++) {
3110 code = array_get(imemory, pref, i, &valref);
3111 if (code < 0)
3112 return code;
3113 check_proc(valref);
3114 }
3115 }
3116
3117 code = dict_find_string(&CIEdict, "RangeHIJK", &pref);
3118 if (code >= 0 && !r_has_type(pref, t_null)) {
3119 if (!r_is_array(pref))
3120 return_error(e_typecheck);
3121 if (r_size(pref) != 8)
3122 return_error(e_rangecheck);
3123
3124 for (i=0;i<8;i++) {
3125 code = array_get(imemory, pref, i, &valref);
3126 if (code < 0)
3127 return code;
3128 if (r_has_type(&valref, t_integer))
3129 value[i] = (float)valref.value.intval;
3130 else if (r_has_type(&valref, t_real))
3131 value[i] = (float)valref.value.realval;
3132 else
3133 return_error(e_typecheck);
3134 }
3135 if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
3136 return_error(e_rangecheck);
3137 }
3138
3139 *r = 0;
3140 return 0;
3141 }
ciedefgdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)3142 static int ciedefgdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3143 {
3144 int i, code;
3145 ref CIEdict, *tempref, valref;
3146
3147 code = array_get(imemory, space, 1, &CIEdict);
3148 if (code < 0)
3149 return code;
3150
3151 /* If we have a RangeDEFG, get the values from that */
3152 code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
3153 if (code >= 0 && !r_has_type(tempref, t_null)) {
3154 for (i=0;i<8;i++) {
3155 code = array_get(imemory, tempref, i, &valref);
3156 if (code < 0)
3157 return code;
3158 if (r_has_type(&valref, t_integer))
3159 ptr[i] = (float)valref.value.intval;
3160 else if (r_has_type(&valref, t_real))
3161 ptr[i] = (float)valref.value.realval;
3162 else
3163 return_error(e_typecheck);
3164 }
3165 } else {
3166 /* Default values for a CIEBasedDEFG */
3167 for (i=0;i<4;i++) {
3168 ptr[2 * i] = 0;
3169 ptr[(2 * i) + 1] = 1;
3170 }
3171 }
3172 return 0;
3173 }
ciedefgrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)3174 static int ciedefgrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3175 {
3176 int i, code;
3177 ref CIEdict, *tempref, valref;
3178
3179 code = array_get(imemory, space, 1, &CIEdict);
3180 if (code < 0)
3181 return code;
3182
3183 /* If we have a RangeDEFG, get the values from that */
3184 code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
3185 if (code >= 0 && !r_has_type(tempref, t_null)) {
3186 for (i=0;i<8;i++) {
3187 code = array_get(imemory, tempref, i, &valref);
3188 if (code < 0)
3189 return code;
3190 if (r_has_type(&valref, t_integer))
3191 ptr[i] = (float)valref.value.intval;
3192 else if (r_has_type(&valref, t_real))
3193 ptr[i] = (float)valref.value.realval;
3194 else
3195 return_error(e_typecheck);
3196 }
3197 } else {
3198 /* Default values for a CIEBasedDEFG */
3199 for (i=0;i<4;i++) {
3200 ptr[2 * i] = 0;
3201 ptr[(2 * i) + 1] = 1;
3202 }
3203 }
3204 return 0;
3205 }
ciedefgvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)3206 static int ciedefgvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
3207 {
3208 os_ptr op = osp;
3209 int i;
3210
3211 if (num_comps < 4)
3212 return_error(e_stackunderflow);
3213
3214 op -= 3;
3215 for (i=0;i < 4;i++) {
3216 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
3217 return_error(e_typecheck);
3218 op++;
3219 }
3220 return 0;
3221 }
ciedefgcompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)3222 static int ciedefgcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
3223 {
3224 /* If the problems mentioned above are resolved, then this code could
3225 * be re-instated.
3226 */
3227 int code = 0;
3228 ref CIEdict1, CIEdict2;
3229
3230 code = array_get(imemory, space, 1, &CIEdict1);
3231 if (code < 0)
3232 return 0;
3233 code = array_get(imemory, testspace, 1, &CIEdict2);
3234 if (code < 0)
3235 return 0;
3236 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
3237 return 0;
3238 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
3239 return 0;
3240 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
3241 return 0;
3242 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
3243 return 0;
3244 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
3245 return 0;
3246 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
3247 return 0;
3248 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
3249 return 0;
3250 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
3251 return 0;
3252 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEFG"))
3253 return 0;
3254 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEFG"))
3255 return 0;
3256 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJK"))
3257 return 0;
3258 if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
3259 return 0;
3260 return 1;
3261 }
3262
3263 static char const * const CIESpaces[] = {
3264 "CIEBasedA",
3265 "CIEBasedABC",
3266 "CIEBasedDEF",
3267 "CIEBasedDEFG"
3268 };
3269 /* This routine returns the Device space equivalents for a CIEBased space.
3270 * Used by currentgray, currentrgb and currentcmyk, the PLRM says that CIE
3271 * spaces return 0 for all components.
3272 */
ciebasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)3273 static int ciebasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
3274 {
3275 os_ptr op;
3276 ref *spacename, nref;
3277 int i, components=1, code;
3278
3279 /* If the spaece is an array, the first element is always the name */
3280 if (r_is_array(space))
3281 spacename = space->value.refs;
3282 else
3283 spacename = space;
3284 /* Check that it really is a name */
3285 if (!r_has_type(spacename, t_name))
3286 return_error(e_typecheck);
3287
3288 /* Find the relevant color space object */
3289 for (i=0;i<4;i++) {
3290 code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)CIESpaces[i], strlen(CIESpaces[i]), &nref, 0);
3291 if (code < 0)
3292 return code;
3293 if (name_eq(spacename, &nref)) {
3294 break;
3295 }
3296 }
3297 /* Find out how many values are on the stack, which depends
3298 * on what kind of CIEBased space this is.
3299 */
3300 switch(i){
3301 case 0:
3302 components = 1;
3303 break;
3304 case 1:
3305 case 2:
3306 components = 3;
3307 break;
3308 case 3:
3309 components = 4;
3310 break;
3311 }
3312 /* Remove teh requisite number of values */
3313 pop(components);
3314 op = osp;
3315 /* Find out how many values we need to return, which
3316 * depends on the requested space.
3317 */
3318 switch(base) {
3319 case 0:
3320 components = 1;
3321 break;
3322 case 1:
3323 case 2:
3324 components = 3;
3325 break;
3326 case 3:
3327 components = 4;
3328 break;
3329 }
3330 push(components);
3331 /* The PLRM says that all the components should be returned as 0.0 */
3332 op -= components-1;
3333 for (i=0;i<components;i++) {
3334 make_real(op, (float)0);
3335 op++;
3336 }
3337 /* However, Adobe implementations actually return 1.0 for the black
3338 * channel of CMYK...
3339 */
3340 if (components == 4) {
3341 op--;
3342 make_real(op, (float)1);
3343 }
3344 *stage = 0;
3345 *cont = 0;
3346 return 0;
3347 }
3348
3349 /* This routine used by both Separatin and DeviceN spaces to convert
3350 * a PostScript tint transform into a Function, either a type 4
3351 * 'PostScript calculator (see PDF reference) or a type 0 'sampled'
3352 * function.
3353 */
convert_transform(i_ctx_t * i_ctx_p,ref * arr,ref * pproc)3354 static int convert_transform(i_ctx_t * i_ctx_p, ref *arr, ref *pproc)
3355 {
3356 os_ptr op = osp; /* required by "push" macro */
3357 int code;
3358
3359 /* buildfunction returns an operand on the stack. In fact
3360 * it replaces the lowest operand, so make sure there is an
3361 * empty sacrificial one present.
3362 */
3363 push(1);
3364 /* Start by trying a type 4 function */
3365 code = buildfunction(i_ctx_p, arr, pproc, 4);
3366
3367 if (code < 0)
3368 /* If that fails, try a type 0. We prefer a type 4
3369 * because a type 0 will require us to sample the
3370 * space, which is expensive
3371 */
3372 code = buildfunction(i_ctx_p, arr, pproc, 0);
3373
3374 return code;
3375 }
3376
3377 /* Separation */
setseparationspace(i_ctx_t * i_ctx_p,ref * sepspace,int * stage,int * cont,int CIESubst)3378 static int setseparationspace(i_ctx_t * i_ctx_p, ref *sepspace, int *stage, int *cont, int CIESubst)
3379 {
3380 os_ptr op = osp; /* required by "push" macro */
3381 int code = 0;
3382 ref sname, proc;
3383 ref name_none, name_all;
3384 separation_type sep_type;
3385 ref_colorspace cspace_old;
3386 gs_color_space *pcs;
3387 gs_color_space * pacs;
3388 gs_function_t *pfn = NULL;
3389 gs_client_color cc;
3390
3391 if (i_ctx_p->language_level < 2)
3392 return_error(e_undefined);
3393
3394 *cont = 0;
3395 if ((*stage) == 0) {
3396 code = array_get(imemory, sepspace, 3, &proc);
3397 if (code < 0)
3398 return code;
3399 /* Check to see if we already have a function (eg from a PDF file) */
3400 pfn = ref_function(&proc);
3401 if (pfn == NULL) {
3402 /* Convert tint transform to a PostScript function */
3403 code = convert_transform(i_ctx_p, sepspace, &proc);
3404 if (code < 0)
3405 return code;
3406 if (code > 0) {
3407 *cont = 1;
3408 (*stage)++;
3409 return code;
3410 }
3411 /* We can only get here if the transform converted to a function
3412 * without requiring a continuation. Most likely this means its a
3413 * type 4 function. If so then it is still on the stack.
3414 */
3415 op = osp;
3416 pfn = ref_function(op);
3417 pop (1);
3418 }
3419 } else {
3420 /* The function is returned on the operand stack */
3421 op = osp;
3422 pfn = ref_function(op);
3423 pop (1);
3424 }
3425
3426 *stage = 0;
3427 if ((code = name_ref(imemory, (const byte *)"All", 3, &name_all, 0)) < 0)
3428 return code;
3429 if ((code = name_ref(imemory, (const byte *)"None", 4, &name_none, 0)) < 0)
3430 return code;
3431 /* Check separation name is a string or name object */
3432 code = array_get(imemory, sepspace, 1, &sname);
3433 if (code < 0)
3434 return code;
3435
3436 if (r_has_type(&sname, t_string)) {
3437 code = name_from_string(imemory, &sname, &sname);
3438 if (code < 0)
3439 return code;
3440 }
3441 sep_type = ( name_eq(&sname, &name_all) ? SEP_ALL :
3442 name_eq(&sname, &name_none) ? SEP_NONE : SEP_OTHER);
3443
3444 /* The alternate color space has been selected as the current color space */
3445 pacs = gs_currentcolorspace(igs);
3446
3447 cspace_old = istate->colorspace[0];
3448 /* Now set the current color space as Separation */
3449 code = gs_cspace_new_Separation(&pcs, pacs, imemory);
3450 if (code < 0)
3451 return code;
3452 pcs->params.separation.sep_type = sep_type;
3453 pcs->params.separation.sep_name = name_index(imemory, &sname);
3454 pcs->params.separation.get_colorname_string = gs_get_colorname_string;
3455 code = array_get(imemory, sepspace, 1, &proc);
3456 if (code < 0)
3457 return code;
3458 istate->colorspace[0].procs.special.separation.layer_name = proc;
3459 code = array_get(imemory, sepspace, 3, &proc);
3460 if (code < 0)
3461 return code;
3462 istate->colorspace[0].procs.special.separation.tint_transform = proc;
3463 if (code >= 0)
3464 code = gs_cspace_set_sepr_function(pcs, pfn);
3465 if (code >= 0)
3466 code = gs_setcolorspace(igs, pcs);
3467 /* release reference from construction */
3468 rc_decrement_only_cs(pcs, "setseparationspace");
3469 if (code < 0) {
3470 istate->colorspace[0] = cspace_old;
3471 return code;
3472 }
3473 cc.pattern = 0x00;
3474 cc.paint.values[0] = 1.0;
3475 code = gs_setcolor(igs, &cc);
3476 return code;
3477 }
validateseparationspace(i_ctx_t * i_ctx_p,ref ** space)3478 static int validateseparationspace(i_ctx_t * i_ctx_p, ref **space)
3479 {
3480 int code = 0;
3481 ref *sepspace = *space;
3482 ref nameref, sref, sname, altspace, tref;
3483
3484 if (!r_is_array(sepspace))
3485 return_error(e_typecheck);
3486 /* Validate parameters, check we have enough operands */
3487 if (r_size(sepspace) != 4)
3488 return_error(e_rangecheck);
3489
3490 /* Check separation name is a string or name object */
3491 code = array_get(imemory, sepspace, 1, &sname);
3492 if (code < 0)
3493 return code;
3494 if (!r_has_type(&sname, t_name)) {
3495 if (!r_has_type(&sname, t_string))
3496 return_error(e_typecheck);
3497 else {
3498 code = name_from_string(imemory, &sname, &sname);
3499 if (code < 0)
3500 return code;
3501 }
3502 }
3503
3504 /* Check the tint transform is a procedure */
3505 code = array_get(imemory, sepspace, 3, &tref);
3506 if (code < 0)
3507 return code;
3508 check_proc(tref);
3509
3510 /* Get the name of the alternate space */
3511 code = array_get(imemory, sepspace, 2, &altspace);
3512 if (code < 0)
3513 return code;
3514 if (r_has_type(&altspace, t_name))
3515 ref_assign(&nameref, &altspace);
3516 else {
3517 /* Make sure the alternate space is an array */
3518 if (!r_is_array(&altspace))
3519 return_error(e_typecheck);
3520 /* And has a name for its type */
3521 code = array_get(imemory, &altspace, 0, &tref);
3522 if (code < 0)
3523 return code;
3524 if (!r_has_type(&tref, t_name))
3525 return_error(e_typecheck);
3526 ref_assign(&nameref, &tref);
3527 }
3528
3529 /* Convert alternate space name to string */
3530 name_string_ref(imemory, &nameref, &sref);
3531 /* Check its not /Indexed or /Pattern or /DeviceN */
3532 if (r_size(&sref) == 7) {
3533 if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
3534 return_error(e_typecheck);
3535 if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
3536 return_error(e_typecheck);
3537 if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
3538 return_error(e_typecheck);
3539 }
3540 /* and also not /Separation */
3541 if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
3542 return_error(e_typecheck);
3543
3544 ref_assign(*space, &altspace);
3545 return 0;
3546 }
separationalternatespace(i_ctx_t * i_ctx_p,ref * sepspace,ref ** r,int * CIESubst)3547 static int separationalternatespace(i_ctx_t * i_ctx_p, ref *sepspace, ref **r, int *CIESubst)
3548 {
3549 ref tref;
3550 int code;
3551
3552 code = array_get(imemory, sepspace, 2, &tref);
3553 if (code < 0)
3554 return code;
3555 ref_assign(*r, &tref);
3556 return 0;
3557 }
sepdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)3558 static int sepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3559 {
3560 ptr[0] = 0;
3561 ptr[1] = 1;
3562 return 0;
3563 }
seprange(i_ctx_t * i_ctx_p,ref * space,float * ptr)3564 static int seprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3565 {
3566 ptr[0] = 0;
3567 ptr[1] = 1;
3568 return 0;
3569 }
septransform(i_ctx_t * i_ctx_p,ref * sepspace,int * usealternate,int * stage,int * stack_depth)3570 static int septransform(i_ctx_t *i_ctx_p, ref *sepspace, int *usealternate, int *stage, int *stack_depth)
3571 {
3572 gx_device * dev = igs->device;
3573 ref sname, proc;
3574 int code, colorant_number;
3575
3576 code = array_get(imemory, sepspace, 1, &sname);
3577 if (code < 0)
3578 return code;
3579 if (r_has_type(&sname, t_name)) {
3580 name_string_ref(imemory, &sname, &sname);
3581 }
3582
3583 /* Check for /All and /None, never need the alternate for these */
3584 if (r_size(&sname) == 3 &&
3585 strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3586 *usealternate = 0;
3587 return 0;
3588 }
3589 if (r_size(&sname) == 4 &&
3590 strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3591 *usealternate = 0;
3592 return 0;
3593 }
3594 /*
3595 * Compare the colorant name to the device's. If the device's
3596 * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
3597 * colorant is in the SeparationNames list but not in the
3598 * SeparationOrder list.
3599 */
3600 colorant_number = (*dev_proc(dev, get_color_comp_index))
3601 (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
3602 if (colorant_number >= 0) { /* If valid colorant name */
3603 *usealternate = 0;
3604 } else
3605 *usealternate = 1;
3606
3607 if (*usealternate && *stage == 0) {
3608 (*stage)++;
3609 esp++;
3610 code = array_get(imemory, sepspace, 3, &proc);
3611 if (code < 0)
3612 return code;
3613 *esp = proc;
3614 return o_push_estack;
3615 }
3616 *stage = 0;
3617 return 0;
3618 }
sepbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)3619 static int sepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
3620 {
3621 os_ptr op = osp; /* required by "push" macro */
3622 int use, code;
3623
3624 code = septransform(i_ctx_p, space, &use, stage, stack_depth);
3625 if (code != 0)
3626 return code;
3627 if (!use) {
3628 *stage = 0;
3629 *cont = 0;
3630 pop(1);
3631 op = osp;
3632 switch(base) {
3633 case 0:
3634 push(1);
3635 make_real(op, 0.0);
3636 break;
3637 case 1:
3638 case 2:
3639 push(3);
3640 make_real(&op[-2], 0.0);
3641 make_real(&op[-1], 0.0);
3642 make_real(op, 0.0);
3643 break;
3644 case 3:
3645 push(4);
3646 make_real(&op[-3], 0.0);
3647 make_real(&op[-2], 0.0);
3648 make_real(&op[-1], 0.0);
3649 make_real(op, 0.0);
3650 break;
3651 }
3652 } else {
3653 *stage = 0;
3654 *cont = 1;
3655 }
3656 return 0;
3657 }
sepvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)3658 static int sepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
3659 {
3660 os_ptr op = osp;
3661
3662 if (num_comps < 1)
3663 return_error(e_stackunderflow);
3664
3665 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
3666 return_error(e_typecheck);
3667
3668 if (*values > 1.0)
3669 *values = 1.0;
3670
3671 if (*values < 0.0)
3672 *values = 0.0;
3673
3674 return 0;
3675 }
sepcompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)3676 static int sepcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
3677 {
3678 ref sname1, sname2;
3679 int code;
3680
3681 code = array_get(imemory, space, 1, &sname1);
3682 if (code < 0)
3683 return 0;
3684
3685 code = array_get(imemory, testspace, 1, &sname2);
3686 if (code < 0)
3687 return 0;
3688
3689 if (r_type(&sname1) != r_type(&sname2))
3690 return 0;
3691
3692 switch(r_type(&sname1)) {
3693 case t_name:
3694 if (!name_eq(&sname1, &sname2))
3695 return 0;
3696 break;
3697 case t_string:
3698 if (r_size(&sname1) != r_size(&sname2))
3699 return 0;
3700 if (strncmp((const char *)sname1.value.const_bytes, (const char *)sname2.value.const_bytes, r_size(&sname1)) != 0)
3701 return 0;
3702 break;
3703 default:
3704 return 0;
3705 }
3706 code = array_get(imemory, testspace, 2, &sname1);
3707 if (code < 0)
3708 return 0;
3709 code = array_get(imemory, testspace, 2, &sname2);
3710 if (code < 0)
3711 return 0;
3712 if (r_type(&sname1) != r_type(&sname2))
3713 return 0;
3714
3715 if (r_is_array(&sname1)) {
3716 if (!comparearrays(i_ctx_p, &sname1, &sname2))
3717 return 0;
3718 } else {
3719 if (!r_has_type(&sname1, t_name))
3720 return 0;
3721 if (!name_eq(&sname1, &sname2))
3722 return 0;
3723 }
3724 code = array_get(imemory, space, 3, &sname1);
3725 if (code < 0)
3726 return 0;
3727 code = array_get(imemory, testspace, 3, &sname2);
3728 if (code < 0)
3729 return 0;
3730 return(comparearrays(i_ctx_p, &sname1, &sname2));
3731 }
sepinitialproc(i_ctx_t * i_ctx_p,ref * space)3732 static int sepinitialproc(i_ctx_t *i_ctx_p, ref *space)
3733 {
3734 gs_client_color cc;
3735
3736 cc.pattern = 0x00;
3737 cc.paint.values[0] = 1.0;
3738 return gs_setcolor(igs, &cc);
3739 }
3740
3741 /* DeviceN */
devicencolorants_cont(i_ctx_t * i_ctx_p)3742 static int devicencolorants_cont(i_ctx_t *i_ctx_p)
3743 {
3744 ref dict, *pdict = &dict, space[2], sname;
3745 int index, code, depth, stage;
3746 es_ptr ep = esp, pindex, pstage;
3747 os_ptr op = osp;
3748 gs_separation_name sep_name;
3749
3750 pindex = &ep[-2];
3751 pstage = &ep[-1];
3752 index = (int)pindex->value.intval;
3753 stage = (int)pstage->value.intval;
3754 ref_assign(&dict, ep);
3755
3756 do {
3757 if (index >= dict_length(pdict)) {
3758 esp -= 4;
3759 return o_pop_estack;
3760 }
3761
3762 if (stage == 0) {
3763 code = gs_gsave(igs);
3764 if (code < 0)
3765 return code;
3766
3767 code = dict_index_entry(pdict, index, (ref *)&space);
3768 if (code < 0) {
3769 make_int(pindex, ++index);
3770 code = gs_grestore(igs);
3771 if (code < 0)
3772 return code;
3773 continue;
3774 }
3775
3776 code = validate_spaces(i_ctx_p, &space[1], &depth);
3777 if (code < 0) {
3778 make_int(pindex, ++index);
3779 code = gs_grestore(igs);
3780 if (code < 0)
3781 return code;
3782 return o_push_estack;
3783 }
3784
3785 /* If we get a continuation from a sub-procedure, we will want to come back
3786 * here afterward, to do any remaining stages. We need to set up for that now.
3787 * so that our continuation is ahead of the sub-proc's continuation.
3788 */
3789 check_estack(1);
3790 push(1);
3791 /* The push_op_estack macro increments esp before use, so we don't need to */
3792 push_op_estack(devicencolorants_cont);
3793
3794 make_int(pstage, 1);
3795 *op = space[1];
3796 code = zsetcolorspace(i_ctx_p);
3797 if (code != 0)
3798 return code;
3799 } else {
3800 stage = 0;
3801 code = dict_index_entry(pdict, index, (ref *)&space);
3802 if (code == 0) {
3803 switch (r_type(&space[0])) {
3804 case t_string:
3805 code = name_from_string(imemory, &space[0], &sname);
3806 if (code == 0)
3807 sep_name = name_index(imemory, &sname);
3808 break;
3809 case t_name:
3810 sep_name = name_index(imemory, &space[0]);
3811 break;
3812 default:
3813 code = e_typecheck;
3814 }
3815 }
3816 make_int(pindex, ++index);
3817 make_int(pstage, stage);
3818 if (code == 0)
3819 gs_attachattributecolorspace(sep_name, igs);
3820 code = gs_grestore(igs);
3821 if (code < 0)
3822 return code;
3823 }
3824 }
3825 while(1);
3826 }
3827
setdevicenspace(i_ctx_t * i_ctx_p,ref * devicenspace,int * stage,int * cont,int CIESubst)3828 static int setdevicenspace(i_ctx_t * i_ctx_p, ref *devicenspace, int *stage, int *cont, int CIESubst)
3829 {
3830 os_ptr op = osp; /* required by "push" macro */
3831 int code = 0, num_components, i;
3832 ref namesarray, proc, sname, tname, sref, tempref[2];
3833 ref_colorspace cspace_old;
3834 gs_color_space *pcs;
3835 gs_color_space * pacs;
3836 gs_function_t *pfn = NULL;
3837 gs_separation_name *names;
3838 gs_device_n_map *pmap;
3839 gs_client_color cc;
3840
3841 if (i_ctx_p->language_level < 3)
3842 return_error(e_undefined);
3843
3844 *cont = 0;
3845 if ((*stage) == 2) {
3846 if (r_size(devicenspace) == 5) {
3847 /* We have a Colorants dictionary from a PDF file. We need to handle this by
3848 * temporarily setting each of the spaces in the dict, and attaching the
3849 * resulting space to the DeviceN array. This is complicated, because
3850 * each space must be fully set up, and may result in running tint transform
3851 * procedures and caching results. We need to handle this in yet another
3852 * layering of continuation procedures.
3853 */
3854 code = array_get(imemory, devicenspace, 4, &sref);
3855 if (code < 0)
3856 return code;
3857 if (!r_has_type(&sref, t_dictionary)) {
3858 *stage = 0;
3859 return 0;
3860 }
3861 if (dict_length(&sref) == 0)
3862 return(0);
3863
3864 code = dict_index_entry(&sref, 0, (ref *)&tempref);
3865 if (code < 0)
3866 return code;
3867 name_string_ref(imemory, &tempref[0], &sname);
3868 if (r_size(&sname) != 9 || strncmp((const char *)sname.value.const_bytes, "Colorants", r_size(&sname)) != 0) {
3869 *stage = 0;
3870 return 0;
3871 }
3872
3873 *stage = 3;
3874 *cont = 1;
3875 check_estack(5);
3876 push_mark_estack(es_other, colour_cleanup);
3877 esp++;
3878 /* variable to hold index of the space we are dealing with */
3879 make_int(esp, 0);
3880 esp++;
3881 /* variable to hold processing step */
3882 make_int(esp, 0);
3883 esp++;
3884 /* Store a pointer to the Colorants dictionary
3885 */
3886 ref_assign(esp, &tempref[1]);
3887 push_op_estack(devicencolorants_cont);
3888 return o_push_estack;
3889 } else {
3890 *stage = 0;
3891 return 0;
3892 }
3893 }
3894 if ((*stage) == 3) {
3895 *stage = 0;
3896 return 0;
3897 }
3898 if ((*stage) == 0) {
3899 code = array_get(imemory, devicenspace, 3, &proc);
3900 if (code < 0)
3901 return code;
3902 pfn = ref_function(&proc);
3903 if (pfn == NULL) {
3904 /* Convert tint transform to a PostScript function */
3905 code = convert_transform(i_ctx_p, devicenspace, &proc);
3906 if (code < 0)
3907 return code;
3908 if (code > 0) {
3909 *cont = 1;
3910 *stage = 1;
3911 return code;
3912 }
3913 /* We can only get here if the transform converted to a function
3914 * without requiring a continuation. Most likely this means its a
3915 * type 4 function. If so then it is still on the stack.
3916 */
3917 op = osp;
3918 pfn = ref_function(op);
3919 pop (1);
3920 }
3921 } else {
3922 /* The function is returned on the operand stack */
3923 op = osp;
3924 pfn = ref_function(op);
3925 pop (1);
3926 }
3927
3928 *stage = 2;
3929
3930 code = array_get(imemory, devicenspace, 1, &namesarray);
3931 if (code < 0)
3932 return code;
3933 num_components = r_size(&namesarray);
3934 /* The alternate color space has been selected as the current color space */
3935 pacs = gs_currentcolorspace(igs);
3936
3937 if (num_components == 1) {
3938 array_get(imemory, &namesarray, (long)0, &sname);
3939 switch (r_type(&sname)) {
3940 case t_string:
3941 tname = sname;
3942 break;
3943 case t_name:
3944 name_string_ref(imemory, &sname, &tname);
3945 break;
3946 default:
3947 return_error(e_typecheck);
3948 break;
3949 }
3950 if (strncmp((const char *)tname.value.const_bytes, "All", 3) == 0 && r_size(&tname) == 3) {
3951 separation_type sep_type;
3952
3953 /* Sigh, Acrobat allows this, even though its contra the spec. Convert to
3954 * a /Separation space and go on
3955 */
3956 sep_type = SEP_ALL;
3957
3958 /* The alternate color space has been selected as the current color space */
3959 pacs = gs_currentcolorspace(igs);
3960
3961 cspace_old = istate->colorspace[0];
3962 /* Now set the current color space as Separation */
3963 code = gs_cspace_new_Separation(&pcs, pacs, imemory);
3964 if (code < 0)
3965 return code;
3966 pcs->params.separation.sep_type = sep_type;
3967 pcs->params.separation.sep_name = name_index(imemory, &sname);
3968 pcs->params.separation.get_colorname_string = gs_get_colorname_string;
3969 code = array_get(imemory, &namesarray, (long)0, &sname);
3970 if (code < 0)
3971 return code;
3972 istate->colorspace[0].procs.special.separation.layer_name = sname;
3973 code = array_get(imemory, devicenspace, 3, &proc);
3974 if (code < 0)
3975 return code;
3976 istate->colorspace[0].procs.special.separation.tint_transform = proc;
3977 if (code >= 0)
3978 code = gs_cspace_set_sepr_function(pcs, pfn);
3979 if (code >= 0)
3980 code = gs_setcolorspace(igs, pcs);
3981 /* release reference from construction */
3982 rc_decrement_only_cs(pcs, "setseparationspace");
3983 if (code < 0) {
3984 istate->colorspace[0] = cspace_old;
3985 return code;
3986 }
3987 cc.pattern = 0x00;
3988 cc.paint.values[0] = 1.0;
3989 code = gs_setcolor(igs, &cc);
3990 return code;
3991 }
3992 }
3993 code = gs_cspace_new_DeviceN(&pcs, num_components, pacs, imemory);
3994 if (code < 0)
3995 return code;
3996 names = pcs->params.device_n.names;
3997 pmap = pcs->params.device_n.map;
3998 pcs->params.device_n.get_colorname_string = gs_get_colorname_string;
3999
4000 /* Pick up the names of the components */
4001 {
4002 uint i;
4003 ref sname;
4004
4005 for (i = 0; i < num_components; ++i) {
4006 array_get(imemory, &namesarray, (long)i, &sname);
4007 switch (r_type(&sname)) {
4008 case t_string:
4009 code = name_from_string(imemory, &sname, &sname);
4010 if (code < 0) {
4011 rc_decrement_cs(pcs, "setdevicenspace");
4012 return code;
4013 }
4014 /* falls through */
4015 case t_name:
4016 names[i] = name_index(imemory, &sname);
4017 break;
4018 default:
4019 rc_decrement_cs(pcs, "setdevicenspace");
4020 return_error(e_typecheck);
4021 }
4022 }
4023 }
4024
4025 /* Now set the current color space as DeviceN */
4026
4027 cspace_old = istate->colorspace[0];
4028 istate->colorspace[0].procs.special.device_n.layer_names = namesarray;
4029 code = array_get(imemory, devicenspace, 3, &proc);
4030 if (code < 0)
4031 return code;
4032 istate->colorspace[0].procs.special.device_n.tint_transform = proc;
4033 gs_cspace_set_devn_function(pcs, pfn);
4034 code = gs_setcolorspace(igs, pcs);
4035 /* release reference from construction */
4036 rc_decrement_only_cs(pcs, "setdevicenspace");
4037 if (code < 0) {
4038 istate->colorspace[0] = cspace_old;
4039 return code;
4040 }
4041
4042 cc.pattern = 0x00;
4043 for (i=0;i<num_components;i++)
4044 cc.paint.values[i] = 1.0;
4045 code = gs_setcolor(igs, &cc);
4046 *cont = 1;
4047 return code;
4048 }
validatedevicenspace(i_ctx_t * i_ctx_p,ref ** space)4049 static int validatedevicenspace(i_ctx_t * i_ctx_p, ref **space)
4050 {
4051 int i, code = 0;
4052 ref *devicenspace = *space, proc;
4053 ref nameref, sref, altspace, namesarray, sname;
4054
4055 /* Check enough arguments in the space */
4056 if (r_size(devicenspace) < 4)
4057 return_error(e_rangecheck);
4058 /* Check the names parameter is an array */
4059 code = array_get(imemory, devicenspace, 1, &namesarray);
4060 if (code < 0)
4061 return code;
4062 if (!r_is_array(&namesarray))
4063 return_error(e_typecheck);
4064 /* Ensure we have at least one ink */
4065 if (r_size(&namesarray) < 1)
4066 return_error(e_typecheck);
4067 /* Make sure no more inks than we can cope with */
4068 if (r_size(&namesarray) > MAX_COMPONENTS_IN_DEVN) /* MUST match psi/icremap.h int_remap_color_info_s */
4069 return_error(e_limitcheck);
4070 /* Check the tint transform is a procedure */
4071 code = array_get(imemory, devicenspace, 3, &proc);
4072 if (code < 0)
4073 return code;
4074 check_proc(proc);
4075
4076 /* Check the array of ink names only contains names or strings */
4077 for (i = 0; i < r_size(&namesarray); ++i) {
4078 array_get(imemory, &namesarray, (long)i, &sname);
4079 switch (r_type(&sname)) {
4080 case t_string:
4081 case t_name:
4082 break;
4083 default:
4084 return_error(e_typecheck);
4085 }
4086 }
4087
4088 /* Get the name of the alternate space */
4089 code = array_get(imemory, devicenspace, 2, &altspace);
4090 if (code < 0)
4091 return code;
4092 if (r_has_type(&altspace, t_name))
4093 ref_assign(&nameref, &altspace);
4094 else {
4095 /* Make sure the alternate space is an array */
4096 if (!r_is_array(&altspace))
4097 return_error(e_typecheck);
4098 /* And has a name for its type */
4099 code = array_get(imemory, &altspace, 0, &nameref);
4100 if (code < 0)
4101 return code;
4102 if (!r_has_type(&nameref, t_name))
4103 return_error(e_typecheck);
4104 }
4105 /* Convert alternate space name to string */
4106 name_string_ref(imemory, &nameref, &sref);
4107 /* Check its not /Indexed, /Pattern, /DeviceN */
4108 if (r_size(&sref) == 7) {
4109 if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
4110 return_error(e_typecheck);
4111 if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
4112 return_error(e_typecheck);
4113 if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
4114 return_error(e_typecheck);
4115 }
4116 /* and also not /Separation */
4117 if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
4118 return_error(e_typecheck);
4119
4120 ref_assign(*space, &altspace);
4121 return 0;
4122 }
devicenalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)4123 static int devicenalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4124 {
4125 ref altspace;
4126 int code;
4127
4128 code = array_get(imemory, space, 2, &altspace);
4129 if (code < 0)
4130 return code;
4131 ref_assign(*r, &altspace);
4132 return 0;
4133 }
devicencomponents(i_ctx_t * i_ctx_p,ref * space,int * n)4134 static int devicencomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
4135 {
4136 ref namesarray;
4137 int code;
4138
4139 code = array_get(imemory, space, 1, &namesarray);
4140 if (code < 0)
4141 return code;
4142 *n = r_size(&namesarray);
4143 return 0;
4144 }
devicendomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)4145 static int devicendomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4146 {
4147 int i, limit, code;
4148 ref namesarray;
4149
4150 code = array_get(imemory, space, 1, &namesarray);
4151 if (code < 0)
4152 return code;
4153
4154 limit = r_size(&namesarray) * 2;
4155 for (i = 0;i < limit;i+=2) {
4156 ptr[i] = 0;
4157 ptr[i+1] = 1;
4158 }
4159 return 0;
4160 }
devicenrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)4161 static int devicenrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4162 {
4163 int i, limit, code;
4164 PS_colour_space_t *cspace;
4165
4166 ref altspace;
4167
4168 code = array_get(imemory, space, 1, &altspace);
4169 if (code < 0)
4170 return code;
4171
4172 code = get_space_object(i_ctx_p, &altspace, &cspace);
4173 if (code < 0)
4174 return code;
4175
4176 code = cspace->numcomponents(i_ctx_p, &altspace, &limit);
4177 if (code < 0)
4178 return code;
4179
4180 for (i = 0;i < limit * 2;i+=2) {
4181 ptr[i] = 0;
4182 ptr[i+1] = 1;
4183 }
4184 return 0;
4185 }
devicentransform(i_ctx_t * i_ctx_p,ref * devicenspace,int * usealternate,int * stage,int * stack_depth)4186 static int devicentransform(i_ctx_t *i_ctx_p, ref *devicenspace, int *usealternate, int *stage, int *stack_depth)
4187 {
4188 gx_device * dev = igs->device;
4189 ref narray, sname, proc;
4190 int i, code, colorant_number;
4191
4192 *usealternate = 0;
4193 code = array_get(imemory, devicenspace, 1, &narray);
4194 if (code < 0)
4195 return code;
4196 if (!r_is_array(&narray))
4197 return_error(e_typecheck);
4198
4199 for (i=0;i<r_size(&narray);i++) {
4200 code = array_get(imemory, &narray, i, &sname);
4201 if (code < 0)
4202 return code;
4203 if (r_has_type(&sname, t_name)) {
4204 name_string_ref(imemory, &sname, &sname);
4205 }
4206
4207 /* Check for /All and /None, never need the alternate for these */
4208 if (r_size(&sname) == 3 &&
4209 strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0)
4210 continue;
4211 if (r_size(&sname) == 4 &&
4212 strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0)
4213 continue;
4214 /*
4215 * Compare the colorant name to the device's. If the device's
4216 * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
4217 * colorant is in the SeparationNames list but not in the
4218 * SeparationOrder list.
4219 */
4220 colorant_number = (*dev_proc(dev, get_color_comp_index))
4221 (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
4222 if (colorant_number < 0) { /* If not valid colorant name */
4223 *usealternate = 1;
4224 break;
4225 }
4226 }
4227 if (*usealternate && *stage == 0) {
4228 (*stage)++;
4229 esp++;
4230 code = array_get(imemory, devicenspace, 3, &proc);
4231 if (code < 0)
4232 return code;
4233 *esp = proc;
4234 return o_push_estack;
4235 }
4236
4237 if (*stage == 1){
4238 *stack_depth = 0;
4239 *stage = 0;
4240 }
4241 return 0;
4242 }
devicenbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4243 static int devicenbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4244 {
4245 os_ptr op = osp; /* required by "push" macro */
4246 int code, use, n_comp;
4247 ref narray;
4248
4249 code = devicentransform(i_ctx_p, space, &use, stage, stack_depth);
4250 if (code != 0)
4251 return code;
4252 if (!use) {
4253 *stage = 0;
4254 *cont = 0;
4255 code = array_get(imemory, space, 1, &narray);
4256 if (code < 0)
4257 return code;
4258 n_comp = r_size(&narray);
4259 pop(n_comp);
4260 op = osp;
4261 switch(base) {
4262 case 0:
4263 push(1);
4264 make_real(op, 0.0);
4265 break;
4266 case 1:
4267 case 2:
4268 push(3);
4269 make_real(&op[-2], 0.0);
4270 make_real(&op[-1], 0.0);
4271 make_real(op, 0.0);
4272 break;
4273 case 3:
4274 push(4);
4275 make_real(&op[-3], 0.0);
4276 make_real(&op[-2], 0.0);
4277 make_real(&op[-1], 0.0);
4278 make_real(op, 0.0);
4279 break;
4280 }
4281 } else {
4282 *stage = 0;
4283 *cont = 1;
4284 }
4285 return 0;
4286 }
devicenvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4287 static int devicenvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4288 {
4289 int i, code;
4290 ref narray;
4291 os_ptr op = osp;
4292
4293 code = array_get(imemory, space, 1, &narray);
4294 if (code < 0)
4295 return code;
4296 if (!r_is_array(&narray))
4297 return_error(e_typecheck);
4298
4299 if (num_comps < r_size(&narray))
4300 return_error(e_stackunderflow);
4301
4302 op -= r_size(&narray) - 1;
4303
4304 for (i=0;i < r_size(&narray); i++) {
4305 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
4306 return_error(e_typecheck);
4307
4308 if (values[i] > 1.0)
4309 values[i] = 1.0;
4310
4311 if (values[i] < 0.0)
4312 values[i] = 0.0;
4313 op++;
4314 }
4315
4316 return 0;
4317 }
devicencompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)4318 static int devicencompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
4319 {
4320 ref sname1, sname2;
4321 int code;
4322
4323 code = array_get(imemory, space, 1, &sname1);
4324 if (code < 0)
4325 return 0;
4326
4327 code = array_get(imemory, testspace, 1, &sname2);
4328 if (code < 0)
4329 return 0;
4330
4331 if (!r_is_array(&sname1))
4332 return 0;
4333 if (!r_is_array(&sname2))
4334 return 0;
4335
4336 if (!comparearrays(i_ctx_p, &sname1, &sname2))
4337 return 0;
4338
4339 code = array_get(imemory, testspace, 2, &sname1);
4340 if (code < 0)
4341 return 0;
4342 code = array_get(imemory, testspace, 2, &sname2);
4343 if (code < 0)
4344 return 0;
4345 if (r_type(&sname1) != r_type(&sname2))
4346 return 0;
4347
4348 if (r_is_array(&sname1)) {
4349 if (!comparearrays(i_ctx_p, &sname1, &sname2))
4350 return 0;
4351 } else {
4352 if (!r_has_type(&sname1, t_name))
4353 return 0;
4354 if (!name_eq(&sname1, &sname2))
4355 return 0;
4356 }
4357 code = array_get(imemory, space, 3, &sname1);
4358 if (code < 0)
4359 return 0;
4360 code = array_get(imemory, testspace, 3, &sname2);
4361 if (code < 0)
4362 return 0;
4363 return(comparearrays(i_ctx_p, &sname1, &sname2));
4364 }
deviceninitialproc(i_ctx_t * i_ctx_p,ref * space)4365 static int deviceninitialproc(i_ctx_t *i_ctx_p, ref *space)
4366 {
4367 gs_client_color cc;
4368 int i, num_components, code;
4369 ref namesarray;
4370
4371 code = array_get(imemory, space, 1, &namesarray);
4372 if (code < 0)
4373 return code;
4374 num_components = r_size(&namesarray);
4375 cc.pattern = 0x00;
4376 for (i=0;i<num_components;i++)
4377 cc.paint.values[i] = 1.0;
4378 return gs_setcolor(igs, &cc);
4379 }
4380
4381 /* Indexed */
4382 /*
4383 * This routine samples the indexed space, it pushes values from -1
4384 * to 'hival', then executes the tint transform procedure. Returns here
4385 * to store the resulting value(s) in the indexed map.
4386 */
4387 static int
indexed_cont(i_ctx_t * i_ctx_p)4388 indexed_cont(i_ctx_t *i_ctx_p)
4389 {
4390 os_ptr op = osp;
4391 es_ptr ep = esp;
4392 int i = (int)ep[csme_index].value.intval;
4393
4394 if (i >= 0) { /* i.e., not first time */
4395 int m = (int)ep[csme_num_components].value.intval;
4396 int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
4397
4398 if (code < 0)
4399 return code;
4400 pop(m);
4401 op -= m;
4402 if (i == (int)ep[csme_hival].value.intval) { /* All done. */
4403 esp -= num_csme;
4404 return o_pop_estack;
4405 }
4406 }
4407 push(1);
4408 ep[csme_index].value.intval = ++i;
4409 make_int(op, i);
4410 make_op_estack(ep + 1, indexed_cont);
4411 ep[2] = ep[csme_proc]; /* lookup proc */
4412 esp = ep + 2;
4413 return o_push_estack;
4414 }
setindexedspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)4415 static int setindexedspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4416 {
4417 ref *pproc = &istate->colorspace[0].procs.special.index_proc;
4418 int code = 0;
4419 uint edepth = ref_stack_count(&e_stack);
4420 ref_colorspace cspace_old;
4421 ref hival, lookup;
4422 gs_color_space *pcs;
4423 gs_color_space *pcs_base;
4424
4425 if (i_ctx_p->language_level < 2)
4426 return_error(e_undefined);
4427
4428 *cont = 0;
4429 if (*stage == 1) {
4430 *stage = 0;
4431 return 0;
4432 }
4433
4434 cspace_old = istate->colorspace[0];
4435
4436 pcs_base = gs_currentcolorspace(igs);
4437
4438 code = array_get(imemory, r, 3, &lookup);
4439 if (code < 0)
4440 return code;
4441 code = array_get(imemory, r, 2, &hival);
4442 if (code < 0)
4443 return code;
4444 if (r_has_type(&lookup, t_string)) {
4445 int num_values = (hival.value.intval + 1) * cs_num_components(pcs_base);
4446 byte *data_tmp;
4447
4448 check_read(lookup);
4449 /*
4450 * The PDF and PS specifications state that the lookup table must have
4451 * the exact number of of data bytes needed. However we have found
4452 * PDF files from Amyuni with extra data bytes. Acrobat 6.0 accepts
4453 * these files without complaint, so we ignore the extra data.
4454 */
4455 if (r_size(&lookup) < num_values)
4456 return_error(e_rangecheck);
4457 pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
4458 if (!pcs) {
4459 return_error(e_VMerror);
4460 }
4461 pcs->base_space = pcs_base;
4462 rc_increment_cs(pcs_base);
4463
4464 data_tmp = (byte *) (pcs->params.indexed.lookup.table.data = ialloc_string (lookup.tas.rsize, "setindexedspace"));
4465 if (!data_tmp) {
4466 rc_decrement(pcs, "setindexedspace");
4467 return_error(e_VMerror);
4468 }
4469
4470 memcpy(data_tmp, lookup.value.const_bytes, lookup.tas.rsize);
4471
4472 pcs->params.indexed.lookup.table.size = num_values;
4473 pcs->params.indexed.use_proc = 0;
4474 make_null(pproc);
4475 code = 0;
4476 } else {
4477 gs_indexed_map *map;
4478
4479 /*
4480 * We have to call zcs_begin_map before moving the parameters,
4481 * since if the color space is a DeviceN or Separation space,
4482 * the memmove will overwrite its parameters.
4483 */
4484 code = zcs_begin_map(i_ctx_p, &map, &lookup, (hival.value.intval + 1),
4485 pcs_base, indexed_cont);
4486 if (code < 0)
4487 return code;
4488 pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
4489 pcs->base_space = pcs_base;
4490 rc_increment_cs(pcs_base);
4491 pcs->params.indexed.use_proc = 1;
4492 *pproc = lookup;
4493 map->proc.lookup_index = lookup_indexed_map;
4494 pcs->params.indexed.lookup.map = map;
4495 }
4496 pcs->params.indexed.hival = hival.value.intval;
4497 pcs->params.indexed.n_comps = cs_num_components(pcs_base);
4498 code = gs_setcolorspace(igs, pcs);
4499 /* release reference from construction */
4500 rc_decrement_only_cs(pcs, "setindexedspace");
4501 if (code < 0) {
4502 istate->colorspace[0] = cspace_old;
4503 ref_stack_pop_to(&e_stack, edepth);
4504 return code;
4505 }
4506 *stage = 0;
4507 if (ref_stack_count(&e_stack) == edepth) {
4508 return 0;
4509 } else {
4510 *cont = 1;
4511 *stage = 1;
4512 return o_push_estack; /* installation will load the caches */
4513 }
4514 }
validateindexedspace(i_ctx_t * i_ctx_p,ref ** space)4515 static int validateindexedspace(i_ctx_t * i_ctx_p, ref **space)
4516 {
4517 int code = 0;
4518 ref *r = *space;
4519 ref nameref, sref, hival, lookup, altspace;
4520
4521 if (!r_is_array(r))
4522 return_error(e_typecheck);
4523 /* Validate parameters, check we have enough operands */
4524 if (r_size(r) != 4)
4525 return_error(e_rangecheck);
4526 /* Check operand type(s) */
4527 /* Make sure 'hival' is an integer */
4528 code = array_get(imemory, r, 2, &hival);
4529 if (code < 0)
4530 return code;
4531 if (!r_has_type(&hival, t_integer))
4532 return_error(e_typecheck);
4533 /* Make sure 'hival' lies between 0 and 4096 */
4534 if (hival.value.intval < 0 || hival.value.intval > 4096)
4535 return_error(e_rangecheck);
4536 /* Ensure the 'lookup' is either a string or a procedure */
4537 code = array_get(imemory, r, 3, &lookup);
4538 if (code < 0)
4539 return code;
4540 if (!r_has_type(&lookup, t_string))
4541 check_proc(lookup);
4542
4543 /* Get the name of the alternate space */
4544 code = array_get(imemory, r, 1, &altspace);
4545 if (code < 0)
4546 return code;
4547 if (r_has_type(&altspace, t_name))
4548 ref_assign(&nameref, &altspace);
4549 else {
4550 if (!r_is_array(&altspace))
4551 return_error(e_typecheck);
4552 code = array_get(imemory, &altspace, 0, &nameref);
4553 if (code < 0)
4554 return code;
4555 }
4556 /* Convert alternate space name to string */
4557 name_string_ref(imemory, &nameref, &sref);
4558 /* Check its not /Indexed or /Pattern */
4559 if (r_size(&sref) == 7) {
4560 if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
4561 return_error(e_typecheck);
4562 if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
4563 return_error(e_typecheck);
4564 }
4565 ref_assign(*space, &altspace);
4566 return 0;
4567 }
indexedalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)4568 static int indexedalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4569 {
4570 ref alt;
4571 int code;
4572
4573 code = array_get(imemory, *r, 1, &alt);
4574 if (code < 0)
4575 return code;
4576 ref_assign(*r, &alt);
4577 return 0;
4578 }
indexeddomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)4579 static int indexeddomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4580 {
4581 ref hival;
4582 int code;
4583
4584 code = array_get(imemory, space, 2, &hival);
4585 if (code < 0)
4586 return code;
4587 ptr[0] = 0;
4588 ptr[1] = (float)hival.value.intval;
4589 return 0;
4590 }
indexedrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)4591 static int indexedrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4592 {
4593 ref hival;
4594 int code;
4595
4596 code = array_get(imemory, space, 2, &hival);
4597 if (code < 0)
4598 return code;
4599 ptr[0] = 0;
4600 ptr[1] = (float)hival.value.intval;
4601 return 0;
4602 }
indexedbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4603 static int indexedbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4604 {
4605 int code;
4606
4607 if (*stage == 0) {
4608 /* Usefully /Indexed can't be the base of any other space, so we know
4609 * the current space in the graphics state is this one.
4610 */
4611 gs_color_space *pcs;
4612 pcs = gs_currentcolorspace(igs);
4613
4614 /* Update the counters */
4615 *stage = 1;
4616 *cont = 1;
4617
4618 /* Indexed spaces can have *either* a procedure or a string for the
4619 * lookup.
4620 */
4621 if (pcs->params.indexed.use_proc) {
4622 es_ptr ep = ++esp;
4623 ref proc;
4624
4625 /* We have a procedure, set up the continuation to run the
4626 * lookup procedure. (The index is already on the operand stack)
4627 */
4628 check_estack(1);
4629 code = array_get(imemory, space, 3, &proc);
4630 if (code < 0)
4631 return code;
4632 *ep = proc; /* lookup proc */
4633 return o_push_estack;
4634 } else {
4635 int i, index;
4636 os_ptr op = osp;
4637 unsigned char *ptr = (unsigned char *)pcs->params.indexed.lookup.table.data;
4638
4639 *stage = 0;
4640 /* We have a string, start by retrieving the index from the op stack */
4641 /* Make sure its an integer! */
4642 if (!r_has_type(op, t_integer))
4643 return_error (e_typecheck);
4644 index = op->value.intval;
4645 /* And remove it from the stack. */
4646 pop(1);
4647 op = osp;
4648
4649 /* Make sure we have enough space on the op stack to hold
4650 * one value for each component of the alternate space
4651 */
4652 push(pcs->params.indexed.n_comps);
4653 op -= pcs->params.indexed.n_comps - 1;
4654
4655 /* Move along the lookup table, one byte for each component , the
4656 * number of times required to get to the lookup for this index
4657 */
4658 ptr += index * pcs->params.indexed.n_comps;
4659
4660 /* For all the components of the alternate space, push the value
4661 * of the component on the stack. The value is given by the byte
4662 * from the lookup table divided by 255 to give a value between
4663 * 0 and 1.
4664 */
4665 for (i = 0; i < pcs->params.indexed.n_comps; i++, op++) {
4666 float rval = (*ptr++) / 255.0;
4667 make_real(op, rval);
4668 }
4669 return 0;
4670 }
4671 } else {
4672 *stage = 0;
4673 *cont = 1;
4674 return 0;
4675 }
4676 }
indexedvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4677 static int indexedvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4678 {
4679 int code;
4680 ref hival;
4681 os_ptr op = osp;
4682
4683 if (num_comps < 1)
4684 return_error(e_stackunderflow);
4685
4686 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
4687 return_error(e_typecheck);
4688
4689 code = array_get(imemory, space, 2, &hival);
4690 if (code < 0)
4691 return code;
4692
4693 if (*values > hival.value.intval)
4694 *values = (float)hival.value.intval;
4695
4696 if (*values < 0)
4697 *values = 0;
4698
4699 /* The PLRM says 'If it is a real number, it is rounded to the nearest integer
4700 * but in fact Acrobat simply floors the value.
4701 */
4702 *values = floor(*values);
4703
4704 return 0;
4705 }
4706
4707 /* Pattern */
setpatternspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)4708 static int setpatternspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4709 {
4710 gs_color_space *pcs;
4711 gs_color_space *pcs_base;
4712 uint edepth = ref_stack_count(&e_stack);
4713 int code = 0;
4714
4715 if (i_ctx_p->language_level < 2)
4716 return_error(e_undefined);
4717
4718 *cont = 0;
4719 pcs_base = NULL;
4720 if (r_is_array(r)) {
4721 check_read(*r);
4722
4723 switch (r_size(r)) {
4724 case 1: /* no base space */
4725 pcs_base = NULL;
4726 break;
4727 default:
4728 return_error(e_rangecheck);
4729 case 2:
4730 pcs_base = gs_currentcolorspace(igs);
4731 if (cs_num_components(pcs_base) < 0) /* i.e., Pattern space */
4732 return_error(e_rangecheck);
4733 }
4734 }
4735 pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Pattern);
4736 pcs->base_space = pcs_base;
4737 pcs->params.pattern.has_base_space = (pcs_base != NULL);
4738 rc_increment_cs(pcs_base);
4739 code = gs_setcolorspace(igs, pcs);
4740 /* release reference from construction */
4741 rc_decrement_only_cs(pcs, "zsetpatternspace");
4742 if (code < 0) {
4743 ref_stack_pop_to(&e_stack, edepth);
4744 return code;
4745 }
4746 make_null(&istate->pattern[0]); /* PLRM: initial color value is a null object */
4747 *stage = 0;
4748 return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
4749 }
validatepatternspace(i_ctx_t * i_ctx_p,ref ** r)4750 static int validatepatternspace(i_ctx_t * i_ctx_p, ref **r)
4751 {
4752 int code;
4753 ref tref;
4754
4755 /* since makepattern has already been run, we don't need to do much validation */
4756 if (!r_has_type(*r, t_name)) {
4757 if (r_is_array(*r)) {
4758 if (r_size(*r) > 1) {
4759 code = array_get(imemory, *r, 1, &tref);
4760 if (code < 0)
4761 return code;
4762 ref_assign(*r, &tref);
4763 } else
4764 *r = 0;
4765 } else
4766 return_error(e_typecheck);
4767 } else
4768 *r = 0;
4769 return 0;
4770 }
patternalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)4771 static int patternalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4772 {
4773 ref tref;
4774 int code;
4775
4776 if (!r_has_type(*r, t_name)) {
4777 if (r_is_array(*r)) {
4778 if (r_size(*r) > 1) {
4779 code = array_get(imemory, space, 1, &tref);
4780 if (code < 0)
4781 return code;
4782 ref_assign(*r, &tref);
4783 } else
4784 *r = 0;
4785 } else
4786 return_error(e_typecheck);
4787 } else
4788 *r = 0;
4789 return 0;
4790 }
patterncomponent(i_ctx_t * i_ctx_p,ref * space,int * n)4791 static int patterncomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
4792 {
4793 os_ptr op = osp;
4794 int n_comps, code;
4795 const gs_color_space * pcs = gs_currentcolorspace(igs);
4796 gs_client_color cc;
4797
4798 /* check for a pattern color space */
4799 if ((n_comps = cs_num_components(pcs)) < 0) {
4800 n_comps = -n_comps;
4801 if (r_has_type(op, t_dictionary)) {
4802 ref *pImpl, pPatInst;
4803
4804 code = dict_find_string(op, "Implementation", &pImpl);
4805 if (code < 0)
4806 return code;
4807 code = array_get(imemory, pImpl, 0, &pPatInst);
4808 if (code < 0)
4809 return code;
4810 cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
4811 if (pattern_instance_uses_base_space(cc.pattern))
4812 *n = n_comps;
4813 else
4814 *n = 1;
4815 } else
4816 *n = 1;
4817 } else
4818 return_error(e_typecheck);
4819
4820 return 0;
4821 }
patternbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4822 static int patternbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4823 {
4824 os_ptr op;
4825 int i, components=0;
4826
4827 if (r_size(space) > 1) {
4828 const gs_color_space * pcs = gs_currentcolorspace(igs);
4829 const gs_client_color * pcc = gs_currentcolor(igs);
4830 int n = cs_num_components(pcs);
4831 bool push_pattern = n < 0;
4832 gs_pattern_instance_t * pinst = pcc->pattern;
4833
4834 if (pinst != 0 && pattern_instance_uses_base_space(pinst)) {
4835 /* check for pattern */
4836 if (push_pattern)
4837 pop(1); /* The pattern instance */
4838 *stage = 0;
4839 *cont = 1;
4840 return 0;
4841 }
4842 /* If the pattern isn't yet initialised, or doesn't use the
4843 * base space, treat as uncolored and return defaults below
4844 * Fall Through.
4845 */
4846 }
4847
4848 pop(1);
4849 op = osp;
4850 switch(base) {
4851 case 0:
4852 components = 1;
4853 break;
4854 case 1:
4855 case 2:
4856 components = 3;
4857 break;
4858 case 3:
4859 components = 4;
4860 break;
4861 }
4862 push(components);
4863 op -= components-1;
4864 for (i=0;i<components;i++) {
4865 make_real(op, (float)0);
4866 op++;
4867 }
4868 if (components == 4) {
4869 op--;
4870 make_real(op, (float)1);
4871 }
4872 *stage = 0;
4873 *cont = 0;
4874 return 0;
4875 }
patternvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4876 static int patternvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4877 {
4878 os_ptr op = osp;
4879
4880 check_op(1);
4881
4882 if (!r_has_type(op, t_dictionary) && !r_has_type(op, t_null))
4883 return_error(e_typecheck);
4884
4885 return 0;
4886 }
4887
4888 /* DevicePixel */
setdevicepspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)4889 static int setdevicepspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4890 {
4891 int code = 0;
4892 gs_color_space *pcs;
4893 ref bpp;
4894
4895 /* The comment in the original PostScript (gs_lev2.ps) said
4896 * "DevicePixel is actually a LanguageLevel 3 feature; it is here for
4897 * historical reasons." Actually DevicePixel is a Display PostScript
4898 * space, as far as I can tell. It certainly isn't a level 3 space.
4899 * Preserve the old behaviour anyway.
4900 */
4901 if (i_ctx_p->language_level < 2)
4902 return_error(e_undefined);
4903
4904 *cont = 0;
4905 code = array_get(imemory, r, 1, &bpp);
4906 if (code < 0)
4907 return code;
4908 if (!r_has_type(&bpp, t_integer))
4909 return_error(e_typecheck);
4910 code = gs_cspace_new_DevicePixel(imemory, &pcs, (int)bpp.value.intval);
4911 if (code < 0)
4912 return code;
4913 code = gs_setcolorspace(igs, pcs);
4914 /* release reference from construction */
4915 *stage = 0;
4916 rc_decrement_only_cs(pcs, "setseparationspace");
4917 return code;
4918 }
validatedevicepspace(i_ctx_t * i_ctx_p,ref ** space)4919 static int validatedevicepspace(i_ctx_t * i_ctx_p, ref **space)
4920 {
4921 int code = 0;
4922 ref *r = *space, bpp;
4923
4924 if (!r_is_array(r))
4925 return_error(e_typecheck);
4926 /* Validate parameters, check we have enough operands */
4927 if (r_size(r) != 2)
4928 return_error(e_rangecheck);
4929 /* Make sure 'bits per pixel' is an integer */
4930 code = array_get(imemory, r, 1, &bpp);
4931 if (code < 0)
4932 return code;
4933 if (!r_has_type(&bpp, t_integer))
4934 return_error(e_typecheck);
4935
4936 /* Make sure 'bits per pixel' lies between 0 and 31 */
4937 if (bpp.value.intval < 0 || bpp.value.intval > 31)
4938 return_error(e_rangecheck);
4939
4940 *space = 0;
4941 return code;
4942 }
devicepdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)4943 static int devicepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4944 {
4945 int code;
4946 ref tref;
4947
4948 code = array_get(imemory, space, 1, &tref);
4949 if (code < 0)
4950 return code;
4951 ptr[0] = 0;
4952 ptr[1] = (float)(1 << tref.value.intval);
4953 return 0;
4954 }
deviceprange(i_ctx_t * i_ctx_p,ref * space,float * ptr)4955 static int deviceprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4956 {
4957 int code;
4958 ref tref;
4959
4960 code = array_get(imemory, space, 1, &tref);
4961 if (code < 0)
4962 return code;
4963 ptr[0] = 0;
4964 ptr[1] = (float)(1 << tref.value.intval);
4965 return 0;
4966 }
devicepbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4967 static int devicepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4968 {
4969 os_ptr op = osp;
4970
4971 *stage = 0;
4972 *cont = 0;
4973 make_int(op, 0);
4974 return 0;
4975 }
devicepvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4976 static int devicepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4977 {
4978 return 0;
4979 }
4980
set_dev_space(i_ctx_t * i_ctx_p,int components)4981 static int set_dev_space(i_ctx_t * i_ctx_p, int components)
4982 {
4983 int code, stage = 1, cont = 0;
4984 switch(components) {
4985 case 1:
4986 code = setgrayspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
4987 break;
4988 case 3:
4989 code = setrgbspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
4990 break;
4991 case 4:
4992 code = setcmykspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
4993 break;
4994 default:
4995 code = gs_note_error(e_rangecheck);
4996 break;
4997 }
4998 return code;
4999 }
5000
5001 /* Lab Space */
5002
5003 /* Check that the range of a the ab values is valid */
checkrangeab(i_ctx_t * i_ctx_p,ref * labdict)5004 static int checkrangeab(i_ctx_t * i_ctx_p, ref *labdict)
5005 {
5006 int code = 0, i;
5007 float value[4];
5008 ref *tempref, valref;
5009
5010 code = dict_find_string(labdict, "Range", &tempref);
5011 if (code >= 0 && !r_has_type(tempref, t_null)) {
5012 if (!r_is_array(tempref))
5013 return_error(e_typecheck);
5014 if (r_size(tempref) != 4)
5015 return_error(e_rangecheck);
5016
5017 for (i=0;i<4;i++) {
5018 code = array_get(imemory, tempref, i, &valref);
5019 if (code < 0)
5020 return code;
5021 if (r_has_type(&valref, t_integer))
5022 value[i] = (float)valref.value.intval;
5023 else if (r_has_type(&valref, t_real))
5024 value[i] = (float)valref.value.realval;
5025 else
5026 return_error(e_typecheck);
5027 }
5028 if (value[1] < value[0] || value[3] < value[2] )
5029 return_error(e_rangecheck);
5030 }
5031 return 0;
5032 }
5033
setlabspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5034 static int setlabspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont,
5035 int CIESubst)
5036 {
5037 /* In this case, we will treat this as an ICC color space, with a
5038 CIELAB 16 bit profile */
5039 ref labdict;
5040 int code = 0;
5041 float range_buff[4], white[3], black[3];
5042 static const float dflt_range[4] = { -100, 100, -100, 100 };
5043 static const float dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5044 int i;
5045 gs_client_color cc;
5046
5047 *cont = 0;
5048 code = array_get(imemory, r, 1, &labdict);
5049 if (code < 0)
5050 return code;
5051 /* Get all the parts */
5052 code = dict_floats_param( imemory, &labdict, "Range", 4, range_buff,
5053 dflt_range );
5054 for (i = 0; i < 4 && range_buff[i + 1] >= range_buff[i]; i += 2);
5055 if (i != 4)
5056 return_error(e_rangecheck);
5057 code = dict_floats_param( imemory, &labdict, "BlackPoint", 3, black,
5058 dflt_black );
5059 code = dict_floats_param( imemory, &labdict, "WhitePoint", 3, white,
5060 dflt_white );
5061 if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5062 return_error(e_rangecheck);
5063 code = seticc_lab(i_ctx_p, white, black, range_buff);
5064 if ( code < 0)
5065 return gs_rethrow(code, "setting PDF lab color space");
5066 cc.pattern = 0x00;
5067 for (i=0;i<3;i++)
5068 cc.paint.values[i] = 0;
5069 code = gs_setcolor(igs, &cc);
5070 return code;
5071 }
5072
validatelabspace(i_ctx_t * i_ctx_p,ref ** r)5073 static int validatelabspace(i_ctx_t * i_ctx_p, ref **r)
5074 {
5075 int code=0;
5076 ref *space, labdict;
5077
5078 space = *r;
5079 if (!r_is_array(space))
5080 return_error(e_typecheck);
5081 /* Validate parameters, check we have enough operands */
5082 if (r_size(space) < 2)
5083 return_error(e_rangecheck);
5084 code = array_get(imemory, space, 1, &labdict);
5085 if (code < 0)
5086 return code;
5087 /* Check the white point, which is required. */
5088 code = checkWhitePoint(i_ctx_p, &labdict);
5089 if (code != 0)
5090 return code;
5091 /* The rest are optional. Need to validate though */
5092 code = checkBlackPoint(i_ctx_p, &labdict);
5093 if (code < 0)
5094 return code;
5095 /* Range on a b values */
5096 code = checkrangeab(i_ctx_p, &labdict);
5097 if (code < 0)
5098 return code;
5099 *r = 0; /* No nested space */
5100 return 0;
5101 }
5102
labrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)5103 static int labrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5104 {
5105 int i, code;
5106 ref CIEdict, *tempref, valref;
5107
5108 code = array_get(imemory, space, 1, &CIEdict);
5109 if (code < 0)
5110 return code;
5111
5112 /* If we have a Range entry, get the values from that */
5113 code = dict_find_string(&CIEdict, "Range", &tempref);
5114 if (code >= 0 && !r_has_type(tempref, t_null)) {
5115 for (i=0;i<4;i++) {
5116 code = array_get(imemory, tempref, i, &valref);
5117 if (code < 0)
5118 return code;
5119 if (r_has_type(&valref, t_integer))
5120 ptr[i] = (float)valref.value.intval;
5121 else if (r_has_type(&valref, t_real))
5122 ptr[i] = (float)valref.value.realval;
5123 else
5124 return_error(e_typecheck);
5125 }
5126 } else {
5127 /* Default values for Lab */
5128 for (i=0;i<2;i++) {
5129 ptr[2 * i] = -100;
5130 ptr[(2 * i) + 1] = 100;
5131 }
5132 }
5133 return 0;
5134 }
5135
labdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)5136 static int labdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5137 {
5138 int i, code;
5139 ref CIEdict, *tempref, valref;
5140
5141 code = array_get(imemory, space, 1, &CIEdict);
5142 if (code < 0)
5143 return code;
5144
5145 /* If we have a Range, get the values from that */
5146 code = dict_find_string(&CIEdict, "Range", &tempref);
5147 if (code >= 0 && !r_has_type(tempref, t_null)) {
5148 for (i=0;i<4;i++) {
5149 code = array_get(imemory, tempref, i, &valref);
5150 if (code < 0)
5151 return code;
5152 if (r_has_type(&valref, t_integer))
5153 ptr[i] = (float)valref.value.intval;
5154 else if (r_has_type(&valref, t_real))
5155 ptr[i] = (float)valref.value.realval;
5156 else
5157 return_error(e_typecheck);
5158 }
5159 } else {
5160 /* Default values for Lab */
5161 for (i=0;i<2;i++) {
5162 ptr[2 * i] = -100;
5163 ptr[(2 * i) + 1] = 100;
5164 }
5165 }
5166 return 0;
5167 }
5168
labbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)5169 static int labbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5170 {
5171 os_ptr op;
5172 int i, components=1;
5173
5174 components = 3;
5175 pop(components);
5176 op = osp;
5177 components = 3;
5178 push(components);
5179 op -= components-1;
5180 for (i=0;i<components;i++) {
5181 make_real(op, (float)0);
5182 op++;
5183 }
5184 *stage = 0;
5185 *cont = 0;
5186 return 0;
5187 }
5188
labvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)5189 static int labvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5190 {
5191 os_ptr op = osp;
5192 int i;
5193
5194 if (num_comps < 3)
5195 return_error(e_stackunderflow);
5196 op -= 2;
5197 for (i=0;i<3;i++) {
5198 if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
5199 return_error(e_typecheck);
5200 op++;
5201 }
5202 return 0;
5203 }
5204
5205 /* Check that the Matrix of a CalRGB and CalGray space is valid */
checkCalMatrix(i_ctx_t * i_ctx_p,ref * CIEdict)5206 static int checkCalMatrix(i_ctx_t * i_ctx_p, ref *CIEdict)
5207 {
5208 int code = 0, i;
5209 float value[9];
5210 ref *tempref, valref;
5211
5212 code = dict_find_string(CIEdict, "Matrix", &tempref);
5213 if (code >= 0 && !r_has_type(tempref, t_null)) {
5214 if (!r_is_array(tempref))
5215 return_error(e_typecheck);
5216 if (r_size(tempref) != 9)
5217 return_error(e_rangecheck);
5218 for (i=0;i<9;i++) {
5219 code = array_get(imemory, tempref, i, &valref);
5220 if (code < 0)
5221 return code;
5222 if (r_has_type(&valref, t_integer))
5223 value[i] = (float)valref.value.intval;
5224 else if (r_has_type(&valref, t_real))
5225 value[i] = (float)valref.value.realval;
5226 else
5227 return_error(e_typecheck);
5228 }
5229 }
5230 return 0;
5231 }
5232
5233 /* Check that the Gamma of a CalRGB and CalGray space is valid */
checkGamma(i_ctx_t * i_ctx_p,ref * CIEdict,int numvalues)5234 static int checkGamma(i_ctx_t * i_ctx_p, ref *CIEdict, int numvalues)
5235 {
5236 int code = 0, i;
5237 float value[3];
5238 ref *tempref, valref;
5239
5240 code = dict_find_string(CIEdict, "Gamma", &tempref);
5241 if (code >= 0 && !r_has_type(tempref, t_null)) {
5242 if (numvalues > 1) {
5243 /* Array of gammas (RGB) */
5244 if (!r_is_array(tempref))
5245 return_error(e_typecheck);
5246 if (r_size(tempref) != numvalues)
5247 return_error(e_rangecheck);
5248 for (i=0;i<numvalues;i++) {
5249 code = array_get(imemory, tempref, i, &valref);
5250 if (code < 0)
5251 return code;
5252 if (r_has_type(&valref, t_integer))
5253 value[i] = (float)valref.value.intval;
5254 else if (r_has_type(&valref, t_real))
5255 value[i] = (float)valref.value.realval;
5256 else
5257 return_error(e_typecheck);
5258 if (value[i] <= 0) return_error(e_rangecheck);
5259 }
5260 } else {
5261 /* Single gamma (gray) */
5262 if (r_has_type(tempref, t_real))
5263 value[0] = (float)(tempref->value.realval);
5264 else if (r_has_type(tempref, t_integer))
5265 value[0] = (float)(tempref->value.intval);
5266 else
5267 return_error(e_typecheck);
5268 if (value[0] <= 0) return_error(e_rangecheck);
5269 }
5270 }
5271 return 0;
5272 }
5273
5274 /* Here we set up an equivalent ICC form for the CalGray color space */
setcalgrayspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5275 static int setcalgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5276 {
5277 ref graydict;
5278 int code = 0;
5279 float gamma, white[3], black[3];
5280 floatp dflt_gamma = 1.0;
5281 static const float dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5282 gs_client_color cc;
5283
5284 *cont = 0;
5285 code = array_get(imemory, r, 1, &graydict);
5286 if (code < 0)
5287 return code;
5288 /* Get all the parts */
5289 code = dict_float_param(&graydict, "Gamma",
5290 dflt_gamma, &gamma);
5291 if (gamma <= 0 ) return_error(e_rangecheck);
5292 code = dict_floats_param( imemory,
5293 &graydict,
5294 "BlackPoint",
5295 3,
5296 black,
5297 dflt_black );
5298 code = dict_floats_param( imemory,
5299 &graydict,
5300 "WhitePoint",
5301 3,
5302 white,
5303 dflt_white );
5304 if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5305 return_error(e_rangecheck);
5306 code = seticc_cal(i_ctx_p, white, black, &gamma, NULL, 1,
5307 graydict.value.saveid);
5308 if ( code < 0)
5309 return gs_rethrow(code, "setting CalGray color space");
5310 cc.pattern = 0x00;
5311 cc.paint.values[0] = 0;
5312 code = gs_setcolor(igs, &cc);
5313 return code;
5314 }
5315
validatecalgrayspace(i_ctx_t * i_ctx_p,ref ** r)5316 static int validatecalgrayspace(i_ctx_t * i_ctx_p, ref **r)
5317 {
5318 int code=0;
5319 ref *space, calgraydict;
5320
5321 space = *r;
5322 if (!r_is_array(space))
5323 return_error(e_typecheck);
5324 /* Validate parameters, check we have enough operands */
5325 if (r_size(space) < 2)
5326 return_error(e_rangecheck);
5327 code = array_get(imemory, space, 1, &calgraydict);
5328 if (code < 0)
5329 return code;
5330 /* Check the white point, which is required */
5331 /* We have to have a white point */
5332 /* Check white point exists, and is an array of three numbers */
5333 code = checkWhitePoint(i_ctx_p, &calgraydict);
5334 if (code != 0)
5335 return code;
5336 /* The rest are optional. Need to validate though */
5337 code = checkBlackPoint(i_ctx_p, &calgraydict);
5338 if (code < 0)
5339 return code;
5340 /* Check Gamma values */
5341 code = checkGamma(i_ctx_p, &calgraydict, 1);
5342 if (code < 0)
5343 return code;
5344 *r = 0; /* No nested space */
5345 return 0;
5346 }
5347
5348 /* Here we set up an equivalent ICC form for the CalRGB color space */
setcalrgbspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5349 static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5350 {
5351 ref rgbdict;
5352 int code = 0;
5353 float gamma[3], white[3], black[3], matrix[9];
5354 static const float dflt_gamma[3] = { 1.0, 1.0, 1.0 };
5355 static const float dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5356 static const float dflt_matrix[9] = {1,0,0,0,1,0,0,0,1};
5357 int i;
5358 gs_client_color cc;
5359
5360 *cont = 0;
5361 code = array_get(imemory, r, 1, &rgbdict);
5362 if (code < 0)
5363 return code;
5364 /* Get all the parts */
5365 code = dict_floats_param( imemory,
5366 &rgbdict,
5367 "Gamma",
5368 3,
5369 gamma,
5370 dflt_gamma );
5371 if (gamma[0] <= 0 || gamma[1] <= 0 || gamma[2] <= 0)
5372 return_error(e_rangecheck);
5373 code = dict_floats_param( imemory,
5374 &rgbdict,
5375 "BlackPoint",
5376 3,
5377 black,
5378 dflt_black );
5379 code = dict_floats_param( imemory,
5380 &rgbdict,
5381 "WhitePoint",
5382 3,
5383 white,
5384 dflt_white );
5385 if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5386 return_error(e_rangecheck);
5387 code = dict_floats_param( imemory,
5388 &rgbdict,
5389 "Matrix",
5390 9,
5391 matrix,
5392 dflt_matrix );
5393 code = seticc_cal(i_ctx_p, white, black, gamma, matrix, 3, rgbdict.value.saveid);
5394 if ( code < 0)
5395 return gs_rethrow(code, "setting CalRGB color space");
5396 cc.pattern = 0x00;
5397 for (i=0;i<3;i++)
5398 cc.paint.values[i] = 0;
5399 code = gs_setcolor(igs, &cc);
5400 return code;
5401 }
5402
validatecalrgbspace(i_ctx_t * i_ctx_p,ref ** r)5403 static int validatecalrgbspace(i_ctx_t * i_ctx_p, ref **r)
5404 {
5405 int code=0;
5406 ref *space, calrgbdict;
5407
5408 space = *r;
5409 if (!r_is_array(space))
5410 return_error(e_typecheck);
5411 /* Validate parameters, check we have enough operands */
5412 if (r_size(space) < 2)
5413 return_error(e_rangecheck);
5414 code = array_get(imemory, space, 1, &calrgbdict);
5415 if (code < 0)
5416 return code;
5417 /* Check the white point, which is required */
5418 code = checkWhitePoint(i_ctx_p, &calrgbdict);
5419 if (code != 0)
5420 return code;
5421 /* The rest are optional. Need to validate though */
5422 code = checkBlackPoint(i_ctx_p, &calrgbdict);
5423 if (code < 0)
5424 return code;
5425 /* Check Gamma values */
5426 code = checkGamma(i_ctx_p, &calrgbdict, 3);
5427 if (code < 0)
5428 return code;
5429 /* Check Matrix */
5430 code = checkCalMatrix(i_ctx_p, &calrgbdict);
5431 if (code < 0)
5432 return code;
5433 *r = 0; /* No nested space */
5434 return 0;
5435 }
5436
5437 /* ICCBased */
5438 static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr);
seticcspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5439 static int seticcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5440 {
5441 os_ptr op = osp;
5442 ref ICCdict, *tempref, *altref=NULL, *nocie;
5443 int components, code;
5444 float range[8];
5445
5446 code = dict_find_string(systemdict, "NOCIE", &nocie);
5447 if (code < 0)
5448 return code;
5449 if (!r_has_type(nocie, t_boolean))
5450 return_error(e_typecheck);
5451 *cont = 0;
5452 do {
5453 switch(*stage) {
5454 case 0:
5455 (*stage)++;
5456 code = array_get(imemory, r, 1, &ICCdict);
5457 if (code < 0)
5458 return code;
5459 code = dict_find_string(&ICCdict, "N", &tempref);
5460 if (code < 0)
5461 return code;
5462 components = tempref->value.intval;
5463 if (components > count_of(range))
5464 return_error(e_rangecheck);
5465
5466 /* Don't allow ICCBased spaces if NOCIE is true */
5467 if (nocie->value.boolval) {
5468 code = dict_find_string(&ICCdict, "Alternate", &altref); /* Alternate is optional */
5469 if (code < 0)
5470 return code;
5471 if ((altref != NULL) && (r_type(altref) != t_null)) {
5472 /* The PDF interpreter sets a null Alternate. If we have an
5473 * Alternate, and its not null, and NOCIE is true, then use the
5474 * Alternate instead of the ICC
5475 */
5476 push(1);
5477 ref_assign(op, altref);
5478 /* If CIESubst, we are already substituting for CIE, so use nosubst
5479 * to prevent further substitution!
5480 */
5481 return setcolorspace_nosubst(i_ctx_p);
5482 } else {
5483 /* There's no /Alternate (or it is null), set a default space
5484 * based on the number of components in the ICCBased space
5485 */
5486 code = set_dev_space(i_ctx_p, components);
5487 if (code != 0)
5488 return code;
5489 *stage = 0;
5490 }
5491 } else {
5492 code = iccrange(i_ctx_p, r, (float *)&range);
5493 if (code < 0)
5494 return code;
5495 code = dict_find_string(&ICCdict, "DataSource", &tempref);
5496 if (code < 0)
5497 return code;
5498 /* Check for string based ICC and convert to a file */
5499 if (r_has_type(tempref, t_string)){
5500 uint n = r_size(tempref);
5501 ref rss;
5502
5503 code = make_rss(i_ctx_p, &rss, tempref->value.const_bytes, n, r_space(tempref), 0L, n, false);
5504 if (code < 0)
5505 return code;
5506 ref_assign(tempref, &rss);
5507 }
5508 /* Make space on operand stack to pass the ICC dictionary */
5509 push(1);
5510 ref_assign(op, &ICCdict);
5511 code = seticc(i_ctx_p, components, op, (float *)&range);
5512 if (code < 0) {
5513 code = dict_find_string(&ICCdict, "Alternate", &altref); /* Alternate is optional */
5514 if (code < 0)
5515 return code;
5516 if ((altref != NULL) && (r_type(altref) != t_null)) {
5517 /* We have a /Alternate in the ICC space */
5518 /* Our ICC dictionary still on operand stack, we can reuse the
5519 * slot on the stack to hold the alternate space.
5520 */
5521 ref_assign(op, (ref *)altref);
5522 /* If CIESubst, we are already substituting for CIE, so use nosubst
5523 * to prevent further substitution!
5524 */
5525 if (CIESubst)
5526 return setcolorspace_nosubst(i_ctx_p);
5527 else
5528 return zsetcolorspace(i_ctx_p);
5529 } else {
5530 /* We have no /Alternate in the ICC space, use hte /N key to
5531 * determine an 'appropriate' default space.
5532 */
5533 code = set_dev_space(i_ctx_p, components);
5534 if (code != 0)
5535 return code;
5536 *stage = 0;
5537 }
5538 pop(1);
5539 }
5540 if (code != 0)
5541 return code;
5542 }
5543 break;
5544 case 1:
5545 /* All done, exit */
5546 *stage = 0;
5547 code = 0;
5548 break;
5549 default:
5550 return_error (e_rangecheck);
5551 break;
5552 }
5553 }while(*stage);
5554 return code;
5555 }
validateiccspace(i_ctx_t * i_ctx_p,ref ** r)5556 static int validateiccspace(i_ctx_t * i_ctx_p, ref **r)
5557 {
5558 int code=0, i, components = 0;
5559 ref *space, *tempref, valref, ICCdict, sref;
5560
5561 space = *r;
5562 if (!r_is_array(space))
5563 return_error(e_typecheck);
5564 /* Validate parameters, check we have enough operands */
5565 if (r_size(space) != 2)
5566 return_error(e_rangecheck);
5567
5568 code = array_get(imemory, space, 1, &ICCdict);
5569 if (code < 0)
5570 return code;
5571
5572 code = dict_find_string(&ICCdict, "N", &tempref);
5573 if (code <= 0)
5574 return code;
5575 if (!r_has_type(tempref, t_null)) {
5576 if (!r_has_type(tempref, t_integer))
5577 return_error(e_typecheck);
5578 components = tempref->value.intval;
5579 } else
5580 return_error(e_typecheck);
5581 code = dict_find_string(&ICCdict, "DataSource", &tempref);
5582 if (code <= 0)
5583 return_error(e_typecheck);
5584 if (!r_has_type(tempref, t_null)) {
5585 if (!r_has_type(tempref, t_string) && !r_has_type(tempref, t_file))
5586 return_error(e_typecheck);
5587 } else
5588 return_error(e_typecheck);
5589
5590 /* Following are optional entries */
5591 code = dict_find_string(&ICCdict, "Range", &tempref);
5592 if (code >= 0 && !r_has_type(tempref, t_null)) {
5593 if (!r_is_array(tempref))
5594 return_error(e_typecheck);
5595 if (r_size(tempref) < (components * 2))
5596 return_error(e_rangecheck);
5597 for (i=0;i<components * 2;i++) {
5598 code = array_get(imemory, tempref, i, &valref);
5599 if (code < 0)
5600 return code;
5601 if (!r_has_type(&valref, t_integer) && !r_has_type(&valref, t_real))
5602 return_error(e_typecheck);
5603 }
5604 }
5605 code = dict_find_string(&ICCdict, "Alternate", &tempref);
5606 if (code >= 0 && !r_has_type(tempref, t_null)) {
5607 ref_assign(*r, tempref);
5608 if (r_has_type(tempref, t_name)) {
5609 name_string_ref(imemory, tempref, &sref);
5610 if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
5611 return_error(e_typecheck);
5612 } else {
5613 if (r_is_array(tempref)) {
5614 code = array_get(imemory, tempref, 0, &valref);
5615 if (code < 0)
5616 return code;
5617 if (!r_has_type(&valref, t_name) && !r_has_type(&valref, t_string))
5618 return_error(e_typecheck);
5619 if (r_has_type(&valref, t_name))
5620 name_string_ref(imemory, &valref, &sref);
5621 else
5622 sref.value.bytes = valref.value.bytes;
5623 if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
5624 return_error(e_typecheck);
5625 } else
5626 return_error(e_typecheck);
5627 }
5628 } else {
5629 ref nameref;
5630
5631 switch (components) {
5632 case 1:
5633 code = name_enter_string(imemory, "DeviceGray", &nameref);
5634 break;
5635 case 3:
5636 code = name_enter_string(imemory, "DeviceRGB", &nameref);
5637 break;
5638 case 4:
5639 code = name_enter_string(imemory, "DeviceCMYK", &nameref);
5640 break;
5641 default:
5642 return_error(e_rangecheck);
5643 }
5644 /* In case this space is the /ALternate for a previous ICCBased space
5645 * insert the named space into the ICC dictionary. If we simply returned
5646 * the named space, as before, then we are replacing the second ICCBased
5647 * space in the first ICCBased space with the named space!
5648 */
5649 code = idict_put_string(&ICCdict, "Alternate", &nameref);
5650 if (code < 0)
5651 return code;
5652
5653 /* And now revalidate with the newly updated dictionary */
5654 return validateiccspace(i_ctx_p, r);
5655 }
5656 return code;
5657 }
5658
iccalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)5659 static int iccalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
5660 {
5661 int components, code = 0;
5662 ref *tempref, ICCdict;
5663
5664 if (!r_is_array(space))
5665 return_error(e_typecheck);
5666 /* Validate parameters, check we have enough operands */
5667 if (r_size(space) != 2)
5668 return_error(e_rangecheck);
5669
5670 code = array_get(imemory, space, 1, &ICCdict);
5671 if (code < 0)
5672 return code;
5673
5674 code = dict_find_string(&ICCdict, "N", &tempref);
5675 if (code <= 0)
5676 return code;
5677
5678 components = tempref->value.intval;
5679
5680 code = dict_find_string(&ICCdict, "Alternate", &tempref);
5681 if (code >= 0 && !r_has_type(tempref, t_null)) {
5682 *r = tempref;
5683 } else {
5684 switch (components) {
5685 case 1:
5686 code = name_enter_string(imemory, "DeviceGray", *r);
5687 break;
5688 case 3:
5689 code = name_enter_string(imemory, "DeviceRGB", *r);
5690 break;
5691 case 4:
5692 code = name_enter_string(imemory, "DeviceCMYK", *r);
5693 break;
5694 default:
5695 return_error(e_rangecheck);
5696 }
5697 }
5698 *CIESubst = 1;
5699 return code;
5700 }
icccomponents(i_ctx_t * i_ctx_p,ref * space,int * n)5701 static int icccomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
5702 {
5703 int code = 0;
5704 ref *tempref, ICCdict;
5705
5706 code = array_get(imemory, space, 1, &ICCdict);
5707 if (code < 0)
5708 return code;
5709
5710 code = dict_find_string(&ICCdict, "N", &tempref);
5711 *n = tempref->value.intval;
5712 return 0;
5713 }
iccdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)5714 static int iccdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5715 {
5716 int components, i, code = 0;
5717 ref *tempref, ICCdict, valref;
5718
5719 code = array_get(imemory, space, 1, &ICCdict);
5720 if (code < 0)
5721 return code;
5722 code = dict_find_string(&ICCdict, "N", &tempref);
5723 components = tempref->value.intval;
5724 code = dict_find_string(&ICCdict, "Range", &tempref);
5725 if (code >= 0 && !r_has_type(tempref, t_null)) {
5726 for (i=0;i<components * 2;i++) {
5727 code = array_get(imemory, tempref, i, &valref);
5728 if (code < 0)
5729 return code;
5730 if (r_has_type(&valref, t_integer))
5731 ptr[i * 2] = (float)valref.value.intval;
5732 else
5733 ptr[i * 2] = valref.value.realval;
5734 }
5735 } else {
5736 for (i=0;i<components;i++) {
5737 ptr[i * 2] = 0;
5738 ptr[(i * 2) + 1] = 1;
5739 }
5740 }
5741 return 0;
5742 }
iccrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)5743 static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5744 {
5745 int components, i, code = 0;
5746 ref *tempref, ICCdict, valref;
5747
5748 code = array_get(imemory, space, 1, &ICCdict);
5749 if (code < 0)
5750 return code;
5751 code = dict_find_string(&ICCdict, "N", &tempref);
5752 components = tempref->value.intval;
5753 code = dict_find_string(&ICCdict, "Range", &tempref);
5754 if (code >= 0 && !r_has_type(tempref, t_null)) {
5755 for (i=0;i<components * 2;i++) {
5756 code = array_get(imemory, tempref, i, &valref);
5757 if (code < 0)
5758 return code;
5759 if (r_has_type(&valref, t_integer))
5760 ptr[i] = (float)valref.value.intval;
5761 else
5762 ptr[i] = (float)valref.value.realval;
5763 }
5764 } else {
5765 for (i=0;i<components;i++) {
5766 ptr[i * 2] = 0;
5767 ptr[(i * 2) + 1] = 1;
5768 }
5769 }
5770 return 0;
5771 }
iccbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)5772 static int iccbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5773 {
5774 *stage = 0;
5775 *cont = 1;
5776 return 0;
5777 }
iccvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)5778 static int iccvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5779 {
5780 return 0;
5781 }
5782
dummydomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)5783 static int dummydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5784 {
5785 return 0;
5786 }
dummyrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)5787 static int dummyrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5788 {
5789 return 0;
5790 }
onecomponent(i_ctx_t * i_ctx_p,ref * space,int * n)5791 static int onecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5792 {
5793 *n = 1;
5794 return 0;
5795 }
threecomponent(i_ctx_t * i_ctx_p,ref * space,int * n)5796 static int threecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5797 {
5798 *n = 3;
5799 return 0;
5800 }
fourcomponent(i_ctx_t * i_ctx_p,ref * space,int * n)5801 static int fourcomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5802 {
5803 *n = 4;
5804 return 0;
5805 }
truecompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)5806 static int truecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
5807 {
5808 return 1;
5809 }
falsecompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)5810 static int falsecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
5811 {
5812 return 0;
5813 }
5814
5815 PS_colour_space_t colorProcs[] = {
5816 {(char *)"DeviceGray", setgrayspace, 0, 0, onecomponent, grayrange, graydomain,
5817 graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
5818 {(char *)"DeviceRGB", setrgbspace, 0, 0, threecomponent, rgbrange, rgbdomain,
5819 rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc},
5820 {(char *)"DeviceCMYK", setcmykspace, 0, 0, fourcomponent, cmykrange, cmykdomain,
5821 cmykbasecolor, 0, cmykvalidate, truecompareproc, cmykinitialproc},
5822 {(char *)"CIEBasedA", setcieaspace, validatecieaspace, 0, onecomponent, ciearange, cieadomain,
5823 ciebasecolor, 0, cieavalidate, cieacompareproc, 0},
5824 {(char *)"CIEBasedABC", setcieabcspace, validatecieabcspace, 0, threecomponent, cieabcrange, cieabcdomain,
5825 ciebasecolor, 0, cieabcvalidate, cieabccompareproc, 0},
5826 {(char *)"CIEBasedDEF", setciedefspace, validateciedefspace, 0, threecomponent, ciedefrange, ciedefdomain,
5827 ciebasecolor, 0, ciedefvalidate, ciedefcompareproc, 0},
5828 {(char *)"CIEBasedDEFG", setciedefgspace, validateciedefgspace, 0, fourcomponent, ciedefgrange, ciedefgdomain,
5829 ciebasecolor, 0, ciedefgvalidate, ciedefgcompareproc, 0},
5830 {(char *)"Separation", setseparationspace, validateseparationspace, separationalternatespace, onecomponent, seprange, sepdomain,
5831 sepbasecolor, septransform, sepvalidate, sepcompareproc, sepinitialproc},
5832 {(char *)"DeviceN", setdevicenspace, validatedevicenspace, devicenalternatespace, devicencomponents, devicenrange, devicendomain,
5833 devicenbasecolor, devicentransform, devicenvalidate, devicencompareproc, deviceninitialproc},
5834 {(char *)"Indexed", setindexedspace, validateindexedspace, indexedalternatespace, onecomponent, indexedrange, indexeddomain,
5835 indexedbasecolor, 0, indexedvalidate, falsecompareproc, 0},
5836 {(char *)"Pattern", setpatternspace, validatepatternspace, patternalternatespace, patterncomponent, dummyrange, dummydomain,
5837 patternbasecolor, 0, patternvalidate, falsecompareproc, 0},
5838 {(char *)"DevicePixel", setdevicepspace, validatedevicepspace, 0, onecomponent, deviceprange, devicepdomain,
5839 devicepbasecolor, 0, devicepvalidate, falsecompareproc, 0},
5840 {(char *)"ICCBased", seticcspace, validateiccspace, iccalternatespace, icccomponents, iccrange, iccdomain,
5841 iccbasecolor, 0, iccvalidate, falsecompareproc, 0},
5842 {(char *)"Lab", setlabspace, validatelabspace, 0, threecomponent, labrange, labdomain,
5843 labbasecolor, 0, labvalidate, truecompareproc, 0},
5844 {(char *)"CalGray", setcalgrayspace, validatecalgrayspace, 0, onecomponent, grayrange, graydomain,
5845 graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
5846 {(char *)"CalRGB", setcalrgbspace, validatecalrgbspace, 0, threecomponent, rgbrange, rgbdomain,
5847 rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc}
5848 };
5849
5850 /*
5851 * Given a color space, this finds the appropriate object from the list above
5852 */
get_space_object(i_ctx_t * i_ctx_p,ref * arr,PS_colour_space_t ** obj)5853 int get_space_object(i_ctx_t *i_ctx_p, ref *arr, PS_colour_space_t **obj)
5854 {
5855 ref spacename, nref;
5856 int i, nprocs = sizeof(colorProcs) / sizeof(PS_colour_space_t), code;
5857
5858 /* If the spaece is an array, the first element is always the name */
5859 if (r_is_array(arr))
5860 code = array_get(imemory, arr, 0, &spacename);
5861 else
5862 ref_assign(&spacename, arr);
5863
5864 /* Check that it really is a name */
5865 if (!r_has_type(&spacename, t_name))
5866 return_error(e_typecheck);
5867
5868 /* Find the relevant color space object */
5869 for (i=0;i<nprocs;i++) {
5870 code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)colorProcs[i].name, strlen(colorProcs[i].name), &nref, 0);
5871 if (code < 0)
5872 return code;
5873 if (name_eq(&spacename, &nref)) {
5874 *obj = &colorProcs[i];
5875 return 0;
5876 }
5877 }
5878 return_error(e_undefined);
5879 }
5880 /*
5881 * This routine checks all the color spaces in an operand by
5882 * calling the specific 'validate' method for each in turn. It also
5883 * returns the 'depth' which is the number of nested spaces.
5884 */
validate_spaces(i_ctx_t * i_ctx_p,ref * arr,int * depth)5885 static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth)
5886 {
5887 ref space, *sp = &space;
5888 int code = 0;
5889 PS_colour_space_t *obj;
5890
5891 ref_assign(&space, arr);
5892 *depth = 0;
5893 do {
5894 code = get_space_object(i_ctx_p, sp, &obj);
5895 if (code < 0)
5896 return code;
5897
5898 (*depth)++;
5899 if (!obj->validateproc)
5900 break;
5901
5902 code = obj->validateproc(i_ctx_p, &sp);
5903 if (code < 0)
5904 return code;
5905 }while(sp);
5906 return 0;
5907 }
5908 /*
5909 * The routine which does all the setcolor dispatching. This is initially set up by
5910 * zsetcolor above. Because setcolorspace samples the space and converts the tint
5911 * transform to a function, we don't need to run the PS tint transform in order to
5912 * set the color. However, some applications, notably Photoshop 5 and above, rely
5913 * on the tint transform being executed, so we must do so if the normal PostScript
5914 * processing would result in the tintr transform being executed.
5915 *
5916 * We check each space in turn to see whether we would normally run the tint
5917 * transform, eg Indexed is always executed, Separation and DeviceN only if the
5918 * required ink(s) aren't present in the device. If we discover that any space
5919 * doesn't require a tint transform, then we can short-circuit the processing.
5920 * Otherwise we set up to execute the tint transform.
5921 */
5922 static int
setcolor_cont(i_ctx_t * i_ctx_p)5923 setcolor_cont(i_ctx_t *i_ctx_p)
5924 {
5925 ref arr, *parr = &arr;
5926 es_ptr ep = esp;
5927 int i=0, code = 0,depth, usealternate, stage, stack_depth, CIESubst = 0;
5928 PS_colour_space_t *obj;
5929
5930 stack_depth = (int)ep[-3].value.intval;
5931 depth = (int)ep[-2].value.intval;
5932 stage = (int)ep[-1].value.intval;
5933 /* If we get a continuation from a sub-procedure, we will want to come back
5934 * here afterward, to do any remaining spaces. We need to set up for that now.
5935 * so that our continuation is ahead of the sub-proc's continuation.
5936 */
5937 check_estack(1);
5938 push_op_estack(setcolor_cont);
5939
5940 while (code == 0) {
5941 ref_assign(&arr, ep);
5942 /* Run along the nested color spaces until we get to the first one
5943 * that we haven't yet processed (given by 'depth')
5944 */
5945 for (i=0;i<=depth;i++) {
5946 code = get_space_object(i_ctx_p, parr, &obj);
5947 if (code < 0)
5948 return code;
5949
5950 if (i < (depth)) {
5951 if (!obj->alternateproc) {
5952 return_error(e_typecheck);
5953 }
5954 code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
5955 if (code < 0)
5956 return code;
5957 }
5958 }
5959 if (obj->runtransformproc) {
5960 code = obj->runtransformproc(i_ctx_p, &istate->colorspace[0].array, &usealternate, &stage, &stack_depth);
5961 make_int(&ep[-3], stack_depth);
5962 make_int(&ep[-1], stage);
5963 if (code != 0) {
5964 return code;
5965 }
5966 make_int(&ep[-2], ++depth);
5967 if (!usealternate)
5968 break;
5969 } else
5970 break;
5971 }
5972 /* Remove our next continuation and our data */
5973 obj->numcomponents(i_ctx_p, parr, &i);
5974 pop(i);
5975 esp -= 5;
5976 return o_pop_estack;
5977 }
5978 /*
5979 * The routine which does all the setcolorspace dispatching. This is initially set up by
5980 * zsetcolorspace above. It starts by descending to the bottom-most space
5981 * and setting that as the current space. It then descends the array again
5982 * to the next-to-bottom- space and sets that as the current, and so on.
5983 *
5984 * The 'stage' parameter is passed in to each 'set' method. If a method needs
5985 * to do a continuation itself (eg sample a space) then it should set the stage
5986 * to a non-zero value. When the continuation is complete we return here, and
5987 * attempt to 'set' the same space again. This time stage will be whatever was
5988 * set the first time, which is a signal to the 'set' routine that a continuation
5989 * took place, and is complete. Stage must always be set to 0 when a 'set'
5990 * of a color space is complete.
5991 */
5992 static int
setcolorspace_cont(i_ctx_t * i_ctx_p)5993 setcolorspace_cont(i_ctx_t *i_ctx_p)
5994 {
5995 ref arr, *parr = &arr;
5996 os_ptr op = osp;
5997 es_ptr ep = esp, pdepth, pstage, pCIESubst;
5998 int i, code = 0,depth, stage, cont, CIESubst = 0;
5999 PS_colour_space_t *obj;
6000
6001 pCIESubst = &ep[-3];
6002 pdepth = &ep[-2];
6003 pstage = &ep[-1];
6004
6005 CIESubst = (int)pCIESubst->value.intval;
6006 depth = (int)pdepth->value.intval;
6007 stage = (int)pstage->value.intval;
6008 /* If we get a continuation from a sub-procedure, we will want to come back
6009 * here afterward, to do any remaining stages. We need to set up for that now.
6010 * so that our continuation is ahead of the sub-proc's continuation.
6011 */
6012 check_estack(1);
6013 push_op_estack(setcolorspace_cont);
6014
6015 while (code == 0 && depth) {
6016 ref_assign(&arr, ep);
6017 /* Run along the nested color spaces until we get to the lowest one
6018 * that we haven't yet processed (given by 'depth')
6019 */
6020 for (i = 0;i < depth;i++) {
6021 code = get_space_object(i_ctx_p, parr, &obj);
6022 if (code < 0)
6023 return code;
6024
6025 if (i < (depth - 1)) {
6026 if (!obj->alternateproc) {
6027 return_error(e_typecheck);
6028 }
6029 code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
6030 if (code < 0)
6031 return code;
6032 }
6033 }
6034
6035 code = obj->setproc(i_ctx_p, parr, &stage, &cont, CIESubst);
6036 make_int(pstage, stage);
6037 if (code != 0)
6038 return code;
6039 if (!cont) {
6040 /* Completed that space, decrement the 'depth' */
6041 make_int(pdepth, --depth);
6042 parr = &arr;
6043 }
6044 }
6045 if (code == 0) {
6046 /* Remove our next continuation and our data */
6047 esp -= 5;
6048 op = osp;
6049 istate->colorspace[0].array = *op;
6050 /* Remove the colorspace array form the operand stack */
6051 pop(1);
6052 code = o_pop_estack;
6053 }
6054 return code;
6055 }
6056 /*
6057 * The routine which does all the dispatching for the device-space specific
6058 * operators below (eg setgray). This is initially set up by the routines below.
6059 *
6060 * It would seem unnecessary to have a continuation procedure, because at first
6061 * sight these can only be a single space with no alternate and can't require
6062 * sampling, because they are device space. However if UseCIEColor is true, then
6063 * we will actually use a Default Color Space Array in place of the requested color
6064 * space. These are often CIEBased spaces, and these do need to be sampled. So
6065 * actually we do need a continuation procedure, unfortunately.
6066 *
6067 * Also, we need to set the initial color value after we have set the color space.
6068 */
6069 static int
setdevicecolor_cont(i_ctx_t * i_ctx_p)6070 setdevicecolor_cont(i_ctx_t *i_ctx_p)
6071 {
6072 os_ptr op = osp;
6073 es_ptr ep = esp, pstage;
6074 int code = 0, stage, base;
6075
6076 pstage = ep;
6077 base = (int)ep[-1].value.intval;
6078 stage = (int)pstage->value.intval;
6079 /* If we get a continuation from a sub-procedure, we will want to come back
6080 * here afterward, to do any remaining stages. We need to set up for that now.
6081 * so that our continuation is ahead of the sub-proc's continuation.
6082 */
6083 check_estack(1);
6084 /* May need to push a /Device... name on the stack so make sure we have space */
6085 check_ostack(1);
6086 /* The push_op_estack macro increments esp before use, so we don't need to */
6087 push_op_estack(setdevicecolor_cont);
6088
6089 do {
6090 switch(stage) {
6091 case 0:
6092 make_int(pstage, ++stage);
6093 push(1);
6094 switch(base) {
6095 case 0: /* DeviceGray */
6096 code = name_enter_string(imemory, "DeviceGray", op);
6097 break;
6098 case 1: /* DeviceRGB */
6099 code = name_enter_string(imemory, "DeviceRGB", op);
6100 break;
6101 case 2: /* DeviceCMYK */
6102 code = name_enter_string(imemory, "DeviceCMYK", op);
6103 break;
6104 }
6105 if (code < 0)
6106 return code;
6107 code = zsetcolorspace(i_ctx_p);
6108 if (code != 0)
6109 return code;
6110 break;
6111 case 1:
6112 make_int(pstage, ++stage);
6113 code = zsetcolor(i_ctx_p);
6114 if (code != 0)
6115 return code;
6116 break;
6117 case 2:
6118 esp -= 3;
6119 return o_pop_estack;
6120 break;
6121 }
6122 }while(1);
6123 return 0;
6124 }
6125
6126 /* These routines implement the device-space set color routines
6127 * These set both the space and the color in a single operation.
6128 * Previously these were implemented in PostScript.
6129 */
6130 static int
zsetgray(i_ctx_t * i_ctx_p)6131 zsetgray(i_ctx_t * i_ctx_p)
6132 {
6133 os_ptr op = osp; /* required by "push" macro */
6134 float value;
6135 int code;
6136
6137 /* Gather numeric operand value(s) */
6138 code = float_params(op, 1, &value);
6139 if (code < 0)
6140 return code;
6141 /* Clamp numeric operand range(s) */
6142 if (value < 0)
6143 value = 0;
6144 else if (value > 1)
6145 value = 1;
6146 code = make_floats(op, &value, 1);
6147 if (code < 0)
6148 return code;
6149
6150 /* Set up for the continuation procedure which will do the work */
6151 /* Make sure the exec stack has enough space */
6152 check_estack(5);
6153 push_mark_estack(es_other, colour_cleanup);
6154 esp++;
6155 /* variable to hold base type (0 = gray) */
6156 make_int(esp, 0);
6157 esp++;
6158 /* Store the 'stage' of processing (initially 0) */
6159 make_int(esp, 0);
6160 /* Finally, the actual continuation routine */
6161 push_op_estack(setdevicecolor_cont);
6162 return o_push_estack;
6163 }
6164 static int
zsethsbcolor(i_ctx_t * i_ctx_p)6165 zsethsbcolor(i_ctx_t * i_ctx_p)
6166 {
6167 os_ptr op = osp; /* required by "push" macro */
6168 int code, i;
6169 float values[3];
6170
6171 /* Gather numeric operand value(s) (also checks type) */
6172 code = float_params(op, 3, (float *)&values);
6173 if (code < 0)
6174 return code;
6175 /* Clamp numeric operand range(s) */
6176 for (i = 0;i < 3; i++) {
6177 if (values[i] < 0)
6178 values[i] = 0;
6179 else if (values[i] > 1)
6180 values[i] = 1;
6181 }
6182
6183 hsb2rgb((float *)&values);
6184
6185 code = make_floats(&op[-2], (const float *)&values, 3);
6186 if (code < 0)
6187 return code;
6188
6189 /* Set up for the continuation procedure which will do the work */
6190 /* Make sure the exec stack has enough space */
6191 check_estack(5);
6192 push_mark_estack(es_other, colour_cleanup);
6193 esp++;
6194 /* variable to hold base type (1 = RGB) */
6195 make_int(esp, 1);
6196 esp++;
6197 /* Store the 'stage' of processing (initially 0) */
6198 make_int(esp, 0);
6199 /* Finally, the actual continuation routine */
6200 push_op_estack(setdevicecolor_cont);
6201 return o_push_estack;
6202 }
6203 static int
zsetrgbcolor(i_ctx_t * i_ctx_p)6204 zsetrgbcolor(i_ctx_t * i_ctx_p)
6205 {
6206 os_ptr op = osp; /* required by "push" macro */
6207 int code, i;
6208 float values[3];
6209
6210 /* Gather numeric operand value(s) (also checks type) */
6211 code = float_params(op, 3, (float *)&values);
6212 if (code < 0)
6213 return code;
6214 /* Clamp numeric operand range(s) */
6215 for (i = 0;i < 3; i++) {
6216 if (values[i] < 0)
6217 values[i] = 0;
6218 else if (values[i] > 1)
6219 values[i] = 1;
6220 }
6221
6222 code = make_floats(&op[-2], (const float *)&values, 3);
6223 if (code < 0)
6224 return code;
6225
6226 /* Set up for the continuation procedure which will do the work */
6227 /* Make sure the exec stack has enough space */
6228 check_estack(5);
6229 push_mark_estack(es_other, colour_cleanup);
6230 esp++;
6231 /* variable to hold base type (1 = RGB) */
6232 make_int(esp, 1);
6233 esp++;
6234 /* Store the 'stage' of processing (initially 0) */
6235 make_int(esp, 0);
6236 /* Finally, the actual continuation routine */
6237 push_op_estack(setdevicecolor_cont);
6238 return o_push_estack;
6239 }
6240
6241 static int
zsetcmykcolor(i_ctx_t * i_ctx_p)6242 zsetcmykcolor(i_ctx_t * i_ctx_p)
6243 {
6244 os_ptr op = osp; /* required by "push" macro */
6245 int code, i;
6246 float values[4];
6247
6248 /* Gather numeric operand value(s) (also checks type) */
6249 code = float_params(op, 4, (float *)&values);
6250 if (code < 0)
6251 return code;
6252 /* Clamp numeric operand range(s) */
6253 for (i = 0;i < 4; i++) {
6254 if (values[i] < 0)
6255 values[i] = 0;
6256 else if (values[i] > 1)
6257 values[i] = 1;
6258 }
6259
6260 code = make_floats(&op[-3], (const float *)&values, 4);
6261 if (code < 0)
6262 return code;
6263
6264 /* Set up for the continuation procedure which will do the work */
6265 /* Make sure the exec stack has enough space */
6266 check_estack(5);
6267 push_mark_estack(es_other, colour_cleanup);
6268 esp++;
6269 /* variable to hold base type (2 = CMYK) */
6270 make_int(esp, 2);
6271 esp++;
6272 /* Store the 'stage' of processing (initially 0) */
6273 make_int(esp, 0);
6274 /* Finally, the actual continuation routine */
6275 push_op_estack(setdevicecolor_cont);
6276 return o_push_estack;
6277 }
6278
6279 /*
6280 * The routine which does all the dispatching for the device-space specific
6281 * 'current color' routines currentgray, currentrgbcolo and currentcmykcolor.
6282 *
6283 * Starting with the top-level color space we need to take the current color
6284 * value(s) and pass it through the tint transform procedure (actually we use the
6285 * converted function) to get equivalent components for the next space. We then
6286 * repeat with each alternate space in turn until we reach a 'terminal' space.
6287 * That can be a device space (eg DeviceGray), a CIEBased or ICCBased space, or
6288 * a Separation or DeviceN space which is not using its alternate space.
6289 *
6290 * Depending on which kind of terminal space we reach we will either return
6291 * fixed values (all 0.0) or we will convert the terminal device space components
6292 * into the requested device space.
6293 *
6294 * Because we might need to run a tint transform procedure, this requires a
6295 * continuation procedure.
6296 */
6297 static int
currentbasecolor_cont(i_ctx_t * i_ctx_p)6298 currentbasecolor_cont(i_ctx_t *i_ctx_p)
6299 {
6300 ref arr, *parr = &arr;
6301 es_ptr ep = esp;
6302 int i, code = 0,depth, stage, base, cont=1, stack_depth = 0, CIESubst=0;
6303 PS_colour_space_t *obj;
6304
6305 stack_depth = (int)ep[-4].value.intval;
6306 base = (int)ep[-3].value.intval;
6307 depth = (int)ep[-2].value.intval;
6308 stage = (int)ep[-1].value.intval;
6309 /* If we get a continuation from a sub-procedure, we will want to come back
6310 * here afterward, to do any remaining stages. We need to set up for that now.
6311 * so that our continuation is ahead of the sub-proc's continuation.
6312 */
6313 check_estack(1);
6314 /* The push_op_estack macro increments esp before use, so we don't need to */
6315 push_op_estack(currentbasecolor_cont);
6316
6317 while (code == 0 && cont) {
6318 ref_assign(&arr, ep);
6319 parr = &arr;
6320 /* Run along the nested color spaces until we get to the lowest one
6321 * that we haven't yet processed (given by 'depth')
6322 */
6323 for (i = 0;i < depth;i++) {
6324 code = get_space_object(i_ctx_p, parr, &obj);
6325 if (code < 0)
6326 return code;
6327
6328 if (i < (depth - 1)) {
6329 if (!obj->alternateproc) {
6330 return_error(e_typecheck);
6331 }
6332 code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
6333 if (code < 0)
6334 return code;
6335 }
6336 }
6337
6338 code = obj->basecolorproc(i_ctx_p, parr, base, &stage, &cont, &stack_depth);
6339 make_int(&ep[-4], stack_depth);
6340 make_int(&ep[-1], stage);
6341 if (code != 0)
6342 return code;
6343 /* Completed that space, increment the 'depth' */
6344 make_int(&ep[-2], ++depth);
6345 }
6346 if (code == 0) {
6347 /* Remove our next continuation and our data */
6348 esp -= 7;
6349 code = o_pop_estack;
6350 }
6351 return code;
6352 }
6353
6354 /* These routines implement the device-space 'current' color routines.
6355 * Previously these were implemented in PostScript.
6356 */
6357 static int
zcurrentgray(i_ctx_t * i_ctx_p)6358 zcurrentgray(i_ctx_t * i_ctx_p)
6359 {
6360 int code, depth;
6361
6362 code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
6363 if (code < 0)
6364 return code;
6365
6366 code = zcurrentcolor(i_ctx_p);
6367 if (code < 0)
6368 return code;
6369 /* Set up for the continuation procedure which will do the work */
6370 /* Make sure the exec stack has enough space */
6371 check_estack(7);
6372 push_mark_estack(es_other, colour_cleanup);
6373 esp++;
6374 /* variable to hold stack depth for tint transform */
6375 make_int(&esp[0], 0);
6376 esp++;
6377 /* Store the 'base' type color wanted, in this case Gray */
6378 make_int(&esp[0], 0);
6379 make_int(&esp[1], 1);
6380 /* Store the 'stage' of processing (initially 0) */
6381 make_int(&esp[2], 0);
6382 /* Store a pointer to the color space stored on the operand stack
6383 * as the stack may grow unpredictably making further access
6384 * to the space difficult
6385 */
6386 esp[3] = istate->colorspace[0].array;
6387 esp += 3; /* The push_op_estack macro increments esp before using it */
6388 /* Finally, the actual continuation routine */
6389 push_op_estack(currentbasecolor_cont);
6390 return o_push_estack;
6391 }
6392 static int
zcurrenthsbcolor(i_ctx_t * i_ctx_p)6393 zcurrenthsbcolor(i_ctx_t * i_ctx_p)
6394 {
6395 int code, depth;
6396
6397 code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
6398 if (code < 0)
6399 return code;
6400
6401 code = zcurrentcolor(i_ctx_p);
6402 if (code < 0)
6403 return code;
6404 /* Set up for the continuation procedure which will do the work */
6405 /* Make sure the exec stack has enough space */
6406 check_estack(7);
6407 push_mark_estack(es_other, colour_cleanup);
6408 esp++;
6409 /* variable to hold stack depth for tint transform */
6410 make_int(&esp[0], 0);
6411 esp++;
6412 /* Store the 'base' type color wanted, in this case HSB */
6413 make_int(&esp[0], 1);
6414 make_int(&esp[1], 1);
6415 /* Store the 'stage' of processing (initially 0) */
6416 make_int(&esp[2], 0);
6417 /* Store a pointer to the color space stored on the operand stack
6418 * as the stack may grow unpredictably making further access
6419 * to the space difficult
6420 */
6421 esp[3] = istate->colorspace[0].array;
6422 esp += 3; /* The push_op_estack macro increments esp before using it */
6423 /* Finally, the actual continuation routine */
6424 push_op_estack(currentbasecolor_cont);
6425 return o_push_estack;
6426 }
6427 static int
zcurrentrgbcolor(i_ctx_t * i_ctx_p)6428 zcurrentrgbcolor(i_ctx_t * i_ctx_p)
6429 {
6430 int code;
6431
6432 code = zcurrentcolor(i_ctx_p);
6433 if (code < 0)
6434 return code;
6435 /* Set up for the continuation procedure which will do the work */
6436 /* Make sure the exec stack has enough space */
6437 check_estack(7);
6438 push_mark_estack(es_other, colour_cleanup);
6439 esp++;
6440 /* variable to hold stack depth for tint transform */
6441 make_int(&esp[0], 0);
6442 esp++;
6443 /* Store the 'base' type color wanted, in this case RGB */
6444 make_int(&esp[0], 2);
6445 make_int(&esp[1], 1);
6446 /* Store the 'stage' of processing (initially 0) */
6447 make_int(&esp[2], 0);
6448 /* Store a pointer to the color space stored on the operand stack
6449 * as the stack may grow unpredictably making further access
6450 * to the space difficult
6451 */
6452 esp[3] = istate->colorspace[0].array;
6453 esp += 3; /* The push_op_estack macro increments esp before using it */
6454 /* Finally, the actual continuation routine */
6455 push_op_estack(currentbasecolor_cont);
6456 return o_push_estack;
6457 }
6458 static int
zcurrentcmykcolor(i_ctx_t * i_ctx_p)6459 zcurrentcmykcolor(i_ctx_t * i_ctx_p)
6460 {
6461 int code;
6462
6463 code = zcurrentcolor(i_ctx_p);
6464 if (code < 0)
6465 return code;
6466 /* Set up for the continuation procedure which will do the work */
6467 /* Make sure the exec stack has enough space */
6468 check_estack(7);
6469 push_mark_estack(es_other, colour_cleanup);
6470 esp++;
6471 /* variable to hold stack depth for tint transform */
6472 make_int(&esp[0], 0);
6473 esp++;
6474 /* Store the 'base' type color wanted, in this case CMYK */
6475 make_int(&esp[0], 3);
6476 make_int(&esp[1], 1);
6477 /* Store the 'stage' of processing (initially 0) */
6478 make_int(&esp[2], 0);
6479 /* Store a pointer to the color space stored on the operand stack
6480 * as the stack may grow unpredictably making further access
6481 * to the space difficult
6482 */
6483 esp[3] = istate->colorspace[0].array;
6484 esp += 3; /* The push_op_estack macro increments esp before using it */
6485 /* Finally, the actual continuation routine */
6486 push_op_estack(currentbasecolor_cont);
6487 return o_push_estack;
6488 }
6489
6490 static int
zswapcolors(i_ctx_t * i_ctx_p)6491 zswapcolors(i_ctx_t * i_ctx_p)
6492 {
6493 ref_colorspace tmp_cs;
6494 ref tmp_pat;
6495
6496 tmp_cs = istate->colorspace[0];
6497 istate->colorspace[0] = istate->colorspace[1];
6498 istate->colorspace[1] = tmp_cs;
6499
6500 tmp_pat = istate->pattern[0];
6501 istate->pattern[0] = istate->pattern[1];
6502 istate->pattern[1] = tmp_pat;
6503
6504 return gs_swapcolors(igs);
6505 }
6506
6507 /* ------ Initialization procedure ------ */
6508
6509 /* We need to split the table because of the 16-element limit. */
6510 const op_def zcolor_op_defs[] =
6511 {
6512 { "0currentcolor", zcurrentcolor },
6513 { "0currentcolorspace", zcurrentcolorspace },
6514 { "0.getuseciecolor", zgetuseciecolor },
6515 { "1setcolor", zsetcolor },
6516 { "1setcolorspace", zsetcolorspace },
6517
6518 /* basic transfer operators */
6519 { "0currenttransfer", zcurrenttransfer },
6520 { "0processcolors", zprocesscolors },
6521 { "1settransfer", zsettransfer },
6522
6523 /* internal operators */
6524 { "1%zcolor_remap_one_finish", zcolor_remap_one_finish },
6525 { "1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish },
6526 { "0%zcolor_reset_transfer", zcolor_reset_transfer },
6527 { "0%zcolor_remap_color", zcolor_remap_color },
6528 { "0.color_test", zcolor_test },
6529 { "1.color_test_all", zcolor_test_all },
6530
6531 /* high level device support */
6532 { "0.includecolorspace", zincludecolorspace },
6533 op_def_end(0)
6534 };
6535
6536 const op_def zcolor_ext_op_defs[] =
6537 {
6538 { "0currentgray", zcurrentgray },
6539 { "1setgray", zsetgray },
6540 { "0currenthsbcolor", zcurrenthsbcolor },
6541 { "3sethsbcolor", zsethsbcolor },
6542 { "0currentrgbcolor", zcurrentrgbcolor },
6543 { "3setrgbcolor", zsetrgbcolor },
6544 { "0currentcmykcolor", zcurrentcmykcolor },
6545 { "4setcmykcolor", zsetcmykcolor },
6546
6547 /* Operators to deal with setting stroking/non-stroking colors
6548 * individually */
6549 { "1.swapcolors", zswapcolors },
6550
6551 /* internal operators, entries here only used for error reporting */
6552 { "0%setcolorspace_cont", setcolorspace_cont },
6553 { "0%setcolor_cont", setcolor_cont },
6554 { "0%devicencolorants_cont", devicencolorants_cont },
6555 { "0%indexed_cont", indexed_cont },
6556 { "0%setdevicecolor_cont", setdevicecolor_cont },
6557 { "0%currentbasecolor_cont", currentbasecolor_cont },
6558 op_def_end(0)
6559 };
6560