1 /* Copyright (C) 1994, 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: zpcolor.c,v 1.15 2004/08/04 19:36:13 stefan Exp $ */
18 /* Pattern color */
19 #include "ghost.h"
20 #include "oper.h"
21 #include "gscolor.h"
22 #include "gsmatrix.h"
23 #include "gsstruct.h"
24 #include "gscoord.h"
25 #include "gxcspace.h"
26 #include "gxfixed.h" /* for gxcolor2.h */
27 #include "gxcolor2.h"
28 #include "gxdcolor.h" /* for gxpcolor.h */
29 #include "gxdevice.h"
30 #include "gxdevmem.h" /* for gxpcolor.h */
31 #include "gxpcolor.h"
32 #include "gxpath.h"
33 #include "estack.h"
34 #include "ialloc.h"
35 #include "icremap.h"
36 #include "istruct.h"
37 #include "idict.h"
38 #include "idparam.h"
39 #include "igstate.h"
40 #include "ipcolor.h"
41 #include "store.h"
42 #include "gzstate.h"
43 #include "memory_.h"
44
45 /* Imported from gspcolor.c */
46 extern const gs_color_space_type gs_color_space_type_Pattern;
47
48 /* Forward references */
49 private int zPaintProc(const gs_client_color *, gs_state *);
50 private int pattern_paint_prepare(i_ctx_t *);
51 private int pattern_paint_finish(i_ctx_t *);
52
53 /* GC descriptors */
54 private_st_int_pattern();
55
56 /* Initialize the Pattern cache. */
57 private int
zpcolor_init(i_ctx_t * i_ctx_p)58 zpcolor_init(i_ctx_t *i_ctx_p)
59 {
60 gstate_set_pattern_cache(igs,
61 gx_pattern_alloc_cache(imemory_system,
62 gx_pat_cache_default_tiles(),
63 gx_pat_cache_default_bits()));
64 return 0;
65 }
66
67 /* Create an interpreter pattern structure. */
68 int
int_pattern_alloc(int_pattern ** ppdata,const ref * op,gs_memory_t * mem)69 int_pattern_alloc(int_pattern **ppdata, const ref *op, gs_memory_t *mem)
70 {
71 int_pattern *pdata =
72 gs_alloc_struct(mem, int_pattern, &st_int_pattern, "int_pattern");
73
74 if (pdata == 0)
75 return_error(e_VMerror);
76 pdata->dict = *op;
77 *ppdata = pdata;
78 return 0;
79 }
80
81 /* <pattern> <matrix> .buildpattern1 <pattern> <instance> */
82 private int
zbuildpattern1(i_ctx_t * i_ctx_p)83 zbuildpattern1(i_ctx_t *i_ctx_p)
84 {
85 os_ptr op = osp;
86 os_ptr op1 = op - 1;
87 int code;
88 gs_matrix mat;
89 float BBox[4];
90 gs_client_pattern template;
91 int_pattern *pdata;
92 gs_client_color cc_instance;
93 ref *pPaintProc;
94
95 check_type(*op1, t_dictionary);
96 check_dict_read(*op1);
97 gs_pattern1_init(&template);
98 if ((code = read_matrix(imemory, op, &mat)) < 0 ||
99 (code = dict_uid_param(op1, &template.uid, 1, imemory, i_ctx_p)) != 1 ||
100 (code = dict_int_param(op1, "PaintType", 1, 2, 0, &template.PaintType)) < 0 ||
101 (code = dict_int_param(op1, "TilingType", 1, 3, 0, &template.TilingType)) < 0 ||
102 (code = dict_floats_param(imemory, op1, "BBox", 4, BBox, NULL)) < 0 ||
103 (code = dict_float_param(op1, "XStep", 0.0, &template.XStep)) != 0 ||
104 (code = dict_float_param(op1, "YStep", 0.0, &template.YStep)) != 0 ||
105 (code = dict_find_string(op1, "PaintProc", &pPaintProc)) <= 0
106 )
107 return_error((code < 0 ? code : e_rangecheck));
108 check_proc(*pPaintProc);
109 template.BBox.p.x = BBox[0];
110 template.BBox.p.y = BBox[1];
111 template.BBox.q.x = BBox[2];
112 template.BBox.q.y = BBox[3];
113 template.PaintProc = zPaintProc;
114 code = int_pattern_alloc(&pdata, op1, imemory);
115 if (code < 0)
116 return code;
117 template.client_data = pdata;
118 code = gs_makepattern(&cc_instance, &template, &mat, igs, imemory);
119 if (code < 0) {
120 ifree_object(pdata, "int_pattern");
121 return code;
122 }
123 make_istruct(op, a_readonly, cc_instance.pattern);
124 return code;
125 }
126
127 /* <array> .setpatternspace - */
128 /* In the case of uncolored patterns, the current color space is */
129 /* the base space for the pattern space. */
130 private int
zsetpatternspace(i_ctx_t * i_ctx_p)131 zsetpatternspace(i_ctx_t *i_ctx_p)
132 {
133 os_ptr op = osp;
134 gs_color_space cs;
135 uint edepth = ref_stack_count(&e_stack);
136 int code;
137
138 if (!r_is_array(op))
139 return_error(e_typecheck);
140 check_read(*op);
141 switch (r_size(op)) {
142 case 1: /* no base space */
143 cs.params.pattern.has_base_space = false;
144 break;
145 default:
146 return_error(e_rangecheck);
147 case 2:
148 cs = *gs_currentcolorspace(igs);
149 if (cs_num_components(&cs) < 0) /* i.e., Pattern space */
150 return_error(e_rangecheck);
151 {
152 /* We can't count on C compilers to recognize the aliasing */
153 /* that would be involved in a direct assignment */
154 /* cs.params.pattern.base_space = *(gs_paint_color_space *)&cs; */
155 /* At least MSVC7 chocks with it. */
156 memmove(&cs.params.pattern.base_space, &cs, sizeof(gs_paint_color_space));
157 }
158 cs.params.pattern.has_base_space = true;
159 }
160 gs_cspace_init(&cs, &gs_color_space_type_Pattern, imemory, false);
161 code = gs_setcolorspace(igs, &cs);
162 if (code < 0) {
163 ref_stack_pop_to(&e_stack, edepth);
164 return code;
165 }
166 make_null(&istate->pattern); /* PLRM: initial color value is a null object */
167 pop(1);
168 return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack); /* installation will load the caches */
169 }
170
171 /* ------ Initialization procedure ------ */
172
173 const op_def zpcolor_l2_op_defs[] =
174 {
175 op_def_begin_level2(),
176 {"2.buildpattern1", zbuildpattern1},
177 {"1.setpatternspace", zsetpatternspace},
178 /* Internal operators */
179 {"0%pattern_paint_prepare", pattern_paint_prepare},
180 {"0%pattern_paint_finish", pattern_paint_finish},
181 op_def_end(zpcolor_init)
182 };
183
184 /* ------ Internal procedures ------ */
185
186 /* Render the pattern by calling the PaintProc. */
187 private int pattern_paint_cleanup(i_ctx_t *);
188 private int
zPaintProc(const gs_client_color * pcc,gs_state * pgs)189 zPaintProc(const gs_client_color * pcc, gs_state * pgs)
190 {
191 /* Just schedule a call on the real PaintProc. */
192 r_ptr(&gs_int_gstate(pgs)->remap_color_info,
193 int_remap_color_info_t)->proc =
194 pattern_paint_prepare;
195 return_error(e_RemapColor);
196 }
197 /* Prepare to run the PaintProc. */
198 private int
pattern_paint_prepare(i_ctx_t * i_ctx_p)199 pattern_paint_prepare(i_ctx_t *i_ctx_p)
200 {
201 gs_state *pgs = igs;
202 gs_pattern1_instance_t *pinst =
203 (gs_pattern1_instance_t *)gs_currentcolor(pgs)->pattern;
204 ref *pdict = &((int_pattern *) pinst->template.client_data)->dict;
205 gx_device_pattern_accum *pdev = NULL;
206 gx_device *cdev = gs_currentdevice_inline(igs);
207 int code;
208 ref *ppp;
209 bool internal_accum = true;
210
211 check_estack(6);
212 if (pgs->have_pattern_streams) {
213 code = dev_proc(cdev, pattern_manage)(cdev, pinst->id, pinst,
214 pattern_manage__can_accum);
215 if (code < 0)
216 return code;
217 internal_accum = (code == 0);
218 }
219 if (internal_accum) {
220 pdev = gx_pattern_accum_alloc(imemory, "pattern_paint_prepare");
221 if (pdev == 0)
222 return_error(e_VMerror);
223 pdev->instance = pinst;
224 pdev->bitmap_memory = gstate_pattern_cache(pgs)->memory;
225 code = (*dev_proc(pdev, open_device)) ((gx_device *) pdev);
226 if (code < 0) {
227 ifree_object(pdev, "pattern_paint_prepare");
228 return code;
229 }
230 } else {
231 code = gx_pattern_cache_add_dummy_entry((gs_imager_state *)igs,
232 pinst, cdev->color_info.depth);
233 if (code < 0)
234 return code;
235 }
236 code = gs_gsave(pgs);
237 if (code < 0)
238 return code;
239 code = gs_setgstate(pgs, pinst->saved);
240 if (code < 0) {
241 gs_grestore(pgs);
242 return code;
243 }
244 /* gx_set_device_only(pgs, (gx_device *) pdev); */
245 if (internal_accum)
246 gs_setdevice_no_init(pgs, (gx_device *)pdev);
247 else {
248 gs_matrix m;
249 gs_fixed_rect clip_box;
250
251 gs_make_identity(&m);
252 gs_setmatrix(igs, &m);
253 clip_box.p.x = float2fixed(pinst->template.BBox.p.x);
254 clip_box.p.y = float2fixed(pinst->template.BBox.p.y);
255 clip_box.q.x = float2fixed(pinst->template.BBox.q.x);
256 clip_box.q.y = float2fixed(pinst->template.BBox.q.y);
257 code = gx_clip_to_rectangle(igs, &clip_box);
258 if (code < 0) {
259 gs_grestore(pgs);
260 return code;
261 }
262 code = dev_proc(cdev, pattern_manage)(cdev, pinst->id, pinst,
263 pattern_manage__start_accum);
264 if (code < 0) {
265 gs_grestore(pgs);
266 return code;
267 }
268 }
269 push_mark_estack(es_other, pattern_paint_cleanup);
270 ++esp;
271 make_istruct(esp, 0, pdev);
272 ++esp;
273 /* Save operator stack depth in case PaintProc leaves junk on ostack. */
274 make_int(esp, ref_stack_count(&o_stack));
275 push_op_estack(pattern_paint_finish);
276 dict_find_string(pdict, "PaintProc", &ppp); /* can't fail */
277 *++esp = *ppp;
278 *++esp = *pdict; /* (push on ostack) */
279 return o_push_estack;
280 }
281 /* Save the rendered pattern. */
282 private int
pattern_paint_finish(i_ctx_t * i_ctx_p)283 pattern_paint_finish(i_ctx_t *i_ctx_p)
284 {
285 int o_stack_adjust = ref_stack_count(&o_stack) - esp->value.intval;
286 gx_device_pattern_accum *pdev = r_ptr(esp - 1, gx_device_pattern_accum);
287
288 if (pdev != NULL) {
289 gx_color_tile *ctile;
290 int code = gx_pattern_cache_add_entry((gs_imager_state *)igs,
291 pdev, &ctile);
292 if (code < 0)
293 return code;
294 }
295 if (o_stack_adjust > 0) {
296 #if 0
297 dlprintf1("PaintProc left %d extra on operator stack!\n", o_stack_adjust);
298 #endif
299 pop(o_stack_adjust);
300 }
301 esp -= 3;
302 pattern_paint_cleanup(i_ctx_p);
303 return o_pop_estack;
304 }
305 /* Clean up after rendering a pattern. Note that iff the rendering */
306 /* succeeded, closing the accumulator won't free the bits. */
307 private int
pattern_paint_cleanup(i_ctx_t * i_ctx_p)308 pattern_paint_cleanup(i_ctx_t *i_ctx_p)
309 {
310 gx_device_pattern_accum *const pdev =
311 r_ptr(esp + 2, gx_device_pattern_accum);
312 int code;
313
314 if (pdev != NULL) {
315 /* grestore will free the device, so close it first. */
316 (*dev_proc(pdev, close_device)) ((gx_device *) pdev);
317 }
318 code = gs_grestore(igs);
319 if (pdev == NULL) {
320 gx_device *cdev = gs_currentdevice_inline(igs);
321 int code1 = dev_proc(cdev, pattern_manage)(cdev, gx_no_bitmap_id, NULL,
322 pattern_manage__finish_accum);
323
324 if (code == 0 && code1 < 0)
325 code = code1;
326 }
327 return code;
328 }
329