xref: /plan9/sys/src/cmd/gs/src/gspcolor.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gspcolor.c,v 1.14 2004/08/04 19:36:12 stefan Exp $ */
18 /* Pattern color operators and procedures for Ghostscript library */
19 #include "math_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsrop.h"
23 #include "gsstruct.h"
24 #include "gsutil.h"		/* for gs_next_ids */
25 #include "gxarith.h"
26 #include "gxfixed.h"
27 #include "gxmatrix.h"
28 #include "gxcoord.h"		/* for gs_concat, gx_tr'_to_fixed */
29 #include "gxcspace.h"		/* for gscolor2.h */
30 #include "gxcolor2.h"
31 #include "gxdcolor.h"
32 #include "gxdevice.h"
33 #include "gxdevmem.h"
34 #include "gxclip2.h"
35 #include "gspath.h"
36 #include "gxpath.h"
37 #include "gxpcolor.h"
38 #include "gzstate.h"
39 #include "gsimage.h"
40 #include "gsiparm4.h"
41 #include "stream.h"
42 
43 /* GC descriptors */
44 public_st_pattern_template();
45 public_st_pattern_instance();
46 
47 /* Define the Pattern color space. */
48 gs_private_st_composite(st_color_space_Pattern, gs_paint_color_space,
49      "gs_color_space_Pattern", cs_Pattern_enum_ptrs, cs_Pattern_reloc_ptrs);
50 private cs_proc_num_components(gx_num_components_Pattern);
51 private cs_proc_base_space(gx_base_space_Pattern);
52 private cs_proc_remap_color(gx_remap_Pattern);
53 private cs_proc_init_color(gx_init_Pattern);
54 private cs_proc_restrict_color(gx_restrict_Pattern);
55 private cs_proc_install_cspace(gx_install_Pattern);
56 private cs_proc_set_overprint(gx_set_overprint_Pattern);
57 private cs_proc_adjust_cspace_count(gx_adjust_cspace_Pattern);
58 private cs_proc_adjust_color_count(gx_adjust_color_Pattern);
59 private cs_proc_serialize(gx_serialize_Pattern);
60 const gs_color_space_type gs_color_space_type_Pattern = {
61     gs_color_space_index_Pattern, false, false,
62     &st_color_space_Pattern, gx_num_components_Pattern,
63     gx_base_space_Pattern,
64     gx_init_Pattern, gx_restrict_Pattern,
65     gx_no_concrete_space,
66     gx_no_concretize_color, NULL,
67     gx_remap_Pattern, gx_install_Pattern,
68     gx_set_overprint_Pattern,
69     gx_adjust_cspace_Pattern, gx_adjust_color_Pattern,
70     gx_serialize_Pattern,
71     gx_cspace_no_linear
72 };
73 
74 /* Initialize a generic pattern template. */
75 void
gs_pattern_common_init(gs_pattern_template_t * ppat,const gs_pattern_type_t * type)76 gs_pattern_common_init(gs_pattern_template_t * ppat,
77 		       const gs_pattern_type_t *type)
78 {
79     ppat->type = type;
80     ppat->PatternType = type->PatternType;
81     uid_set_invalid(&ppat->uid);
82     ppat->client_data = 0;	/* for GC */
83 }
84 
85 /* Generic makepattern */
86 int
gs_make_pattern(gs_client_color * pcc,const gs_pattern_template_t * pcp,const gs_matrix * pmat,gs_state * pgs,gs_memory_t * mem)87 gs_make_pattern(gs_client_color * pcc, const gs_pattern_template_t * pcp,
88 		const gs_matrix * pmat, gs_state * pgs, gs_memory_t * mem)
89 {
90     return pcp->type->procs.make_pattern(pcc, pcp, pmat, pgs, mem);
91 }
92 
93 /*
94  * Do the generic work for makepattern: allocate the instance and the
95  * saved graphics state, and fill in the common members.
96  */
97 int
gs_make_pattern_common(gs_client_color * pcc,const gs_pattern_template_t * ptemp,const gs_matrix * pmat,gs_state * pgs,gs_memory_t * mem,gs_memory_type_ptr_t pstype)98 gs_make_pattern_common(gs_client_color *pcc,
99 		       const gs_pattern_template_t *ptemp,
100 		       const gs_matrix *pmat, gs_state *pgs, gs_memory_t *mem,
101 		       gs_memory_type_ptr_t pstype)
102 {
103     gs_pattern_instance_t *pinst;
104     gs_state *saved;
105 
106     if (mem == 0)
107 	mem = gs_state_memory(pgs);
108     rc_alloc_struct_1(pinst, gs_pattern_instance_t, pstype, mem,
109 		      return_error(gs_error_VMerror),
110 		      "gs_make_pattern_common");
111     pinst->rc.free = rc_free_pattern_instance;
112     pinst->type = ptemp->type;
113     saved = gs_state_copy(pgs, mem);
114     if (saved == 0) {
115 	gs_free_object(mem, pinst, "gs_make_pattern_common");
116 	return_error(gs_error_VMerror);
117     }
118     gs_concat(saved, pmat);
119     gs_newpath(saved);
120     pinst->saved = saved;
121     pcc->pattern = pinst;
122     pcc->pattern->pattern_id = gs_next_ids(mem, 1);
123     return 0;
124 }
125 
126 /* Free the saved gstate when freeing a Pattern instance. */
127 void
rc_free_pattern_instance(gs_memory_t * mem,void * pinst_void,client_name_t cname)128 rc_free_pattern_instance(gs_memory_t * mem, void *pinst_void,
129 			 client_name_t cname)
130 {
131     gs_pattern_instance_t *pinst = pinst_void;
132 
133     gs_state_free(pinst->saved);
134     rc_free_struct_only(mem, pinst_void, cname);
135 }
136 
137 /* setpattern */
138 int
gs_setpattern(gs_state * pgs,const gs_client_color * pcc)139 gs_setpattern(gs_state * pgs, const gs_client_color * pcc)
140 {
141     int code = gs_setpatternspace(pgs);
142 
143     if (code < 0)
144 	return code;
145     return gs_setcolor(pgs, pcc);
146 }
147 
148 /* setpatternspace */
149 /* This does all the work of setpattern except for the final setcolor. */
150 int
gs_setpatternspace(gs_state * pgs)151 gs_setpatternspace(gs_state * pgs)
152 {
153     int code = 0;
154 
155     if (pgs->in_cachedevice)
156 	return_error(gs_error_undefined);
157     if (pgs->color_space->type->index != gs_color_space_index_Pattern) {
158 	gs_color_space cs;
159 
160 	gs_cspace_init(&cs, &gs_color_space_type_Pattern, pgs->memory, false);
161 	/**************** base_space SETTING IS WRONG ****************/
162 	cs.params.pattern.base_space =
163 	    *(gs_paint_color_space *) pgs->color_space;
164 	cs.params.pattern.has_base_space = true;
165 	*pgs->color_space = cs;
166 	cs_full_init_color(pgs->ccolor, &cs);
167 	gx_unset_dev_color(pgs);
168     }
169     return code;
170 }
171 
172 /*
173  * Adjust the reference count of a pattern. This is intended to support
174  * applications (such as PCL) which maintain client colors outside of the
175  * graphic state. Since the pattern instance structure is opaque to these
176  * applications, they need some way to release or retain the instances as
177  * needed.
178  */
179 void
gs_pattern_reference(gs_client_color * pcc,int delta)180 gs_pattern_reference(gs_client_color * pcc, int delta)
181 {
182     if (pcc->pattern != 0)
183         rc_adjust(pcc->pattern, delta, "gs_pattern_reference");
184 }
185 
186 /* getpattern */
187 /* This is only intended for the benefit of pattern PaintProcs. */
188 const gs_pattern_template_t *
gs_get_pattern(const gs_client_color * pcc)189 gs_get_pattern(const gs_client_color * pcc)
190 {
191     const gs_pattern_instance_t *pinst = pcc->pattern;
192 
193     return (pinst == 0 ? 0 : pinst->type->procs.get_pattern(pinst));
194 }
195 
196 /*
197  * Get the number of components in a Pattern color.
198  * For backward compatibility, and to distinguish Pattern color spaces
199  * from all others, we negate the result.
200  */
201 private int
gx_num_components_Pattern(const gs_color_space * pcs)202 gx_num_components_Pattern(const gs_color_space * pcs)
203 {
204     return
205 	(pcs->params.pattern.has_base_space ?
206 	 -1 - cs_num_components((const gs_color_space *)
207 				&(pcs->params.pattern.base_space)) :
208 	 -1 /* Pattern dictionary only */ );
209 }
210 
211 /* Get the base space of a Pattern color space. */
212 private const gs_color_space *
gx_base_space_Pattern(const gs_color_space * pcs)213 gx_base_space_Pattern(const gs_color_space * pcs)
214 {
215     return
216 	(pcs->params.pattern.has_base_space ?
217 	 (const gs_color_space *)&(pcs->params.pattern.base_space) :
218 	 NULL);
219 }
220 
221 /* Remap a Pattern color. */
222 private int
gx_remap_Pattern(const gs_client_color * pc,const gs_color_space * pcs,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)223 gx_remap_Pattern(const gs_client_color * pc, const gs_color_space * pcs,
224 		 gx_device_color * pdc, const gs_imager_state * pis,
225 		 gx_device * dev, gs_color_select_t select)
226 {
227     if (pc->pattern == 0) {
228         pdc->ccolor_valid = false;
229 	color_set_null_pattern(pdc);
230 	return 0;
231     }
232     return
233 	pc->pattern->type->procs.remap_color(pc, pcs, pdc, pis, dev, select);
234 }
235 
236 /* Initialize a Pattern color. */
237 private void
gx_init_Pattern(gs_client_color * pcc,const gs_color_space * pcs)238 gx_init_Pattern(gs_client_color * pcc, const gs_color_space * pcs)
239 {
240     if (pcs->params.pattern.has_base_space) {
241 	const gs_color_space *pbcs =
242 	(const gs_color_space *)&pcs->params.pattern.base_space;
243 
244 	cs_init_color(pcc, pbcs);
245     }
246     /*pcc->pattern = 0; *//* cs_full_init_color handles this */
247 }
248 
249 /* Force a Pattern color into legal range. */
250 /* Note that if the pattern is uncolored (PaintType = 2), */
251 /* the color space must have a base space: we check this here only */
252 /* to prevent accessing uninitialized data, but if there is no base space, */
253 /* it is an error that we count on being detected elsewhere. */
254 private void
gx_restrict_Pattern(gs_client_color * pcc,const gs_color_space * pcs)255 gx_restrict_Pattern(gs_client_color * pcc, const gs_color_space * pcs)
256 {
257     /* We need a special check for the null pattern. */
258     if (pcc->pattern &&
259 	pcc->pattern->type->procs.uses_base_space(gs_get_pattern(pcc)) &&
260 	pcs->params.pattern.has_base_space
261 	) {
262 	const gs_color_space *pbcs =
263 	    (const gs_color_space *)&pcs->params.pattern.base_space;
264 
265 	(*pbcs->type->restrict_color) (pcc, pbcs);
266     }
267 }
268 
269 /* Install a Pattern color space. */
270 private int
gx_install_Pattern(const gs_color_space * pcs,gs_state * pgs)271 gx_install_Pattern(const gs_color_space * pcs, gs_state * pgs)
272 {
273     if (!pcs->params.pattern.has_base_space)
274 	return 0;
275     return (*pcs->params.pattern.base_space.type->install_cspace)
276 	((const gs_color_space *) & pcs->params.pattern.base_space, pgs);
277 }
278 
279 /*
280  * Set the overprint compositor for a Pattern color space. This does nothing;
281  * for patterns the overprint compositor is set at set_device_color time.
282 */
283 private int
gx_set_overprint_Pattern(const gs_color_space * pcs,gs_state * pgs)284 gx_set_overprint_Pattern(const gs_color_space * pcs, gs_state * pgs)
285 {
286     return 0;
287 }
288 
289 /* Adjust the reference counts for Pattern color spaces or colors. */
290 private void
gx_adjust_cspace_Pattern(const gs_color_space * pcs,int delta)291 gx_adjust_cspace_Pattern(const gs_color_space * pcs, int delta)
292 {
293     if (pcs->params.pattern.has_base_space)
294 	(*pcs->params.pattern.base_space.type->adjust_cspace_count)
295 	    ((const gs_color_space *)&pcs->params.pattern.base_space, delta);
296 }
297 
298 private void
gx_adjust_color_Pattern(const gs_client_color * pcc,const gs_color_space * pcs,int delta)299 gx_adjust_color_Pattern(const gs_client_color * pcc,
300 			const gs_color_space * pcs, int delta)
301 {
302     gs_pattern_instance_t *pinst = pcc->pattern;
303 
304     rc_adjust_only(pinst, delta, "gx_adjust_color_Pattern");
305     if (pcs && pcs->params.pattern.has_base_space)
306 	(*pcs->params.pattern.base_space.type->adjust_color_count)
307 	    (pcc, (const gs_color_space *)&pcs->params.pattern.base_space,
308 	     delta);
309 }
310 
311 /* GC procedures */
312 
313 private
ENUM_PTRS_BEGIN_PROC(cs_Pattern_enum_ptrs)314 ENUM_PTRS_BEGIN_PROC(cs_Pattern_enum_ptrs)
315 {
316     EV_CONST gs_color_space *const pcs = vptr;
317 
318     if (!pcs->params.pattern.has_base_space)
319 	return 0;
320     return ENUM_USING(*pcs->params.pattern.base_space.type->stype,
321 		      &pcs->params.pattern.base_space,
322 		      sizeof(pcs->params.pattern.base_space), index);
323 }
324 ENUM_PTRS_END_PROC
RELOC_PTRS_WITH(cs_Pattern_reloc_ptrs,gs_color_space * pcs)325 private RELOC_PTRS_WITH(cs_Pattern_reloc_ptrs, gs_color_space *pcs)
326 {
327     if (!pcs->params.pattern.has_base_space)
328 	return;
329     RELOC_USING(*pcs->params.pattern.base_space.type->stype,
330 		&pcs->params.pattern.base_space,
331 		sizeof(gs_paint_color_space));
332 }
333 RELOC_PTRS_END
334 
335 /* ---------------- Serialization. -------------------------------- */
336 
337 private int
gx_serialize_Pattern(const gs_color_space * pcs,stream * s)338 gx_serialize_Pattern(const gs_color_space * pcs, stream * s)
339 {
340     const gs_pattern_params * p = &pcs->params.pattern;
341     uint n;
342     int code = gx_serialize_cspace_type(pcs, s);
343 
344     if (code < 0)
345 	return code;
346     code = sputs(s, (byte *)&p->has_base_space, sizeof(p->has_base_space), &n);
347     if (code < 0)
348 	return code;
349     if (!p->has_base_space)
350 	return 0;
351     return cs_serialize((const gs_color_space *)&p->base_space, s);
352 }
353