1 /* Copyright (C) 1993, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: zcsindex.c,v 1.3.6.1.2.1 2003/01/17 00:49:05 giles Exp $ */
20 /* Indexed color space support */
21 #include "memory_.h"
22 #include "ghost.h"
23 #include "oper.h"
24 #include "gsstruct.h"
25 #include "gscolor.h"
26 #include "gsmatrix.h"		/* for gxcolor2.h */
27 #include "gxcspace.h"
28 #include "gxfixed.h"		/* ditto */
29 #include "gxcolor2.h"
30 #include "estack.h"
31 #include "ialloc.h"
32 #include "icsmap.h"
33 #include "igstate.h"
34 #include "ivmspace.h"
35 #include "store.h"
36 
37 /* Imported from gscolor2.c */
38 extern const gs_color_space_type gs_color_space_type_Indexed;
39 
40 /* Forward references. */
41 private int indexed_map1(P1(i_ctx_t *));
42 
43 /* <array> .setindexedspace - */
44 /* The current color space is the base space for the indexed space. */
45 private int
zsetindexedspace(i_ctx_t * i_ctx_p)46 zsetindexedspace(i_ctx_t *i_ctx_p)
47 {
48     os_ptr op = osp;
49     ref *pproc = &istate->colorspace.procs.special.index_proc;
50     const ref *pcsa;
51     gs_color_space cs;
52     ref_colorspace cspace_old;
53     uint edepth = ref_stack_count(&e_stack);
54     int num_entries;
55     int code;
56 
57     check_read_type(*op, t_array);
58     if (r_size(op) != 4)
59 	return_error(e_rangecheck);
60     pcsa = op->value.const_refs + 1;
61     check_type_only(pcsa[1], t_integer);
62     if (pcsa[1].value.intval < 0 || pcsa[1].value.intval > 4095)
63 	return_error(e_rangecheck);
64     num_entries = (int)pcsa[1].value.intval + 1;
65     cs = *gs_currentcolorspace(igs);
66     if (!cs.type->can_be_base_space)
67 	return_error(e_rangecheck);
68     cspace_old = istate->colorspace;
69     /*
70      * We can't count on C compilers to recognize the aliasing
71      * that would be involved in a direct assignment.
72      * Formerly, we used the following code:
73 	 cs_base = *(gs_direct_color_space *)&cs;
74 	 cs.params.indexed.base_space = cs_base;
75      * But the Watcom C 10.0 compiler is too smart: it turns this into
76      * a direct assignment (and compiles incorrect code for it),
77      * defeating our purpose.  Instead, we have to do it by brute force
78      * using memmove.
79      */
80     if (r_has_type(&pcsa[2], t_string)) {
81 	int num_values = num_entries * cs_num_components(&cs);
82 
83 	check_read(pcsa[2]);
84 	if (r_size(&pcsa[2]) != num_values)
85 	    return_error(e_rangecheck);
86 	memmove(&cs.params.indexed.base_space, &cs,
87 		sizeof(cs.params.indexed.base_space));
88 	gs_cspace_init(&cs, &gs_color_space_type_Indexed, NULL);
89 	cs.params.indexed.lookup.table.data = pcsa[2].value.const_bytes;
90 	cs.params.indexed.lookup.table.size = num_values;
91 	cs.params.indexed.use_proc = 0;
92 	make_null(pproc);
93 	code = 0;
94     } else {
95 	gs_indexed_map *map;
96 
97 	check_proc(pcsa[2]);
98 	/*
99 	 * We have to call zcs_begin_map before moving the parameters,
100 	 * since if the color space is a DeviceN or Separation space,
101 	 * the memmove will overwrite its parameters.
102 	 */
103 	code = zcs_begin_map(i_ctx_p, &map, &pcsa[2], num_entries,
104 			     (const gs_direct_color_space *)&cs,
105 			     indexed_map1);
106 	if (code < 0)
107 	    return code;
108 	memmove(&cs.params.indexed.base_space, &cs,
109 		sizeof(cs.params.indexed.base_space));
110 	gs_cspace_init(&cs, &gs_color_space_type_Indexed, NULL);
111 	cs.params.indexed.use_proc = 1;
112 	*pproc = pcsa[2];
113 	map->proc.lookup_index = lookup_indexed_map;
114 	cs.params.indexed.lookup.map = map;
115     }
116     cs.params.indexed.hival = num_entries - 1;
117     code = gs_setcolorspace(igs, &cs);
118     if (code < 0) {
119 	istate->colorspace = cspace_old;
120 	ref_stack_pop_to(&e_stack, edepth);
121 	return code;
122     }
123     pop(1);
124     return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);	/* installation will load the caches */
125 }
126 
127 /* Continuation procedure for saving mapped Indexed color values. */
128 private int
indexed_map1(i_ctx_t * i_ctx_p)129 indexed_map1(i_ctx_t *i_ctx_p)
130 {
131     os_ptr op = osp;
132     es_ptr ep = esp;
133     int i = (int)ep[csme_index].value.intval;
134 
135     if (i >= 0) {		/* i.e., not first time */
136 	int m = (int)ep[csme_num_components].value.intval;
137 	int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
138 
139 	if (code < 0)
140 	    return code;
141 	pop(m);
142 	op -= m;
143 	if (i == (int)ep[csme_hival].value.intval) {	/* All done. */
144 	    esp -= num_csme;
145 	    return o_pop_estack;
146 	}
147     }
148     push(1);
149     ep[csme_index].value.intval = ++i;
150     make_int(op, i);
151     make_op_estack(ep + 1, indexed_map1);
152     ep[2] = ep[csme_proc];	/* lookup proc */
153     esp = ep + 2;
154     return o_push_estack;
155 }
156 
157 /* ------ Initialization procedure ------ */
158 
159 const op_def zcsindex_l2_op_defs[] =
160 {
161     op_def_begin_level2(),
162     {"1.setindexedspace", zsetindexedspace},
163 		/* Internal operators */
164     {"1%indexed_map1", indexed_map1},
165     op_def_end(0)
166 };
167 
168 /* ------ Internal routines ------ */
169 
170 /* Allocate, and prepare to load, the index or tint map. */
171 int
zcs_begin_map(i_ctx_t * i_ctx_p,gs_indexed_map ** pmap,const ref * pproc,int num_entries,const gs_direct_color_space * base_space,op_proc_t map1)172 zcs_begin_map(i_ctx_t *i_ctx_p, gs_indexed_map ** pmap, const ref * pproc,
173 	      int num_entries,  const gs_direct_color_space * base_space,
174 	      op_proc_t map1)
175 {
176     gs_memory_t *mem = gs_state_memory(igs);
177     int space = imemory_space((gs_ref_memory_t *)mem);
178     int num_components =
179 	cs_num_components((const gs_color_space *)base_space);
180     int num_values = num_entries * num_components;
181     gs_indexed_map *map;
182     int code = alloc_indexed_map(&map, num_values, mem,
183 				 "setcolorspace(mapped)");
184     es_ptr ep;
185 
186     if (code < 0)
187 	return code;
188     /* Set the reference count to 0 rather than 1. */
189     rc_init_free(map, mem, 0, free_indexed_map);
190     *pmap = map;
191     /* Map the entire set of color indices.  Since the */
192     /* o-stack may not be able to hold N*4096 values, we have */
193     /* to load them into the cache as they are generated. */
194     check_estack(num_csme + 1);	/* 1 extra for map1 proc */
195     ep = esp += num_csme;
196     make_int(ep + csme_num_components, num_components);
197     make_struct(ep + csme_map, space, map);
198     ep[csme_proc] = *pproc;
199     make_int(ep + csme_hival, num_entries - 1);
200     make_int(ep + csme_index, -1);
201     push_op_estack(map1);
202     return o_push_estack;
203 }
204