1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
|
/* Copyright (C) 2001-2006 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
implied.
This software is distributed under license and may not be copied, modified
or distributed except as expressly authorized under the terms of that
license. Refer to licensing information at http://www.artifex.com/
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
*/
/* $Id$ */
/* Pattern color */
#include "ghost.h"
#include "oper.h"
#include "gscolor.h"
#include "gsmatrix.h"
#include "gsstruct.h"
#include "gscoord.h"
#include "gxcspace.h"
#include "gxfixed.h" /* for gxcolor2.h */
#include "gxcolor2.h"
#include "gxdcolor.h" /* for gxpcolor.h */
#include "gxdevice.h"
#include "gxdevmem.h" /* for gxpcolor.h */
#include "gxpcolor.h"
#include "gxpath.h"
#include "estack.h"
#include "ialloc.h"
#include "icremap.h"
#include "istruct.h"
#include "idict.h"
#include "idparam.h"
#include "igstate.h"
#include "ipcolor.h"
#include "store.h"
#include "gzstate.h"
#include "memory_.h"
#include "gdevp14.h"
#include "gxdevsop.h"
/* Imported from gspcolor.c */
extern const gs_color_space_type gs_color_space_type_Pattern;
/* Forward references */
static int zPaintProc(const gs_client_color *, gs_state *);
static int pattern_paint_prepare(i_ctx_t *);
static int pattern_paint_finish(i_ctx_t *);
/* GC descriptors */
private_st_int_pattern();
/* Initialize the Pattern cache. */
static int
zpcolor_init(i_ctx_t *i_ctx_p)
{
gstate_set_pattern_cache(igs,
gx_pattern_alloc_cache(imemory_system,
gx_pat_cache_default_tiles(),
gx_pat_cache_default_bits()));
return 0;
}
/* Create an interpreter pattern structure. */
int
int_pattern_alloc(int_pattern **ppdata, const ref *op, gs_memory_t *mem)
{
int_pattern *pdata =
gs_alloc_struct(mem, int_pattern, &st_int_pattern, "int_pattern");
if (pdata == 0)
return_error(e_VMerror);
pdata->dict = *op;
*ppdata = pdata;
return 0;
}
/* <pattern> <matrix> .buildpattern1 <pattern> <instance> */
static int
zbuildpattern1(i_ctx_t *i_ctx_p)
{
os_ptr op = osp;
os_ptr op1 = op - 1;
int code;
gs_matrix mat;
float BBox[4];
gs_client_pattern templat;
int_pattern *pdata;
gs_client_color cc_instance;
ref *pPaintProc;
code = read_matrix(imemory, op, &mat);
if (code < 0)
return code;
check_type(*op1, t_dictionary);
check_dict_read(*op1);
gs_pattern1_init(&templat);
code = dict_uid_param(op1, &templat.uid, 1, imemory, i_ctx_p);
if (code < 0)
return code;
if (code != 1)
return_error(e_rangecheck);
code = dict_int_param(op1, "PaintType", 1, 2, 0, &templat.PaintType);
if (code < 0)
return code;
code = dict_int_param(op1, "TilingType", 1, 3, 0, &templat.TilingType);
if (code < 0)
return code;
code = dict_bool_param(op1, ".pattern_uses_transparency", 0, &templat.uses_transparency);
if (code < 0)
return code;
code = dict_floats_param(imemory, op1, "BBox", 4, BBox, NULL);
if (code < 0)
return code;
if (code == 0)
return_error(e_undefined);
code = dict_float_param(op1, "XStep", 0.0, &templat.XStep);
if (code < 0)
return code;
if (code == 1)
return_error(e_undefined);
code = dict_float_param(op1, "YStep", 0.0, &templat.YStep);
if (code < 0)
return code;
if (code == 1)
return_error(e_undefined);
code = dict_find_string(op1, "PaintProc", &pPaintProc);
if (code < 0)
return code;
if (code == 0)
return_error(e_undefined);
check_proc(*pPaintProc);
if (mat.xx * mat.yy == mat.xy * mat.yx)
return_error(e_undefinedresult);
if (BBox[0] >= BBox[2] || BBox[1] >= BBox[3])
return_error(e_rangecheck);
templat.BBox.p.x = BBox[0];
templat.BBox.p.y = BBox[1];
templat.BBox.q.x = BBox[2];
templat.BBox.q.y = BBox[3];
templat.PaintProc = zPaintProc;
code = int_pattern_alloc(&pdata, op1, imemory);
if (code < 0)
return code;
templat.client_data = pdata;
code = gs_makepattern(&cc_instance, &templat, &mat, igs, imemory);
if (code < 0) {
ifree_object(pdata, "int_pattern");
return code;
}
make_istruct(op, a_readonly, cc_instance.pattern);
return code;
}
/* ------ Initialization procedure ------ */
const op_def zpcolor_l2_op_defs[] =
{
op_def_begin_level2(),
{"2.buildpattern1", zbuildpattern1},
{"0%pattern_paint_prepare", pattern_paint_prepare},
{"0%pattern_paint_finish", pattern_paint_finish},
op_def_end(zpcolor_init)
};
/* ------ Internal procedures ------ */
/* Render the pattern by calling the PaintProc. */
static int pattern_paint_cleanup(i_ctx_t *);
static int
zPaintProc(const gs_client_color * pcc, gs_state * pgs)
{
/* Just schedule a call on the real PaintProc. */
r_ptr(&gs_int_gstate(pgs)->remap_color_info,
int_remap_color_info_t)->proc =
pattern_paint_prepare;
return_error(e_RemapColor);
}
/* Prepare to run the PaintProc. */
static int
pattern_paint_prepare(i_ctx_t *i_ctx_p)
{
gs_state *pgs = igs;
gs_pattern1_instance_t *pinst =
(gs_pattern1_instance_t *)gs_currentcolor(pgs)->pattern;
ref *pdict = &((int_pattern *) pinst->templat.client_data)->dict;
gx_device_forward *pdev = NULL;
gx_device *cdev = gs_currentdevice_inline(igs);
int code;
ref *ppp;
bool internal_accum = true;
check_estack(6);
if (pgs->have_pattern_streams) {
code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_pattern_can_accum,
pinst, pinst->id);
if (code < 0)
return code;
internal_accum = (code == 0);
}
if (internal_accum) {
gs_memory_t *storage_memory = gstate_pattern_cache(pgs)->memory;
pdev = gx_pattern_accum_alloc(imemory, storage_memory, pinst, "pattern_paint_prepare");
if (pdev == 0)
return_error(e_VMerror);
code = (*dev_proc(pdev, open_device)) ((gx_device *) pdev);
if (code < 0) {
ifree_object(pdev, "pattern_paint_prepare");
return code;
}
} else {
code = gx_pattern_cache_add_dummy_entry((gs_imager_state *)igs,
pinst, cdev->color_info.depth);
if (code < 0)
return code;
}
code = gs_gsave(pgs);
if (code < 0)
return code;
code = gs_setgstate(pgs, pinst->saved);
if (code < 0) {
gs_grestore(pgs);
return code;
}
/* gx_set_device_only(pgs, (gx_device *) pdev); */
if (internal_accum) {
gs_setdevice_no_init(pgs, (gx_device *)pdev);
if (pinst->templat.uses_transparency) {
if_debug0('v', " pushing the pdf14 compositor device into this graphics state\n");
if ((code = gs_push_pdf14trans_device(pgs, true)) < 0)
return code;
} else { /* not transparent */
if (pinst->templat.PaintType == 1)
if ((code = gx_erase_colored_pattern(pgs)) < 0)
return code;
}
} else {
gs_matrix m;
gs_rect bbox;
gs_fixed_rect clip_box;
dev_proc(pgs->device, get_initial_matrix)(pgs->device, &m);
gs_setmatrix(igs, &m);
code = gs_bbox_transform(&pinst->templat.BBox, &ctm_only(pgs), &bbox);
if (code < 0) {
gs_grestore(pgs);
return code;
}
clip_box.p.x = float2fixed(bbox.p.x);
clip_box.p.y = float2fixed(bbox.p.y);
clip_box.q.x = float2fixed(bbox.q.x);
clip_box.q.y = float2fixed(bbox.q.y);
code = gx_clip_to_rectangle(igs, &clip_box);
if (code < 0) {
gs_grestore(pgs);
return code;
}
code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_pattern_start_accum,
pinst, pinst->id);
if (code < 0) {
gs_grestore(pgs);
return code;
}
}
push_mark_estack(es_other, pattern_paint_cleanup);
++esp;
make_istruct(esp, 0, pdev);
++esp;
/* Save operator stack depth in case PaintProc leaves junk on ostack. */
make_int(esp, ref_stack_count(&o_stack));
push_op_estack(pattern_paint_finish);
dict_find_string(pdict, "PaintProc", &ppp); /* can't fail */
*++esp = *ppp;
*++esp = *pdict; /* (push on ostack) */
return o_push_estack;
}
/* Save the rendered pattern. */
static int
pattern_paint_finish(i_ctx_t *i_ctx_p)
{
int o_stack_adjust = ref_stack_count(&o_stack) - esp->value.intval;
gx_device_forward *pdev = r_ptr(esp - 1, gx_device_forward);
gs_pattern1_instance_t *pinst =
(gs_pattern1_instance_t *)gs_currentcolor(igs->saved)->pattern;
gx_device_pattern_accum const *padev = (const gx_device_pattern_accum *) pdev;
if (pdev != NULL) {
gx_color_tile *ctile;
int code;
if (pinst->templat.uses_transparency) {
gs_state *pgs = igs;
int code;
if (pinst->is_clist) {
/* Send the compositor command to close the PDF14 device */
code = (gs_pop_pdf14trans_device(pgs, true) < 0);
if (code < 0)
return code;
} else {
/* Not a clist, get PDF14 buffer information */
code = pdf14_get_buffer_information(pgs->device,
padev->transbuff, pgs->memory,
true);
/* PDF14 device (and buffer) is destroyed when pattern cache
entry is removed */
if (code < 0)
return code;
}
}
code = gx_pattern_cache_add_entry((gs_imager_state *)igs, pdev, &ctile);
if (code < 0)
return code;
}
if (o_stack_adjust > 0) {
#if 0
dlprintf1("PaintProc left %d extra on operator stack!\n", o_stack_adjust);
#endif
pop(o_stack_adjust);
}
esp -= 3;
pattern_paint_cleanup(i_ctx_p);
return o_pop_estack;
}
/* Clean up after rendering a pattern. Note that iff the rendering */
/* succeeded, closing the accumulator won't free the bits. */
static int
pattern_paint_cleanup(i_ctx_t *i_ctx_p)
{
gx_device_pattern_accum *const pdev =
r_ptr(esp + 2, gx_device_pattern_accum);
int code;
if (pdev != NULL) {
/* grestore will free the device, so close it first. */
(*dev_proc(pdev, close_device)) ((gx_device *) pdev);
}
code = gs_grestore(igs);
gx_unset_dev_color(igs); /* dev_color may need updating if GC ran */
if (pdev == NULL) {
gx_device *cdev = gs_currentdevice_inline(igs);
int code1 = dev_proc(cdev, dev_spec_op)(cdev,
gxdso_pattern_finish_accum, NULL, gx_no_bitmap_id);
if (code == 0 && code1 < 0)
code = code1;
}
return code;
}
|