/src/ghostpdl/base/gxclrast.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Command list interpreter/rasterizer */ |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gp.h" /* for gp_fmode_rb */ |
21 | | #include "gpcheck.h" |
22 | | #include "gserrors.h" |
23 | | #include "gscdefs.h" /* for image type table */ |
24 | | #include "gsbitops.h" |
25 | | #include "gsparams.h" |
26 | | #include "gsstate.h" /* (should only be gs_gstate) */ |
27 | | #include "gstrans.h" /* for gs_is_pdf14trans_compositor */ |
28 | | #include "gxdcolor.h" |
29 | | #include "gxdevice.h" |
30 | | #include "gscoord.h" /* requires gsmatrix.h */ |
31 | | #include "gsdevice.h" /* for gs_deviceinitialmatrix */ |
32 | | #include "gsiparm4.h" |
33 | | #include "gxdevmem.h" /* must precede gxcldev.h */ |
34 | | #include "gxcldev.h" |
35 | | #include "gxclpath.h" |
36 | | #include "gxcmap.h" |
37 | | #include "gxcolor2.h" |
38 | | #include "gxcspace.h" /* for gs_color_space_type */ |
39 | | #include "gxdhtres.h" |
40 | | #include "gxgetbit.h" |
41 | | #include "gxpaint.h" /* for gx_fill/stroke_params */ |
42 | | #include "gxpcolor.h" |
43 | | #include "gxhttile.h" |
44 | | #include "gxiparam.h" |
45 | | #include "gximask.h" |
46 | | #include "gzpath.h" |
47 | | #include "gzcpath.h" |
48 | | #include "gzacpath.h" |
49 | | #include "stream.h" |
50 | | #include "strimpl.h" |
51 | | #include "gxcomp.h" |
52 | | #include "gsserial.h" |
53 | | #include "gxdhtserial.h" |
54 | | #include "gzht.h" |
55 | | #include "gxshade.h" |
56 | | #include "gxshade4.h" |
57 | | #include "gsicc_manage.h" |
58 | | #include "gsicc.h" |
59 | | |
60 | | extern_gx_device_halftone_list(); |
61 | | extern_gx_image_type_table(); |
62 | | |
63 | | /* We need color space types for constructing temporary color spaces. */ |
64 | | extern const gs_color_space_type gs_color_space_type_Indexed; |
65 | | |
66 | | /* Print a bitmap for tracing */ |
67 | | #ifdef DEBUG |
68 | | static void |
69 | | cmd_print_bits(gs_memory_t *mem, const byte * data, int width, int height, int raster) |
70 | | { |
71 | | int i, j; |
72 | | |
73 | | dmlprintf3(mem, "[L]width=%d, height=%d, raster=%d\n", |
74 | | width, height, raster); |
75 | | for (i = 0; i < height; i++) { |
76 | | const byte *row = data + i * raster; |
77 | | |
78 | | dmlprintf(mem, "[L]"); |
79 | | for (j = 0; j < raster; j++) |
80 | | dmprintf1(mem, " %02x", row[j]); |
81 | | dmputc(mem, '\n'); |
82 | | } |
83 | | } |
84 | | #else |
85 | | # define cmd_print_bits(mem, data, width, height, raster) DO_NOTHING |
86 | | #endif |
87 | | |
88 | | /* Get a variable-length integer operand. */ |
89 | | #define cmd_getw(var, p)\ |
90 | 1.33G | BEGIN\ |
91 | 1.33G | if ( *p < 0x80 ) var = *p++;\ |
92 | 1.33G | else { const byte *_cbp; var = cmd_get_w(p, &_cbp); p = _cbp; }\ |
93 | 1.33G | END |
94 | | |
95 | | static long |
96 | | cmd_get_w(const byte * p, const byte ** rp) |
97 | 1.08G | { |
98 | 1.08G | int val = *p++ & 0x7f; |
99 | 1.08G | int shift = 7; |
100 | | |
101 | 2.07G | for (; val |= (int)(*p & 0x7f) << shift, *p++ > 0x7f; shift += 7); |
102 | 1.08G | *rp = p; |
103 | 1.08G | return val; |
104 | 1.08G | } |
105 | | |
106 | | /* Get a variable-length fractional operand. */ |
107 | | #define cmd_getfrac(var, p)\ |
108 | 30.0M | BEGIN\ |
109 | 30.0M | if ( !(*p & 1) ) var = (*p++) << 24;\ |
110 | 30.0M | else { const byte *_cbp; var = cmd_get_frac31(p, &_cbp); p = _cbp; }\ |
111 | 30.0M | END |
112 | | static frac31 |
113 | | cmd_get_frac31(const byte * p, const byte ** rp) |
114 | 10.7M | { |
115 | 10.7M | frac31 val = (*p++ & 0xFE) << 24; |
116 | 10.7M | int shift = 24 - 7; |
117 | | |
118 | 10.7M | for (; val |= (frac31)(*p & 0xFE) << shift, *p++ & 1; shift -= 7); |
119 | 10.7M | *rp = p; |
120 | 10.7M | return val; |
121 | 10.7M | } |
122 | | |
123 | | /* |
124 | | * Define the structure for keeping track of the command reading buffer. |
125 | | * |
126 | | * The ptr member is only used for passing the current pointer to, and |
127 | | * receiving an updated pointer from, commands implemented as separate |
128 | | * procedures: normally it is kept in a register. |
129 | | */ |
130 | | typedef struct command_buf_s { |
131 | | byte *data; /* actual buffer, guaranteed aligned */ |
132 | | uint size; |
133 | | const byte *ptr; /* next byte to be read (see above) */ |
134 | | const byte *warn_limit; /* refill warning point */ |
135 | | const byte *end; /* byte just beyond valid data */ |
136 | | stream *s; /* for refilling buffer */ |
137 | | int end_status; |
138 | | } command_buf_t; |
139 | | |
140 | | /* Set the end of a command buffer. */ |
141 | | static void |
142 | | set_cb_end(command_buf_t *pcb, const byte *end) |
143 | 47.0M | { |
144 | 47.0M | pcb->end = end; |
145 | 47.0M | pcb->warn_limit = pcb->data + (pcb->size - cmd_largest_size + 1); |
146 | 47.0M | if ( pcb->warn_limit > pcb->end ) |
147 | 2.97M | pcb->warn_limit = pcb->end; /**** This is dangerous. Other places ****/ |
148 | | /**** assume that the limit is a soft ****/ |
149 | | /**** limit and should check 'end' ****/ |
150 | 47.0M | } |
151 | | |
152 | | static inline void |
153 | | advance_buffer(command_buf_t *pcb, const byte *cbp) |
154 | 44.0M | { |
155 | | #ifdef DEBUG |
156 | | stream_state *st = pcb->s->state; |
157 | | |
158 | | top_up_offset_map(st, pcb->data, cbp, pcb->end); |
159 | | #endif |
160 | 44.0M | memmove(pcb->data, cbp, pcb->end - cbp); |
161 | 44.0M | } |
162 | | |
163 | | static inline void |
164 | | next_is_skip(command_buf_t *pcb) |
165 | 23.6k | { |
166 | | #ifdef DEBUG |
167 | | stream_state *st = pcb->s->state; |
168 | | |
169 | | offset_map_next_data_out_of_band(st); |
170 | | #endif |
171 | 23.6k | } |
172 | | |
173 | | /* Read more data into a command buffer. */ |
174 | | static int |
175 | | top_up_cbuf(command_buf_t *pcb, const byte **pcbp) |
176 | 62.2M | { |
177 | 62.2M | uint nread; |
178 | 62.2M | const byte *cbp = *pcbp; |
179 | 62.2M | byte *cb_top = pcb->data + (pcb->end - cbp); |
180 | | |
181 | 62.2M | if (cbp < pcb->data || cbp > pcb->end) { |
182 | 0 | errprintf(pcb->s->memory, "Clist I/O error: cbp outside of buffer\n"); |
183 | 0 | return (gs_error_ioerror); |
184 | 0 | } |
185 | | |
186 | 62.2M | if (seofp(pcb->s)) { |
187 | | /* Can't use offset_map, because s_close resets s->state. Don't top up. */ |
188 | 18.2M | pcb->end_status = pcb->s->end_status; |
189 | 18.2M | return 0; |
190 | 18.2M | } |
191 | 43.9M | advance_buffer(pcb, cbp); |
192 | 43.9M | nread = pcb->end - cb_top; |
193 | 43.9M | pcb->end_status = sgets(pcb->s, cb_top, nread, &nread); |
194 | 43.9M | if ( nread == 0 ) { |
195 | | /* No data for this band at all. */ |
196 | 234 | if (cb_top >= pcb->end) { |
197 | | /* should not happen */ |
198 | 0 | *pcbp = pcb->data; |
199 | 0 | pcb->data[0] = cmd_opv_end_run; |
200 | 0 | return_error(gs_error_ioerror); |
201 | 0 | } |
202 | 234 | *cb_top = cmd_opv_end_run; |
203 | 234 | nread = 1; |
204 | 234 | } |
205 | 43.9M | set_cb_end(pcb, cb_top + nread); |
206 | 43.9M | process_interrupts(pcb->s->memory); |
207 | 43.9M | *pcbp = pcb->data; |
208 | 43.9M | return 0; |
209 | 43.9M | } |
210 | | |
211 | | /* Read data from the command buffer and stream. */ |
212 | | /* From the command_buffer pcb, read rsize bytes to ptr, starting from cbp. |
213 | | * Return the new value for pcb->ptr. */ |
214 | | static const byte * |
215 | | cmd_read_data(command_buf_t *pcb, byte *ptr, uint rsize, const byte *cbp) |
216 | 25.2M | { |
217 | 25.2M | if (pcb->end - cbp >= rsize) { |
218 | 25.1M | memmove(ptr, cbp, rsize); |
219 | 25.1M | return cbp + rsize; |
220 | 25.1M | } else { |
221 | 76.3k | uint cleft = pcb->end - cbp; |
222 | 76.3k | uint rleft = rsize - cleft; |
223 | | |
224 | 76.3k | memmove(ptr, cbp, cleft); |
225 | 76.3k | sgets(pcb->s, ptr + cleft, rleft, &rleft); |
226 | | #ifdef DEBUG |
227 | | { |
228 | | stream_state *st = pcb->s->state; |
229 | | |
230 | | adjust_offset_map_for_skipped_data(st, (uint)(pcb->end - pcb->data), rleft); |
231 | | } |
232 | | #endif |
233 | 76.3k | return pcb->end; |
234 | 76.3k | } |
235 | 25.2M | } |
236 | | |
237 | | /* Read a fixed-size value from the command buffer. */ |
238 | | static inline const byte * |
239 | | cmd_copy_value(void *pvar, int var_size, const byte *cbp) |
240 | 4.47M | { |
241 | 4.47M | memcpy(pvar, cbp, var_size); |
242 | 4.47M | return cbp + var_size; |
243 | 4.47M | } |
244 | | #define cmd_get_value(var, cbp)\ |
245 | 4.47M | cbp = cmd_copy_value(&var, sizeof(var), cbp) |
246 | | |
247 | | /* |
248 | | * Define a buffer structure to hold a serialized halftone. This is |
249 | | * used only if the serialized halftone is too large to fit into |
250 | | * the command buffer. |
251 | | */ |
252 | | typedef struct ht_buff_s { |
253 | | uint ht_size, read_size; |
254 | | byte * pcurr; |
255 | | byte * pbuff; |
256 | | } ht_buff_t; |
257 | | |
258 | | /* |
259 | | * Render one band to a specified target device. Note that if |
260 | | * action == setup, target may be 0. |
261 | | */ |
262 | | static int read_set_tile_size(command_buf_t *pcb, tile_slot *bits, bool for_pattern); |
263 | | static int read_set_bits(command_buf_t *pcb, tile_slot *bits, |
264 | | int compress, gx_clist_state *pcls, |
265 | | gx_strip_bitmap *tile, tile_slot **pslot, |
266 | | gx_device_clist_reader *cdev, gs_memory_t *mem); |
267 | | static int read_set_misc2(command_buf_t *pcb, gs_gstate *pgs, |
268 | | segment_notes *pnotes); |
269 | | static int read_set_color_space(command_buf_t *pcb, gs_gstate *pgs, |
270 | | gx_device_clist_reader *cdev, gs_memory_t *mem); |
271 | | static int read_begin_image(command_buf_t *pcb, gs_image_common_t *pic, |
272 | | gs_color_space *pcs); |
273 | | static int read_put_params(command_buf_t *pcb, gs_gstate *pgs, |
274 | | gx_device_clist_reader *cdev, |
275 | | gs_memory_t *mem); |
276 | | static int read_composite(command_buf_t *pcb, gs_memory_t *mem, gs_composite_t **ppcomp); |
277 | | static int apply_composite(gx_device_clist_reader *cdev, gs_gstate *pgs, |
278 | | gs_memory_t *mem, gs_composite_t *pcomp, |
279 | | int x0, int y0, gx_device **ptarget); |
280 | | static int read_alloc_ht_buff(ht_buff_t *, uint, gs_memory_t *); |
281 | | static int read_ht_segment(ht_buff_t *, command_buf_t *, gs_gstate *, |
282 | | gx_device *, gs_memory_t *); |
283 | | |
284 | | static const byte *cmd_read_rect(int, gx_cmd_rect *, const byte *); |
285 | | static const byte *cmd_read_short_bits(command_buf_t *pcb, byte *data, int tot_bytes, |
286 | | int width_bytes, int height, |
287 | | uint raster, const byte *cbp); |
288 | | static int cmd_select_map(cmd_map_index, cmd_map_contents, |
289 | | gs_gstate *, int **, |
290 | | frac **, uint *, gs_memory_t *); |
291 | | static int cmd_create_dev_ht(gx_device_halftone **, gs_memory_t *); |
292 | | static int cmd_resize_halftone(gx_device_halftone **, uint, |
293 | | gs_memory_t *); |
294 | | static int clist_decode_segment(gx_path *, int, fixed[6], |
295 | | gs_fixed_point *, int, int, |
296 | | segment_notes); |
297 | | static int clist_do_polyfill(gx_device *, gx_path *, |
298 | | const gx_drawing_color *, |
299 | | gs_logical_operation_t); |
300 | | |
301 | | static inline void |
302 | | enqueue_compositor(gs_composite_t **ppcomp_first, gs_composite_t **ppcomp_last, gs_composite_t *pcomp) |
303 | 256M | { |
304 | 256M | if (*ppcomp_last == NULL) { |
305 | 20.2M | pcomp->prev = pcomp->next = NULL; |
306 | 20.2M | *ppcomp_last = *ppcomp_first = pcomp; |
307 | 236M | } else { |
308 | 236M | (*ppcomp_last)->next = pcomp; |
309 | 236M | pcomp->prev = *ppcomp_last; |
310 | 236M | pcomp->next = NULL; |
311 | 236M | *ppcomp_last = pcomp; |
312 | 236M | } |
313 | 256M | } |
314 | | |
315 | | #if 0 /* Appears unused - keep for a while. */ |
316 | | static inline gs_composite_t * |
317 | | dequeue_last_compositor(gs_composite_t **ppcomp_first, gs_composite_t **ppcomp_last) |
318 | | { |
319 | | gs_composite_t *pcomp = *ppcomp_last; |
320 | | |
321 | | if (*ppcomp_first == *ppcomp_last) |
322 | | *ppcomp_first = *ppcomp_last = NULL; |
323 | | else { |
324 | | *ppcomp_last = (*ppcomp_last)->prev; |
325 | | pcomp->prev = NULL; |
326 | | (*ppcomp_last)->next = NULL; |
327 | | } |
328 | | return pcomp; |
329 | | } |
330 | | |
331 | | static inline gs_composite_t * |
332 | | dequeue_first_compositor(gs_composite_t **ppcomp_first, gs_composite_t **ppcomp_last) |
333 | | { |
334 | | gs_composite_t *pcomp = *ppcomp_first; |
335 | | |
336 | | if (*ppcomp_first == *ppcomp_last) |
337 | | *ppcomp_first = *ppcomp_last = NULL; |
338 | | else { |
339 | | *ppcomp_first = (*ppcomp_first)->next; |
340 | | pcomp->next = NULL; |
341 | | (*ppcomp_last)->prev = NULL; |
342 | | } |
343 | | return pcomp; |
344 | | } |
345 | | #endif |
346 | | |
347 | | static inline int |
348 | | dequeue_compositor(gs_composite_t **ppcomp_first, gs_composite_t **ppcomp_last, gs_composite_t *pcomp) |
349 | 256M | { |
350 | 256M | if (*ppcomp_last == *ppcomp_first) { |
351 | 20.2M | if (*ppcomp_last == pcomp) { |
352 | 20.2M | *ppcomp_last = *ppcomp_first = NULL; |
353 | 20.2M | return 0; |
354 | 20.2M | } else |
355 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
356 | 236M | } else { |
357 | 236M | gs_composite_t *pcomp_next = pcomp->next, *pcomp_prev = pcomp->prev; |
358 | | |
359 | 236M | if (*ppcomp_last == pcomp) |
360 | 18.3M | *ppcomp_last = pcomp->prev; |
361 | 217M | else |
362 | 217M | pcomp_next->prev = pcomp_prev; |
363 | 236M | if (*ppcomp_first == pcomp) |
364 | 217M | *ppcomp_first = pcomp->next; |
365 | 18.3M | else |
366 | 18.3M | pcomp_prev->next = pcomp_next; |
367 | 236M | pcomp->next = pcomp->prev = NULL; |
368 | 236M | return 0; |
369 | 236M | } |
370 | 256M | } |
371 | | |
372 | | static inline void |
373 | | free_compositor(gs_composite_t *pcomp, gs_memory_t *mem) |
374 | 27.3M | { |
375 | 27.3M | gs_free_object(mem, pcomp, "free_compositor"); |
376 | 27.3M | } |
377 | | |
378 | | static inline bool |
379 | | is_null_compositor_op(const byte *cbp, int *length) |
380 | 145M | { |
381 | 145M | if (cbp[0] == cmd_opv_end_run) { |
382 | 132M | *length = 1; |
383 | 132M | return true; |
384 | 132M | } |
385 | 13.3M | return false; |
386 | 145M | } |
387 | | |
388 | | static int |
389 | | execute_compositor_queue(gx_device_clist_reader *cdev, gx_device **target, gx_device **tdev, gs_gstate *pgs, |
390 | | gs_composite_t **ppcomp_first, gs_composite_t **ppcomp_last, gs_composite_t *pcomp_from, |
391 | | int x0, int y0, gs_memory_t *mem, bool idle) |
392 | 13.0M | { |
393 | 242M | while (pcomp_from != NULL) { |
394 | 229M | gs_composite_t *pcomp = pcomp_from; |
395 | 229M | int code; |
396 | | |
397 | 229M | pcomp_from = pcomp->next; |
398 | 229M | code = dequeue_compositor(ppcomp_first, ppcomp_last, pcomp); |
399 | 229M | if (code < 0) |
400 | 0 | return code; |
401 | 229M | pcomp->idle |= idle; |
402 | 229M | code = apply_composite(cdev, pgs, mem, pcomp, x0, y0, target); /* Releases the compositor. */ |
403 | 229M | if (code < 0) |
404 | 8 | return code; |
405 | 229M | *tdev = *target; |
406 | 229M | } |
407 | 13.0M | return 0; |
408 | 13.0M | } |
409 | | |
410 | | static void |
411 | | mark_as_idle(gs_composite_t *pcomp_start, gs_composite_t *pcomp_end) |
412 | 2.55M | { |
413 | 2.55M | gs_composite_t *pcomp = pcomp_start; |
414 | | |
415 | 5.80M | while (pcomp != NULL) { |
416 | 5.80M | pcomp->idle = true; |
417 | 5.80M | if (pcomp == pcomp_end) |
418 | 2.55M | break; |
419 | 3.25M | pcomp = pcomp->next; |
420 | 3.25M | } |
421 | 2.55M | } |
422 | | |
423 | | static inline int |
424 | | drop_compositor_queue(gs_composite_t **ppcomp_first, gs_composite_t **ppcomp_last, |
425 | | gs_composite_t *pcomp_from, gs_memory_t *mem, int x0, int y0, |
426 | | gs_gstate *pgs) |
427 | 115k | { |
428 | 115k | gs_composite_t *pcomp; |
429 | | |
430 | 668k | do { |
431 | 668k | int code; |
432 | | |
433 | 668k | pcomp = *ppcomp_last; |
434 | 668k | if (pcomp == NULL) |
435 | 0 | return 0; |
436 | 668k | dequeue_compositor(ppcomp_first, ppcomp_last, *ppcomp_last); |
437 | 668k | code = pcomp->type->procs.adjust_ctm(pcomp, x0, y0, pgs); |
438 | 668k | if (code < 0) |
439 | 0 | return code; |
440 | 668k | free_compositor(pcomp, mem); |
441 | 668k | } while (pcomp != pcomp_from); |
442 | 115k | return 0; |
443 | 115k | } |
444 | | |
445 | | static int |
446 | | read_set_misc_map(byte cb, command_buf_t *pcb, gs_gstate *pgs, gs_memory_t *mem) |
447 | 7.63M | { |
448 | 7.63M | const byte *cbp = pcb->ptr; |
449 | 7.63M | frac *mdata; |
450 | 7.63M | int *pcomp_num; |
451 | 7.63M | uint count = 0; /* quiet compiler */ |
452 | 7.63M | cmd_map_contents cont = |
453 | 7.63M | (cmd_map_contents)(cb & 0x30) >> 4; |
454 | 7.63M | int code; |
455 | | |
456 | 7.63M | code = cmd_select_map(cb & 0xf, cont, |
457 | 7.63M | pgs, |
458 | 7.63M | &pcomp_num, |
459 | 7.63M | &mdata, &count, mem); |
460 | | |
461 | 7.63M | if (code < 0) |
462 | 0 | return code; |
463 | | /* Get component number if relevant */ |
464 | 7.63M | if (pcomp_num == NULL) |
465 | 7.63M | cbp++; |
466 | 726 | else { |
467 | 726 | *pcomp_num = (int) *cbp++; |
468 | 726 | if_debug1m('L', mem, " comp_num=%d", *pcomp_num); |
469 | 726 | } |
470 | 7.63M | if (cont == cmd_map_other) { |
471 | 6.06M | cbp = cmd_read_data(pcb, (byte *)mdata, count, cbp); |
472 | | |
473 | | #ifdef DEBUG |
474 | | if (gs_debug_c('L')) { |
475 | | uint i; |
476 | | |
477 | | for (i = 0; i < count / sizeof(*mdata); ++i) |
478 | | dmprintf1(mem, " 0x%04x", mdata[i]); |
479 | | dmputc(mem, '\n'); |
480 | | } |
481 | | } else { |
482 | | if_debug0m('L', mem, " none\n"); |
483 | | #endif |
484 | 6.06M | } |
485 | | /* Recompute the effective transfer, */ |
486 | | /* in case this was a transfer map. */ |
487 | 7.63M | gx_gstate_set_effective_xfer(pgs); |
488 | 7.63M | pcb->ptr = cbp; |
489 | 7.63M | return 0; |
490 | 7.63M | } |
491 | | |
492 | | #ifdef DEBUG |
493 | | void clist_debug_op(gs_memory_t *mem, const unsigned char *cbp) |
494 | | { |
495 | | unsigned char op = *cbp++; |
496 | | const char *const *sub = cmd_sub_op_names[op >> 4]; |
497 | | if (op == cmd_opv_extend) { |
498 | | unsigned char op2 = *cbp; |
499 | | if (cmd_extend_op_names[op2]) |
500 | | dmlprintf1(mem, " %s", cmd_extend_op_names[op2]); |
501 | | else |
502 | | dmlprintf1(mem, " ?0x%02x?", (int)op2); |
503 | | } else if (sub) |
504 | | dmlprintf1(mem, " %s", sub[op & 0xf]); |
505 | | else |
506 | | dmlprintf2(mem, " %s %d", cmd_op_names[op >> 4], op & 0xf); |
507 | | } |
508 | | #endif |
509 | | |
510 | | int |
511 | | clist_playback_band(clist_playback_action playback_action, /* lgtm [cpp/use-of-goto] */ |
512 | | gx_device_clist_reader *cdev, stream *s, |
513 | | gx_device *target, int x0, int y0, |
514 | | gs_memory_t * mem) |
515 | 3.00M | { |
516 | 3.00M | byte *cbuf_storage; |
517 | 3.00M | command_buf_t cbuf; |
518 | | /* data_bits is for short copy_* bits and copy_* compressed, */ |
519 | | /* must be aligned */ |
520 | 3.00M | byte *data_bits = 0; |
521 | 3.00M | const byte *cbp; |
522 | 3.00M | int dev_depth; /* May vary due to compositing devices */ |
523 | 3.00M | int dev_depth_bytes; |
524 | 3.00M | int odd_delta_shift; |
525 | 3.00M | int num_zero_bytes; |
526 | 3.00M | gx_device *tdev; |
527 | 3.00M | gx_clist_state state; |
528 | 3.00M | gx_color_index *set_colors; |
529 | 3.00M | gx_device_color *set_dev_colors; |
530 | 3.00M | tile_slot *state_slot; |
531 | 3.00M | gx_strip_bitmap state_tile; /* parameters for reading tiles */ |
532 | 3.00M | tile_slot tile_bits; /* parameters of current tile */ |
533 | 3.00M | gs_int_point tile_phase; |
534 | 3.00M | gx_path path; |
535 | 3.00M | bool in_path; |
536 | 3.00M | gs_fixed_point ppos; |
537 | 3.00M | gx_clip_path clip_path; |
538 | 3.00M | bool use_clip; |
539 | 3.00M | gx_clip_path *pcpath; |
540 | 3.00M | gx_device_cpath_accum clip_accum; |
541 | 3.00M | gs_fixed_rect target_box; |
542 | 3.00M | struct _cas { |
543 | 3.00M | bool lop_enabled; |
544 | 3.00M | gx_device_color dcolor; |
545 | 3.00M | gs_fixed_point fa_save; |
546 | 3.00M | } clip_save; |
547 | 3.00M | bool in_clip = false; |
548 | 3.00M | gs_gstate gs_gstate; |
549 | 3.00M | gx_device_color fill_color = { 0 }; |
550 | 3.00M | gx_device_color stroke_color = { 0 }; |
551 | 3.00M | float dash_pattern[cmd_max_dash]; |
552 | 3.00M | gx_fill_params fill_params; |
553 | 3.00M | gx_stroke_params stroke_params; |
554 | | #ifdef DEBUG |
555 | | gs_halftone_type halftone_type; |
556 | | #endif |
557 | 3.00M | union im_ { |
558 | 3.00M | gs_image_common_t c; |
559 | 3.00M | gs_data_image_t d; |
560 | 3.00M | gs_image1_t i1; |
561 | 3.00M | gs_image4_t i4; |
562 | 3.00M | } image; |
563 | 3.00M | gs_int_rect image_rect; |
564 | 3.00M | gs_color_space *pcs = NULL; |
565 | 3.00M | gx_image_enum_common_t *image_info; |
566 | 3.00M | gx_image_plane_t planes[32]; |
567 | 3.00M | uint data_height; |
568 | 3.00M | uint data_size; |
569 | 3.00M | byte *data_on_heap; |
570 | 3.00M | fixed vs[6]; |
571 | 3.00M | segment_notes notes; |
572 | 3.00M | int data_x; |
573 | 3.00M | int code = 0; |
574 | 3.00M | ht_buff_t ht_buff; |
575 | 3.00M | gx_device *const orig_target = target; |
576 | 3.00M | gx_device_clip clipper_dev; |
577 | 3.00M | bool clipper_dev_open = false; |
578 | 3.00M | patch_fill_state_t pfs; |
579 | 3.00M | int op = 0; |
580 | 3.00M | int plane_height = 0; |
581 | | |
582 | | #ifdef DEBUG |
583 | | stream_state *st = s->state; /* Save because s_close resets s->state. */ |
584 | | #endif |
585 | 3.00M | gs_composite_t *pcomp_first = NULL, *pcomp_last = NULL; |
586 | 3.00M | tile_slot bits; /* parameters for reading bits */ |
587 | | |
588 | | /* pad the cbuf data area a bit (just in case) */ |
589 | 3.00M | if ((cbuf_storage = gs_alloc_bytes(mem, cbuf_size + sizeof(double), |
590 | 3.00M | "clist_playback_band(cbuf_storage)")) == NULL) { |
591 | 0 | return_error(gs_error_VMerror); |
592 | 0 | } |
593 | 3.00M | cbuf.data = (byte *)cbuf_storage; |
594 | 3.00M | cbuf.size = cbuf_size; |
595 | 3.00M | cbuf.s = s; |
596 | 3.00M | cbuf.end_status = 0; |
597 | 3.00M | set_cb_end(&cbuf, cbuf.data + cbuf.size); |
598 | 3.00M | cbp = cbuf.end; |
599 | | |
600 | 3.00M | pfs.dev = NULL; /* Indicate "not initialized". */ |
601 | 3.00M | memset(&ht_buff, 0, sizeof(ht_buff)); |
602 | | |
603 | | /* The following initializations are to quiet gcc warnings. */ |
604 | 3.00M | memset(&bits, 0, sizeof(bits)); |
605 | 3.00M | memset(&tile_bits, 0, sizeof(tile_bits)); |
606 | 3.00M | memset(&clip_save, 0, sizeof(clip_save)); |
607 | 3.00M | memset(&state_slot, 0, sizeof(state_slot)); |
608 | 3.00M | ppos.x = ppos.y = 0; |
609 | | |
610 | 3.00M | in: /* Initialize for a new page. */ |
611 | 3.00M | tdev = target; |
612 | 3.00M | set_colors = state.colors; |
613 | 3.00M | set_dev_colors = state.tile_color_devn; |
614 | 3.00M | use_clip = false; |
615 | 3.00M | pcpath = NULL; |
616 | 3.00M | if (clipper_dev_open) |
617 | 0 | gx_destroy_clip_device_on_stack(&clipper_dev); |
618 | 3.00M | clipper_dev_open = false; |
619 | 3.00M | notes = sn_none; |
620 | 3.00M | data_x = 0; |
621 | 3.00M | { |
622 | 3.00M | static const gx_clist_state cls_initial = { cls_initial_values }; |
623 | | |
624 | 3.00M | state = cls_initial; |
625 | 3.00M | } |
626 | 3.00M | state_tile.id = gx_no_bitmap_id; |
627 | 3.00M | state_tile.shift = state_tile.rep_shift = 0; |
628 | 3.00M | state_tile.size.x = state_tile.size.y = 0; |
629 | 3.00M | state_tile.num_planes = 1; |
630 | 3.00M | tile_phase.x = x0; |
631 | 3.00M | tile_phase.y = y0; |
632 | 3.00M | gx_path_init_local(&path, mem); |
633 | 3.00M | in_path = false; |
634 | | /* |
635 | | * Initialize the clipping region to the full page. |
636 | | * (Since we also initialize use_clip to false, this is arbitrary.) |
637 | | */ |
638 | 3.00M | { |
639 | 3.00M | gs_fixed_rect cbox; |
640 | | |
641 | 3.00M | gx_cpath_init_local(&clip_path, mem); |
642 | 3.00M | cbox.p.x = 0; |
643 | 3.00M | cbox.p.y = 0; |
644 | 3.00M | cbox.q.x = cdev->width; |
645 | 3.00M | cbox.q.y = cdev->height; |
646 | 3.00M | gx_cpath_from_rectangle(&clip_path, &cbox); |
647 | 3.00M | } |
648 | 3.00M | if (target != 0) |
649 | 3.00M | (*dev_proc(target, get_clipping_box))(target, &target_box); |
650 | 3.00M | memset(&gs_gstate, 0, sizeof(gs_gstate)); |
651 | 3.00M | GS_STATE_INIT_VALUES_CLIST((&gs_gstate)); |
652 | 3.00M | code = gs_gstate_initialize(&gs_gstate, mem); |
653 | 3.00M | if (code < 0) |
654 | 0 | goto out; |
655 | 3.00M | gs_gstate.device = tdev; |
656 | 3.00M | gs_gstate.view_clip = NULL; /* Avoid issues in pdf14 fill stroke */ |
657 | 3.00M | gs_gstate.clip_path = &clip_path; |
658 | 3.00M | pcs = gs_cspace_new_DeviceGray(mem); |
659 | 3.00M | if (pcs == NULL) { |
660 | 0 | code = gs_note_error(gs_error_VMerror); |
661 | 0 | goto out; |
662 | 0 | } |
663 | 3.00M | code = pcs->type->install_cspace(pcs, &gs_gstate); |
664 | 3.00M | if (code < 0) { |
665 | 0 | rc_decrement(pcs, "clist_playback_band"); |
666 | 0 | goto out; |
667 | 0 | } |
668 | 3.00M | gs_gstate.color[0].color_space = pcs; /* we already have one ref */ |
669 | 3.00M | gs_gstate.color[1].color_space = pcs; |
670 | 3.00M | rc_increment_cs(pcs); /* increment for second ref */ |
671 | | /* Initialize client color and device color */ |
672 | 3.00M | gs_gstate.color[0].ccolor = |
673 | 3.00M | gs_alloc_struct(mem, gs_client_color, &st_client_color, "clist_playback_band"); |
674 | 3.00M | gs_gstate.color[1].ccolor = |
675 | 3.00M | gs_alloc_struct(mem, gs_client_color, &st_client_color, "clist_playback_band"); |
676 | 3.00M | gs_gstate.color[0].dev_color = |
677 | 3.00M | gs_alloc_struct(mem, gx_device_color, &st_device_color, "clist_playback_band"); |
678 | 3.00M | gs_gstate.color[1].dev_color = |
679 | 3.00M | gs_alloc_struct(mem, gx_device_color, &st_device_color, "clist_playback_band"); |
680 | 3.00M | if (gs_gstate.color[0].ccolor == 0 || gs_gstate.color[0].dev_color == 0 || |
681 | 3.00M | gs_gstate.color[1].ccolor == 0 || gs_gstate.color[1].dev_color == 0 |
682 | 3.00M | ) { |
683 | 0 | gs_free_object(mem, gs_gstate.color[0].ccolor, "clist_playback_band"); |
684 | 0 | gs_free_object(mem, gs_gstate.color[1].ccolor, "clist_playback_band"); |
685 | 0 | gs_free_object(mem, gs_gstate.color[0].dev_color, "clist_playback_band"); |
686 | 0 | gs_free_object(mem, gs_gstate.color[1].dev_color, "clist_playback_band"); |
687 | 0 | if (clipper_dev_open) |
688 | 0 | gx_destroy_clip_device_on_stack(&clipper_dev); |
689 | 0 | return_error(gs_error_VMerror); |
690 | 0 | } |
691 | 3.00M | gs_gstate.color[0].color_space->pclient_color_space_data = |
692 | 3.00M | pcs->pclient_color_space_data; |
693 | 3.00M | cs_full_init_color(gs_gstate.color[0].ccolor, pcs); |
694 | 3.00M | gx_unset_dev_color(&gs_gstate); |
695 | | |
696 | 3.00M | gs_gstate.color[1].color_space->pclient_color_space_data = |
697 | 3.00M | pcs->pclient_color_space_data; |
698 | 3.00M | cs_full_init_color(gs_gstate.color[1].ccolor, pcs); |
699 | 3.00M | gx_unset_dev_color(&gs_gstate); |
700 | | |
701 | | /* Remove the ICC link cache and replace with the device link cache |
702 | | so that we share the cache across bands */ |
703 | 3.00M | rc_decrement(gs_gstate.icc_link_cache,"clist_playback_band"); |
704 | 3.00M | gs_gstate.icc_link_cache = cdev->icc_cache_cl; |
705 | | /* Need to lock during the increment of the link cache */ |
706 | 3.00M | gx_monitor_enter(cdev->icc_cache_cl->lock); |
707 | 3.00M | rc_increment(cdev->icc_cache_cl); |
708 | 3.00M | gx_monitor_leave(cdev->icc_cache_cl->lock); /* let everyone run */ |
709 | 3.00M | if (code < 0) |
710 | 0 | goto out; |
711 | | |
712 | 3.00M | gs_gstate.line_params.dash.pattern = dash_pattern; |
713 | 3.00M | if (tdev != 0) { |
714 | 3.00M | gx_set_cmap_procs(&gs_gstate, tdev); |
715 | 3.00M | } |
716 | 3.00M | gx_gstate_setscreenphase(&gs_gstate, -x0, -y0, gs_color_select_all); |
717 | | #ifdef DEBUG |
718 | | halftone_type = ht_type_none; |
719 | | #endif |
720 | 3.00M | fill_color.ccolor_valid = false; |
721 | 3.00M | color_unset(&fill_color); |
722 | 3.00M | data_bits = gs_alloc_bytes(mem, data_bits_size, |
723 | 3.00M | "clist_playback_band(data_bits)"); |
724 | 3.00M | if (data_bits == 0) { |
725 | 0 | code = gs_note_error(gs_error_VMerror); |
726 | 0 | goto out; |
727 | 0 | } |
728 | 644M | while (code >= 0) { |
729 | 644M | int compress; |
730 | 644M | int depth = 0x7badf00d; /* Initialize against indeterminizm. */ |
731 | 644M | int raster = 0x7badf00d; /* Initialize against indeterminizm. */ |
732 | 644M | byte *source = NULL; /* Initialize against indeterminizm. */ |
733 | 644M | gx_color_index colors[2]; |
734 | 644M | gx_color_index *pcolor; |
735 | 644M | gx_device_color *pdcolor = NULL; |
736 | 644M | gs_logical_operation_t log_op; |
737 | | |
738 | | /* Make sure the buffer contains a full command. */ |
739 | 644M | if (cbp >= cbuf.warn_limit) { |
740 | 4.65M | if (cbuf.end_status < 0) { /* End of file or error. */ |
741 | 33.1k | if (cbp >= cbuf.end) { |
742 | 0 | code = (cbuf.end_status == EOFC ? 0 : |
743 | 0 | gs_note_error(gs_error_ioerror)); |
744 | 0 | break; |
745 | 0 | } |
746 | 4.62M | } else { |
747 | 4.62M | code = top_up_cbuf(&cbuf, &cbp); |
748 | 4.62M | if (code < 0) |
749 | 0 | goto top_up_failed; |
750 | 4.62M | } |
751 | 4.65M | } |
752 | 644M | op = *cbp++; |
753 | | #ifdef DEBUG |
754 | | if (gs_debug_c('L')) { |
755 | | int64_t offset = clist_file_offset(st, cbp - 1 - cbuf.data); |
756 | | |
757 | | dmlprintf1(mem, "[L] %"PRIu64":", offset); |
758 | | clist_debug_op(mem, cbp-1); |
759 | | } |
760 | | #endif |
761 | 644M | switch (op >> 4) { |
762 | 111M | case cmd_op_misc >> 4: |
763 | 111M | switch (op) { |
764 | 11.7M | case cmd_opv_end_run: |
765 | 11.7M | if_debug0m('L', mem, "\n"); |
766 | 11.7M | continue; |
767 | 3.73k | case cmd_opv_set_tile_size: |
768 | 3.73k | cbuf.ptr = cbp; |
769 | 3.73k | code = read_set_tile_size(&cbuf, &tile_bits, |
770 | 3.73k | gx_device_is_pattern_clist((gx_device *)cdev)); |
771 | 3.73k | cbp = cbuf.ptr; |
772 | 3.73k | if (code < 0) |
773 | 0 | goto out; |
774 | 3.73k | continue; |
775 | 31.5k | case cmd_opv_set_tile_phase: |
776 | 31.5k | cmd_getw(state.tile_phase.x, cbp); |
777 | 31.5k | cmd_getw(state.tile_phase.y, cbp); |
778 | 31.5k | if_debug2m('L', mem, " (%d,%d)\n", |
779 | 31.5k | state.tile_phase.x, |
780 | 31.5k | state.tile_phase.y); |
781 | 31.5k | goto set_tile_phase; |
782 | 103k | case cmd_opv_set_screen_phaseT: |
783 | 103k | cmd_getw(state.screen_phase[gs_color_select_texture].x, cbp); |
784 | 103k | cmd_getw(state.screen_phase[gs_color_select_texture].y, cbp); |
785 | 103k | if_debug2m('L', mem, " (%d,%d)\n", |
786 | 103k | state.screen_phase[0].x, |
787 | 103k | state.screen_phase[gs_color_select_texture].y); |
788 | 103k | gx_gstate_setscreenphase(&gs_gstate, |
789 | 103k | state.screen_phase[gs_color_select_texture].x - x0, |
790 | 103k | state.screen_phase[gs_color_select_texture].y - y0, |
791 | 103k | gs_color_select_texture); |
792 | 103k | continue; |
793 | 0 | case cmd_opv_set_screen_phaseS: |
794 | 0 | cmd_getw(state.screen_phase[gs_color_select_source].x, cbp); |
795 | 0 | cmd_getw(state.screen_phase[gs_color_select_source].y, cbp); |
796 | 0 | if_debug2m('L', mem, " (%d,%d)\n", |
797 | 0 | state.screen_phase[gs_color_select_source].x, |
798 | 0 | state.screen_phase[gs_color_select_source].y); |
799 | 0 | gx_gstate_setscreenphase(&gs_gstate, |
800 | 0 | state.screen_phase[gs_color_select_source].x - x0, |
801 | 0 | state.screen_phase[gs_color_select_source].y - y0, |
802 | 0 | gs_color_select_source); |
803 | 0 | continue; |
804 | 16.8k | case cmd_opv_set_tile_bits: |
805 | 16.8k | bits = tile_bits; |
806 | 16.8k | compress = 0; |
807 | 15.4M | stb: |
808 | 15.4M | cbuf.ptr = cbp; |
809 | 15.4M | code = read_set_bits(&cbuf, &bits, compress, |
810 | 15.4M | &state, &state_tile, &state_slot, |
811 | 15.4M | cdev, mem); |
812 | 15.4M | cbp = cbuf.ptr; |
813 | 15.4M | if (code < 0) |
814 | 0 | goto out; |
815 | 15.4M | goto stp; |
816 | 15.4M | case cmd_opv_set_bits: |
817 | 15.3M | do_opv_set_bits: |
818 | 15.3M | compress = *cbp & 3; |
819 | 15.3M | bits.head.depth = *cbp++ >> 2; |
820 | 15.3M | cmd_getw(bits.width, cbp); |
821 | 15.3M | cmd_getw(bits.height, cbp); |
822 | 15.3M | if (op == cmd_opv_set_bits_planar) |
823 | 15.3M | cmd_getw(bits.num_planes, cbp); |
824 | 15.3M | else |
825 | 15.3M | bits.num_planes = 1; |
826 | 15.3M | if_debug5m('L', mem, " compress=%d depth=%d size=(%d,%d) planes=%d", |
827 | 15.3M | compress, bits.head.depth, |
828 | 15.3M | bits.width, bits.height, bits.num_planes); |
829 | 15.3M | bits.raster = |
830 | 15.3M | bitmap_raster(bits.width * bits.head.depth); |
831 | 15.3M | bits.x_reps = bits.y_reps = 1; |
832 | 15.3M | bits.shift = bits.rep_shift = 0; |
833 | 15.3M | goto stb; |
834 | 246k | case cmd_opv_set_tile_color: |
835 | 246k | set_colors = state.tile_colors; |
836 | 246k | if_debug0m('L', mem, "\n"); |
837 | 246k | continue; |
838 | 9.13M | case cmd_opv_set_misc: |
839 | 9.13M | { |
840 | 9.13M | uint cb = *cbp++; |
841 | | |
842 | 9.13M | switch (cb >> 6) { |
843 | 1.87M | case cmd_set_misc_lop >> 6: |
844 | 1.87M | cmd_getw(state.lop, cbp); |
845 | 1.87M | state.lop = (state.lop << 6) + (cb & 0x3f); |
846 | 1.87M | if_debug1m('L', mem, " lop=0x%x\n", state.lop); |
847 | 1.87M | if (state.lop_enabled) |
848 | 1.38M | gs_gstate.log_op = state.lop; |
849 | 1.87M | break; |
850 | 592k | case cmd_set_misc_data_x >> 6: |
851 | 592k | if (cb & 0x20) |
852 | 592k | cmd_getw(data_x, cbp); |
853 | 592k | else |
854 | 592k | data_x = 0; |
855 | 592k | data_x = (data_x << 5) + (cb & 0x1f); |
856 | 592k | if_debug1m('L', mem, " data_x=%d\n", data_x); |
857 | 592k | break; |
858 | 6.67M | case cmd_set_misc_map >> 6: |
859 | 6.67M | cbuf.ptr = cbp; |
860 | 6.67M | code = read_set_misc_map(cb, &cbuf, &gs_gstate, mem); |
861 | 6.67M | if (code < 0) |
862 | 0 | goto out; |
863 | 6.67M | cbp = cbuf.ptr; |
864 | 6.67M | break; |
865 | 0 | case cmd_set_misc_halftone >> 6: { |
866 | 0 | uint num_comp; |
867 | | #ifdef DEBUG |
868 | | halftone_type = cb & 0x3f; |
869 | | #endif |
870 | 0 | cmd_getw(num_comp, cbp); |
871 | | #ifdef DEBUG |
872 | | if_debug2m('L', mem, " halftone type=%d num_comp=%u\n", |
873 | | halftone_type, num_comp); |
874 | | #endif |
875 | 0 | code = cmd_resize_halftone( |
876 | 0 | &gs_gstate.dev_ht[HT_OBJTYPE_DEFAULT], |
877 | 0 | num_comp, mem); |
878 | 0 | if (code < 0) |
879 | 0 | goto out; |
880 | 0 | break; |
881 | 0 | } |
882 | 0 | default: |
883 | 0 | goto bad_op; |
884 | 9.13M | } |
885 | 9.13M | } |
886 | 9.13M | continue; |
887 | 9.13M | case cmd_opv_enable_lop: |
888 | 487k | state.lop_enabled = true; |
889 | 487k | gs_gstate.log_op = state.lop; |
890 | 487k | if_debug0m('L', mem, "\n"); |
891 | 487k | continue; |
892 | 354k | case cmd_opv_disable_lop: |
893 | 354k | state.lop_enabled = false; |
894 | 354k | gs_gstate.log_op = lop_default; |
895 | 354k | if_debug0m('L', mem, "\n"); |
896 | 354k | continue; |
897 | 3.00M | case cmd_opv_end_page: |
898 | 3.00M | if_debug0m('L', mem, "\n"); |
899 | | /* |
900 | | * Do end-of-page cleanup, then reinitialize if |
901 | | * there are more pages to come. |
902 | | */ |
903 | 3.00M | goto out; |
904 | 0 | case cmd_opv_delta_color0: |
905 | 0 | pcolor = &set_colors[0]; |
906 | 0 | goto delta2_c; |
907 | 70.6M | case cmd_opv_delta_color1: |
908 | 70.6M | pcolor = &set_colors[1]; |
909 | 70.6M | delta2_c:set_colors = state.colors; |
910 | | /* See comments for cmd_put_color() in gxclutil.c. */ |
911 | 70.6M | { |
912 | 70.6M | gx_color_index delta = 0; |
913 | 70.6M | uint data; |
914 | | |
915 | 70.6M | dev_depth = (tdev->color_info.depth <= 8*sizeof(gx_color_index) ? |
916 | 70.6M | tdev->color_info.depth : 8*sizeof(gx_color_index)); |
917 | 70.6M | dev_depth_bytes = (dev_depth + 7) >> 3; |
918 | 70.6M | switch (dev_depth_bytes) { |
919 | | /* For cases with an even number of bytes */ |
920 | 0 | case 8: |
921 | 0 | data = *cbp++; |
922 | 0 | delta = (((gx_color_index) |
923 | 0 | ((data & 0xf0) << 4) + (data & 0x0f)) << 24) << 24; |
924 | | /* fall through */ |
925 | 0 | case 6: |
926 | 0 | data = *cbp++; |
927 | 0 | delta |= (((gx_color_index) |
928 | 0 | ((data & 0xf0) << 4) + (data & 0x0f)) << 16) << 16; |
929 | | /* fall through */ |
930 | 52.0M | case 4: |
931 | 52.0M | data = *cbp++; |
932 | 52.0M | delta |= ((gx_color_index) |
933 | 52.0M | ((data & 0xf0) << 4) + (data & 0x0f)) << 16; |
934 | | /* fall through */ |
935 | 52.0M | case 2: |
936 | 52.0M | data = *cbp++; |
937 | 52.0M | delta |= ((gx_color_index) |
938 | 52.0M | ((data & 0xf0) << 4) + (data & 0x0f)); |
939 | 52.0M | break; |
940 | | /* For cases with an odd number of bytes */ |
941 | 0 | case 7: |
942 | 0 | data = *cbp++; |
943 | 0 | delta = ((gx_color_index) |
944 | 0 | ((data & 0xf0) << 4) + (data & 0x0f)) << 16; |
945 | | /* fall through */ |
946 | 0 | case 5: |
947 | 0 | data = *cbp++; |
948 | 0 | delta |= ((gx_color_index) |
949 | 0 | ((data & 0xf0) << 4) + (data & 0x0f)); |
950 | | /* fall through */ |
951 | 18.5M | case 3: |
952 | 18.5M | data = *cbp++; |
953 | 18.5M | odd_delta_shift = (dev_depth_bytes - 3) * 8; |
954 | 18.5M | delta |= ((gx_color_index) |
955 | 18.5M | ((data & 0xe0) << 3) + (data & 0x1f)) << odd_delta_shift; |
956 | 18.5M | data = *cbp++; |
957 | 18.5M | delta |= ((gx_color_index) ((data & 0xf8) << 2) + (data & 0x07)) |
958 | 18.5M | << (odd_delta_shift + 11); |
959 | 70.6M | } |
960 | 70.6M | *pcolor += delta - cmd_delta_offsets[dev_depth_bytes]; |
961 | 70.6M | } |
962 | 70.6M | if (sizeof(*pcolor) <= sizeof(ulong)) |
963 | 70.6M | if_debug1m('L', mem, " 0x%lx\n", (ulong)*pcolor); |
964 | 0 | else |
965 | 70.6M | if_debug2m('L', mem, " 0x%8lx%08lx\n", |
966 | 70.6M | (ulong)(*pcolor >> 8*(sizeof(*pcolor) - sizeof(ulong))), (ulong)*pcolor); |
967 | 70.6M | continue; |
968 | 0 | case cmd_opv_set_copy_color: |
969 | 0 | state.color_is_alpha = 0; |
970 | 0 | if_debug0m('L', mem, "\n"); |
971 | 0 | continue; |
972 | 0 | case cmd_opv_set_copy_alpha: |
973 | 0 | state.color_is_alpha = 1; |
974 | 0 | if_debug0m('L', mem, "\n"); |
975 | 0 | continue; |
976 | 0 | default: |
977 | 0 | goto bad_op; |
978 | 111M | } |
979 | | /*NOTREACHED */ |
980 | 131k | case cmd_op_set_color0 >> 4: |
981 | 131k | pcolor = &set_colors[0]; |
982 | 131k | goto set_color; |
983 | 39.6M | case cmd_op_set_color1 >> 4: |
984 | 39.6M | pcolor = &set_colors[1]; |
985 | 39.7M | set_color:set_colors = state.colors; |
986 | | /* |
987 | | * We have a special case for gx_no_color_index. If the low |
988 | | * order 4 bits are "cmd_no_color_index" then we really |
989 | | * have a value of gx_no_color_index. Otherwise the these |
990 | | * bits indicate the number of low order zero bytes in the |
991 | | * value. See comments for cmd_put_color() in gxclutil.c. |
992 | | */ |
993 | 39.7M | num_zero_bytes = op & 0x0f; |
994 | | |
995 | 39.7M | if (num_zero_bytes == cmd_no_color_index) |
996 | 19 | *pcolor = gx_no_color_index; |
997 | 39.7M | else { |
998 | 39.7M | gx_color_index color = 0; |
999 | | |
1000 | 39.7M | dev_depth = (tdev->color_info.depth < 8*sizeof(gx_color_index) ? |
1001 | 39.7M | tdev->color_info.depth : 8*sizeof(gx_color_index)); |
1002 | 39.7M | dev_depth_bytes = (dev_depth + 7) >> 3; |
1003 | 39.7M | switch (dev_depth_bytes - num_zero_bytes) { |
1004 | 0 | case 8: |
1005 | 0 | color = (gx_color_index) * cbp++; |
1006 | 0 | case 7: |
1007 | 0 | color = (color << 8) | (gx_color_index) * cbp++; |
1008 | 0 | case 6: |
1009 | 0 | color = (color << 8) | (gx_color_index) * cbp++; |
1010 | 0 | case 5: |
1011 | 0 | color = (color << 8) | (gx_color_index) * cbp++; |
1012 | 4.65M | case 4: |
1013 | 4.65M | color = (color << 8) | (gx_color_index) * cbp++; |
1014 | 8.67M | case 3: |
1015 | 8.67M | color = (color << 8) | (gx_color_index) * cbp++; |
1016 | 9.79M | case 2: |
1017 | 9.79M | color = (color << 8) | (gx_color_index) * cbp++; |
1018 | 37.8M | case 1: |
1019 | 37.8M | color = (color << 8) | (gx_color_index) * cbp++; |
1020 | 39.7M | default: |
1021 | 39.7M | break; |
1022 | 39.7M | } |
1023 | 39.7M | color <<= num_zero_bytes * 8; |
1024 | 39.7M | *pcolor = color; |
1025 | 39.7M | } |
1026 | 39.7M | if (sizeof(*pcolor) <= sizeof(ulong)) |
1027 | 39.7M | if_debug1m('L', mem, " 0x%lx\n", (ulong)*pcolor); |
1028 | 0 | else |
1029 | 39.7M | if_debug2m('L', mem, " 0x%8lx%08lx\n", |
1030 | 39.7M | (ulong)(*pcolor >> 8*(sizeof(*pcolor) - sizeof(ulong))), (ulong)*pcolor); |
1031 | 39.7M | continue; |
1032 | 7.14M | case cmd_op_fill_rect >> 4: |
1033 | 7.26M | case cmd_op_tile_rect >> 4: |
1034 | 7.26M | cbp = cmd_read_rect(op, &state.rect, cbp); |
1035 | 7.26M | break; |
1036 | 13.3M | case cmd_op_fill_rect_short >> 4: |
1037 | 14.0M | case cmd_op_tile_rect_short >> 4: |
1038 | 14.0M | state.rect.x += *cbp + cmd_min_short; |
1039 | 14.0M | state.rect.width += cbp[1] + cmd_min_short; |
1040 | 14.0M | if (op & 0xf) { |
1041 | 5.91M | state.rect.height += (op & 0xf) + cmd_min_dxy_tiny; |
1042 | 5.91M | cbp += 2; |
1043 | 8.16M | } else { |
1044 | 8.16M | state.rect.y += cbp[2] + cmd_min_short; |
1045 | 8.16M | state.rect.height += cbp[3] + cmd_min_short; |
1046 | 8.16M | cbp += 4; |
1047 | 8.16M | } |
1048 | 14.0M | break; |
1049 | 135M | case cmd_op_fill_rect_tiny >> 4: |
1050 | 136M | case cmd_op_tile_rect_tiny >> 4: |
1051 | 136M | if (op & 8) |
1052 | 94.4M | state.rect.x += state.rect.width; |
1053 | 42.3M | else { |
1054 | 42.3M | int txy = *cbp++; |
1055 | | |
1056 | 42.3M | state.rect.x += (txy >> 4) + cmd_min_dxy_tiny; |
1057 | 42.3M | state.rect.y += (txy & 0xf) + cmd_min_dxy_tiny; |
1058 | 42.3M | } |
1059 | 136M | state.rect.width += (op & 7) + cmd_min_dw_tiny; |
1060 | 136M | break; |
1061 | 44.7M | case cmd_op_copy_mono_planes >> 4: |
1062 | 44.7M | cmd_getw(plane_height, cbp); |
1063 | 44.7M | if (plane_height == 0) { |
1064 | | /* We are doing a copy mono */ |
1065 | 44.7M | depth = 1; |
1066 | 44.7M | } else { |
1067 | 6.81k | depth = tdev->color_info.depth; |
1068 | 6.81k | } |
1069 | 44.7M | if_debug1m('L', mem, " plane_height=0x%x", plane_height); |
1070 | 44.7M | goto copy; |
1071 | 4.53M | case cmd_op_copy_color_alpha >> 4: |
1072 | 4.53M | if (state.color_is_alpha) { |
1073 | 0 | if (!(op & 8)) |
1074 | 0 | depth = *cbp++; |
1075 | 0 | } else |
1076 | 4.53M | depth = tdev->color_info.depth; |
1077 | 4.53M | plane_height = 0; |
1078 | 49.2M | copy:cmd_getw(state.rect.x, cbp); |
1079 | 49.2M | cmd_getw(state.rect.y, cbp); |
1080 | 49.2M | if (op & cmd_copy_use_tile) { /* Use the current "tile". */ |
1081 | | #ifdef DEBUG |
1082 | | if (state_slot->index != state.tile_index) { |
1083 | | mlprintf2(mem, "state_slot->index = %d, state.tile_index = %d!\n", |
1084 | | state_slot->index, |
1085 | | state.tile_index); |
1086 | | code = gs_note_error(gs_error_ioerror); |
1087 | | goto out; |
1088 | | } |
1089 | | #endif |
1090 | 43.9M | depth = state_slot->head.depth; |
1091 | 43.9M | state.rect.width = state_slot->width; |
1092 | 43.9M | state.rect.height = state_slot->height; |
1093 | 43.9M | if (state.rect.y + state.rect.height > cdev->height) |
1094 | 57.9k | state.rect.height = cdev->height - state.rect.y; /* clamp as writer did */ |
1095 | 43.9M | raster = state_slot->raster; |
1096 | 43.9M | source = (byte *) (state_slot + 1); |
1097 | 43.9M | } else { /* Read width, height, bits. */ |
1098 | | /* depth was set already. */ |
1099 | 5.32M | uint width_bits, width_bytes; |
1100 | 5.32M | uint bytes; |
1101 | 5.32M | uchar planes = 1; |
1102 | 5.32M | uint plane_depth = depth; |
1103 | 5.32M | uint pln; |
1104 | 5.32M | byte compression = op & 3; |
1105 | 5.32M | uint out_bytes; |
1106 | | |
1107 | 5.32M | cmd_getw(state.rect.width, cbp); |
1108 | 5.32M | cmd_getw(state.rect.height, cbp); |
1109 | 5.32M | if (plane_height != 0) { |
1110 | 6.81k | planes = tdev->color_info.num_components; |
1111 | 6.81k | plane_depth /= planes; |
1112 | 6.81k | } |
1113 | 5.32M | width_bits = state.rect.width * plane_depth; |
1114 | 5.32M | bytes = clist_bitmap_bytes(width_bits, |
1115 | 5.32M | state.rect.height, |
1116 | 5.32M | op & 3, &width_bytes, |
1117 | 5.32M | (uint *)&raster); |
1118 | 5.32M | if (planes > 1) { |
1119 | 6.81k | out_bytes = raster * state.rect.height; |
1120 | 6.81k | plane_height = state.rect.height; |
1121 | 5.32M | } else { |
1122 | 5.32M | out_bytes = bytes; |
1123 | 5.32M | } |
1124 | | /* copy_mono and copy_color/alpha */ |
1125 | | /* ensure that the bits will fit in a single buffer, */ |
1126 | | /* even after decompression if compressed. */ |
1127 | | #ifdef DEBUG |
1128 | | if (planes * out_bytes > data_bits_size) { |
1129 | | mlprintf6(mem, "bitmap size exceeds buffer! width=%d raster=%d height=%d\n file pos %"PRId64" buf pos %d/%d\n", |
1130 | | state.rect.width, raster, |
1131 | | state.rect.height, |
1132 | | stell(s), (int)(cbp - cbuf.data), |
1133 | | (int)(cbuf.end - cbuf.data)); |
1134 | | code = gs_note_error(gs_error_ioerror); |
1135 | | goto out; |
1136 | | } |
1137 | | #endif |
1138 | 10.6M | for (pln = 0; pln < planes; pln++) { |
1139 | 5.34M | byte *plane_bits = data_bits + pln * plane_height * raster; |
1140 | | |
1141 | | /* Fill the cbuf if needed to get the data for the plane */ |
1142 | 5.34M | if (cbp + out_bytes >= cbuf.warn_limit) { |
1143 | 70.1k | code = top_up_cbuf(&cbuf, &cbp); |
1144 | 70.1k | if (code < 0) |
1145 | 0 | goto top_up_failed; |
1146 | 70.1k | } |
1147 | 5.34M | if (pln) |
1148 | 20.4k | compression = *cbp++; |
1149 | | |
1150 | 5.34M | if (compression == cmd_compress_const) { |
1151 | 0 | cbp = cmd_read_data(&cbuf, plane_bits, 1, cbp); |
1152 | 0 | if (width_bytes > 0 && state.rect.height > 0) |
1153 | 0 | memset(plane_bits+1, *plane_bits, width_bytes * state.rect.height - 1); |
1154 | 0 | if (pln == 0) |
1155 | 0 | source = data_bits; |
1156 | |
|
1157 | 5.34M | } else if (compression) { /* Decompress the image data. */ |
1158 | 444 | stream_cursor_read r; |
1159 | 444 | stream_cursor_write w; |
1160 | | |
1161 | | /* We don't know the data length a priori, */ |
1162 | | /* so to be conservative, we read */ |
1163 | | /* the uncompressed size. */ |
1164 | 444 | uint cleft = cbuf.end - cbp; |
1165 | | |
1166 | 444 | if (cleft < bytes && !cbuf.end_status) { |
1167 | 0 | uint nread = cbuf_size - cleft; |
1168 | |
|
1169 | 0 | advance_buffer(&cbuf, cbp); |
1170 | 0 | cbuf.end_status = sgets(s, cbuf.data + cleft, nread, &nread); |
1171 | 0 | set_cb_end(&cbuf, cbuf.data + cleft + nread); |
1172 | 0 | cbp = cbuf.data; |
1173 | 0 | } |
1174 | 444 | r.ptr = cbp - 1; |
1175 | 444 | r.limit = cbuf.end - 1; |
1176 | 444 | w.ptr = plane_bits - 1; |
1177 | 444 | w.limit = w.ptr + data_bits_size; |
1178 | 444 | switch (compression) { |
1179 | 0 | case cmd_compress_rle: |
1180 | 0 | { |
1181 | 0 | stream_RLD_state sstate; |
1182 | |
|
1183 | 0 | clist_rld_init(&sstate); |
1184 | | /* The process procedure can't fail. */ |
1185 | 0 | (*s_RLD_template.process) |
1186 | 0 | ((stream_state *)&sstate, &r, &w, true); |
1187 | 0 | } |
1188 | 0 | break; |
1189 | 444 | case cmd_compress_cfe: |
1190 | 444 | { |
1191 | 444 | stream_CFD_state sstate; |
1192 | | |
1193 | 444 | clist_cfd_init(&sstate, |
1194 | 444 | width_bytes << 3 /*state.rect.width */ , |
1195 | 444 | state.rect.height, mem); |
1196 | | /* The process procedure can't fail. */ |
1197 | 444 | (*s_CFD_template.process) |
1198 | 444 | ((stream_state *)&sstate, &r, &w, true); |
1199 | 444 | (*s_CFD_template.release) |
1200 | 444 | ((stream_state *)&sstate); |
1201 | 444 | } |
1202 | 444 | break; |
1203 | 0 | default: |
1204 | 0 | goto bad_op; |
1205 | 444 | } |
1206 | 444 | cbp = r.ptr + 1; |
1207 | 444 | if (pln == 0) |
1208 | 444 | source = data_bits; |
1209 | 5.34M | } else if ((state.rect.height > 1 && width_bytes != raster) || |
1210 | 5.34M | (plane_height != 0)) { |
1211 | 150k | cbp = cmd_read_short_bits(&cbuf, plane_bits, bytes, width_bytes, |
1212 | 150k | state.rect.height, raster, cbp); |
1213 | 150k | if (pln == 0) |
1214 | 129k | source = data_bits; |
1215 | 5.19M | } else { |
1216 | | /* Never used for planar data */ |
1217 | 5.19M | cbp = cmd_read_data(&cbuf, cbuf.data, bytes, cbp); |
1218 | 5.19M | source = cbuf.data; |
1219 | 5.19M | } |
1220 | 5.34M | } |
1221 | | #ifdef DEBUG |
1222 | | if (gs_debug_c('L')) { |
1223 | | dmprintf2(mem, " depth=%d, data_x=%d\n", |
1224 | | depth, data_x); |
1225 | | cmd_print_bits(mem, source, state.rect.width, |
1226 | | state.rect.height, raster); |
1227 | | } |
1228 | | #endif |
1229 | 5.32M | } |
1230 | 49.2M | break; |
1231 | 49.2M | case cmd_op_delta_tile_index >> 4: |
1232 | 9.15M | state.tile_index += (int)(op & 0xf) - 8; |
1233 | 9.15M | goto sti; |
1234 | 18.3M | case cmd_op_set_tile_index >> 4: |
1235 | 18.3M | state.tile_index = |
1236 | 18.3M | ((op & 0xf) << 8) + *cbp++; |
1237 | 27.4M | sti:state_slot = |
1238 | 27.4M | (tile_slot *) (cdev->cache_chunk->data + |
1239 | 27.4M | cdev->tile_table[state.tile_index].offset); |
1240 | 27.4M | if_debug2m('L', mem, " index=%u offset=%lu\n", |
1241 | 27.4M | state.tile_index, |
1242 | 27.4M | cdev->tile_table[state.tile_index].offset); |
1243 | 27.4M | state_tile.data = (byte *) (state_slot + 1); |
1244 | 42.8M | stp:state_tile.size.x = state_slot->width; |
1245 | 42.8M | state_tile.size.y = state_slot->height; |
1246 | 42.8M | state_tile.raster = state_slot->raster; |
1247 | 42.8M | state_tile.rep_width = state_tile.size.x / |
1248 | 42.8M | state_slot->x_reps; |
1249 | 42.8M | state_tile.rep_height = state_tile.size.y / |
1250 | 42.8M | state_slot->y_reps; |
1251 | 42.8M | state_tile.rep_shift = state_slot->rep_shift; |
1252 | 42.8M | state_tile.shift = state_slot->shift; |
1253 | 42.8M | state_tile.id = state_slot->id; |
1254 | 42.8M | state_tile.num_planes = state_slot->num_planes; |
1255 | 42.9M | set_tile_phase: |
1256 | 42.9M | if (state_tile.size.x) |
1257 | 42.9M | tile_phase.x = |
1258 | 42.9M | (state.tile_phase.x + x0) % state_tile.size.x; |
1259 | | /* |
1260 | | * The true tile height for shifted tiles is not |
1261 | | * size.y: see gxbitmap.h for the computation. |
1262 | | */ |
1263 | 42.9M | if (state_tile.size.y) { |
1264 | 42.9M | int full_height; |
1265 | | |
1266 | 42.9M | if (state_tile.shift == 0) |
1267 | 42.9M | full_height = state_tile.size.y; |
1268 | 0 | else |
1269 | 0 | full_height = state_tile.rep_height * |
1270 | 0 | (state_tile.rep_width / |
1271 | 0 | igcd(state_tile.rep_shift, |
1272 | 0 | state_tile.rep_width)); |
1273 | 42.9M | tile_phase.y = (state.tile_phase.y + y0) % full_height; |
1274 | 42.9M | } |
1275 | 42.9M | continue; |
1276 | 67.8M | case cmd_op_misc2 >> 4: |
1277 | 67.8M | switch (op) { |
1278 | 0 | case cmd_opv_set_bits_planar: |
1279 | 0 | goto do_opv_set_bits; |
1280 | 195k | case cmd_opv_set_fill_adjust: |
1281 | 195k | cmd_get_value(gs_gstate.fill_adjust.x, cbp); |
1282 | 195k | cmd_get_value(gs_gstate.fill_adjust.y, cbp); |
1283 | 195k | if_debug2m('L', mem, " (%g,%g)\n", |
1284 | 195k | fixed2float(gs_gstate.fill_adjust.x), |
1285 | 195k | fixed2float(gs_gstate.fill_adjust.y)); |
1286 | 195k | continue; |
1287 | 3.50M | case cmd_opv_set_ctm: |
1288 | 3.50M | { |
1289 | 3.50M | gs_matrix mat; |
1290 | | |
1291 | 3.50M | cbp = cmd_read_matrix(&mat, cbp); |
1292 | 3.50M | if_debug6m('L', mem, " [%g %g %g %g %g %g]\n", |
1293 | 3.50M | mat.xx, mat.xy, mat.yx, mat.yy, |
1294 | 3.50M | mat.tx, mat.ty); |
1295 | 3.50M | mat.tx -= x0; |
1296 | 3.50M | mat.ty -= y0; |
1297 | 3.50M | gs_gstate_setmatrix(&gs_gstate, &mat); |
1298 | 3.50M | } |
1299 | 3.50M | continue; |
1300 | 2.83M | case cmd_opv_set_misc2: |
1301 | 2.83M | cbuf.ptr = cbp; |
1302 | 2.83M | code = read_set_misc2(&cbuf, &gs_gstate, ¬es); |
1303 | 2.83M | cbp = cbuf.ptr; |
1304 | 2.83M | if (code < 0) |
1305 | 0 | goto out; |
1306 | 2.83M | continue; |
1307 | 2.83M | case cmd_opv_set_dash: |
1308 | 456k | { |
1309 | 456k | int nb = *cbp++; |
1310 | 456k | int n = nb & 0x3f; |
1311 | 456k | float dot_length, offset; |
1312 | | |
1313 | 456k | cmd_get_value(dot_length, cbp); |
1314 | 456k | cmd_get_value(offset, cbp); |
1315 | 456k | memcpy(dash_pattern, cbp, n * sizeof(float)); |
1316 | | |
1317 | 456k | gx_set_dash(&gs_gstate.line_params.dash, |
1318 | 456k | dash_pattern, n, offset, |
1319 | 456k | NULL); |
1320 | 456k | gx_set_dash_adapt(&gs_gstate.line_params.dash, |
1321 | 456k | (nb & 0x80) != 0); |
1322 | 456k | gx_set_dot_length(&gs_gstate.line_params, |
1323 | 456k | dot_length, |
1324 | 456k | (nb & 0x40) != 0); |
1325 | | #ifdef DEBUG |
1326 | | if (gs_debug_c('L')) { |
1327 | | int i; |
1328 | | |
1329 | | dmprintf4(mem, " dot=%g(mode %d) adapt=%d offset=%g [", |
1330 | | dot_length, |
1331 | | (nb & 0x40) != 0, |
1332 | | (nb & 0x80) != 0, offset); |
1333 | | for (i = 0; i < n; ++i) |
1334 | | dmprintf1(mem, "%g ", dash_pattern[i]); |
1335 | | dmputs(mem, "]\n"); |
1336 | | } |
1337 | | #endif |
1338 | 456k | cbp += n * sizeof(float); |
1339 | 456k | } |
1340 | 456k | break; |
1341 | 8.70k | case cmd_opv_enable_clip: |
1342 | 8.70k | pcpath = (use_clip ? &clip_path : NULL); |
1343 | 8.70k | if (pcpath) { |
1344 | 523 | code = gx_cpath_ensure_path_list(pcpath); |
1345 | 523 | if (code < 0) |
1346 | 0 | goto out; |
1347 | 523 | } |
1348 | 8.70k | if (clipper_dev_open) |
1349 | 0 | gx_destroy_clip_device_on_stack(&clipper_dev); |
1350 | 8.70k | clipper_dev_open = false; |
1351 | 8.70k | if_debug0m('L', mem, "\n"); |
1352 | 8.70k | break; |
1353 | 14.9k | case cmd_opv_disable_clip: |
1354 | 14.9k | pcpath = NULL; |
1355 | 14.9k | if (clipper_dev_open) |
1356 | 18 | gx_destroy_clip_device_on_stack(&clipper_dev); |
1357 | 14.9k | clipper_dev_open = false; |
1358 | 14.9k | if_debug0m('L', mem, "\n"); |
1359 | 14.9k | break; |
1360 | 5.47M | case cmd_opv_begin_clip: |
1361 | 5.47M | pcpath = NULL; |
1362 | 5.47M | if (clipper_dev_open) |
1363 | 1.53k | gx_destroy_clip_device_on_stack(&clipper_dev); |
1364 | 5.47M | clipper_dev_open = false; |
1365 | 5.47M | in_clip = true; |
1366 | 5.47M | if_debug0m('L', mem, "\n"); |
1367 | 5.47M | code = gx_cpath_reset(&clip_path); |
1368 | 5.47M | if (code < 0) |
1369 | 0 | goto out; |
1370 | 5.47M | gx_cpath_accum_begin(&clip_accum, mem, false); |
1371 | 5.47M | gx_cpath_accum_set_cbox(&clip_accum, |
1372 | 5.47M | &target_box); |
1373 | 5.47M | tdev = (gx_device *)&clip_accum; |
1374 | 5.47M | clip_save.lop_enabled = state.lop_enabled; |
1375 | 5.47M | clip_save.dcolor = fill_color; |
1376 | 5.47M | clip_save.fa_save.x = gs_gstate.fill_adjust.x; |
1377 | 5.47M | clip_save.fa_save.y = gs_gstate.fill_adjust.y; |
1378 | 5.47M | cmd_getw(gs_gstate.fill_adjust.x, cbp); |
1379 | 5.47M | cmd_getw(gs_gstate.fill_adjust.y, cbp); |
1380 | | /* temporarily set a solid color */ |
1381 | 5.47M | color_set_pure(&fill_color, (gx_color_index)1); |
1382 | 5.47M | state.lop_enabled = false; |
1383 | 5.47M | gs_gstate.log_op = lop_default; |
1384 | 5.47M | break; |
1385 | 5.47M | case cmd_opv_end_clip: |
1386 | 5.47M | if_debug0m('L', mem, "\n"); |
1387 | 5.47M | gx_cpath_accum_end(&clip_accum, &clip_path); |
1388 | 5.47M | tdev = target; |
1389 | | /* |
1390 | | * If the entire band falls within the clip |
1391 | | * path, no clipping is needed. |
1392 | | */ |
1393 | 5.47M | { |
1394 | 5.47M | gs_fixed_rect cbox; |
1395 | | |
1396 | 5.47M | gx_cpath_inner_box(&clip_path, &cbox); |
1397 | 5.47M | use_clip = |
1398 | 5.47M | !(cbox.p.x <= target_box.p.x && |
1399 | 5.47M | cbox.q.x >= target_box.q.x && |
1400 | 5.47M | cbox.p.y <= target_box.p.y && |
1401 | 5.47M | cbox.q.y >= target_box.q.y); |
1402 | 5.47M | } |
1403 | 5.47M | pcpath = (use_clip ? &clip_path : NULL); |
1404 | 5.47M | if (pcpath) { |
1405 | 3.23M | code = gx_cpath_ensure_path_list(pcpath); |
1406 | 3.23M | if (code < 0) |
1407 | 0 | goto out; |
1408 | 3.23M | } |
1409 | 5.47M | if (clipper_dev_open) |
1410 | 0 | gx_destroy_clip_device_on_stack(&clipper_dev); |
1411 | 5.47M | clipper_dev_open = false; |
1412 | 5.47M | state.lop_enabled = clip_save.lop_enabled; |
1413 | 5.47M | gs_gstate.log_op = |
1414 | 5.47M | (state.lop_enabled ? state.lop : |
1415 | 5.47M | lop_default); |
1416 | 5.47M | fill_color = clip_save.dcolor; |
1417 | | /* restore the fill_adjust if it was changed by begin_clip */ |
1418 | 5.47M | gs_gstate.fill_adjust.x = clip_save.fa_save.x; |
1419 | 5.47M | gs_gstate.fill_adjust.y = clip_save.fa_save.y; |
1420 | 5.47M | in_clip = false; |
1421 | 5.47M | break; |
1422 | 627k | case cmd_opv_set_color_space: |
1423 | 627k | cbuf.ptr = cbp; |
1424 | 627k | code = read_set_color_space(&cbuf, &gs_gstate, cdev, mem); |
1425 | 627k | pcs = gs_gstate.color[0].color_space; |
1426 | 627k | cbp = cbuf.ptr; |
1427 | 627k | if (code < 0) { |
1428 | 0 | if (code == gs_error_rangecheck) |
1429 | 0 | goto bad_op; |
1430 | 0 | goto out; |
1431 | 0 | } |
1432 | 627k | break; |
1433 | 5.47M | case cmd_op_fill_rect_hl: |
1434 | 5.47M | { |
1435 | 5.47M | gs_fixed_rect rect_hl; |
1436 | | |
1437 | 5.47M | cbp = cmd_read_rect(op & 0xf0, &state.rect, cbp); |
1438 | 5.47M | if (fill_color.type != gx_dc_type_devn) { |
1439 | 0 | if_debug0m('L', mem, "hl rect fill without devn color\n"); |
1440 | 0 | code = gs_note_error(gs_error_typecheck); |
1441 | 0 | goto out; |
1442 | 0 | } |
1443 | 5.47M | if_debug4m('L', mem, " x=%d y=%d w=%d h=%d\n", |
1444 | 5.47M | state.rect.x, state.rect.y, |
1445 | 5.47M | state.rect.width,state.rect.height); |
1446 | 5.47M | rect_hl.p.x = int2fixed(state.rect.x - x0); |
1447 | 5.47M | rect_hl.p.y = int2fixed(state.rect.y - y0); |
1448 | 5.47M | rect_hl.q.x = int2fixed(state.rect.width) + rect_hl.p.x; |
1449 | 5.47M | rect_hl.q.y = int2fixed(state.rect.height) + rect_hl.p.y; |
1450 | 5.47M | code = dev_proc(tdev, fill_rectangle_hl_color) (tdev, |
1451 | 5.47M | &rect_hl, NULL, |
1452 | 5.47M | &fill_color, NULL); |
1453 | 5.47M | } |
1454 | 0 | continue; |
1455 | 636k | case cmd_opv_begin_image_rect: |
1456 | 636k | cbuf.ptr = cbp; |
1457 | 636k | code = read_begin_image(&cbuf, &image.c, pcs); |
1458 | 636k | cbp = cbuf.ptr; |
1459 | 636k | if (code < 0) |
1460 | 0 | goto out; |
1461 | 636k | { |
1462 | 636k | uint diff; |
1463 | | |
1464 | 636k | cmd_getw(image_rect.p.x, cbp); |
1465 | 636k | cmd_getw(image_rect.p.y, cbp); |
1466 | 636k | cmd_getw(diff, cbp); |
1467 | 636k | image_rect.q.x = image.d.Width - diff; |
1468 | 636k | cmd_getw(diff, cbp); |
1469 | 636k | image_rect.q.y = image.d.Height - diff; |
1470 | 636k | if_debug4m('L', mem, " rect=(%d,%d),(%d,%d)", |
1471 | 636k | image_rect.p.x, image_rect.p.y, |
1472 | 636k | image_rect.q.x, image_rect.q.y); |
1473 | 636k | } |
1474 | 636k | goto ibegin; |
1475 | 95.3k | case cmd_opv_begin_image: |
1476 | 95.3k | cbuf.ptr = cbp; |
1477 | 95.3k | code = read_begin_image(&cbuf, &image.c, pcs); |
1478 | 95.3k | cbp = cbuf.ptr; |
1479 | 95.3k | if (code < 0) |
1480 | 0 | goto out; |
1481 | 95.3k | image_rect.p.x = 0; |
1482 | 95.3k | image_rect.p.y = 0; |
1483 | 95.3k | image_rect.q.x = image.d.Width; |
1484 | 95.3k | image_rect.q.y = image.d.Height; |
1485 | 95.3k | if_debug2m('L', mem, " size=(%d,%d)", |
1486 | 95.3k | image.d.Width, image.d.Height); |
1487 | 732k | ibegin: if_debug0m('L', mem, "\n"); |
1488 | 732k | { |
1489 | | /* Processing an image operation */ |
1490 | 732k | dev_proc(tdev, set_graphics_type_tag)(tdev, GS_IMAGE_TAG);/* FIXME: what about text bitmaps? */ |
1491 | 732k | image.i4.override_in_smask = 0; |
1492 | 732k | code = (*dev_proc(tdev, begin_typed_image)) |
1493 | 732k | (tdev, &gs_gstate, NULL, |
1494 | 732k | (const gs_image_common_t *)&image, |
1495 | 732k | &image_rect, &fill_color, pcpath, mem, |
1496 | 732k | &image_info); |
1497 | 732k | } |
1498 | 732k | if (code < 0) |
1499 | 0 | goto out; |
1500 | 732k | break; |
1501 | 732k | case cmd_opv_image_plane_data: |
1502 | 0 | cmd_getw(data_height, cbp); |
1503 | 0 | if (data_height == 0) { |
1504 | 0 | if_debug0m('L', mem, " done image\n"); |
1505 | 0 | code = gx_image_end(image_info, true); |
1506 | 0 | if (code < 0) |
1507 | 0 | goto out; |
1508 | 0 | continue; |
1509 | 0 | } |
1510 | 0 | { |
1511 | 0 | uint flags; |
1512 | 0 | int plane; |
1513 | 0 | uint raster1 = 0xbaadf00d; /* Initialize against indeterminizm. */ |
1514 | |
|
1515 | 0 | cmd_getw(flags, cbp); |
1516 | 0 | for (plane = 0; |
1517 | 0 | plane < image_info->num_planes; |
1518 | 0 | ++plane, flags >>= 1) { |
1519 | 0 | if (flags & 1) { |
1520 | 0 | if (cbuf.end - cbp < |
1521 | 0 | 2 * cmd_max_intsize(sizeof(uint))) { |
1522 | 0 | code = top_up_cbuf(&cbuf, &cbp); |
1523 | 0 | if (code < 0) |
1524 | 0 | goto top_up_failed; |
1525 | 0 | } |
1526 | 0 | cmd_getw(planes[plane].raster, cbp); |
1527 | 0 | if ((raster1 = planes[plane].raster) != 0) |
1528 | 0 | cmd_getw(data_x, cbp); |
1529 | 0 | } else { |
1530 | 0 | planes[plane].raster = raster1; |
1531 | 0 | } |
1532 | 0 | planes[plane].data_x = data_x; |
1533 | 0 | } |
1534 | 0 | } |
1535 | 0 | goto idata; |
1536 | 3.86M | case cmd_opv_image_data: |
1537 | 3.86M | cmd_getw(data_height, cbp); |
1538 | 3.86M | if (data_height == 0) { |
1539 | 732k | if_debug0m('L', mem, " done image\n"); |
1540 | 732k | code = gx_image_end(image_info, true); |
1541 | 732k | if (code < 0) |
1542 | 0 | goto out; |
1543 | 732k | continue; |
1544 | 732k | } |
1545 | 3.13M | { |
1546 | 3.13M | uint bytes_per_plane; |
1547 | 3.13M | int plane; |
1548 | | |
1549 | 3.13M | cmd_getw(bytes_per_plane, cbp); |
1550 | 3.13M | if_debug2m('L', mem, " height=%u raster=%u\n", |
1551 | 3.13M | data_height, bytes_per_plane); |
1552 | 3.13M | for (plane = 0; |
1553 | 6.26M | plane < image_info->num_planes; |
1554 | 3.13M | ++plane |
1555 | 3.13M | ) { |
1556 | 3.13M | planes[plane].data_x = data_x; |
1557 | 3.13M | planes[plane].raster = bytes_per_plane; |
1558 | 3.13M | } |
1559 | 3.13M | } |
1560 | 3.13M | idata: data_size = 0; |
1561 | 3.13M | { |
1562 | 3.13M | int plane; |
1563 | | |
1564 | 6.26M | for (plane = 0; plane < image_info->num_planes; |
1565 | 3.13M | ++plane) |
1566 | 3.13M | data_size += planes[plane].raster; |
1567 | 3.13M | } |
1568 | 3.13M | data_size *= data_height; |
1569 | 3.13M | data_on_heap = 0; |
1570 | 3.13M | if (cbuf.end - cbp < data_size) { |
1571 | 547k | code = top_up_cbuf(&cbuf, &cbp); |
1572 | 547k | if (code < 0) |
1573 | 0 | goto top_up_failed; |
1574 | 547k | } |
1575 | 3.13M | if (cbuf.end - cbp >= data_size) { |
1576 | 3.10M | planes[0].data = cbp; |
1577 | 3.10M | cbp += data_size; |
1578 | 3.10M | } else { |
1579 | 23.6k | uint cleft = cbuf.end - cbp; |
1580 | 23.6k | uint rleft = data_size - cleft; |
1581 | 23.6k | byte *rdata; |
1582 | | |
1583 | 23.6k | if (data_size > cbuf.end - cbuf.data) { |
1584 | | /* Allocate a separate buffer. */ |
1585 | 23.6k | rdata = data_on_heap = |
1586 | 23.6k | gs_alloc_bytes(mem, data_size, |
1587 | 23.6k | "clist image_data"); |
1588 | 23.6k | if (rdata == 0) { |
1589 | 0 | code = gs_note_error(gs_error_VMerror); |
1590 | 0 | goto out; |
1591 | 0 | } |
1592 | 23.6k | } else |
1593 | 0 | rdata = cbuf.data; |
1594 | 23.6k | memmove(rdata, cbp, cleft); |
1595 | 23.6k | if (data_on_heap) |
1596 | 23.6k | next_is_skip(&cbuf); |
1597 | 23.6k | if (sgets(s, rdata + cleft, rleft, &rleft) < 0) { |
1598 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
1599 | 0 | goto out; |
1600 | 0 | } |
1601 | 23.6k | planes[0].data = rdata; |
1602 | 23.6k | cbp = cbuf.end; /* force refill */ |
1603 | 23.6k | } |
1604 | 3.13M | { |
1605 | 3.13M | int plane; |
1606 | 3.13M | const byte *data = planes[0].data; |
1607 | | |
1608 | 3.13M | for (plane = 0; |
1609 | 6.26M | plane < image_info->num_planes; |
1610 | 3.13M | ++plane |
1611 | 3.13M | ) { |
1612 | 3.13M | if (planes[plane].raster == 0) |
1613 | 0 | planes[plane].data = 0; |
1614 | 3.13M | else { |
1615 | 3.13M | planes[plane].data = data; |
1616 | 3.13M | data += planes[plane].raster * |
1617 | 3.13M | data_height; |
1618 | 3.13M | } |
1619 | 3.13M | } |
1620 | 3.13M | } |
1621 | | #ifdef DEBUG |
1622 | | if (gs_debug_c('L')) { |
1623 | | int plane; |
1624 | | |
1625 | | for (plane = 0; plane < image_info->num_planes; |
1626 | | ++plane) |
1627 | | if (planes[plane].data != 0) |
1628 | | cmd_print_bits(mem, |
1629 | | planes[plane].data, |
1630 | | image_rect.q.x - |
1631 | | image_rect.p.x, |
1632 | | data_height, |
1633 | | planes[plane].raster); |
1634 | | } |
1635 | | #endif |
1636 | 3.13M | code = gx_image_plane_data(image_info, planes, |
1637 | 3.13M | data_height); |
1638 | 3.13M | if (code < 0) |
1639 | 0 | gx_image_end(image_info, false); |
1640 | 3.13M | if (data_on_heap) |
1641 | 23.6k | gs_free_object(mem, data_on_heap, |
1642 | 3.13M | "clist image_data"); |
1643 | 3.13M | data_x = 0; |
1644 | 3.13M | if (code < 0) |
1645 | 0 | goto out; |
1646 | 3.13M | continue; |
1647 | 39.1M | case cmd_opv_extend: |
1648 | 39.1M | switch (*cbp++) { |
1649 | 0 | case cmd_opv_ext_put_params: |
1650 | 0 | if_debug0m('L', mem, "put_params\n"); |
1651 | 0 | cbuf.ptr = cbp; |
1652 | 0 | code = read_put_params(&cbuf, &gs_gstate, |
1653 | 0 | cdev, mem); |
1654 | 0 | cbp = cbuf.ptr; |
1655 | 0 | if (code > 0) |
1656 | 0 | break; /* empty list */ |
1657 | 0 | if (code < 0) |
1658 | 0 | goto out; |
1659 | 0 | if (playback_action == playback_action_setup) |
1660 | 0 | goto out; |
1661 | 0 | break; |
1662 | 11.6M | case cmd_opv_ext_composite: |
1663 | 11.6M | if_debug0m('L', mem, " ext_composite\n"); |
1664 | 11.6M | cbuf.ptr = cbp; |
1665 | | /* |
1666 | | * The screen phase may have been changed during |
1667 | | * the processing of masked images. |
1668 | | */ |
1669 | 11.6M | gx_gstate_setscreenphase(&gs_gstate, |
1670 | 11.6M | -x0, -y0, gs_color_select_all); |
1671 | 11.6M | cbp -= 2; /* Step back to simplify the cycle invariant below. */ |
1672 | 412M | for (;;) { |
1673 | | /* This internal loop looks ahead for compositor commands and |
1674 | | copies them into a temporary queue. Compositors, which do not paint something, |
1675 | | are marked as idle and later executed with a reduced functionality |
1676 | | for reducing time and memory expense. */ |
1677 | 412M | int len; |
1678 | | |
1679 | 412M | if (cbp >= cbuf.warn_limit) { |
1680 | 246k | code = top_up_cbuf(&cbuf, &cbp); |
1681 | 246k | if (code < 0) |
1682 | 0 | goto out; |
1683 | 246k | } |
1684 | | #ifdef DEBUG |
1685 | | if (gs_debug_c('L')) { |
1686 | | long offset = (long)clist_file_offset(st, cbp - cbuf.data); |
1687 | | |
1688 | | dmlprintf1(mem, "[L] %ld:", offset); |
1689 | | clist_debug_op(mem, cbp); |
1690 | | dmlprintf(mem, "\n"); |
1691 | | } |
1692 | | #endif |
1693 | 412M | if (cbp[0] == cmd_opv_extend && cbp[1] == cmd_opv_ext_composite) { |
1694 | 266M | gs_composite_t *pcomp, *pcomp_opening; |
1695 | 266M | gs_compositor_closing_state closing_state; |
1696 | | |
1697 | 266M | cbuf.ptr = cbp += 2; |
1698 | 266M | code = read_composite(&cbuf, mem, &pcomp); |
1699 | 266M | if (code < 0) |
1700 | 0 | goto out; |
1701 | 266M | cbp = cbuf.ptr; |
1702 | 266M | if (pcomp == NULL) |
1703 | 0 | continue; |
1704 | 266M | if (gs_is_pdf14trans_compositor(pcomp) && |
1705 | 266M | playback_action == playback_action_render_no_pdf14) { |
1706 | | /* free the compositor object */ |
1707 | 10.3M | gs_free_object(mem, pcomp, "read_composite"); |
1708 | 10.3M | pcomp = NULL; |
1709 | 10.3M | continue; |
1710 | 10.3M | } |
1711 | 256M | pcomp_opening = pcomp_last; |
1712 | 256M | closing_state = pcomp->type->procs.is_closing(pcomp, &pcomp_opening, tdev); |
1713 | 256M | switch(closing_state) |
1714 | 256M | { |
1715 | 0 | default: |
1716 | 0 | code = (int)closing_state; |
1717 | 0 | if (code >= 0) |
1718 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
1719 | 0 | goto out; |
1720 | 225M | case COMP_ENQUEUE: |
1721 | | /* Enqueue. */ |
1722 | 225M | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1723 | 225M | break; |
1724 | 0 | case COMP_EXEC_IDLE: |
1725 | | /* Execute idle. */ |
1726 | 0 | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1727 | 0 | code = execute_compositor_queue(cdev, &target, &tdev, |
1728 | 0 | &gs_gstate, &pcomp_first, &pcomp_last, pcomp_opening, x0, y0, mem, true); |
1729 | 0 | if (code < 0) |
1730 | 0 | goto out; |
1731 | 0 | break; |
1732 | 1.40M | case COMP_EXEC_QUEUE: |
1733 | | /* The opening command was executed. Execute the queue. */ |
1734 | 1.40M | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1735 | 1.40M | code = execute_compositor_queue(cdev, &target, &tdev, |
1736 | 1.40M | &gs_gstate, &pcomp_first, &pcomp_last, pcomp_first, x0, y0, mem, false); |
1737 | 1.40M | if (code < 0) |
1738 | 0 | goto out; |
1739 | 1.40M | break; |
1740 | 1.40M | case COMP_REPLACE_PREV: |
1741 | | /* Replace last compositors. */ |
1742 | 0 | code = execute_compositor_queue(cdev, &target, &tdev, |
1743 | 0 | &gs_gstate, &pcomp_first, &pcomp_last, pcomp_opening, x0, y0, mem, true); |
1744 | 0 | if (code < 0) |
1745 | 0 | goto out; |
1746 | 0 | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1747 | 0 | break; |
1748 | 26.6M | case COMP_REPLACE_CURR: |
1749 | | /* Replace specific compositor. */ |
1750 | 26.6M | code = dequeue_compositor(&pcomp_first, &pcomp_last, pcomp_opening); |
1751 | 26.6M | if (code < 0) |
1752 | 0 | goto out; |
1753 | 26.6M | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1754 | 26.6M | free_compositor(pcomp_opening, mem); |
1755 | 26.6M | break; |
1756 | 115k | case COMP_DROP_QUEUE: |
1757 | | /* Annihilate the last compositors. */ |
1758 | 115k | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1759 | 115k | code = drop_compositor_queue(&pcomp_first, &pcomp_last, pcomp_opening, mem, x0, y0, &gs_gstate); |
1760 | 115k | if (code < 0) |
1761 | 0 | goto out; |
1762 | 115k | break; |
1763 | 2.55M | case COMP_MARK_IDLE: |
1764 | | /* Mark as idle. */ |
1765 | 2.55M | enqueue_compositor(&pcomp_first, &pcomp_last, pcomp); |
1766 | 2.55M | mark_as_idle(pcomp_opening, pcomp); |
1767 | 256M | } |
1768 | 256M | } else if (is_null_compositor_op(cbp, &len)) { |
1769 | 132M | cbuf.ptr = cbp += len; |
1770 | 132M | } else if (cbp[0] == cmd_opv_end_page) { |
1771 | | /* End page, drop the queue. */ |
1772 | 2.40M | code = execute_compositor_queue(cdev, &target, &tdev, |
1773 | 2.40M | &gs_gstate, &pcomp_first, &pcomp_last, pcomp_first, x0, y0, mem, true); |
1774 | 2.40M | if (code < 0) |
1775 | 7 | goto out; |
1776 | 2.40M | break; |
1777 | 10.9M | } else if (pcomp_last != NULL && |
1778 | 10.9M | pcomp_last->type->procs.is_friendly(pcomp_last, cbp[0], cbp[1])) { |
1779 | | /* Immediately execute friendly commands |
1780 | | inside the compositor lookahead loop. |
1781 | | Currently there are few friendly commands for the pdf14 compositor only |
1782 | | due to the logic defined in c_pdf14trans_is_friendly. |
1783 | | This code duplicates some code portions from the main loop, |
1784 | | but we have no better idea with no slowdown to the main loop. |
1785 | | */ |
1786 | 1.69M | uint cb; |
1787 | | |
1788 | 1.69M | switch (*cbp++) { |
1789 | 732k | case cmd_opv_extend: |
1790 | 732k | switch (*cbp++) { |
1791 | 274k | case cmd_opv_ext_put_halftone: |
1792 | 274k | { |
1793 | 274k | uint ht_size; |
1794 | | |
1795 | 274k | enc_u_getw(ht_size, cbp); |
1796 | 274k | code = read_alloc_ht_buff(&ht_buff, ht_size, mem); |
1797 | 274k | if (code < 0) |
1798 | 0 | goto out; |
1799 | 274k | } |
1800 | 274k | break; |
1801 | 458k | case cmd_opv_ext_put_ht_seg: |
1802 | 458k | cbuf.ptr = cbp; |
1803 | 458k | code = read_ht_segment(&ht_buff, &cbuf, |
1804 | 458k | &gs_gstate, tdev, |
1805 | 458k | mem); |
1806 | 458k | cbp = cbuf.ptr; |
1807 | 458k | if (code < 0) |
1808 | 0 | goto out; |
1809 | 458k | break; |
1810 | 458k | default: |
1811 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
1812 | 0 | goto out; |
1813 | 732k | } |
1814 | 732k | break; |
1815 | 957k | case cmd_opv_set_misc: |
1816 | 957k | cb = *cbp++; |
1817 | 957k | switch (cb >> 6) { |
1818 | 957k | case cmd_set_misc_map >> 6: |
1819 | 957k | cbuf.ptr = cbp; |
1820 | 957k | code = read_set_misc_map(cb, &cbuf, &gs_gstate, mem); |
1821 | 957k | if (code < 0) |
1822 | 0 | goto out; |
1823 | 957k | cbp = cbuf.ptr; |
1824 | 957k | break; |
1825 | 0 | default: |
1826 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
1827 | 0 | goto out; |
1828 | 957k | } |
1829 | 957k | break; |
1830 | 957k | default: |
1831 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
1832 | 0 | goto out; |
1833 | 1.69M | } |
1834 | 9.21M | } else { |
1835 | | /* A drawing command, execute entire queue. */ |
1836 | 9.21M | code = execute_compositor_queue(cdev, &target, &tdev, |
1837 | 9.21M | &gs_gstate, &pcomp_first, &pcomp_last, pcomp_first, x0, y0, mem, false); |
1838 | 9.21M | if (code < 0) |
1839 | 1 | goto out; |
1840 | 9.21M | break; |
1841 | 9.21M | } |
1842 | 412M | } |
1843 | 11.6M | if (pcomp_last != NULL) { |
1844 | 0 | code = gs_note_error(gs_error_unregistered); |
1845 | 0 | goto out; |
1846 | 0 | } |
1847 | 11.6M | break; |
1848 | 11.6M | case cmd_opv_ext_put_halftone: |
1849 | 689k | { |
1850 | 689k | uint ht_size; |
1851 | | |
1852 | 689k | if_debug0m('L', mem, " ext_put_halftone\n"); |
1853 | 689k | enc_u_getw(ht_size, cbp); |
1854 | 689k | code = read_alloc_ht_buff(&ht_buff, ht_size, mem); |
1855 | 689k | if (code < 0) |
1856 | 0 | goto out; |
1857 | 689k | } |
1858 | 689k | break; |
1859 | 1.14M | case cmd_opv_ext_put_ht_seg: |
1860 | 1.14M | if_debug0m('L', mem, " ext_put_ht_seg\n"); |
1861 | 1.14M | cbuf.ptr = cbp; |
1862 | 1.14M | code = read_ht_segment(&ht_buff, &cbuf, |
1863 | 1.14M | &gs_gstate, tdev, |
1864 | 1.14M | mem); |
1865 | 1.14M | cbp = cbuf.ptr; |
1866 | 1.14M | if (code < 0) |
1867 | 0 | goto out; |
1868 | 1.14M | break; |
1869 | 1.14M | case cmd_opv_ext_set_color_is_devn: |
1870 | 0 | state.color_is_devn = true; |
1871 | 0 | if_debug0m('L', mem, " ext_set_color_is_devn\n"); |
1872 | 0 | break; |
1873 | 0 | case cmd_opv_ext_unset_color_is_devn: |
1874 | 0 | state.color_is_devn = false; |
1875 | 0 | if_debug0m('L', mem, " ext_unset_color_is_devn\n"); |
1876 | 0 | break; |
1877 | 248 | case cmd_opv_ext_tile_rect_hl: |
1878 | | /* Strip tile with devn colors */ |
1879 | 248 | cbp = cmd_read_rect(op & 0xf0, &state.rect, cbp); |
1880 | 248 | if_debug4m('L', mem, " x=%d y=%d w=%d h=%d\n", |
1881 | 248 | state.rect.x, state.rect.y, |
1882 | 248 | state.rect.width,state.rect.height); |
1883 | 248 | code = (*dev_proc(tdev, strip_tile_rect_devn)) |
1884 | 248 | (tdev, &state_tile, |
1885 | 248 | state.rect.x - x0, state.rect.y - y0, |
1886 | 248 | state.rect.width, state.rect.height, |
1887 | 248 | &(state.tile_color_devn[0]), |
1888 | 248 | &(state.tile_color_devn[1]), |
1889 | 248 | tile_phase.x, tile_phase.y); |
1890 | 248 | break; |
1891 | 24.0M | case cmd_opv_ext_put_fill_dcolor: |
1892 | 24.0M | pdcolor = &fill_color; |
1893 | 24.0M | goto load_dcolor; |
1894 | 1.61M | case cmd_opv_ext_put_stroke_dcolor: |
1895 | 1.61M | pdcolor = &stroke_color; |
1896 | 1.61M | goto load_dcolor; |
1897 | 248 | case cmd_opv_ext_put_tile_devn_color0: |
1898 | 248 | pdcolor = &set_dev_colors[0]; |
1899 | 248 | goto load_dcolor; |
1900 | 248 | case cmd_opv_ext_put_tile_devn_color1: |
1901 | 248 | pdcolor = &set_dev_colors[1]; |
1902 | 25.7M | load_dcolor:{ |
1903 | 25.7M | uint color_size; |
1904 | 25.7M | int left, offset, l; |
1905 | 25.7M | const gx_device_color_type_t * pdct; |
1906 | 25.7M | byte type_and_flag = *cbp++; |
1907 | 25.7M | byte is_continuation = type_and_flag & 0x80; |
1908 | | |
1909 | 25.7M | if_debug0m('L', mem, " cmd_opv_ext_put_drawing_color\n"); |
1910 | 25.7M | pdct = gx_get_dc_type_from_index(type_and_flag & 0x7F); |
1911 | 25.7M | if (pdct == 0) { |
1912 | 0 | code = gs_note_error(gs_error_rangecheck); |
1913 | 0 | goto out; |
1914 | 0 | } |
1915 | 25.7M | offset = 0; |
1916 | 25.7M | if (is_continuation) |
1917 | 25.7M | enc_u_getw(offset, cbp); |
1918 | 25.7M | enc_u_getw(color_size, cbp); |
1919 | 25.7M | left = color_size; |
1920 | 25.7M | if (!left) { |
1921 | | /* We still need to call pdct->read because it may change dev_color.type - |
1922 | | see gx_dc_null_read.*/ |
1923 | 676k | code = pdct->read(pdcolor, &gs_gstate, |
1924 | 676k | pdcolor, tdev, offset, |
1925 | 676k | cbp, 0, mem, x0, y0); |
1926 | 676k | if (code < 0) |
1927 | 0 | goto out; |
1928 | 676k | } |
1929 | 85.3M | while (left) { |
1930 | 59.6M | if (cbuf.warn_limit - cbp < (int)left) { /* cbp can be past warn_limit */ |
1931 | 36.5M | code = top_up_cbuf(&cbuf, &cbp); |
1932 | 36.5M | if (code < 0) |
1933 | 0 | goto top_up_failed; |
1934 | 36.5M | } |
1935 | 59.6M | l = min(left, cbuf.end - cbp); |
1936 | 59.6M | code = pdct->read(pdcolor, &gs_gstate, |
1937 | 59.6M | pdcolor, tdev, offset, |
1938 | 59.6M | cbp, l, mem, x0, y0); |
1939 | 59.6M | if (code < 0) |
1940 | 0 | goto out; |
1941 | 59.6M | l = code; |
1942 | 59.6M | cbp += l; |
1943 | 59.6M | offset += l; |
1944 | 59.6M | left -= l; |
1945 | 59.6M | } |
1946 | 25.7M | code = gx_color_load(pdcolor, &gs_gstate, |
1947 | 25.7M | tdev); |
1948 | 25.7M | if (code < 0) |
1949 | 0 | goto out; |
1950 | 25.7M | } |
1951 | 25.7M | break; |
1952 | 25.7M | default: |
1953 | 0 | goto bad_op; |
1954 | 39.1M | } |
1955 | 39.1M | break; |
1956 | 39.1M | default: |
1957 | 0 | goto bad_op; |
1958 | 67.8M | } |
1959 | 51.9M | continue; |
1960 | 79.6M | case cmd_op_segment >> 4: |
1961 | 79.6M | { |
1962 | 79.6M | int i; |
1963 | 79.6M | static const byte op_num_operands[] = { |
1964 | 79.6M | cmd_segment_op_num_operands_values |
1965 | 79.6M | }; |
1966 | 79.6M | rgapto: |
1967 | 79.6M | if (!in_path) { |
1968 | 13.9M | ppos.x = int2fixed(state.rect.x); |
1969 | 13.9M | ppos.y = int2fixed(state.rect.y); |
1970 | 13.9M | if_debug2m('L', mem, " (%d,%d)", state.rect.x, |
1971 | 13.9M | state.rect.y); |
1972 | 13.9M | notes = sn_none; |
1973 | 13.9M | in_path = true; |
1974 | 13.9M | } |
1975 | 208M | for (i = 0; i < op_num_operands[op & 0xf]; ++i) { |
1976 | 129M | fixed v; |
1977 | 129M | int b = *cbp; |
1978 | | |
1979 | 129M | switch (b >> 5) { |
1980 | 29.3M | case 0: |
1981 | 54.1M | case 1: |
1982 | 54.1M | vs[i++] = |
1983 | 54.1M | ((fixed) ((b ^ 0x20) - 0x20) << 13) + |
1984 | 54.1M | ((int)cbp[1] << 5) + (cbp[2] >> 3); |
1985 | 54.1M | if_debug1m('L', mem, " %g", fixed2float(vs[i - 1])); |
1986 | 54.1M | cbp += 2; |
1987 | 54.1M | v = (int)((*cbp & 7) ^ 4) - 4; |
1988 | 54.1M | break; |
1989 | 24.9M | case 2: |
1990 | 46.5M | case 3: |
1991 | 46.5M | v = (b ^ 0x60) - 0x20; |
1992 | 46.5M | break; |
1993 | 4.88M | case 4: |
1994 | 8.31M | case 5: |
1995 | | /* |
1996 | | * Without the following cast, C's |
1997 | | * brain-damaged coercion rules cause the |
1998 | | * result to be considered unsigned, and not |
1999 | | * sign-extended on machines where |
2000 | | * sizeof(long) > sizeof(int). |
2001 | | */ |
2002 | 8.31M | v = (((b ^ 0xa0) - 0x20) << 8) + (int)*++cbp; |
2003 | 8.31M | break; |
2004 | 15.8M | case 6: |
2005 | 15.8M | v = (b ^ 0xd0) - 0x10; |
2006 | 15.8M | vs[i] = |
2007 | 15.8M | ((v << 8) + cbp[1]) << (_fixed_shift - 2); |
2008 | 15.8M | if_debug1m('L', mem, " %g", fixed2float(vs[i])); |
2009 | 15.8M | cbp += 2; |
2010 | 15.8M | continue; |
2011 | 4.26M | default /*case 7 */ : |
2012 | 4.26M | v = (int)(*++cbp ^ 0x80) - 0x80; |
2013 | 8.52M | for (b = 0; b < sizeof(fixed) - 3; ++b) |
2014 | 4.26M | v = (v << 8) + *++cbp; |
2015 | 4.26M | break; |
2016 | 129M | } |
2017 | 113M | cbp += 3; |
2018 | | /* Absent the cast in the next statement, */ |
2019 | | /* the Borland C++ 4.5 compiler incorrectly */ |
2020 | | /* sign-extends the result of the shift. */ |
2021 | 113M | vs[i] = (v << 16) + (uint) (cbp[-2] << 8) + cbp[-1]; |
2022 | 113M | if_debug1m('L', mem, " %g", fixed2float(vs[i])); |
2023 | 113M | } |
2024 | 79.6M | if_debug0m('L', mem, "\n"); |
2025 | 79.6M | code = clist_decode_segment(&path, op, vs, &ppos, |
2026 | 79.6M | x0, y0, notes); |
2027 | 79.6M | if (code < 0) |
2028 | 0 | goto out; |
2029 | 79.6M | } |
2030 | 79.6M | continue; |
2031 | 110M | case cmd_op_path >> 4: |
2032 | 110M | if (op == cmd_opv_rgapto) |
2033 | 0 | goto rgapto; |
2034 | 110M | else if (op == cmd_opv_lock_pattern) { |
2035 | 2.01k | gs_id id; |
2036 | 2.01k | int lock = *cbp++; |
2037 | 2.01k | cmd_get_value(id, cbp); |
2038 | 2.01k | if_debug2m('L', mem, "id=0x%lx, lock=%d\n", id, lock); |
2039 | | /* We currently lock the pattern in all the bands, even in ones |
2040 | | * where we haven't used the pattern. This can cause the following |
2041 | | * call to return with 'undefined' because the pattern is not |
2042 | | * found. Just swallow this error and continue. */ |
2043 | 2.01k | code = gx_pattern_cache_entry_set_lock(&gs_gstate, id, lock); |
2044 | 2.01k | if (code == gs_error_undefined) |
2045 | 0 | code = 0; |
2046 | 2.01k | if (code < 0) |
2047 | 0 | goto out; |
2048 | 2.01k | continue; |
2049 | 110M | } else { |
2050 | 110M | gx_path fpath; |
2051 | 110M | gx_path *ppath = &path; |
2052 | | |
2053 | 110M | if_debug0m('L', mem, "\n"); |
2054 | | /* if in clip, flatten path first */ |
2055 | 110M | if (in_clip) { |
2056 | 1.64M | gx_path_init_local(&fpath, mem); |
2057 | 1.64M | code = gx_path_add_flattened_accurate(&path, &fpath, |
2058 | 1.64M | gs_currentflat_inline(&gs_gstate), |
2059 | 1.64M | gs_gstate.accurate_curves); |
2060 | 1.64M | if (code < 0) |
2061 | 0 | goto out; |
2062 | 1.64M | ppath = &fpath; |
2063 | 1.64M | } |
2064 | 110M | switch (op) { |
2065 | 9.91M | case cmd_opv_fill: |
2066 | 9.91M | fill_params.rule = gx_rule_winding_number; |
2067 | 9.91M | goto fill; |
2068 | 487k | case cmd_opv_eofill: |
2069 | 487k | fill_params.rule = gx_rule_even_odd; |
2070 | 10.4M | fill: |
2071 | 10.4M | fill_params.adjust = gs_gstate.fill_adjust; |
2072 | 10.4M | fill_params.flatness = gs_gstate.flatness; |
2073 | 10.4M | code = (*dev_proc(tdev, fill_path))(tdev, &gs_gstate, ppath, |
2074 | 10.4M | &fill_params, &fill_color, pcpath); |
2075 | 10.4M | break; |
2076 | 293k | case cmd_opv_fill_stroke: |
2077 | 293k | fill_params.rule = gx_rule_winding_number; |
2078 | 293k | goto fill_stroke; |
2079 | 20.5k | case cmd_opv_eofill_stroke: |
2080 | 20.5k | fill_params.rule = gx_rule_even_odd; |
2081 | 314k | fill_stroke: |
2082 | 314k | fill_params.adjust = gs_gstate.fill_adjust; |
2083 | 314k | fill_params.flatness = gs_gstate.flatness; |
2084 | 314k | stroke_params.flatness = gs_gstate.flatness; |
2085 | 314k | stroke_params.traditional = false; |
2086 | 314k | code = (*dev_proc(tdev, fill_stroke_path))(tdev, &gs_gstate, ppath, |
2087 | 314k | &fill_params, &fill_color, |
2088 | 314k | &stroke_params, &stroke_color, pcpath); |
2089 | 314k | break; |
2090 | 5.79M | case cmd_opv_stroke: |
2091 | 5.79M | stroke_params.flatness = gs_gstate.flatness; |
2092 | 5.79M | stroke_params.traditional = false; |
2093 | 5.79M | code = (*dev_proc(tdev, stroke_path)) |
2094 | 5.79M | (tdev, &gs_gstate, |
2095 | 5.79M | ppath, &stroke_params, |
2096 | 5.79M | &stroke_color, pcpath); |
2097 | 5.79M | break; |
2098 | 852k | case cmd_opv_polyfill: |
2099 | 852k | code = clist_do_polyfill(tdev, ppath, &fill_color, |
2100 | 852k | gs_gstate.log_op); |
2101 | 852k | break; |
2102 | 93.4M | case cmd_opv_fill_trapezoid: |
2103 | 93.4M | { |
2104 | 93.4M | gs_fixed_edge left, right; |
2105 | 93.4M | fixed ybot, ytop; |
2106 | 93.4M | int options, swap_axes, wh; |
2107 | 93.4M | fixed x0f; |
2108 | 93.4M | fixed y0f; |
2109 | 93.4M | gx_device *ttdev = tdev; |
2110 | | |
2111 | 93.4M | if (pcpath != NULL && !clipper_dev_open) { |
2112 | 3.01k | gx_make_clip_device_on_stack(&clipper_dev, pcpath, tdev); |
2113 | 3.01k | clipper_dev_open = true; |
2114 | 3.01k | } |
2115 | 93.4M | if (clipper_dev_open) |
2116 | 82.3M | ttdev = (gx_device *)&clipper_dev; |
2117 | | /* Note that if we have transparency present, the clipper device may need to have |
2118 | | its color information updated to be synced up with the target device. |
2119 | | This can occur if we had fills of a path first with a transparency mask to get |
2120 | | an XPS opacity followed by a fill with a transparency group. This occurs in |
2121 | | the XPS gradient code */ |
2122 | 93.4M | if (tdev->color_info.num_components != ttdev->color_info.num_components){ |
2123 | | /* Reset the clipper device color information. Only worry about |
2124 | | the information that is used in the trap code */ |
2125 | 0 | ttdev->color_info.num_components = tdev->color_info.num_components; |
2126 | 0 | ttdev->color_info.depth = tdev->color_info.depth; |
2127 | 0 | ttdev->color_info.polarity = tdev->color_info.polarity; |
2128 | 0 | memcpy(&(ttdev->color_info.comp_bits),&(tdev->color_info.comp_bits),GX_DEVICE_COLOR_MAX_COMPONENTS); |
2129 | 0 | memcpy(&(ttdev->color_info.comp_shift),&(tdev->color_info.comp_shift),GX_DEVICE_COLOR_MAX_COMPONENTS); |
2130 | 0 | } |
2131 | 93.4M | cmd_getw(left.start.x, cbp); |
2132 | 93.4M | cmd_getw(left.start.y, cbp); |
2133 | 93.4M | cmd_getw(left.end.x, cbp); |
2134 | 93.4M | cmd_getw(left.end.y, cbp); |
2135 | 93.4M | cmd_getw(right.start.x, cbp); |
2136 | 93.4M | cmd_getw(right.start.y, cbp); |
2137 | 93.4M | cmd_getw(right.end.x, cbp); |
2138 | 93.4M | cmd_getw(right.end.y, cbp); |
2139 | 93.4M | cmd_getw(options, cbp); |
2140 | 93.4M | if (!(options & 4)) { |
2141 | 90.3M | cmd_getw(ybot, cbp); |
2142 | 90.3M | cmd_getw(ytop, cbp); |
2143 | 90.3M | } else |
2144 | 3.17M | ytop = ybot = 0; /* Unused, but quiet gcc warning. */ |
2145 | 93.4M | swap_axes = options & 1; |
2146 | 93.4M | wh = swap_axes ? tdev->width : tdev->height; |
2147 | 93.4M | x0f = int2fixed(swap_axes ? y0 : x0); |
2148 | 93.4M | y0f = int2fixed(swap_axes ? x0 : y0); |
2149 | 93.4M | left.start.x -= x0f; |
2150 | 93.4M | left.start.y -= y0f; |
2151 | 93.4M | left.end.x -= x0f; |
2152 | 93.4M | left.end.y -= y0f; |
2153 | 93.4M | right.start.x -= x0f; |
2154 | 93.4M | right.start.y -= y0f; |
2155 | 93.4M | right.end.x -= x0f; |
2156 | 93.4M | right.end.y -= y0f; |
2157 | 93.4M | if (options & 2) { |
2158 | 3.70M | uchar num_components = tdev->color_info.num_components; |
2159 | 3.70M | frac31 c[4][GX_DEVICE_COLOR_MAX_COMPONENTS], *cc[4]; |
2160 | 3.70M | byte colors_mask, i, j, m = 1; |
2161 | 3.70M | gs_fill_attributes fa; |
2162 | 3.70M | gs_fixed_rect clip; |
2163 | 3.70M | fixed hh = int2fixed(swap_axes ? target->width : target->height); |
2164 | | |
2165 | 3.70M | if (cbuf.end - cbp < 5 * cmd_max_intsize(sizeof(frac31))) { |
2166 | 1.46k | code = top_up_cbuf(&cbuf, &cbp); |
2167 | 1.46k | if (code < 0) |
2168 | 0 | goto top_up_failed; |
2169 | 1.46k | } |
2170 | 3.70M | cmd_getw(clip.p.x, cbp); |
2171 | 3.70M | cmd_getw(clip.p.y, cbp); |
2172 | 3.70M | cmd_getw(clip.q.x, cbp); |
2173 | 3.70M | cmd_getw(clip.q.y, cbp); |
2174 | 3.70M | clip.p.x -= x0f; |
2175 | 3.70M | clip.p.y -= y0f; |
2176 | 3.70M | clip.q.x -= x0f; |
2177 | 3.70M | clip.q.y -= y0f; |
2178 | 3.70M | if (clip.p.y < 0) |
2179 | 1.46M | clip.p.y = 0; |
2180 | 3.70M | if (clip.q.y > hh) |
2181 | 2.65M | clip.q.y = hh; |
2182 | 3.70M | fa.clip = &clip; |
2183 | 3.70M | fa.swap_axes = swap_axes; |
2184 | 3.70M | fa.ht = NULL; |
2185 | 3.70M | fa.lop = lop_default; /* fgixme: gs_gstate.log_op; */ |
2186 | 3.70M | fa.ystart = ybot - y0f; |
2187 | 3.70M | fa.yend = ytop - y0f; |
2188 | 3.70M | cmd_getw(colors_mask, cbp); |
2189 | 18.5M | for (i = 0; i < 4; i++, m <<= 1) { |
2190 | 14.8M | if (colors_mask & m) { |
2191 | 10.5M | if (cbuf.end - cbp < num_components * cmd_max_intsize(sizeof(frac31))) { |
2192 | 2.38k | code = top_up_cbuf(&cbuf, &cbp); |
2193 | 2.38k | if (code < 0) |
2194 | 0 | goto top_up_failed; |
2195 | 2.38k | } |
2196 | 10.5M | cc[i] = c[i]; |
2197 | 25.6M | for (j = 0; j < num_components; j++) |
2198 | 15.0M | cmd_getfrac(c[i][j], cbp); |
2199 | 10.5M | } else |
2200 | 4.23M | cc[i] = NULL; |
2201 | 14.8M | } |
2202 | 3.70M | if (options & 4) { |
2203 | 3.17M | # if 1 /* Disable to debug gx_fill_triangle_small. */ |
2204 | 3.17M | code = dev_proc(ttdev, fill_linear_color_triangle)(ttdev, &fa, |
2205 | 3.17M | &left.start, &left.end, &right.start, |
2206 | 3.17M | cc[0], cc[1], cc[2]); |
2207 | | # else |
2208 | | code = 0; |
2209 | | # endif |
2210 | 3.17M | if (code == 0) { |
2211 | | /* The target device didn't fill the trapezoid and |
2212 | | requests a decomposition. Subdivide into smaller triangles : */ |
2213 | 0 | if (pfs.dev == NULL) |
2214 | 0 | code = gx_init_patch_fill_state_for_clist(tdev, &pfs, mem); |
2215 | 0 | if (code >= 0) { |
2216 | 0 | pfs.dev = ttdev; |
2217 | 0 | pfs.rect = clip; /* fixme: eliminate 'clip'. */ |
2218 | 0 | fa.pfs = &pfs; |
2219 | 0 | code = gx_fill_triangle_small(ttdev, &fa, |
2220 | 0 | &left.start, &left.end, &right.start, |
2221 | 0 | cc[0], cc[1], cc[2]); |
2222 | 0 | } |
2223 | 0 | } |
2224 | 3.17M | } else { |
2225 | 527k | code = dev_proc(ttdev, fill_linear_color_trapezoid)(ttdev, &fa, |
2226 | 527k | &left.start, &left.end, &right.start, &right.end, |
2227 | 527k | cc[0], cc[1], cc[2], cc[3]); |
2228 | 527k | if (code == 0) { |
2229 | | /* Fixme : The target device didn't fill the trapezoid and |
2230 | | requests a decomposition. |
2231 | | Currently we never call it with 4 colors (see gxshade6.c) |
2232 | | and 2 colors must not return 0 - see comment to |
2233 | | dev_t_proc_fill_linear_color_trapezoid in gxdevcli.c . |
2234 | | Must not happen. */ |
2235 | 0 | code = gs_note_error(gs_error_unregistered); |
2236 | 0 | } |
2237 | 527k | } |
2238 | 3.70M | } else |
2239 | 89.7M | code = gx_default_fill_trapezoid(ttdev, &left, &right, |
2240 | 89.7M | max(ybot - y0f, fixed_half), |
2241 | 89.7M | min(ytop - y0f, int2fixed(wh)), swap_axes, |
2242 | 89.7M | &fill_color, gs_gstate.log_op); |
2243 | 93.4M | } |
2244 | 93.4M | break; |
2245 | 93.4M | default: |
2246 | 0 | goto bad_op; |
2247 | 110M | } |
2248 | 110M | if (ppath != &path) |
2249 | 1.64M | gx_path_free(ppath, "clist_render_band"); |
2250 | 110M | } |
2251 | 110M | if (in_path) { /* path might be empty! */ |
2252 | 13.9M | state.rect.x = fixed2int_var(ppos.x); |
2253 | 13.9M | state.rect.y = fixed2int_var(ppos.y); |
2254 | 13.9M | in_path = false; |
2255 | 13.9M | } |
2256 | 110M | gx_path_free(&path, "clist_render_band"); |
2257 | 110M | gx_path_init_local(&path, mem); |
2258 | 110M | if (code < 0) |
2259 | 3 | goto out; |
2260 | 110M | continue; |
2261 | 110M | default: |
2262 | 0 | bad_op:mlprintf5(mem, "Bad op %02x band y0 = %d file pos %"PRId64" buf pos %d/%d\n", |
2263 | 0 | op, y0, stell(s), (int)(cbp - cbuf.data), (int)(cbuf.end - cbuf.data)); |
2264 | 0 | { |
2265 | 0 | const byte *pp; |
2266 | |
|
2267 | 0 | for (pp = cbuf.data; pp < cbuf.end; pp += 10) { |
2268 | 0 | dmlprintf1(mem, "%4d:", (int)(pp - cbuf.data)); |
2269 | 0 | dmprintf10(mem, " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", |
2270 | 0 | pp[0], pp[1], pp[2], pp[3], pp[4], |
2271 | 0 | pp[5], pp[6], pp[7], pp[8], pp[9]); |
2272 | 0 | } |
2273 | 0 | } |
2274 | 0 | code = gs_note_error(gs_error_Fatal); |
2275 | 0 | goto out; |
2276 | 644M | } |
2277 | 644M | if_debug4m('L', mem, " x=%d y=%d w=%d h=%d\n", |
2278 | 207M | state.rect.x, state.rect.y, state.rect.width, |
2279 | 207M | state.rect.height); |
2280 | 207M | switch (op >> 4) { |
2281 | 7.14M | case cmd_op_fill_rect >> 4: |
2282 | 7.14M | if (state.rect.width == 0 && state.rect.height == 0 && |
2283 | 7.14M | state.rect.x == 0 && state.rect.y == 0) { |
2284 | | /* FIXME: This test should be unnecessary. Bug 692076 |
2285 | | * is open pending a proper fix. */ |
2286 | 2.96M | code = (dev_proc(tdev, fillpage) == NULL ? 0 : |
2287 | 2.96M | (*dev_proc(tdev, fillpage))(tdev, &gs_gstate, |
2288 | 2.96M | &fill_color)); |
2289 | 2.96M | break; |
2290 | 2.96M | } |
2291 | 17.4M | case cmd_op_fill_rect_short >> 4: |
2292 | 153M | case cmd_op_fill_rect_tiny >> 4: |
2293 | 153M | if (!state.lop_enabled) { |
2294 | 153M | code = (*dev_proc(tdev, fill_rectangle)) |
2295 | 153M | (tdev, state.rect.x - x0, state.rect.y - y0, |
2296 | 153M | state.rect.width, state.rect.height, |
2297 | 153M | state.colors[1]); |
2298 | 153M | break; |
2299 | 153M | } |
2300 | 0 | source = NULL; |
2301 | 0 | data_x = 0; |
2302 | 0 | raster = 0; |
2303 | 0 | colors[0] = colors[1] = state.colors[1]; |
2304 | 0 | log_op = state.lop; |
2305 | 0 | pcolor = colors; |
2306 | 0 | do_rop:code = (*dev_proc(tdev, strip_copy_rop2)) |
2307 | 0 | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2308 | 0 | pcolor, &state_tile, |
2309 | 0 | (state.tile_colors[0] == gx_no_color_index && |
2310 | 0 | state.tile_colors[1] == gx_no_color_index ? |
2311 | 0 | NULL : state.tile_colors), |
2312 | 0 | state.rect.x - x0, state.rect.y - y0, |
2313 | 0 | state.rect.width - data_x, state.rect.height, |
2314 | 0 | tile_phase.x, tile_phase.y, log_op, |
2315 | 0 | plane_height); |
2316 | 0 | plane_height = 0; |
2317 | 0 | data_x = 0; |
2318 | 0 | break; |
2319 | 120k | case cmd_op_tile_rect >> 4: |
2320 | 120k | if (state.rect.width == 0 && state.rect.height == 0 && |
2321 | 120k | state.rect.x == 0 && state.rect.y == 0) { |
2322 | 0 | code = (*dev_proc(tdev, fillpage))(tdev, &gs_gstate, &fill_color); |
2323 | 0 | break; |
2324 | 0 | } |
2325 | 875k | case cmd_op_tile_rect_short >> 4: |
2326 | 2.10M | case cmd_op_tile_rect_tiny >> 4: |
2327 | | /* Currently we don't use lop with strip_tile_rectangle. */ |
2328 | 2.10M | code = (*dev_proc(tdev, strip_tile_rectangle)) |
2329 | 2.10M | (tdev, &state_tile, |
2330 | 2.10M | state.rect.x - x0, state.rect.y - y0, |
2331 | 2.10M | state.rect.width, state.rect.height, |
2332 | 2.10M | state.tile_colors[0], state.tile_colors[1], |
2333 | 2.10M | tile_phase.x, tile_phase.y); |
2334 | 2.10M | break; |
2335 | 44.7M | case cmd_op_copy_mono_planes >> 4: |
2336 | 44.7M | if (state.lop_enabled) { |
2337 | 0 | pcolor = state.colors; |
2338 | 0 | log_op = state.lop; |
2339 | 0 | goto do_rop; |
2340 | 0 | } |
2341 | 44.7M | if ((op & cmd_copy_use_tile) || pcpath != NULL) { /* |
2342 | | * This call of copy_mono originated as a call |
2343 | | * of fill_mask. |
2344 | | */ |
2345 | 43.9M | code = gx_image_fill_masked |
2346 | 43.9M | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2347 | 43.9M | state.rect.x - x0, state.rect.y - y0, |
2348 | 43.9M | state.rect.width - data_x, state.rect.height, |
2349 | 43.9M | &fill_color, 1, gs_gstate.log_op, pcpath); |
2350 | 43.9M | } else { |
2351 | 790k | if (plane_height == 0) { |
2352 | 784k | code = (*dev_proc(tdev, copy_mono)) |
2353 | 784k | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2354 | 784k | state.rect.x - x0, state.rect.y - y0, |
2355 | 784k | state.rect.width - data_x, state.rect.height, |
2356 | 784k | state.colors[0], state.colors[1]); |
2357 | 784k | } else { |
2358 | 6.81k | code = (*dev_proc(tdev, copy_planes)) |
2359 | 6.81k | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2360 | 6.81k | state.rect.x - x0, state.rect.y - y0, |
2361 | 6.81k | state.rect.width - data_x, state.rect.height, |
2362 | 6.81k | plane_height); |
2363 | 6.81k | } |
2364 | 790k | } |
2365 | 44.7M | plane_height = 0; |
2366 | 44.7M | data_x = 0; |
2367 | 44.7M | break; |
2368 | 4.53M | case cmd_op_copy_color_alpha >> 4: |
2369 | 4.53M | if (state.color_is_alpha) { |
2370 | | /****** CAN'T DO ROP WITH ALPHA ******/ |
2371 | 0 | if (state.color_is_devn && |
2372 | 0 | dev_proc(tdev, copy_alpha_hl_color) != gx_default_no_copy_alpha_hl_color) { /* FIXME */ |
2373 | 0 | code = (*dev_proc(tdev, copy_alpha_hl_color)) |
2374 | 0 | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2375 | 0 | state.rect.x - x0, state.rect.y - y0, |
2376 | 0 | state.rect.width - data_x, state.rect.height, |
2377 | 0 | &fill_color, depth); |
2378 | 0 | } else { |
2379 | 0 | code = (*dev_proc(tdev, copy_alpha)) |
2380 | 0 | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2381 | 0 | state.rect.x - x0, state.rect.y - y0, |
2382 | 0 | state.rect.width - data_x, state.rect.height, |
2383 | 0 | state.colors[1], depth); |
2384 | 0 | } |
2385 | 4.53M | } else { |
2386 | 4.53M | if (state.lop_enabled) { |
2387 | 0 | pcolor = NULL; |
2388 | 0 | log_op = state.lop; |
2389 | 0 | goto do_rop; |
2390 | 0 | } |
2391 | 4.53M | code = (*dev_proc(tdev, copy_color)) |
2392 | 4.53M | (tdev, source, data_x, raster, gx_no_bitmap_id, |
2393 | 4.53M | state.rect.x - x0, state.rect.y - y0, |
2394 | 4.53M | state.rect.width - data_x, state.rect.height); |
2395 | 4.53M | } |
2396 | 4.53M | data_x = 0; |
2397 | 4.53M | break; |
2398 | 0 | default: /* can't happen */ |
2399 | 0 | goto bad_op; |
2400 | 207M | } |
2401 | 207M | } |
2402 | | /* Clean up before we exit. */ |
2403 | 3.00M | out: |
2404 | 3.00M | if (ht_buff.pbuff != 0) { |
2405 | 0 | gs_free_object(mem, ht_buff.pbuff, "clist_playback_band(ht_buff)"); |
2406 | 0 | ht_buff.pbuff = 0; |
2407 | 0 | ht_buff.pcurr = 0; |
2408 | 0 | } |
2409 | 3.00M | ht_buff.ht_size = 0; |
2410 | 3.00M | ht_buff.read_size = 0; |
2411 | | |
2412 | 3.00M | if (pcomp_last != NULL) { |
2413 | 0 | int code1 = drop_compositor_queue(&pcomp_first, &pcomp_last, NULL, mem, x0, y0, &gs_gstate); |
2414 | |
|
2415 | 0 | if (code == 0) |
2416 | 0 | code = code1; |
2417 | 0 | } |
2418 | 3.00M | gx_cpath_free(&clip_path, "clist_render_band exit"); |
2419 | 3.00M | gx_path_free(&path, "clist_render_band exit"); |
2420 | 3.00M | if (gs_gstate.pattern_cache != NULL) { |
2421 | 85.1k | gx_pattern_cache_free(gs_gstate.pattern_cache); |
2422 | 85.1k | gs_gstate.pattern_cache = NULL; |
2423 | 85.1k | } |
2424 | | /* Free the client color and device colors allocated upon entry */ |
2425 | 3.00M | gs_free_object(mem, gs_gstate.color[0].ccolor, "clist_playback_band"); |
2426 | 3.00M | gs_free_object(mem, gs_gstate.color[1].ccolor, "clist_playback_band"); |
2427 | 3.00M | gs_free_object(mem, gs_gstate.color[0].dev_color, "clist_playback_band"); |
2428 | 3.00M | gs_free_object(mem, gs_gstate.color[1].dev_color, "clist_playback_band"); |
2429 | 3.00M | gs_gstate.color[0].ccolor = gs_gstate.color[1].ccolor = NULL; |
2430 | 3.00M | gs_gstate.color[0].dev_color = gs_gstate.color[1].dev_color = NULL; |
2431 | | |
2432 | | /* The imager state release will decrement the icc link cache. To avoid |
2433 | | race conditions lock the cache */ |
2434 | 3.00M | gx_monitor_enter(cdev->icc_cache_cl->lock); |
2435 | 3.00M | gs_gstate_release(&gs_gstate); |
2436 | 3.00M | gx_monitor_leave(cdev->icc_cache_cl->lock); /* done with increment, let everyone run */ |
2437 | 3.00M | gs_free_object(mem, data_bits, "clist_playback_band(data_bits)"); |
2438 | 3.00M | if (target != orig_target) { |
2439 | 1.64M | if (target->rc.ref_count != 1) { |
2440 | | /* This can occur if we are coming from a pattern clist that |
2441 | | includes transparency. In this case, we do not want to |
2442 | | free the compositor since it is really the main target that |
2443 | | we are tiling into. i.e. the tile itself does not have |
2444 | | a pdf14 device, but rather we push a trans group, draw and |
2445 | | then pop the group to properly blend */ |
2446 | 0 | rc_decrement(target, "gxclrast(target compositor)"); |
2447 | 1.64M | } else { |
2448 | | /* Ref count was 1. close the device and then free it */ |
2449 | 1.64M | if (target->is_open) |
2450 | 247 | dev_proc(target, close_device)(target); |
2451 | 1.64M | gs_free_object(target->memory, target, "gxclrast discard compositor"); |
2452 | 1.64M | } |
2453 | 1.64M | target = orig_target; |
2454 | 1.64M | } |
2455 | 3.00M | if (code < 0) { |
2456 | 11 | if (pfs.dev != NULL) |
2457 | 0 | term_patch_fill_state(&pfs); |
2458 | 11 | rc_decrement(gs_gstate.color[0].color_space, "clist_playback_band"); |
2459 | 11 | rc_decrement(gs_gstate.color[1].color_space, "clist_playback_band"); |
2460 | 11 | gs_free_object(mem, cbuf_storage, "clist_playback_band(cbuf_storage)"); |
2461 | 11 | gx_cpath_free(&clip_path, "clist_playback_band"); |
2462 | 11 | if (pcpath != &clip_path) |
2463 | 8 | gx_cpath_free(pcpath, "clist_playback_band"); |
2464 | 11 | if (clipper_dev_open) |
2465 | 0 | gx_destroy_clip_device_on_stack(&clipper_dev); |
2466 | 11 | return_error(code); |
2467 | 11 | } |
2468 | | /* Check whether we have more pages to process. */ |
2469 | 3.00M | if ((playback_action != playback_action_setup && |
2470 | 3.00M | (cbp < cbuf.end || !seofp(s)) && (op != cmd_opv_end_page) ) |
2471 | 3.00M | ) |
2472 | 0 | goto in; |
2473 | 3.00M | if (pfs.dev != NULL) |
2474 | 0 | term_patch_fill_state(&pfs); |
2475 | 3.00M | rc_decrement(gs_gstate.color[0].color_space, "clist_playback_band"); |
2476 | 3.00M | rc_decrement(gs_gstate.color[1].color_space, "clist_playback_band"); |
2477 | 3.00M | gs_free_object(mem, cbuf_storage, "clist_playback_band(cbuf_storage)"); |
2478 | 3.00M | gx_cpath_free(&clip_path, "clist_playback_band"); |
2479 | 3.00M | if (pcpath != &clip_path) |
2480 | 2.53M | gx_cpath_free(pcpath, "clist_playback_band"); |
2481 | 3.00M | if (clipper_dev_open) |
2482 | 1.46k | gx_destroy_clip_device_on_stack(&clipper_dev); |
2483 | 3.00M | return code; |
2484 | 0 | top_up_failed: |
2485 | 0 | gx_cpath_free(&clip_path, "clist_playback_band"); |
2486 | 0 | if (pcpath != &clip_path) |
2487 | 0 | gx_cpath_free(pcpath, "clist_playback_band"); |
2488 | 0 | if (clipper_dev_open) |
2489 | 0 | gx_destroy_clip_device_on_stack(&clipper_dev); |
2490 | 0 | return code; |
2491 | 3.00M | } |
2492 | | |
2493 | | /* ---------------- Individual commands ---------------- */ |
2494 | | |
2495 | | /* |
2496 | | * These single-use procedures implement a few large individual commands, |
2497 | | * primarily for readability but also to avoid overflowing compilers' |
2498 | | * optimization limits. They all take the command buffer as their first |
2499 | | * parameter (pcb), assume that the current buffer pointer is in pcb->ptr, |
2500 | | * and update it there. |
2501 | | */ |
2502 | | |
2503 | | static int |
2504 | | read_set_tile_size(command_buf_t *pcb, tile_slot *bits, bool for_pattern) |
2505 | 3.73k | { |
2506 | 3.73k | const byte *cbp = pcb->ptr; |
2507 | 3.73k | uint rep_width, rep_height; |
2508 | 3.73k | uint pdepth; |
2509 | 3.73k | byte bd = *cbp++; |
2510 | | |
2511 | 3.73k | bits->head.depth = cmd_code_to_depth(bd); |
2512 | 3.73k | if (for_pattern) |
2513 | 3.73k | cmd_getw(bits->id, cbp); |
2514 | 3.73k | cmd_getw(rep_width, cbp); |
2515 | 3.73k | cmd_getw(rep_height, cbp); |
2516 | 3.73k | if (bd & 0x20) { |
2517 | 3.67k | cmd_getw(bits->x_reps, cbp); |
2518 | 3.67k | bits->width = rep_width * bits->x_reps; |
2519 | 3.67k | } else { |
2520 | 60 | bits->x_reps = 1; |
2521 | 60 | bits->width = rep_width; |
2522 | 60 | } |
2523 | 3.73k | if (bd & 0x40) { |
2524 | 1.30k | cmd_getw(bits->y_reps, cbp); |
2525 | 1.30k | bits->height = rep_height * bits->y_reps; |
2526 | 2.43k | } else { |
2527 | 2.43k | bits->y_reps = 1; |
2528 | 2.43k | bits->height = rep_height; |
2529 | 2.43k | } |
2530 | 3.73k | if (bd & 0x80) |
2531 | 3.73k | cmd_getw(bits->rep_shift, cbp); |
2532 | 3.73k | else |
2533 | 3.73k | bits->rep_shift = 0; |
2534 | 3.73k | if (bd & 0x10) |
2535 | 0 | bits->num_planes = *cbp++; |
2536 | 3.73k | else |
2537 | 3.73k | bits->num_planes = 1; |
2538 | 3.73k | if_debug7('L', " depth=%d size=(%d,%d), rep_size=(%d,%d), rep_shift=%d, num_planes=%d\n", |
2539 | 3.73k | bits->head.depth, bits->width, |
2540 | 3.73k | bits->height, rep_width, |
2541 | 3.73k | rep_height, bits->rep_shift, bits->num_planes); |
2542 | 3.73k | bits->shift = |
2543 | 3.73k | (bits->rep_shift == 0 ? 0 : |
2544 | 3.73k | (bits->rep_shift * (bits->height / rep_height)) % rep_width); |
2545 | 3.73k | pdepth = bits->head.depth; |
2546 | 3.73k | if (bits->num_planes != 1) |
2547 | 0 | pdepth /= bits->num_planes; |
2548 | 3.73k | bits->raster = bitmap_raster(bits->width * pdepth); |
2549 | 3.73k | pcb->ptr = cbp; |
2550 | 3.73k | return 0; |
2551 | 3.73k | } |
2552 | | |
2553 | | static int |
2554 | | read_set_bits(command_buf_t *pcb, tile_slot *bits, int compress, |
2555 | | gx_clist_state *pcls, gx_strip_bitmap *tile, tile_slot **pslot, |
2556 | | gx_device_clist_reader *cdev, gs_memory_t *mem) |
2557 | 15.4M | { |
2558 | 15.4M | const byte *cbp = pcb->ptr; |
2559 | 15.4M | uint rep_width = bits->width / bits->x_reps; |
2560 | 15.4M | uint rep_height = bits->height / bits->y_reps; |
2561 | 15.4M | uint index; |
2562 | 15.4M | ulong offset; |
2563 | 15.4M | uint width_bits; |
2564 | 15.4M | uint width_bytes; |
2565 | 15.4M | uint raster; |
2566 | 15.4M | uint bytes; |
2567 | 15.4M | byte *data; |
2568 | 15.4M | tile_slot *slot; |
2569 | 15.4M | uint depth = bits->head.depth; |
2570 | | |
2571 | 15.4M | if (bits->num_planes != 1) |
2572 | 0 | depth /= bits->num_planes; |
2573 | 15.4M | width_bits = rep_width * depth; |
2574 | | |
2575 | 15.4M | bytes = clist_bitmap_bytes(width_bits, rep_height * bits->num_planes, |
2576 | 15.4M | compress | |
2577 | 15.4M | (rep_width < bits->width ? |
2578 | 15.3M | decompress_spread : 0) | |
2579 | 15.4M | decompress_elsewhere, |
2580 | 15.4M | &width_bytes, |
2581 | 15.4M | (uint *)&raster); |
2582 | | |
2583 | 15.4M | cmd_getw(index, cbp); |
2584 | 15.4M | cmd_getw(offset, cbp); |
2585 | 15.4M | if_debug2m('L', mem, " index=%d offset=%lu\n", index, offset); |
2586 | 15.4M | pcls->tile_index = index; |
2587 | 15.4M | cdev->tile_table[pcls->tile_index].offset = offset; |
2588 | 15.4M | slot = (tile_slot *)(cdev->cache_chunk->data + offset); |
2589 | 15.4M | *pslot = slot; |
2590 | 15.4M | *slot = *bits; |
2591 | 15.4M | tile->data = data = (byte *)(slot + 1); |
2592 | | #ifdef DEBUG |
2593 | | slot->index = pcls->tile_index; |
2594 | | #endif |
2595 | 15.4M | if (compress == cmd_compress_const) { |
2596 | 0 | cbp = cmd_read_data(pcb, data, 1, cbp); |
2597 | 0 | if (width_bytes > 0 && rep_height > 0) |
2598 | 0 | memset(data+1, *data, width_bytes * rep_height - 1); |
2599 | 15.4M | } else if (compress) { |
2600 | | /* |
2601 | | * Decompress the image data. We'd like to share this code with the |
2602 | | * similar code in copy_*, but right now we don't see how. |
2603 | | */ |
2604 | 1.58M | stream_cursor_read r; |
2605 | 1.58M | stream_cursor_write w; |
2606 | | /* |
2607 | | * We don't know the data length a priori, so to be conservative, we |
2608 | | * read the uncompressed size. |
2609 | | */ |
2610 | 1.58M | uint cleft = pcb->end - cbp; |
2611 | | |
2612 | 1.58M | if (cleft < bytes && !pcb->end_status) { |
2613 | 15.2k | uint nread = cbuf_size - cleft; |
2614 | | |
2615 | 15.2k | advance_buffer(pcb, cbp); |
2616 | 15.2k | pcb->end_status = sgets(pcb->s, pcb->data + cleft, nread, &nread); |
2617 | 15.2k | set_cb_end(pcb, pcb->data + cleft + nread); |
2618 | 15.2k | cbp = pcb->data; |
2619 | 15.2k | } |
2620 | 1.58M | r.ptr = cbp - 1; |
2621 | 1.58M | r.limit = pcb->end - 1; |
2622 | 1.58M | w.ptr = data - 1; |
2623 | 1.58M | w.limit = w.ptr + bytes; |
2624 | 1.58M | switch (compress) { |
2625 | 0 | case cmd_compress_rle: |
2626 | 0 | { |
2627 | 0 | stream_RLD_state sstate; |
2628 | |
|
2629 | 0 | clist_rld_init(&sstate); |
2630 | 0 | (*s_RLD_template.process) |
2631 | 0 | ((stream_state *)&sstate, &r, &w, true); |
2632 | 0 | } |
2633 | 0 | break; |
2634 | 1.58M | case cmd_compress_cfe: |
2635 | 1.58M | { |
2636 | 1.58M | stream_CFD_state sstate; |
2637 | | |
2638 | 1.58M | clist_cfd_init(&sstate, |
2639 | 1.58M | width_bytes << 3 /*width_bits */ , |
2640 | 1.58M | rep_height, mem); |
2641 | 1.58M | (*s_CFD_template.process) |
2642 | 1.58M | ((stream_state *)&sstate, &r, &w, true); |
2643 | 1.58M | (*s_CFD_template.release) |
2644 | 1.58M | ((stream_state *)&sstate); |
2645 | 1.58M | } |
2646 | 1.58M | break; |
2647 | 0 | default: |
2648 | 0 | return_error(gs_error_unregistered); |
2649 | 1.58M | } |
2650 | 1.58M | cbp = r.ptr + 1; |
2651 | 13.8M | } else if (rep_height * bits->num_planes > 1 && width_bytes != bits->raster) { |
2652 | 13.7M | cbp = cmd_read_short_bits(pcb, data, bytes, |
2653 | 13.7M | width_bytes, rep_height * bits->num_planes, |
2654 | 13.7M | bits->raster, cbp); |
2655 | 13.7M | } else { |
2656 | 78.7k | cbp = cmd_read_data(pcb, data, bytes, cbp); |
2657 | 78.7k | } |
2658 | 15.4M | if (bits->width > rep_width) |
2659 | 16.7k | bits_replicate_horizontally(data, |
2660 | 16.7k | rep_width * depth, rep_height * bits->num_planes, |
2661 | 16.7k | bits->raster, |
2662 | 16.7k | bits->width * depth, |
2663 | 16.7k | bits->raster); |
2664 | 15.4M | if (bits->height > rep_height) |
2665 | 2.46k | bits_replicate_vertically(data, |
2666 | 2.46k | rep_height, bits->raster, |
2667 | 2.46k | bits->height); |
2668 | | #ifdef DEBUG |
2669 | | if (gs_debug_c('L')) |
2670 | | cmd_print_bits(mem, data, bits->width, bits->height, bits->raster); |
2671 | | #endif |
2672 | 15.4M | pcb->ptr = cbp; |
2673 | 15.4M | return 0; |
2674 | 15.4M | } |
2675 | | |
2676 | | /* if necessary, allocate a buffer to hold a serialized halftone */ |
2677 | | static int |
2678 | | read_alloc_ht_buff(ht_buff_t * pht_buff, uint ht_size, gs_memory_t * mem) |
2679 | 963k | { |
2680 | | /* free the existing buffer, if any (usually none) */ |
2681 | 963k | if (pht_buff->pbuff != 0) { |
2682 | 0 | gs_free_object(mem, pht_buff->pbuff, "read_alloc_ht_buff"); |
2683 | 0 | pht_buff->pbuff = 0; |
2684 | 0 | } |
2685 | | |
2686 | | /* |
2687 | | * If the serialized halftone fits in the command buffer, no |
2688 | | * additional buffer is required. |
2689 | | */ |
2690 | 963k | if (ht_size > cbuf_ht_seg_max_size) { |
2691 | 631k | pht_buff->pbuff = gs_alloc_bytes(mem, ht_size, "read_alloc_ht_buff"); |
2692 | 631k | if (pht_buff->pbuff == 0) |
2693 | 0 | return_error(gs_error_VMerror); |
2694 | 631k | } |
2695 | 963k | pht_buff->ht_size = ht_size; |
2696 | 963k | pht_buff->read_size = 0; |
2697 | 963k | pht_buff->pcurr = pht_buff->pbuff; |
2698 | 963k | return 0; |
2699 | 963k | } |
2700 | | |
2701 | | /* read a halftone segment; if it is the final segment, build the halftone */ |
2702 | | static int |
2703 | | read_ht_segment( |
2704 | | ht_buff_t * pht_buff, |
2705 | | command_buf_t * pcb, |
2706 | | gs_gstate * pgs, |
2707 | | gx_device * dev, |
2708 | | gs_memory_t * mem ) |
2709 | 1.59M | { |
2710 | 1.59M | const byte * cbp = pcb->ptr; |
2711 | 1.59M | const byte * pbuff = 0; |
2712 | 1.59M | uint ht_size = pht_buff->ht_size, seg_size; |
2713 | 1.59M | int code = 0; |
2714 | | |
2715 | | /* get the segment size; refill command buffer if necessary */ |
2716 | 1.59M | enc_u_getw(seg_size, cbp); |
2717 | 1.59M | if (pcb->warn_limit - cbp < (int)seg_size) { /* cbp can be past warn_limit */ |
2718 | 639k | code = top_up_cbuf(pcb, &cbp); |
2719 | 639k | if (code < 0) |
2720 | 0 | return code; |
2721 | 639k | if (pcb->end - cbp < (int)seg_size) { |
2722 | 0 | emprintf(mem, " *** ht segment size doesn't fit in buffer ***\n"); |
2723 | 0 | return_error(gs_error_unknownerror); |
2724 | 0 | } |
2725 | 639k | } |
2726 | | |
2727 | 1.59M | if (pht_buff->pbuff == 0) { |
2728 | | /* if not separate buffer, must be only one segment */ |
2729 | 331k | if (seg_size != ht_size) |
2730 | 0 | return_error(gs_error_unknownerror); |
2731 | 331k | pbuff = cbp; |
2732 | 1.26M | } else { |
2733 | 1.26M | if (seg_size + pht_buff->read_size > pht_buff->ht_size) |
2734 | 0 | return_error(gs_error_unknownerror); |
2735 | 1.26M | memcpy(pht_buff->pcurr, cbp, seg_size); |
2736 | 1.26M | pht_buff->pcurr += seg_size; |
2737 | 1.26M | if ((pht_buff->read_size += seg_size) == ht_size) |
2738 | 631k | pbuff = pht_buff->pbuff; |
2739 | 1.26M | } |
2740 | | |
2741 | | /* if everything has been read, convert back to a halftone */ |
2742 | 1.59M | if (pbuff != 0) { |
2743 | 963k | code = gx_ht_read_and_install(pgs, dev, pbuff, ht_size, mem); |
2744 | | |
2745 | | /* release any buffered information */ |
2746 | 963k | if (pht_buff->pbuff != 0) { |
2747 | 631k | gs_free_object(mem, pht_buff->pbuff, "read_alloc_ht_buff"); |
2748 | 631k | pht_buff->pbuff = 0; |
2749 | 631k | pht_buff->pcurr = 0; |
2750 | 631k | } |
2751 | 963k | pht_buff->ht_size = 0; |
2752 | 963k | pht_buff->read_size = 0; |
2753 | 963k | } |
2754 | | |
2755 | | /* update the command buffer ponter */ |
2756 | 1.59M | pcb->ptr = cbp + seg_size; |
2757 | | |
2758 | 1.59M | return code; |
2759 | 1.59M | } |
2760 | | |
2761 | | static int |
2762 | | read_set_misc2(command_buf_t *pcb, gs_gstate *pgs, segment_notes *pnotes) |
2763 | 2.83M | { |
2764 | 2.83M | const byte *cbp = pcb->ptr; |
2765 | 2.83M | uint mask, cb; |
2766 | | |
2767 | 2.83M | if_debug0m('L', pgs->memory, "\n"); |
2768 | 2.83M | cmd_getw(mask, cbp); |
2769 | 2.83M | if (mask & cap_join_known) { |
2770 | 457k | cb = *cbp++; |
2771 | 457k | pgs->line_params.start_cap = (gs_line_cap)((cb >> 3) & 7); |
2772 | 457k | pgs->line_params.join = (gs_line_join)(cb & 7); |
2773 | 457k | if_debug2m('L', pgs->memory, "[L] start_cap=%d join=%d\n", |
2774 | 457k | pgs->line_params.start_cap, pgs->line_params.join); |
2775 | 457k | cb = *cbp++; |
2776 | 457k | pgs->line_params.end_cap = (gs_line_cap)((cb >> 3) & 7); |
2777 | 457k | pgs->line_params.dash_cap = (gs_line_cap)(cb & 7); |
2778 | 457k | if_debug2m('L', pgs->memory, "[L] end_cap=%d dash_cap=%d\n", |
2779 | 457k | pgs->line_params.end_cap, pgs->line_params.dash_cap); |
2780 | 457k | } |
2781 | 2.83M | if (mask & cj_ac_sa_known) { |
2782 | 168k | cb = *cbp++; |
2783 | 168k | pgs->line_params.curve_join = ((cb >> 2) & 7) - 1; |
2784 | 168k | pgs->accurate_curves = (cb & 2) != 0; |
2785 | 168k | pgs->stroke_adjust = cb & 1; |
2786 | 168k | if_debug3m('L', pgs->memory, "[L] CJ=%d AC=%d SA=%d\n", |
2787 | 168k | pgs->line_params.curve_join, pgs->accurate_curves, |
2788 | 168k | pgs->stroke_adjust); |
2789 | 168k | } |
2790 | 2.83M | if (mask & flatness_known) { |
2791 | 241k | cmd_get_value(pgs->flatness, cbp); |
2792 | 241k | if_debug1m('L', pgs->memory, "[L] flatness=%g\n", pgs->flatness); |
2793 | 241k | } |
2794 | 2.83M | if (mask & line_width_known) { |
2795 | 1.06M | float width; |
2796 | | |
2797 | 1.06M | cmd_get_value(width, cbp); |
2798 | 1.06M | if_debug1m('L', pgs->memory, "[L] line_width=%g\n", width); |
2799 | 1.06M | gx_set_line_width(&pgs->line_params, width); |
2800 | 1.06M | } |
2801 | 2.83M | if (mask & miter_limit_known) { |
2802 | 20.2k | float limit; |
2803 | | |
2804 | 20.2k | cmd_get_value(limit, cbp); |
2805 | 20.2k | if_debug1m('L', pgs->memory, "[L] miter_limit=%g\n", limit); |
2806 | 20.2k | gx_set_miter_limit(&pgs->line_params, limit); |
2807 | 20.2k | } |
2808 | 2.83M | if (mask & op_bm_tk_known) { |
2809 | 1.39M | cb = *cbp++; |
2810 | 1.39M | pgs->blend_mode = cb >> 3; |
2811 | 1.39M | pgs->text_knockout = cb & 1; |
2812 | | /* the following usually have no effect; see gxclpath.c */ |
2813 | 1.39M | cb = *cbp++; |
2814 | 1.39M | pgs->overprint_mode = (cb >> 2) & 1; |
2815 | 1.39M | pgs->stroke_overprint = (cb >> 1) & 1; |
2816 | 1.39M | pgs->overprint = cb & 1; |
2817 | 1.39M | cb = *cbp++; |
2818 | 1.39M | pgs->renderingintent = cb; |
2819 | 1.39M | if_debug6m('L', pgs->memory, "[L] BM=%d TK=%d OPM=%d OP=%d op=%d RI=%d\n", |
2820 | 1.39M | pgs->blend_mode, pgs->text_knockout, pgs->overprint_mode, |
2821 | 1.39M | pgs->stroke_overprint, pgs->overprint, pgs->renderingintent); |
2822 | 1.39M | } |
2823 | 2.83M | if (mask & segment_notes_known) { |
2824 | 552 | cb = *cbp++; |
2825 | 552 | *pnotes = (segment_notes)(cb & 0x3f); |
2826 | 552 | if_debug1m('L', pgs->memory, "[L] notes=%d\n", *pnotes); |
2827 | 552 | } |
2828 | 2.83M | if (mask & ais_known) { |
2829 | 114k | cmd_get_value(pgs->alphaisshape, cbp); |
2830 | 114k | if_debug1m('L', pgs->memory, "[L] alphaisshape=%d\n", pgs->alphaisshape); |
2831 | 114k | } |
2832 | 2.83M | if (mask & stroke_alpha_known) { |
2833 | 831k | cmd_get_value(pgs->strokeconstantalpha, cbp); |
2834 | 831k | if_debug1m('L', pgs->memory, "[L] strokeconstantalpha=%g\n", pgs->strokeconstantalpha); |
2835 | 831k | } |
2836 | 2.83M | if (mask & fill_alpha_known) { |
2837 | 889k | cmd_get_value(pgs->fillconstantalpha, cbp); |
2838 | 889k | if_debug1m('L', pgs->memory, "[L] fillconstantalpha=%u\n", (uint)(pgs->fillconstantalpha)); |
2839 | 889k | } |
2840 | 2.83M | pcb->ptr = cbp; |
2841 | 2.83M | return 0; |
2842 | 2.83M | } |
2843 | | |
2844 | | static int |
2845 | | read_set_color_space(command_buf_t *pcb, gs_gstate *pgs, |
2846 | | gx_device_clist_reader *cdev, gs_memory_t *mem) |
2847 | 627k | { |
2848 | 627k | const byte *cbp = pcb->ptr; |
2849 | 627k | byte b = *cbp++; |
2850 | 627k | int index = b >> 4; |
2851 | 627k | gs_color_space *pcs; |
2852 | 627k | int code = 0; |
2853 | 627k | cmm_profile_t *picc_profile; |
2854 | 627k | clist_icc_color_t icc_information; |
2855 | | |
2856 | 627k | if_debug3m('L', mem, " %d%s%s\n", index, |
2857 | 627k | (b & 8 ? " (indexed)" : ""), |
2858 | 627k | (b & 4 ? "(proc)" : "")); |
2859 | | /* They all store the ICC information. Even if it is NULL |
2860 | | it is used in the ICC case to avoid reading from the |
2861 | | serialized profile data which is stored elsewhere in the |
2862 | | clist. Hence we avoid jumping around in the file. */ |
2863 | 627k | memcpy(&icc_information, cbp, sizeof(clist_icc_color_t)); |
2864 | 627k | cbp = cbp + sizeof(clist_icc_color_t); |
2865 | 627k | switch (index) { |
2866 | 0 | case gs_color_space_index_DeviceGray: |
2867 | 0 | pcs = gs_cspace_new_DeviceGray(mem); |
2868 | 0 | break; |
2869 | 0 | case gs_color_space_index_DeviceRGB: |
2870 | 0 | pcs = gs_cspace_new_DeviceRGB(mem); |
2871 | 0 | break; |
2872 | 0 | case gs_color_space_index_DeviceCMYK: |
2873 | 0 | pcs = gs_cspace_new_DeviceCMYK(mem); |
2874 | 0 | break; |
2875 | 627k | case gs_color_space_index_ICC: |
2876 | | /* build the color space object */ |
2877 | 627k | code = gs_cspace_build_ICC(&pcs, NULL, mem); |
2878 | | /* Don't bother getting the ICC stuff from the clist yet */ |
2879 | 627k | picc_profile = gsicc_profile_new(NULL, cdev->memory, NULL, 0); |
2880 | 627k | if (picc_profile == NULL) |
2881 | 0 | return gs_rethrow(-1, "Failed to find ICC profile during clist read"); |
2882 | 627k | picc_profile->num_comps = icc_information.icc_num_components; |
2883 | 627k | picc_profile->hashcode = icc_information.icc_hash; |
2884 | 627k | picc_profile->hash_is_valid = true; |
2885 | 627k | picc_profile->islab = icc_information.is_lab; |
2886 | 627k | picc_profile->default_match = icc_information.default_match; |
2887 | 627k | picc_profile->data_cs = icc_information.data_cs; |
2888 | | /* Store the clist reader address in the profile |
2889 | | structure so that we can get to the buffer |
2890 | | data if we really neeed it. Ideally, we |
2891 | | will use a cached link and only access this once. */ |
2892 | 627k | picc_profile->dev = (gx_device*) cdev; |
2893 | | /* Assign it to the colorspace */ |
2894 | 627k | code = gsicc_set_gscs_profile(pcs, picc_profile, mem); |
2895 | | /* And we no longer need our reference to the profile */ |
2896 | 627k | gsicc_adjust_profile_rc(picc_profile, -1, "read_set_color_space"); |
2897 | 627k | break; |
2898 | 0 | default: |
2899 | 0 | code = gs_note_error(gs_error_rangecheck); /* others are NYI */ |
2900 | 0 | goto out; |
2901 | 627k | } |
2902 | | |
2903 | 627k | if (pcs == NULL) { |
2904 | 0 | code = gs_note_error(gs_error_VMerror); |
2905 | 0 | goto out; |
2906 | 0 | } |
2907 | | |
2908 | 627k | if (b & 8) { |
2909 | 20.8k | bool use_proc = (b & 4) != 0; |
2910 | 20.8k | int hival; |
2911 | 20.8k | int num_values; |
2912 | 20.8k | byte *data; |
2913 | 20.8k | uint data_size; |
2914 | 20.8k | gs_color_space *pcs_indexed; |
2915 | | |
2916 | 20.8k | pcs_indexed = gs_cspace_alloc(mem, &gs_color_space_type_Indexed); |
2917 | 20.8k | if (pcs_indexed == 0) { |
2918 | 0 | rc_decrement_cs(pcs, "read_set_color_space"); |
2919 | 0 | code = gs_note_error(gs_error_VMerror); |
2920 | 0 | goto out; |
2921 | 0 | } |
2922 | 20.8k | pcs_indexed->base_space = pcs; |
2923 | 20.8k | pcs = pcs_indexed; |
2924 | 20.8k | pcs->params.indexed.use_proc = 0; |
2925 | 20.8k | pcs->params.indexed.lookup.table.data = 0; |
2926 | 20.8k | pcs->params.indexed.lookup.table.size = 0; |
2927 | 20.8k | cmd_getw(hival, cbp); |
2928 | 20.8k | pcs->params.indexed.n_comps = gs_color_space_num_components(pcs->base_space); |
2929 | 20.8k | num_values = (hival + 1) * pcs->params.indexed.n_comps; |
2930 | 20.8k | if (use_proc) { |
2931 | 0 | gs_indexed_map *map; |
2932 | |
|
2933 | 0 | code = alloc_indexed_map(&map, num_values, mem, "indexed map"); |
2934 | 0 | if (code < 0) { |
2935 | 0 | rc_decrement_cs(pcs, "read_set_color_space"); |
2936 | 0 | goto out; |
2937 | 0 | } |
2938 | 0 | map->proc.lookup_index = lookup_indexed_map; |
2939 | 0 | pcs->params.indexed.lookup.map = map; |
2940 | 0 | data = (byte *)map->values; |
2941 | 0 | data_size = num_values * sizeof(map->values[0]); |
2942 | 20.8k | } else { |
2943 | 20.8k | byte *table = gs_alloc_string(mem, num_values, "color_space indexed table"); |
2944 | | |
2945 | 20.8k | if (table == 0) { |
2946 | 0 | code = gs_note_error(gs_error_VMerror); |
2947 | 0 | rc_decrement_cs(pcs, "read_set_color_space"); |
2948 | 0 | goto out; |
2949 | 0 | } |
2950 | 20.8k | pcs->params.indexed.lookup.table.data = table; |
2951 | 20.8k | pcs->params.indexed.lookup.table.size = num_values; |
2952 | 20.8k | data = table; |
2953 | 20.8k | data_size = num_values; |
2954 | 20.8k | } |
2955 | 20.8k | cbp = cmd_read_data(pcb, data, data_size, cbp); |
2956 | 20.8k | pcs->params.indexed.hival = hival; |
2957 | 20.8k | pcs->params.indexed.use_proc = use_proc; |
2958 | 20.8k | } |
2959 | | |
2960 | | /* Release reference to old color space before installing new one. */ |
2961 | 627k | if (pgs->color[0].color_space != NULL) |
2962 | 627k | rc_decrement_only_cs(pgs->color[0].color_space, "read_set_color_space"); |
2963 | 627k | pgs->color[0].color_space = pcs; |
2964 | 627k | out: |
2965 | 627k | pcb->ptr = cbp; |
2966 | 627k | return code; |
2967 | 627k | } |
2968 | | |
2969 | | static int |
2970 | | read_begin_image(command_buf_t *pcb, gs_image_common_t *pic, |
2971 | | gs_color_space *pcs) |
2972 | 732k | { |
2973 | 732k | uint index = *(pcb->ptr)++; |
2974 | 732k | const gx_image_type_t *image_type = gx_image_type_table[index]; |
2975 | 732k | stream s; |
2976 | 732k | int code; |
2977 | | |
2978 | | /* This is sloppy, but we don't have enough information to do better. */ |
2979 | 732k | code = top_up_cbuf(pcb, &pcb->ptr); |
2980 | 732k | if (code < 0) |
2981 | 0 | return code; |
2982 | 732k | s_init(&s, NULL); |
2983 | 732k | sread_string(&s, pcb->ptr, pcb->end - pcb->ptr); |
2984 | 732k | code = image_type->sget(pic, &s, pcs); |
2985 | 732k | pcb->ptr = sbufptr(&s); |
2986 | 732k | pic->imagematrices_are_untrustworthy = 0; |
2987 | 732k | return code; |
2988 | 732k | } |
2989 | | |
2990 | | static int |
2991 | | read_put_params(command_buf_t *pcb, gs_gstate *pgs, |
2992 | | gx_device_clist_reader *cdev, gs_memory_t *mem) |
2993 | 0 | { |
2994 | 0 | const byte *cbp = pcb->ptr; |
2995 | 0 | gs_c_param_list param_list; |
2996 | 0 | uint cleft; |
2997 | 0 | uint rleft; |
2998 | 0 | bool alloc_data_on_heap = false; |
2999 | 0 | byte *param_buf; |
3000 | 0 | uint param_length; |
3001 | 0 | int code; |
3002 | |
|
3003 | 0 | cmd_get_value(param_length, cbp); |
3004 | 0 | if_debug1m('L', mem, " length=%d\n", param_length); |
3005 | 0 | if (param_length == 0) { |
3006 | 0 | code = 1; /* empty list */ |
3007 | 0 | goto out; |
3008 | 0 | } |
3009 | | |
3010 | | /* Make sure entire serialized param list is in cbuf */ |
3011 | | /* + force void* alignment */ |
3012 | 0 | code = top_up_cbuf(pcb, &cbp); |
3013 | 0 | if (code < 0) |
3014 | 0 | return code; |
3015 | 0 | if (pcb->end - cbp >= param_length) { |
3016 | 0 | param_buf = (byte *)cbp; |
3017 | 0 | cbp += param_length; |
3018 | 0 | } else { |
3019 | | /* NOTE: param_buf must be maximally aligned */ |
3020 | 0 | param_buf = gs_alloc_bytes(mem, param_length, |
3021 | 0 | "clist put_params"); |
3022 | 0 | if (param_buf == 0) { |
3023 | 0 | code = gs_note_error(gs_error_VMerror); |
3024 | 0 | goto out; |
3025 | 0 | } |
3026 | 0 | alloc_data_on_heap = true; |
3027 | 0 | cleft = pcb->end - cbp; |
3028 | 0 | rleft = param_length - cleft; |
3029 | 0 | memmove(param_buf, cbp, cleft); |
3030 | 0 | next_is_skip(pcb); |
3031 | 0 | pcb->end_status = sgets(pcb->s, param_buf + cleft, rleft, &rleft); |
3032 | 0 | cbp = pcb->end; /* force refill */ |
3033 | 0 | } |
3034 | | |
3035 | | /* |
3036 | | * Create a gs_c_param_list & expand into it. |
3037 | | * NB that gs_c_param_list doesn't copy objects into |
3038 | | * it, but rather keeps *pointers* to what's passed. |
3039 | | * That's OK because the serialized format keeps enough |
3040 | | * space to hold expanded versions of the structures, |
3041 | | * but this means we cannot deallocate source buffer |
3042 | | * until the gs_c_param_list is deleted. |
3043 | | */ |
3044 | 0 | gs_c_param_list_write(¶m_list, mem); |
3045 | 0 | code = gs_param_list_unserialize |
3046 | 0 | ( (gs_param_list *)¶m_list, param_buf ); |
3047 | 0 | if (code >= 0 && code != param_length) |
3048 | 0 | code = gs_error_unknownerror; /* must match */ |
3049 | 0 | if (code >= 0) { |
3050 | 0 | gs_c_param_list_read(¶m_list); |
3051 | 0 | code = gs_gstate_putdeviceparams(pgs, (gx_device *)cdev, |
3052 | 0 | (gs_param_list *)¶m_list); |
3053 | 0 | } |
3054 | 0 | gs_c_param_list_release(¶m_list); |
3055 | 0 | if (alloc_data_on_heap) |
3056 | 0 | gs_free_object(mem, param_buf, "clist put_params"); |
3057 | |
|
3058 | 0 | out: |
3059 | 0 | pcb->ptr = cbp; |
3060 | 0 | return code; |
3061 | 0 | } |
3062 | | |
3063 | | /* |
3064 | | * Read a "composite" command, and execute the command. |
3065 | | * |
3066 | | * This code assumes that a the largest create compositor command, |
3067 | | * including the compositor name size, is smaller than the data buffer |
3068 | | * size. This assumption is inherent in the basic design of the coding |
3069 | | * and the de-serializer interface, as no length field is provided. |
3070 | | * |
3071 | | * At the time of this writing, no compositor violates this assumption. |
3072 | | * The largest composite is currently 1275 bytes, while the command |
3073 | | * data buffer is 4096 bytes. |
3074 | | * |
3075 | | * In the event that this assumption is violated, a change in the encoding |
3076 | | * would be called for. |
3077 | | * |
3078 | | * See comment in gdevp14.c c_pdf14trans_read PDF14_BEGIN_TRANS_MASK case. |
3079 | | */ |
3080 | | extern_gs_find_compositor(); |
3081 | | |
3082 | | static int |
3083 | | read_composite( |
3084 | | command_buf_t *pcb, gs_memory_t *mem, gs_composite_t **ppcomp) |
3085 | 266M | { |
3086 | 266M | const byte * cbp = pcb->ptr; |
3087 | 266M | int comp_id = 0, code = 0; |
3088 | 266M | const gs_composite_type_t * pcomp_type = 0; |
3089 | | |
3090 | | /* fill the command buffer (see comment above) */ |
3091 | 266M | if (pcb->end - cbp < MAX_CLIST_COMPOSITOR_SIZE + sizeof(comp_id)) { |
3092 | 18.8M | code = top_up_cbuf(pcb, &cbp); |
3093 | 18.8M | if (code < 0) |
3094 | 0 | return code; |
3095 | 18.8M | } |
3096 | | |
3097 | | /* find the appropriate compositor method vector */ |
3098 | 266M | comp_id = *cbp++; |
3099 | 266M | if ((pcomp_type = gs_find_compositor(comp_id)) == 0) |
3100 | 0 | return_error(gs_error_unknownerror); |
3101 | | |
3102 | | /* de-serialize the compositor */ |
3103 | 266M | code = pcomp_type->procs.read(ppcomp, cbp, pcb->end - cbp, mem); |
3104 | | |
3105 | | /* If we read more than the maximum expected, return a rangecheck error */ |
3106 | 266M | if ( code > MAX_CLIST_COMPOSITOR_SIZE ) |
3107 | 0 | return_error(gs_error_rangecheck); |
3108 | | |
3109 | 266M | if (code > 0) |
3110 | 266M | cbp += code; |
3111 | 266M | pcb->ptr = cbp; |
3112 | 266M | return code; |
3113 | 266M | } |
3114 | | |
3115 | | static int apply_composite(gx_device_clist_reader *cdev, gs_gstate *pgs, |
3116 | | gs_memory_t *mem, gs_composite_t *pcomp, |
3117 | | int x0, int y0, gx_device **ptarget) |
3118 | 229M | { |
3119 | 229M | gx_device *tdev = *ptarget; |
3120 | 229M | int code; |
3121 | | |
3122 | 229M | code = pcomp->type->procs.adjust_ctm(pcomp, x0, y0, pgs); |
3123 | 229M | if (code < 0) |
3124 | 0 | goto exit; |
3125 | | /* |
3126 | | * Apply the compositor to the target device; note that this may |
3127 | | * change the target device. |
3128 | | */ |
3129 | 229M | code = dev_proc(tdev, composite)(tdev, &tdev, pcomp, pgs, mem, (gx_device*) cdev); |
3130 | 229M | if (code == 1) { |
3131 | | /* A new compositor was created that wrapped tdev. This should |
3132 | | * be our new target. */ |
3133 | 1.64M | *ptarget = tdev; |
3134 | 1.64M | code = 0; |
3135 | 1.64M | } |
3136 | 229M | if (code < 0) |
3137 | 8 | goto exit; |
3138 | | |
3139 | | /* Perform any updates for the clist device required */ |
3140 | 229M | code = pcomp->type->procs.clist_compositor_read_update(pcomp, |
3141 | 229M | (gx_device *)cdev, tdev, pgs, mem); |
3142 | 229M | exit: |
3143 | | /* free the compositor object */ |
3144 | 229M | gs_free_object(mem, pcomp, "read_composite"); |
3145 | | |
3146 | 229M | return code; |
3147 | 229M | } |
3148 | | |
3149 | | /* ---------------- Utilities ---------------- */ |
3150 | | |
3151 | | /* Read and unpack a short bitmap */ |
3152 | | /* |
3153 | | * The 'raster' in the dest buffer may be larger than the 'width_bytes' |
3154 | | * in the src, so after reading we memmove data down to the proper |
3155 | | * alignment from the last line backwards. |
3156 | | * THIS RELIES on width_bytes <= raster to work. |
3157 | | */ |
3158 | | static const byte * |
3159 | | cmd_read_short_bits(command_buf_t *pcb, byte *data, int tot_bytes, |
3160 | | int width_bytes, int height, uint raster, const byte *cbp) |
3161 | 13.8M | { |
3162 | | /* Note the following may read from the file past the end of the buffer */ |
3163 | | /* leaving cbp at pcb->end. No further reading using cbp can be done */ |
3164 | | /* without top_up_cbuf to reload the buffer. */ |
3165 | 13.8M | cbp = cmd_read_data(pcb, data, tot_bytes, cbp); |
3166 | | |
3167 | | /* if needed, adjust buffer contents for dest raster > width_bytes */ |
3168 | 13.8M | if (width_bytes < raster) { |
3169 | 13.8M | const byte *pdata = data /*src*/ + width_bytes * height; |
3170 | 13.8M | byte *udata = data /*dest*/ + height * raster; |
3171 | | |
3172 | 220M | while (--height > 0) { /* don't need to move the first line to itself */ |
3173 | 206M | udata -= raster, pdata -= width_bytes; |
3174 | 206M | switch (width_bytes) { |
3175 | 0 | default: |
3176 | 0 | memmove(udata, pdata, width_bytes); |
3177 | 0 | break; |
3178 | 578k | case 6: |
3179 | 578k | udata[5] = pdata[5]; |
3180 | 2.01M | case 5: |
3181 | 2.01M | udata[4] = pdata[4]; |
3182 | 7.45M | case 4: |
3183 | 7.45M | udata[3] = pdata[3]; |
3184 | 44.8M | case 3: |
3185 | 44.8M | udata[2] = pdata[2]; |
3186 | 166M | case 2: |
3187 | 166M | udata[1] = pdata[1]; |
3188 | 206M | case 1: |
3189 | 206M | udata[0] = pdata[0]; |
3190 | 206M | case 0:; /* shouldn't happen */ |
3191 | 206M | } |
3192 | 206M | } |
3193 | 13.8M | } |
3194 | 13.8M | return cbp; |
3195 | 13.8M | } |
3196 | | |
3197 | | /* Read a rectangle. */ |
3198 | | static const byte * |
3199 | | cmd_read_rect(int op, gx_cmd_rect * prect, const byte * cbp) |
3200 | 12.7M | { |
3201 | 12.7M | cmd_getw(prect->x, cbp); |
3202 | 12.7M | if (op & 0xf) |
3203 | 1.45M | prect->y += ((op >> 2) & 3) - 2; |
3204 | 11.2M | else { |
3205 | 11.2M | cmd_getw(prect->y, cbp); |
3206 | 11.2M | } |
3207 | 12.7M | cmd_getw(prect->width, cbp); |
3208 | 12.7M | if (op & 0xf) |
3209 | 1.45M | prect->height += (op & 3) - 2; |
3210 | 11.2M | else { |
3211 | 11.2M | cmd_getw(prect->height, cbp); |
3212 | 11.2M | } |
3213 | 12.7M | return cbp; |
3214 | 12.7M | } |
3215 | | |
3216 | | /* |
3217 | | * Select a map for loading with data. |
3218 | | * |
3219 | | * This routine has three outputs: |
3220 | | * *pmdata - points to the map data. |
3221 | | * *pcomp_num - points to a component number if the map is a transfer |
3222 | | * map which has been set via the setcolortransfer operator. |
3223 | | * A. value of NULL indicates that no component number is to |
3224 | | * be sent for this map. |
3225 | | * *pcount - the size of the map (in bytes). |
3226 | | */ |
3227 | | static int |
3228 | | cmd_select_map(cmd_map_index map_index, cmd_map_contents cont, |
3229 | | gs_gstate * pgs, int ** pcomp_num, frac ** pmdata, |
3230 | | uint * pcount, gs_memory_t * mem) |
3231 | 7.63M | { |
3232 | 7.63M | gx_transfer_map *map; |
3233 | 7.63M | gx_transfer_map **pmap; |
3234 | 7.63M | const char *cname; |
3235 | | |
3236 | 7.63M | *pcomp_num = NULL; /* Only used for color transfer maps */ |
3237 | 7.63M | switch (map_index) { |
3238 | 2.45M | case cmd_map_transfer: |
3239 | 2.45M | if_debug0m('L', mem, " transfer"); |
3240 | 2.45M | rc_unshare_struct(pgs->set_transfer.gray, gx_transfer_map, |
3241 | 2.45M | &st_transfer_map, mem, return_error(gs_error_VMerror), |
3242 | 2.45M | "cmd_select_map(default_transfer)"); |
3243 | 2.45M | map = pgs->set_transfer.gray; |
3244 | | /* Release all current maps */ |
3245 | 2.45M | rc_decrement(pgs->set_transfer.red, "cmd_select_map(red)"); |
3246 | 2.45M | pgs->set_transfer.red = NULL; |
3247 | 2.45M | pgs->set_transfer.red_component_num = -1; |
3248 | 2.45M | rc_decrement(pgs->set_transfer.green, "cmd_select_map(green)"); |
3249 | 2.45M | pgs->set_transfer.green = NULL; |
3250 | 2.45M | pgs->set_transfer.green_component_num = -1; |
3251 | 2.45M | rc_decrement(pgs->set_transfer.blue, "cmd_select_map(blue)"); |
3252 | 2.45M | pgs->set_transfer.blue = NULL; |
3253 | 2.45M | pgs->set_transfer.blue_component_num = -1; |
3254 | 2.45M | goto transfer2; |
3255 | 242 | case cmd_map_transfer_0: |
3256 | 242 | pmap = &pgs->set_transfer.red; |
3257 | 242 | *pcomp_num = &pgs->set_transfer.red_component_num; |
3258 | 242 | goto transfer1; |
3259 | 242 | case cmd_map_transfer_1: |
3260 | 242 | pmap = &pgs->set_transfer.green; |
3261 | 242 | *pcomp_num = &pgs->set_transfer.green_component_num; |
3262 | 242 | goto transfer1; |
3263 | 242 | case cmd_map_transfer_2: |
3264 | 242 | pmap = &pgs->set_transfer.blue; |
3265 | 242 | *pcomp_num = &pgs->set_transfer.blue_component_num; |
3266 | 242 | goto transfer1; |
3267 | 0 | case cmd_map_transfer_3: |
3268 | 0 | pmap = &pgs->set_transfer.gray; |
3269 | 0 | *pcomp_num = &pgs->set_transfer.gray_component_num; |
3270 | 726 | transfer1: if_debug1m('L', mem, " transfer[%d]", (int)(map_index - cmd_map_transfer_0)); |
3271 | 726 | rc_unshare_struct(*pmap, gx_transfer_map, &st_transfer_map, mem, |
3272 | 726 | return_error(gs_error_VMerror), "cmd_select_map(transfer)"); |
3273 | 726 | map = *pmap; |
3274 | | |
3275 | 2.45M | transfer2: if (cont != cmd_map_other) { |
3276 | 1.56M | gx_set_identity_transfer(map); |
3277 | 1.56M | *pmdata = 0; |
3278 | 1.56M | *pcount = 0; |
3279 | 1.56M | return 0; |
3280 | 1.56M | } |
3281 | 890k | break; |
3282 | 2.58M | case cmd_map_black_generation: |
3283 | 2.58M | if_debug0m('L', mem, " black generation"); |
3284 | 2.58M | pmap = &pgs->black_generation; |
3285 | 2.58M | cname = "cmd_select_map(black generation)"; |
3286 | 2.58M | goto alloc; |
3287 | 2.58M | case cmd_map_undercolor_removal: |
3288 | 2.58M | if_debug0m('L', mem, " undercolor removal"); |
3289 | 2.58M | pmap = &pgs->undercolor_removal; |
3290 | 2.58M | cname = "cmd_select_map(undercolor removal)"; |
3291 | 5.17M | alloc: if (cont == cmd_map_none) { |
3292 | 0 | rc_decrement(*pmap, cname); |
3293 | 0 | *pmap = 0; |
3294 | 0 | *pmdata = 0; |
3295 | 0 | *pcount = 0; |
3296 | 0 | return 0; |
3297 | 0 | } |
3298 | 5.17M | rc_unshare_struct(*pmap, gx_transfer_map, &st_transfer_map, |
3299 | 5.17M | mem, return_error(gs_error_VMerror), cname); |
3300 | 5.17M | map = *pmap; |
3301 | 5.17M | if (cont == cmd_map_identity) { |
3302 | 0 | gx_set_identity_transfer(map); |
3303 | 0 | *pmdata = 0; |
3304 | 0 | *pcount = 0; |
3305 | 0 | return 0; |
3306 | 0 | } |
3307 | 5.17M | break; |
3308 | 5.17M | default: |
3309 | 0 | *pmdata = 0; |
3310 | 0 | return 0; |
3311 | 7.63M | } |
3312 | 6.06M | map->proc = gs_mapped_transfer; |
3313 | 6.06M | *pmdata = map->values; |
3314 | 6.06M | *pcount = sizeof(map->values); |
3315 | 6.06M | return 0; |
3316 | 7.63M | } |
3317 | | |
3318 | | /* Create a device halftone for the imager if necessary. */ |
3319 | | static int |
3320 | | cmd_create_dev_ht(gx_device_halftone **ppdht, gs_memory_t *mem) |
3321 | 0 | { |
3322 | 0 | gx_device_halftone *pdht = *ppdht; |
3323 | |
|
3324 | 0 | if (pdht == 0) { |
3325 | 0 | rc_header rc; |
3326 | |
|
3327 | 0 | rc_alloc_struct_1(pdht, gx_device_halftone, &st_device_halftone, mem, |
3328 | 0 | return_error(gs_error_VMerror), |
3329 | 0 | "cmd_create_dev_ht"); |
3330 | 0 | rc = pdht->rc; |
3331 | 0 | memset(pdht, 0, sizeof(*pdht)); |
3332 | 0 | pdht->rc = rc; |
3333 | 0 | *ppdht = pdht; |
3334 | 0 | } |
3335 | 0 | return 0; |
3336 | 0 | } |
3337 | | |
3338 | | /* Resize the halftone components array if necessary. */ |
3339 | | static int |
3340 | | cmd_resize_halftone(gx_device_halftone **ppdht, uint num_comp, |
3341 | | gs_memory_t * mem) |
3342 | 0 | { |
3343 | 0 | int code = cmd_create_dev_ht(ppdht, mem); |
3344 | 0 | gx_device_halftone *pdht = *ppdht; |
3345 | |
|
3346 | 0 | if (code < 0) |
3347 | 0 | return code; |
3348 | 0 | if (num_comp != pdht->num_comp) { |
3349 | 0 | gx_ht_order_component *pcomp; |
3350 | | |
3351 | | /* |
3352 | | * We must be careful not to shrink or free the components array |
3353 | | * before releasing any relevant elements. |
3354 | | */ |
3355 | 0 | if (num_comp < pdht->num_comp) { |
3356 | 0 | uint i; |
3357 | | |
3358 | | /* Don't release the default order. */ |
3359 | 0 | for (i = pdht->num_comp; i-- > num_comp;) |
3360 | 0 | if (pdht->components[i].corder.bit_data != pdht->order.bit_data) |
3361 | 0 | gx_ht_order_release(&pdht->components[i].corder, mem, true); |
3362 | 0 | if (num_comp == 0) { |
3363 | 0 | gs_free_object(mem, pdht->components, "cmd_resize_halftone"); |
3364 | 0 | pcomp = 0; |
3365 | 0 | } else { |
3366 | 0 | pcomp = gs_resize_object(mem, pdht->components, num_comp, |
3367 | 0 | "cmd_resize_halftone"); |
3368 | 0 | if (pcomp == 0) { |
3369 | 0 | pdht->num_comp = num_comp; /* attempt consistency */ |
3370 | 0 | return_error(gs_error_VMerror); |
3371 | 0 | } |
3372 | 0 | } |
3373 | 0 | } else { |
3374 | | /* num_comp > pdht->num_comp */ |
3375 | 0 | if (pdht->num_comp == 0) |
3376 | 0 | pcomp = gs_alloc_struct_array(mem, num_comp, |
3377 | 0 | gx_ht_order_component, |
3378 | 0 | &st_ht_order_component_element, |
3379 | 0 | "cmd_resize_halftone"); |
3380 | 0 | else |
3381 | 0 | pcomp = gs_resize_object(mem, pdht->components, num_comp, |
3382 | 0 | "cmd_resize_halftone"); |
3383 | 0 | if (pcomp == 0) |
3384 | 0 | return_error(gs_error_VMerror); |
3385 | 0 | memset(&pcomp[pdht->num_comp], 0, |
3386 | 0 | sizeof(*pcomp) * (num_comp - pdht->num_comp)); |
3387 | 0 | } |
3388 | 0 | pdht->num_comp = num_comp; |
3389 | 0 | pdht->components = pcomp; |
3390 | 0 | } |
3391 | 0 | return 0; |
3392 | 0 | } |
3393 | | |
3394 | | /* ------ Path operations ------ */ |
3395 | | |
3396 | | /* Decode a path segment. */ |
3397 | | static int |
3398 | | clist_decode_segment(gx_path * ppath, int op, fixed vs[6], |
3399 | | gs_fixed_point * ppos, int x0, int y0, segment_notes notes) |
3400 | 79.6M | { |
3401 | 79.6M | fixed px = ppos->x - int2fixed(x0); |
3402 | 79.6M | fixed py = ppos->y - int2fixed(y0); |
3403 | 79.6M | int code; |
3404 | | |
3405 | 105M | #define A vs[0] |
3406 | 79.6M | #define B vs[1] |
3407 | 79.6M | #define C vs[2] |
3408 | 79.6M | #define D vs[3] |
3409 | 79.6M | #define E vs[4] |
3410 | 79.6M | #define F vs[5] |
3411 | | |
3412 | 79.6M | switch (op) { |
3413 | 13.4M | case cmd_opv_rmoveto: |
3414 | 13.4M | code = gx_path_add_point(ppath, px += A, py += B); |
3415 | 13.4M | break; |
3416 | 6.77M | case cmd_opv_rlineto: |
3417 | 6.77M | code = gx_path_add_line_notes(ppath, px += A, py += B, notes); |
3418 | 6.77M | break; |
3419 | 0 | case cmd_opv_rgapto: |
3420 | 0 | code = gx_path_add_gap_notes(ppath, px += A, py += B, notes); |
3421 | 0 | break; |
3422 | 13.1M | case cmd_opv_hlineto: |
3423 | 13.1M | code = gx_path_add_line_notes(ppath, px += A, py, notes); |
3424 | 13.1M | break; |
3425 | 18.9M | case cmd_opv_vlineto: |
3426 | 18.9M | code = gx_path_add_line_notes(ppath, px, py += A, notes); |
3427 | 18.9M | break; |
3428 | 1.75M | case cmd_opv_rmlineto: |
3429 | 1.75M | if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0) |
3430 | 0 | break; |
3431 | 1.75M | code = gx_path_add_line_notes(ppath, px += C, py += D, notes); |
3432 | 1.75M | break; |
3433 | 1.68M | case cmd_opv_rm2lineto: |
3434 | 1.68M | if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0 || |
3435 | 1.68M | (code = gx_path_add_line_notes(ppath, px += C, py += D, |
3436 | 1.68M | notes)) < 0 |
3437 | 1.68M | ) |
3438 | 0 | break; |
3439 | 1.68M | code = gx_path_add_line_notes(ppath, px += E, py += F, notes); |
3440 | 1.68M | break; |
3441 | 285k | case cmd_opv_rm3lineto: |
3442 | 285k | if ((code = gx_path_add_point(ppath, px += A, py += B)) < 0 || |
3443 | 285k | (code = gx_path_add_line_notes(ppath, px += C, py += D, |
3444 | 285k | notes)) < 0 || |
3445 | 285k | (code = gx_path_add_line_notes(ppath, px += E, py += F, |
3446 | 285k | notes)) < 0 |
3447 | 285k | ) |
3448 | 0 | break; |
3449 | 285k | code = gx_path_add_line_notes(ppath, px -= C, py -= D, notes); |
3450 | 285k | break; |
3451 | 11.5M | case cmd_opv_rrcurveto: /* a b c d e f => a b a+c b+d a+c+e b+d+f */ |
3452 | 11.6M | rrc: E += (C += A); |
3453 | 11.6M | F += (D += B); |
3454 | 17.5M | curve: code = gx_path_add_curve_notes(ppath, px + A, py + B, |
3455 | 17.5M | px + C, py + D, |
3456 | 17.5M | px + E, py + F, notes); |
3457 | 17.5M | px += E, py += F; |
3458 | 17.5M | break; |
3459 | 2.51M | case cmd_opv_hvcurveto: /* a b c d => a 0 a+b c a+b c+d */ |
3460 | 2.56M | hvc: F = C + D, D = C, E = C = A + B, B = 0; |
3461 | 2.56M | goto curve; |
3462 | 2.49M | case cmd_opv_vhcurveto: /* a b c d => 0 a b a+c b+d a+c */ |
3463 | 3.24M | vhc: E = B + D, F = D = A + C, C = B, B = A, A = 0; |
3464 | 3.24M | goto curve; |
3465 | 55.2k | case cmd_opv_nrcurveto: /* a b c d => 0 0 a b a+c b+d */ |
3466 | 55.2k | F = B + D, E = A + C, D = B, C = A, B = A = 0; |
3467 | 55.2k | goto curve; |
3468 | 75.3k | case cmd_opv_rncurveto: /* a b c d => a b a+c b+d a+c b+d */ |
3469 | 75.3k | F = D += B, E = C += A; |
3470 | 75.3k | goto curve; |
3471 | 748k | case cmd_opv_vqcurveto: /* a b => VH a b TS(a,b) TS(b,a) */ |
3472 | 748k | if ((A ^ B) < 0) |
3473 | 39.1k | C = -B, D = -A; |
3474 | 708k | else |
3475 | 708k | C = B, D = A; |
3476 | 748k | goto vhc; |
3477 | 47.1k | case cmd_opv_hqcurveto: /* a b => HV a TS(a,b) b TS(b,a) */ |
3478 | 47.1k | if ((A ^ B) < 0) |
3479 | 17.3k | D = -A, C = B, B = -B; |
3480 | 29.7k | else |
3481 | 29.7k | D = A, C = B; |
3482 | 47.1k | goto hvc; |
3483 | 67.3k | case cmd_opv_scurveto: /* (a b c d e f) => */ |
3484 | 67.3k | { |
3485 | 67.3k | fixed a = A, b = B; |
3486 | | |
3487 | | /* See gxclpath.h for details on the following. */ |
3488 | 67.3k | if (A == 0) { |
3489 | | /* Previous curve was vh or vv */ |
3490 | 62.2k | A = E - C, B = D - F, C = C - a, D = b - D, E = a, F = -b; |
3491 | 62.2k | } else { |
3492 | | /* Previous curve was hv or hh */ |
3493 | 5.10k | A = C - E, B = F - D, C = a - C, D = D - b, E = -a, F = b; |
3494 | 5.10k | } |
3495 | 67.3k | } |
3496 | 67.3k | goto rrc; |
3497 | 5.86M | case cmd_opv_closepath: |
3498 | 5.86M | if ((code = gx_path_close_subpath(ppath)) < 0) |
3499 | 5.86M | return code;; |
3500 | 5.86M | if ((code = gx_path_current_point(ppath, (gs_fixed_point *) vs)) < 0) |
3501 | 5.86M | return code;; |
3502 | 5.86M | px = A, py = B; |
3503 | 5.86M | break; |
3504 | 0 | default: |
3505 | 0 | return_error(gs_error_rangecheck); |
3506 | 79.6M | } |
3507 | 79.6M | #undef A |
3508 | 79.6M | #undef B |
3509 | 79.6M | #undef C |
3510 | 79.6M | #undef D |
3511 | 79.6M | #undef E |
3512 | 79.6M | #undef F |
3513 | 79.6M | ppos->x = px + int2fixed(x0); |
3514 | 79.6M | ppos->y = py + int2fixed(y0); |
3515 | 79.6M | return code; |
3516 | 79.6M | } |
3517 | | |
3518 | | /* |
3519 | | * Execute a polyfill -- either a fill_parallelogram or a fill_triangle. |
3520 | | * |
3521 | | * Note that degenerate parallelograms or triangles may collapse into |
3522 | | * a single line or point. We must check for this so we don't try to |
3523 | | * access non-existent segments. |
3524 | | */ |
3525 | | static int |
3526 | | clist_do_polyfill(gx_device *dev, gx_path *ppath, |
3527 | | const gx_drawing_color *pdcolor, |
3528 | | gs_logical_operation_t lop) |
3529 | 852k | { |
3530 | 852k | const subpath *psub = ppath->first_subpath; |
3531 | 852k | const segment *pseg1; |
3532 | 852k | const segment *pseg2; |
3533 | 852k | int code; |
3534 | | |
3535 | 852k | if (psub && (pseg1 = psub->next) != 0 && (pseg2 = pseg1->next) != 0) { |
3536 | 852k | fixed px = psub->pt.x, py = psub->pt.y; |
3537 | 852k | fixed ax = pseg1->pt.x - px, ay = pseg1->pt.y - py; |
3538 | 852k | fixed bx, by; |
3539 | | /* |
3540 | | * We take advantage of the fact that the parameter lists for |
3541 | | * fill_parallelogram and fill_triangle are identical. |
3542 | | */ |
3543 | 852k | dev_proc_fill_parallelogram((*fill)); |
3544 | | |
3545 | | /* close_path of 3 point triangle adds 4th point, detected here.*/ |
3546 | | /* close_path on parallelogram adds 5th point also ignored. */ |
3547 | 852k | if (pseg2->next && !(px == pseg2->next->pt.x && py == pseg2->next->pt.y)) { |
3548 | | /* Parallelogram */ |
3549 | 381k | fill = dev_proc(dev, fill_parallelogram); |
3550 | 381k | bx = pseg2->pt.x - pseg1->pt.x; |
3551 | 381k | by = pseg2->pt.y - pseg1->pt.y; |
3552 | 471k | } else { |
3553 | | /* Triangle */ |
3554 | 471k | fill = dev_proc(dev, fill_triangle); |
3555 | 471k | bx = pseg2->pt.x - px; |
3556 | 471k | by = pseg2->pt.y - py; |
3557 | 471k | } |
3558 | 852k | code = fill(dev, px, py, ax, ay, bx, by, pdcolor, lop); |
3559 | 852k | } else |
3560 | 0 | code = 0; |
3561 | 852k | gx_path_new(ppath); |
3562 | 852k | return code; |
3563 | 852k | } |