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