/src/ghostpdl/base/gxclutil.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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 writing utilities. */ |
18 | | |
19 | | #include "memory_.h" |
20 | | #include "string_.h" |
21 | | #include "gx.h" |
22 | | #include "gp.h" |
23 | | #include "gpcheck.h" |
24 | | #include "gserrors.h" |
25 | | #include "gxdevice.h" |
26 | | #include "gxdevmem.h" /* must precede gxcldev.h */ |
27 | | #include "gxcldev.h" |
28 | | #include "gxclpath.h" |
29 | | #include "gsparams.h" |
30 | | |
31 | | #include "valgrind.h" |
32 | | #include <limits.h> |
33 | | |
34 | | /* ---------------- Statistics ---------------- */ |
35 | | |
36 | | #ifdef DEBUG |
37 | | const char *const cmd_op_names[16] = |
38 | | {cmd_op_name_strings}; |
39 | | static const char *const cmd_misc_op_names[16] = |
40 | | {cmd_misc_op_name_strings}; |
41 | | static const char *const cmd_misc2_op_names[16] = |
42 | | {cmd_misc2_op_name_strings}; |
43 | | static const char *const cmd_segment_op_names[16] = |
44 | | {cmd_segment_op_name_strings}; |
45 | | static const char *const cmd_path_op_names[16] = |
46 | | {cmd_path_op_name_strings}; |
47 | | const char *const *const cmd_sub_op_names[16] = |
48 | | {cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0, |
49 | | 0, 0, 0, 0, |
50 | | 0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names |
51 | | }; |
52 | | const char *cmd_extend_op_names[256] = |
53 | | {cmd_extend_op_name_strings}; |
54 | | |
55 | | #ifdef COLLECT_STATS_CLIST |
56 | | struct stats_cmd_s { |
57 | | ulong op_counts[512]; |
58 | | ulong op_sizes[512]; |
59 | | ulong tile_reset, tile_found, tile_added; |
60 | | ulong same_band, other_band; |
61 | | } stats_cmd; |
62 | | extern ulong stats_cmd_diffs[5]; /* in gxclpath.c */ |
63 | | int |
64 | | cmd_count_op(int op, uint size,const gs_memory_t *mem) |
65 | | { |
66 | | stats_cmd.op_counts[op]++; |
67 | | stats_cmd.op_sizes[op] += size; |
68 | | if (gs_debug_c('L')) { |
69 | | const char *const *sub = cmd_sub_op_names[op >> 4]; |
70 | | |
71 | | if (sub) |
72 | | dmlprintf2(mem, ", %s(%u)\n", sub[op & 0xf], size); |
73 | | else |
74 | | dmlprintf3(mem, ", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf, |
75 | | size); |
76 | | dmflush(mem); |
77 | | } |
78 | | return op; |
79 | | } |
80 | | int |
81 | | cmd_count_extended_op(int op, uint size,const gs_memory_t *mem) |
82 | | { |
83 | | stats_cmd.op_counts[cmd_opv_extend]++; |
84 | | stats_cmd.op_sizes[cmd_opv_extend] += size; |
85 | | stats_cmd.op_counts[256+op]++; |
86 | | stats_cmd.op_sizes[256+op] += size; |
87 | | if (gs_debug_c('L')) { |
88 | | const char *ext = cmd_extend_op_names[op]; |
89 | | |
90 | | if (ext) |
91 | | dmlprintf2(mem, ", %s(%u)\n", ext, size); |
92 | | else |
93 | | dmlprintf2(mem, ", ?0x%02x?(%u)\n", op, |
94 | | size); |
95 | | dmflush(mem); |
96 | | } |
97 | | return op; |
98 | | } |
99 | | void |
100 | | cmd_uncount_op(int op, uint size) |
101 | | { |
102 | | stats_cmd.op_counts[op]--; |
103 | | stats_cmd.op_sizes[op] -= size; |
104 | | } |
105 | | #endif |
106 | | #endif |
107 | | |
108 | | /* Print statistics. */ |
109 | | #ifdef COLLECT_STATS_CLIST |
110 | | void |
111 | | cmd_print_stats(const gs_memory_t *mem) |
112 | | { |
113 | | int ci, cj; |
114 | | |
115 | | dmlprintf3(mem, "[l]counts: reset = %lu, found = %lu, added = %lu\n", |
116 | | stats_cmd.tile_reset, stats_cmd.tile_found, |
117 | | stats_cmd.tile_added); |
118 | | dmlprintf5(mem, " diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n", |
119 | | stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2], |
120 | | stats_cmd_diffs[3], stats_cmd_diffs[4]); |
121 | | dmlprintf2(mem, " same_band = %lu, other_band = %lu\n", |
122 | | stats_cmd.same_band, stats_cmd.other_band); |
123 | | for (ci = 0; ci < 0x100; ci += 0x10) { |
124 | | const char *const *sub = cmd_sub_op_names[ci >> 4]; |
125 | | |
126 | | if (sub != 0) { |
127 | | dmlprintf1(mem, "[l] %s =", cmd_op_names[ci >> 4]); |
128 | | for (cj = ci; cj < ci + 0x10; cj += 2) |
129 | | dmprintf6(mem, "\n\t%s = %lu(%lu), %s = %lu(%lu)", |
130 | | sub[cj - ci], |
131 | | stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj], |
132 | | sub[cj - ci + 1], |
133 | | stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]); |
134 | | } else { |
135 | | ulong tcounts = 0, tsizes = 0; |
136 | | |
137 | | for (cj = ci; cj < ci + 0x10; cj++) |
138 | | tcounts += stats_cmd.op_counts[cj], |
139 | | tsizes += stats_cmd.op_sizes[cj]; |
140 | | dmlprintf3(mem, "[l] %s (%lu,%lu) =\n\t", |
141 | | cmd_op_names[ci >> 4], tcounts, tsizes); |
142 | | for (cj = ci; cj < ci + 0x10; cj++) |
143 | | if (stats_cmd.op_counts[cj] == 0) |
144 | | dmputs(mem, " -"); |
145 | | else |
146 | | dmprintf2(mem, " %lu(%lu)", stats_cmd.op_counts[cj], |
147 | | stats_cmd.op_sizes[cj]); |
148 | | } |
149 | | dmputs(mem, "\n"); |
150 | | } |
151 | | for (ci = 0x100; ci < 0x200; ci ++) { |
152 | | const char *ext = cmd_extend_op_names[ci-0x100]; |
153 | | |
154 | | if (ext != NULL) { |
155 | | dmprintf3(mem, "[l] %s (%lu,%lu)\n", |
156 | | ext, |
157 | | stats_cmd.op_counts[ci], stats_cmd.op_sizes[ci]); |
158 | | } else if (stats_cmd.op_counts[ci] || stats_cmd.op_sizes[ci]) { |
159 | | dmprintf3(mem, "[l] ?0x%02x? (%lu,%lu)\n", |
160 | | ci-0x100, |
161 | | stats_cmd.op_counts[ci], stats_cmd.op_sizes[ci]); |
162 | | } |
163 | | dmputs(mem, "\n"); |
164 | | } |
165 | | } |
166 | | #endif /* DEBUG */ |
167 | | |
168 | | /* ---------------- Writing utilities ---------------- */ |
169 | | |
170 | | /* Update the 'trans_bbox' in the states for bands affected by the given rectangle */ |
171 | | /* The caller has determined the the PDF 1.4 transparency will actuall be needed */ |
172 | | /* for the given rectangle (conservatively). This will allow some bands that only */ |
173 | | /* paint to the page level with full opacity to skip the pdf14 compositor during */ |
174 | | /* rendering/reading and thus run faster and with less memory for those bands. */ |
175 | | void |
176 | | clist_update_trans_bbox(gx_device_clist_writer *cldev, gs_int_rect *bbox) |
177 | 165M | { |
178 | 165M | int p_y, q_y; |
179 | 165M | int band, first_band, last_band; |
180 | | |
181 | 165M | first_band = max(0, bbox->p.y / cldev->page_info.band_params.BandHeight); |
182 | 165M | p_y = bbox->p.y - (first_band * cldev->page_info.band_params.BandHeight); |
183 | 165M | last_band = min((cldev->nbands - 1), bbox->q.y / cldev->page_info.band_params.BandHeight); |
184 | | |
185 | 475M | for (band=first_band; band <= last_band; band++) { |
186 | 310M | if (cldev->states[band].color_usage.trans_bbox.p.y > p_y) |
187 | 1.72M | cldev->states[band].color_usage.trans_bbox.p.y = p_y; |
188 | 310M | if (cldev->states[band].color_usage.trans_bbox.p.x > bbox->p.x) |
189 | 2.09M | cldev->states[band].color_usage.trans_bbox.p.x = bbox->p.x; |
190 | 310M | p_y = 0; /* will be top of next band */ |
191 | 310M | q_y = (band == last_band) ? bbox->q.y - (last_band * cldev->page_info.band_params.BandHeight) : |
192 | 310M | cldev->page_info.band_params.BandHeight - 1; |
193 | 310M | if (cldev->states[band].color_usage.trans_bbox.q.y < q_y) |
194 | 2.09M | cldev->states[band].color_usage.trans_bbox.q.y = q_y; |
195 | 310M | if (cldev->states[band].color_usage.trans_bbox.q.x < bbox->q.x) |
196 | 27.9M | cldev->states[band].color_usage.trans_bbox.q.x = bbox->q.x; |
197 | 310M | } |
198 | 165M | } |
199 | | |
200 | | /* Write the commands for one band or band range. */ |
201 | | static int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */ |
202 | | cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max, |
203 | | cmd_list * pcl, byte cmd_end) |
204 | 212M | { |
205 | 212M | const cmd_prefix *cp = pcl->head; |
206 | 212M | int code_b = 0; |
207 | 212M | int code_c = 0; |
208 | | |
209 | 212M | if (cp != 0 || cmd_end != cmd_opv_end_run) { |
210 | 33.5M | clist_file_ptr cfile = cldev->page_info.cfile; |
211 | 33.5M | clist_file_ptr bfile = cldev->page_info.bfile; |
212 | 33.5M | cmd_block cb; |
213 | 33.5M | byte end; |
214 | | |
215 | 33.5M | if (cfile == 0 || bfile == 0) |
216 | 0 | return_error(gs_error_ioerror); |
217 | 33.5M | cb.band_min = band_min; |
218 | 33.5M | cb.band_max = band_max; |
219 | 33.5M | cb.pos = cldev->page_info.io_procs->ftell(cfile); |
220 | 33.5M | if_debug3m('l', cldev->memory, "[l]writing for bands (%d,%d) at %"PRId64"\n", |
221 | 33.5M | band_min, band_max, cb.pos); |
222 | 33.5M | cldev->page_info.io_procs->fwrite_chars(&cb, sizeof(cb), bfile); |
223 | 33.5M | if (cp != 0) { |
224 | 11.2M | pcl->tail->next = 0; /* terminate the list */ |
225 | 77.5M | for (; cp != 0; cp = cp->next) { |
226 | | #ifdef DEBUG |
227 | | if ((const byte *)cp < cldev->cbuf || |
228 | | (const byte *)cp >= cldev->cend || |
229 | | cp->size > cldev->cend - (const byte *)cp |
230 | | ) { |
231 | | mlprintf1(cldev->memory, "cmd_write_band error at "PRI_INTPTR"\n", (intptr_t) cp); |
232 | | return_error(gs_error_Fatal); |
233 | | } |
234 | | #endif |
235 | 66.3M | if_debug2m('L', cldev->memory, "[L] cmd id=%ld at %"PRId64"\n", |
236 | 66.3M | cp->id, cldev->page_info.io_procs->ftell(cfile)); |
237 | 66.3M | cldev->page_info.io_procs->fwrite_chars(cp + 1, cp->size, cfile); |
238 | 66.3M | } |
239 | 11.2M | pcl->head = pcl->tail = 0; |
240 | 11.2M | } |
241 | 33.5M | if_debug0m('L', cldev->memory, "[L] adding terminator\n"); |
242 | 33.5M | end = cmd_count_op(cmd_end, 1, cldev->memory); |
243 | 33.5M | cldev->page_info.io_procs->fwrite_chars(&end, 1, cfile); |
244 | 33.5M | process_interrupts(cldev->memory); |
245 | 33.5M | code_b = cldev->page_info.io_procs->ferror_code(bfile); |
246 | 33.5M | code_c = cldev->page_info.io_procs->ferror_code(cfile); |
247 | 33.5M | if (code_b < 0) |
248 | 0 | return_error(code_b); |
249 | 33.5M | if (code_c < 0) |
250 | 0 | return_error(code_c); |
251 | 33.5M | } |
252 | 212M | return code_b | code_c; |
253 | 212M | } |
254 | | |
255 | | /* Write out a pseudo-band block of data, using the specific pseudo_band_offset */ |
256 | | int |
257 | | cmd_write_pseudo_band(gx_device_clist_writer * cldev, unsigned char *pbuf, int data_size, int pseudo_band_offset) |
258 | 705k | { |
259 | | |
260 | | /* Data is written out maxband + pseudo_band_offset */ |
261 | | |
262 | 705k | int band = cldev->band_range_max + pseudo_band_offset; |
263 | 705k | clist_file_ptr cfile = cldev->page_info.cfile; |
264 | 705k | clist_file_ptr bfile = cldev->page_info.bfile; |
265 | 705k | cmd_block cb; |
266 | 705k | int code_b, code_c; |
267 | | |
268 | 705k | if (cfile == 0 || bfile == 0) |
269 | 0 | return_error(gs_error_ioerror); |
270 | | |
271 | | /* Set up the command block information that |
272 | | is stored in the bfile. */ |
273 | | |
274 | 705k | cb.band_min = band; |
275 | 705k | cb.band_max = band; |
276 | 705k | cb.pos = cldev->page_info.io_procs->ftell(cfile); |
277 | | |
278 | 705k | if_debug2m('l', cldev->memory, "[l]writing pseudo band %d cb pos %"PRId64"\n", |
279 | 705k | band, cb.pos); |
280 | | |
281 | 705k | cldev->page_info.io_procs->fwrite_chars(&cb, sizeof(cb), bfile); |
282 | | |
283 | | /* Now store the information in the cfile */ |
284 | 705k | if_debug2m('l', cldev->memory, "[l]writing %d bytes into cfile at %"PRId64"\n", |
285 | 705k | data_size, cldev->page_info.io_procs->ftell(cfile)); |
286 | | |
287 | 705k | cldev->page_info.io_procs->fwrite_chars(pbuf, data_size, cfile); |
288 | | |
289 | 705k | process_interrupts(cldev->memory); |
290 | 705k | code_b = cldev->page_info.io_procs->ferror_code(bfile); |
291 | 705k | code_c = cldev->page_info.io_procs->ferror_code(cfile); |
292 | | |
293 | 705k | if (code_b < 0) |
294 | 0 | return_error(code_b); |
295 | 705k | if (code_c < 0) |
296 | 0 | return_error(code_c); |
297 | | |
298 | 705k | return code_b | code_c; |
299 | 705k | } |
300 | | |
301 | | /* Write out the buffered commands, and reset the buffer. */ |
302 | | int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */ |
303 | | cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end) |
304 | 1.51M | { |
305 | 1.51M | int nbands = cldev->nbands; |
306 | 1.51M | gx_clist_state *pcls; |
307 | 1.51M | int band; |
308 | 1.51M | int code = cmd_write_band(cldev, cldev->band_range_min, |
309 | 1.51M | cldev->band_range_max, |
310 | 1.51M | cldev->band_range_list, |
311 | 1.51M | cmd_opv_end_run); |
312 | | |
313 | 1.51M | int warning = code; |
314 | | |
315 | 1.51M | for (band = 0, pcls = cldev->states; |
316 | 212M | code >= 0 && band < nbands; band++, pcls++ |
317 | 211M | ) { |
318 | 211M | code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end); |
319 | 211M | warning |= code; |
320 | 211M | } |
321 | | /* If an error occurred, finish cleaning up the pointers. */ |
322 | 1.51M | for (; band < nbands; band++, pcls++) |
323 | 0 | pcls->list.head = pcls->list.tail = 0; |
324 | 1.51M | cldev->cnext = cldev->cbuf; |
325 | | #ifdef HAVE_VALGRIND |
326 | | VALGRIND_MAKE_MEM_UNDEFINED(cldev->cbuf, cldev->cend - cldev->cbuf); |
327 | | #endif |
328 | 1.51M | cldev->ccl = 0; |
329 | | #ifdef COLLECT_STATS_CLIST |
330 | | if (gs_debug_c('l')) |
331 | | cmd_print_stats(cldev->memory); |
332 | | #endif |
333 | 1.51M | return_check_interrupt(cldev->memory, code != 0 ? code : warning); |
334 | 1.51M | } |
335 | | |
336 | | /* |
337 | | * Add a command to the appropriate band list, and allocate space for its |
338 | | * data. Return the pointer to the data area. If an error or (low-memory |
339 | | * warning) occurs, set cldev->error_code and return 0. |
340 | | */ |
341 | 777M | #define cmd_headroom (sizeof(cmd_prefix) + ARCH_ALIGN_PTR_MOD) |
342 | | byte * |
343 | | cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size) |
344 | 677M | { |
345 | 677M | byte *dp = cldev->cnext; |
346 | | |
347 | 677M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
348 | | |
349 | 677M | if (size + cmd_headroom > cldev->cend - dp) { |
350 | 99.5k | cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run); |
351 | | /* error_code can come back as +ve as a warning that memory |
352 | | * is getting tight. Don't fail on that. */ |
353 | 99.5k | if (cldev->error_code < 0 || |
354 | 99.5k | (size + cmd_headroom > cldev->cend - cldev->cnext)) { |
355 | 0 | if (cldev->error_code == 0) |
356 | 0 | cldev->error_code = gs_error_VMerror; |
357 | 0 | return 0; |
358 | 0 | } |
359 | 99.5k | else |
360 | 99.5k | return cmd_put_list_op(cldev, pcl, size); |
361 | 99.5k | } |
362 | 677M | if (cldev->ccl == pcl) { /* We're adding another command for the same band. */ |
363 | | /* Tack it onto the end of the previous one. */ |
364 | 610M | cmd_count_add1(stats_cmd.same_band); |
365 | | #ifdef DEBUG |
366 | | if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) { |
367 | | lprintf1("cmd_put_list_op error at "PRI_INTPTR"\n", (intptr_t)pcl->tail); |
368 | | } |
369 | | #endif |
370 | 610M | if_debug2m('L', cldev->memory, "[L] id:%ld+%ld", |
371 | 610M | pcl->tail->id, (long)pcl->tail->size); |
372 | 610M | pcl->tail->size += size; |
373 | 610M | } else { |
374 | | /* Skip to an appropriate alignment boundary. */ |
375 | | /* (We assume the command buffer itself is aligned.) */ |
376 | 66.8M | cmd_prefix *cp = (cmd_prefix *) |
377 | 66.8M | (dp + ((cldev->cbuf - dp) & (ARCH_ALIGN_PTR_MOD - 1))); |
378 | | |
379 | 66.8M | cp->id = cldev->ins_count++; |
380 | | #ifdef DEBUG |
381 | | if (gs_debug_c('L')) |
382 | | { |
383 | | if (pcl == cldev->band_range_list) |
384 | | dmlprintf2(cldev->memory, "[L]Change to bands=(%d->%d)", cldev->band_range_min, cldev->band_range_max); |
385 | | else |
386 | | dmlprintf1(cldev->memory, "[L]Change to band=%d", |
387 | | (int)(((intptr_t)pcl-(intptr_t)&cldev->states->list)/sizeof(*cldev->states))); |
388 | | |
389 | | dmlprintf2(cldev->memory, ", align=%d\n[L] id:%ld+0", |
390 | | (int)((char *)cp-(char *)dp), cp->id); |
391 | | } |
392 | | #endif |
393 | | |
394 | 66.8M | cmd_count_add1(stats_cmd.other_band); |
395 | 66.8M | dp = (byte *) (cp + 1); |
396 | 66.8M | if (pcl->tail != 0) { |
397 | | #ifdef DEBUG |
398 | | if (pcl->tail < pcl->head || |
399 | | pcl->tail->size > dp - (byte *) (pcl->tail + 1) |
400 | | ) { |
401 | | lprintf1("cmd_put_list_op error at "PRI_INTPTR"\n", |
402 | | (intptr_t)pcl->tail); |
403 | | } |
404 | | #endif |
405 | 55.4M | pcl->tail->next = cp; |
406 | 55.4M | } else |
407 | 11.4M | pcl->head = cp; |
408 | 66.8M | pcl->tail = cp; |
409 | 66.8M | cldev->ccl = pcl; |
410 | 66.8M | cp->size = size; |
411 | 66.8M | } |
412 | 677M | cldev->cnext = dp + size; |
413 | 677M | return dp; |
414 | 677M | } |
415 | | |
416 | | byte * |
417 | | cmd_put_list_extended_op(gx_device_clist_writer *cldev, cmd_list *pcl, int op, uint size) |
418 | 0 | { |
419 | 0 | byte *dp = cmd_put_list_op(cldev, pcl, size); |
420 | |
|
421 | 0 | if (dp) { |
422 | 0 | dp[1] = op; |
423 | |
|
424 | 0 | if (gs_debug_c('L')) { |
425 | 0 | clist_debug_op(cldev->memory, dp); |
426 | 0 | dmlprintf1(cldev->memory, "[%u]\n", size); |
427 | 0 | } |
428 | 0 | } |
429 | |
|
430 | 0 | return dp; |
431 | 0 | } |
432 | | |
433 | | /* Request a space in the buffer. |
434 | | Writes out the buffer if necessary. |
435 | | Returns the size of available space. */ |
436 | | int |
437 | | cmd_get_buffer_space(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size) |
438 | 49.6M | { |
439 | 49.6M | size_t z; |
440 | 49.6M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
441 | | |
442 | 49.6M | if (size + cmd_headroom > cldev->cend - cldev->cnext) { |
443 | | /* error_code can come back as +ve as a warning that memory |
444 | | * is getting tight. Don't fail on that. */ |
445 | 40.9k | cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run); |
446 | 40.9k | if (cldev->error_code < 0) { |
447 | 0 | return cldev->error_code; |
448 | 0 | } |
449 | 40.9k | } |
450 | | /* Calculate the available size as a size_t. If this won't fit in |
451 | | * an int, clip the value. This is a bit crap, but it should be |
452 | | * safe at least until we can change the clist to use size_t's |
453 | | * where appropriate. */ |
454 | 49.6M | z = cldev->cend - cldev->cnext - cmd_headroom; |
455 | 49.6M | if (z > INT_MAX) |
456 | 0 | z = INT_MAX; |
457 | 49.6M | return z; |
458 | 49.6M | } |
459 | | |
460 | | #ifdef DEBUG |
461 | | byte * |
462 | | cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size) |
463 | | { |
464 | | return cmd_put_list_op(cldev, &pcls->list, size); |
465 | | } |
466 | | #endif |
467 | | |
468 | | /* Add a command for a range of bands. */ |
469 | | byte * |
470 | | cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max, |
471 | | uint size) |
472 | 2.70M | { |
473 | 2.70M | CMD_CHECK_LAST_OP_BLOCK_DEFINED(cldev); |
474 | | |
475 | 2.70M | if (cldev->ccl != 0 && |
476 | 2.70M | (cldev->ccl != cldev->band_range_list || |
477 | 2.06M | band_min != cldev->band_range_min || |
478 | 2.06M | band_max != cldev->band_range_max) |
479 | 2.70M | ) { |
480 | 679k | cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run); |
481 | | /* error_code can come back as +ve as a warning that memory |
482 | | * is getting tight. Don't fail on that. */ |
483 | 679k | if (cldev->error_code < 0) { |
484 | 0 | return NULL; |
485 | 0 | } |
486 | 679k | cldev->band_range_min = band_min; |
487 | 679k | cldev->band_range_max = band_max; |
488 | 679k | if_debug2m('L', cldev->memory, "[L]Band range(%d,%d)\n", |
489 | 679k | band_min, band_max); |
490 | 679k | } |
491 | 2.70M | return cmd_put_list_op(cldev, cldev->band_range_list, size); |
492 | 2.70M | } |
493 | | |
494 | | /* Write a variable-size positive integer. */ |
495 | | int |
496 | | cmd_size_w(register uint w) |
497 | 1.01G | { |
498 | 1.01G | register int size = 1; |
499 | | |
500 | 2.89G | while (w > 0x7f) |
501 | 1.88G | w >>= 7, size++; |
502 | 1.01G | return size; |
503 | 1.01G | } |
504 | | byte * |
505 | | cmd_put_w(register uint w, register byte * dp) |
506 | 1.03G | { |
507 | 2.92G | while (w > 0x7f) |
508 | 1.89G | *dp++ = w | 0x80, w >>= 7; |
509 | 1.03G | *dp = w; |
510 | 1.03G | return dp + 1; |
511 | 1.03G | } |
512 | | /* Write a variable-size positive fractional. */ |
513 | | int |
514 | | cmd_size_frac31(register frac31 w) |
515 | 31.3M | { |
516 | 31.3M | register int size = 1; |
517 | 31.3M | register uint32_t v = w; |
518 | | |
519 | 65.7M | while (v & 0x01FFFFFF) |
520 | 34.4M | v <<= 7, size++; |
521 | 31.3M | return size; |
522 | 31.3M | } |
523 | | byte * |
524 | | cmd_put_frac31(register frac31 w, register byte * dp) |
525 | 31.3M | { |
526 | 31.3M | register uint32_t v = w; |
527 | | |
528 | 65.7M | while (v & 0x01FFFFFF) |
529 | 34.4M | *dp++ = (v >> 24) | 1, v <<= 7; |
530 | 31.3M | *dp = (v >> 24); |
531 | 31.3M | return dp + 1; |
532 | 31.3M | } |
533 | | |
534 | | /* |
535 | | * This next two arrays are used for the 'delta' mode of placing a color |
536 | | * in the clist. These arrays are indexed by the number of bytes in the |
537 | | * color value (the depth). |
538 | | * |
539 | | * Delta values are calculated by subtracting the old value for the color |
540 | | * from the desired new value. Then each byte of the differenece is |
541 | | * examined. For most bytes, if the difference fits into 4 bits (signed) |
542 | | * then those bits are packed into the clist along with an opcode. If |
543 | | * the size of the color (the depth) is an odd number of bytes then instead |
544 | | * of four bits per byte, extra bits are used for the upper three bytes |
545 | | * of the color. In this case, five bits are used for the first byte, |
546 | | * six bits for the second byte, and five bits for third byte. This |
547 | | * maximizes the chance that the 'delta' mode can be used for placing |
548 | | * colors in the clist. |
549 | | */ |
550 | | /* |
551 | | * Depending upon the compiler and user choices, the size of a gx_color_index |
552 | | * may be 4 to 8 bytes. We will define table entries for up to 8 bytes. |
553 | | * This macro is being used to prevent compiler warnings if gx_color_index is |
554 | | * only 4 bytes. |
555 | | */ |
556 | | #define tab_entry(x) ((x) & (~((gx_color_index) 0))) |
557 | | |
558 | | const gx_color_index cmd_delta_offsets[] = { |
559 | | tab_entry(0), |
560 | | tab_entry(0), |
561 | | tab_entry(0x0808), |
562 | | tab_entry(0x102010), |
563 | | tab_entry(0x08080808) |
564 | | #if ARCH_SIZEOF_GX_COLOR_INDEX > 4 |
565 | | , |
566 | | tab_entry(0x1020100808), |
567 | | tab_entry(0x080808080808), |
568 | | tab_entry(0x10201008080808), |
569 | | tab_entry(0x0808080808080808) |
570 | | #endif |
571 | | }; |
572 | | |
573 | | static const gx_color_index cmd_delta_masks[] = { |
574 | | tab_entry(0), |
575 | | tab_entry(0), |
576 | | tab_entry(0x0f0f), |
577 | | tab_entry(0x1f3f1f), |
578 | | tab_entry(0x0f0f0f0f) |
579 | | #if ARCH_SIZEOF_GX_COLOR_INDEX > 4 |
580 | | , |
581 | | tab_entry(0x1f3f1f0f0f), |
582 | | tab_entry(0x0f0f0f0f0f0f), |
583 | | tab_entry(0x1f3f1f0f0f0f0f), |
584 | | tab_entry(0x0f0f0f0f0f0f0f0f) |
585 | | #endif |
586 | | }; |
587 | | |
588 | | #undef tab_entry |
589 | | |
590 | | /* |
591 | | * There are currently only four different color "types" that can be placed |
592 | | * into the clist. These are called "color0", "color1", and "tile_color0", |
593 | | * and "tile_color1". There are separate command codes for color0 versus |
594 | | * color1, both for the full value and delta commands - see cmd_put_color. |
595 | | * Tile colors are preceded by a cmd_opv_set_tile_color command. |
596 | | */ |
597 | | const clist_select_color_t |
598 | | clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 0}, |
599 | | clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 0}, |
600 | | clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 1}, |
601 | | clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 1}; |
602 | | |
603 | | /* |
604 | | * This routine is used to place a color into the clist. Colors, in the |
605 | | * clist, can be specified either as by a full value or by a "delta" value. |
606 | | * |
607 | | * See the comments before cmd_delta_offsets[] for a description of the |
608 | | * 'delta' mode. The delta mode may allow for a smaller command in the clist. |
609 | | * |
610 | | * For the full value mode, values are sent as a cmd code plus n bytes of |
611 | | * data. To minimize the number of bytes, a count is made of any low order |
612 | | * bytes which are zero. This count is packed into the low order 4 bits |
613 | | * of the cmd code. The data for these bytes are not sent. |
614 | | * |
615 | | * The gx_no_color_index value is treated as a special case. This is done |
616 | | * because it is both a commonly sent value and because it may require |
617 | | * more bytes then the other color values. |
618 | | * |
619 | | * Parameters: |
620 | | * cldev - Pointer to clist device |
621 | | * pcls - Pointer to clist state |
622 | | * select - Descriptor record for type of color being sent. See comments |
623 | | * by clist_select_color_t. |
624 | | * color - The new color value. |
625 | | * pcolor - Pointer to previous color value. (If the color value is the |
626 | | * same as the previous value then nothing is placed into the clist.) |
627 | | * |
628 | | * Returns: |
629 | | * Error code |
630 | | * clist and pcls and cldev may be updated. |
631 | | */ |
632 | | int |
633 | | cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
634 | | const clist_select_color_t * select, |
635 | | gx_color_index color, gx_color_index * pcolor) |
636 | 101M | { |
637 | 101M | byte * dp; /* This is manipulated by the set_cmd_put_op macro */ |
638 | 101M | gx_color_index diff = color - *pcolor; |
639 | 101M | byte op, op_delta; |
640 | 101M | int code; |
641 | | |
642 | 101M | if (diff == 0) |
643 | 0 | return 0; |
644 | | |
645 | | /* If this is a tile color then send tile color type */ |
646 | 101M | if (select->tile_color) { |
647 | 235k | code = set_cmd_put_op(&dp, cldev, pcls, cmd_opv_set_tile_color, 1); |
648 | 235k | if (code < 0) |
649 | 0 | return code; |
650 | 235k | } |
651 | 101M | op = select->set_op; |
652 | 101M | op_delta = select->delta_op; |
653 | 101M | if (color == gx_no_color_index) { |
654 | | /* |
655 | | * We must handle this specially, because it may take more |
656 | | * bytes than the color depth. |
657 | | */ |
658 | 19 | code = set_cmd_put_op(&dp, cldev, pcls, op + cmd_no_color_index, 1); |
659 | 19 | if (code < 0) |
660 | 0 | return code; |
661 | 101M | } else { |
662 | | /* Check if the "delta" mode command can be used. */ |
663 | | /* clist_color_info may be different than target device due to |
664 | | * transparency group during clist writing phase */ |
665 | 101M | int depth = (cldev->clist_color_info.depth <= sizeof(gx_color_index)*8 ? |
666 | 101M | cldev->clist_color_info.depth : sizeof(gx_color_index)*8); |
667 | 101M | int num_bytes = (depth + 7) >> 3; |
668 | 101M | int delta_bytes = (num_bytes + 1) / 2; |
669 | 101M | gx_color_index delta_offset = cmd_delta_offsets[num_bytes]; |
670 | 101M | gx_color_index delta_mask = cmd_delta_masks[num_bytes]; |
671 | 101M | gx_color_index delta = (diff + delta_offset) & delta_mask; |
672 | 101M | bool use_delta = (color == (*pcolor + delta - delta_offset)); |
673 | 101M | int bytes_dropped = 0; |
674 | 101M | gx_color_index data = color; |
675 | | |
676 | | /* |
677 | | * If we use the full value mode, we do not send low order bytes |
678 | | * which are zero. Determine how many low order bytes are zero. |
679 | | */ |
680 | 101M | if (color == 0) { |
681 | 1.79M | bytes_dropped = num_bytes; |
682 | 1.79M | } |
683 | 99.7M | else { |
684 | 101M | while ((data & 0xff) == 0) { |
685 | 1.45M | bytes_dropped++; |
686 | 1.45M | data >>= 8; |
687 | 1.45M | } |
688 | 99.7M | } |
689 | | /* Now send one of the two command forms */ |
690 | 101M | if (use_delta && delta_bytes < (num_bytes - bytes_dropped)) { |
691 | 65.0M | code = set_cmd_put_op(&dp, cldev, pcls, |
692 | 65.0M | op_delta, delta_bytes + 1); |
693 | 65.0M | if (code < 0) |
694 | 0 | return code; |
695 | | /* |
696 | | * If we have an odd number of bytes then use extra bits for |
697 | | * the high order three bytes of the color. |
698 | | */ |
699 | 65.0M | if ((num_bytes >= 3) && (num_bytes & 1)) { |
700 | 17.0M | data = delta >> ((num_bytes - 3) * 8); |
701 | 17.0M | dp[delta_bytes--] = (byte)(((data >> 13) & 0xf8) + ((data >> 11) & 0x07)); |
702 | 17.0M | dp[delta_bytes--] = (byte)(((data >> 3) & 0xe0) + (data & 0x1f)); |
703 | 17.0M | } |
704 | 161M | for(; delta_bytes>0; delta_bytes--) { |
705 | 96.0M | dp[delta_bytes] = (byte)((delta >> 4) + delta); |
706 | 96.0M | delta >>= 16; |
707 | 96.0M | } |
708 | 65.0M | } |
709 | 36.4M | else { |
710 | 36.4M | num_bytes -= bytes_dropped; |
711 | 36.4M | code = set_cmd_put_op(&dp, cldev, pcls, |
712 | 36.4M | (byte)(op + bytes_dropped), num_bytes + 1); |
713 | 36.4M | if (code < 0) |
714 | 0 | return code; |
715 | 92.0M | for(; num_bytes>0; num_bytes--) { |
716 | 55.6M | dp[num_bytes] = (byte)data; |
717 | 55.6M | data >>= 8; |
718 | 55.6M | } |
719 | 36.4M | } |
720 | 101M | } |
721 | 101M | *pcolor = color; |
722 | 101M | return 0; |
723 | 101M | } |
724 | | |
725 | | /* Put out a command to set the tile colors. */ |
726 | | int |
727 | | cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
728 | | gx_color_index color0, gx_color_index color1) |
729 | 141k | { |
730 | 141k | int code = 0; |
731 | | |
732 | 141k | if (color0 != pcls->tile_colors[0]) { |
733 | 125k | code = cmd_put_color(cldev, pcls, |
734 | 125k | &clist_select_tile_color0, |
735 | 125k | color0, &pcls->tile_colors[0]); |
736 | 125k | if (code != 0) |
737 | 0 | return code; |
738 | 125k | } |
739 | 141k | if (color1 != pcls->tile_colors[1]) |
740 | 109k | code = cmd_put_color(cldev, pcls, |
741 | 109k | &clist_select_tile_color1, |
742 | 109k | color1, &pcls->tile_colors[1]); |
743 | 141k | return code; |
744 | 141k | } |
745 | | |
746 | | /* Put out a command to set the tile phase. */ |
747 | | int |
748 | | cmd_set_tile_phase_generic(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
749 | | int px, int py, bool all_bands) |
750 | 26.8k | { |
751 | 26.8k | int pcsize; |
752 | 26.8k | byte *dp; |
753 | 26.8k | int code; |
754 | | |
755 | 26.8k | pcsize = 1 + cmd_size2w(px, py); |
756 | 26.8k | if (all_bands) |
757 | 0 | code = set_cmd_put_all_op(&dp, cldev, (byte)cmd_opv_set_tile_phase, pcsize); |
758 | 26.8k | else |
759 | 26.8k | code = set_cmd_put_op(&dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize); |
760 | 26.8k | if (code < 0) |
761 | 0 | return code; |
762 | 26.8k | ++dp; |
763 | 26.8k | pcls->tile_phase.x = px; |
764 | 26.8k | pcls->tile_phase.y = py; |
765 | 26.8k | cmd_putxy(pcls->tile_phase, &dp); |
766 | 26.8k | return 0; |
767 | 26.8k | } |
768 | | |
769 | | int |
770 | | cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
771 | | int px, int py) |
772 | 26.8k | { |
773 | 26.8k | return cmd_set_tile_phase_generic(cldev, pcls, px, py, false); |
774 | 26.8k | } |
775 | | |
776 | | int |
777 | | cmd_set_screen_phase_generic(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
778 | | int px, int py, gs_color_select_t color_select, |
779 | | bool all_bands) |
780 | 2.58k | { |
781 | 2.58k | int pcsize; |
782 | 2.58k | byte *dp; |
783 | 2.58k | int code; |
784 | | |
785 | 2.58k | pcsize = 1 + cmd_size2w(px, py); |
786 | 2.58k | if (all_bands) |
787 | 2.58k | code = set_cmd_put_all_op(&dp, cldev, (byte)cmd_opv_set_screen_phaseT + color_select, pcsize); |
788 | 0 | else |
789 | 0 | code = set_cmd_put_op(&dp, cldev, pcls, (byte)cmd_opv_set_screen_phaseT + color_select, pcsize); |
790 | 2.58k | if (code < 0) |
791 | 0 | return code; |
792 | 2.58k | ++dp; |
793 | 2.58k | pcls->screen_phase[color_select].x = px; |
794 | 2.58k | pcls->screen_phase[color_select].y = py; |
795 | 2.58k | cmd_putxy(pcls->screen_phase[color_select], &dp); |
796 | 2.58k | return 0; |
797 | 2.58k | } |
798 | | |
799 | | int |
800 | | cmd_set_screen_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
801 | | int px, int py, gs_color_select_t color_select) |
802 | 0 | { |
803 | 0 | return cmd_set_screen_phase_generic(cldev, pcls, px, py, color_select, false); |
804 | 0 | } |
805 | | |
806 | | /* Write a command to enable or disable the logical operation. */ |
807 | | int |
808 | | cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
809 | | int enable) |
810 | 843k | { |
811 | 843k | byte *dp; |
812 | 843k | int code = set_cmd_put_op(&dp, cldev, pcls, |
813 | 843k | (byte)(enable ? cmd_opv_enable_lop : |
814 | 843k | cmd_opv_disable_lop), |
815 | 843k | 1); |
816 | | |
817 | 843k | if (code < 0) |
818 | 0 | return code; |
819 | 843k | pcls->lop_enabled = enable; |
820 | 843k | return 0; |
821 | 843k | } |
822 | | |
823 | | /* Write a command to enable or disable clipping. */ |
824 | | /* This routine is only called if the path extensions are included. */ |
825 | | int |
826 | | cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
827 | | int enable) |
828 | 24.7k | { |
829 | 24.7k | byte *dp; |
830 | 24.7k | int code = set_cmd_put_op(&dp, cldev, pcls, |
831 | 24.7k | (byte)(enable ? cmd_opv_enable_clip : |
832 | 24.7k | cmd_opv_disable_clip), |
833 | 24.7k | 1); |
834 | | |
835 | 24.7k | if (code < 0) |
836 | 0 | return code; |
837 | 24.7k | pcls->clip_enabled = enable; |
838 | 24.7k | return 0; |
839 | 24.7k | } |
840 | | |
841 | | /* Write a command to set the logical operation. */ |
842 | | int |
843 | | cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls, |
844 | | gs_logical_operation_t lop) |
845 | 1.95M | { |
846 | 1.95M | byte *dp; |
847 | 1.95M | uint lop_msb = lop >> 6; |
848 | 1.95M | int code = set_cmd_put_op(&dp, cldev, pcls, |
849 | 1.95M | cmd_opv_set_misc, 2 + cmd_size_w(lop_msb)); |
850 | | |
851 | 1.95M | if (code < 0) |
852 | 0 | return code; |
853 | 1.95M | dp[1] = cmd_set_misc_lop + (lop & 0x3f); |
854 | 1.95M | cmd_put_w(lop_msb, dp + 2); |
855 | 1.95M | pcls->lop = lop; |
856 | 1.95M | return 0; |
857 | 1.95M | } |
858 | | |
859 | | /* Disable (if default) or enable the logical operation, setting it if */ |
860 | | /* needed. */ |
861 | | int |
862 | | cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls, |
863 | | gs_logical_operation_t lop) |
864 | 147M | { |
865 | 147M | int code; |
866 | | |
867 | 147M | if (lop == lop_default) |
868 | 145M | return cmd_disable_lop(cldev, pcls); |
869 | 1.95M | code = cmd_set_lop(cldev, pcls, lop); |
870 | 1.95M | if (code < 0) |
871 | 0 | return code; |
872 | 1.95M | return cmd_enable_lop(cldev, pcls); |
873 | 1.95M | } |
874 | | |
875 | | /* Write a parameter list */ |
876 | | int /* ret 0 all ok, -ve error */ |
877 | | cmd_put_params(gx_device_clist_writer *cldev, |
878 | | gs_param_list *param_list) /* NB open for READ */ |
879 | 0 | { |
880 | 0 | byte *dp; |
881 | 0 | int code; |
882 | 0 | byte local_buf[512]; /* arbitrary */ |
883 | 0 | int param_length; |
884 | | |
885 | | /* Get serialized list's length + try to get it into local var if it fits. */ |
886 | 0 | param_length = code = |
887 | 0 | gs_param_list_serialize(param_list, local_buf, sizeof(local_buf)); |
888 | 0 | if (param_length > 0) { |
889 | | /* Get cmd buffer space for serialized */ |
890 | 0 | code = set_cmd_put_all_extended_op(&dp, cldev, cmd_opv_ext_put_params, |
891 | 0 | 2 + sizeof(unsigned) + param_length); |
892 | 0 | if (code < 0) |
893 | 0 | return code; |
894 | | |
895 | | /* write param list to cmd list: needs to all fit in cmd buffer */ |
896 | 0 | if_debug1m('l', cldev->memory, "[l]put_params, length=%d\n", param_length); |
897 | 0 | dp += 2; |
898 | 0 | memcpy(dp, ¶m_length, sizeof(unsigned)); |
899 | 0 | dp += sizeof(unsigned); |
900 | 0 | if (param_length > sizeof(local_buf)) { |
901 | 0 | int old_param_length = param_length; |
902 | |
|
903 | 0 | param_length = code = |
904 | 0 | gs_param_list_serialize(param_list, dp, old_param_length); |
905 | 0 | if (param_length >= 0) |
906 | 0 | code = (old_param_length != param_length ? |
907 | 0 | gs_note_error(gs_error_unknownerror) : 0); |
908 | 0 | if (code < 0) { |
909 | | /* error serializing: back out by writing a 0-length parm list */ |
910 | 0 | memset(dp - sizeof(unsigned), 0, sizeof(unsigned)); |
911 | 0 | cmd_shorten_list_op(cldev, cldev->band_range_list, |
912 | 0 | old_param_length); |
913 | 0 | } |
914 | 0 | } else |
915 | 0 | memcpy(dp, local_buf, param_length); /* did this when computing length */ |
916 | 0 | } |
917 | 0 | return code; |
918 | 0 | } |
919 | | |
920 | | /* Initialize CCITTFax filters. */ |
921 | | static void |
922 | | clist_cf_init(stream_CF_state *ss, int width) |
923 | 3.63M | { |
924 | 3.63M | ss->K = -1; |
925 | 3.63M | ss->Columns = width; |
926 | | #if 0 /* Disabled due to a crash with ppmraw -r216 c327.bin : |
927 | | the decoding filter overruns in 1 byte. |
928 | | */ |
929 | | ss->EndOfBlock = false; |
930 | | #else |
931 | 3.63M | ss->EndOfBlock = true; |
932 | 3.63M | #endif |
933 | 3.63M | ss->BlackIs1 = true; |
934 | 3.63M | ss->DecodedByteAlign = align_bitmap_mod; |
935 | 3.63M | } |
936 | | void |
937 | | clist_cfe_init(stream_CFE_state *ss, int width, gs_memory_t *mem) |
938 | 2.13M | { |
939 | 2.13M | s_init_state((stream_state *)ss, &s_CFE_template, mem); |
940 | 2.13M | s_CFE_set_defaults_inline(ss); |
941 | 2.13M | clist_cf_init((stream_CF_state *)ss, width); |
942 | 2.13M | s_CFE_template.init((stream_state *)(ss)); |
943 | 2.13M | } |
944 | | void |
945 | | clist_cfd_init(stream_CFD_state *ss, int width, int height, gs_memory_t *mem) |
946 | 1.50M | { |
947 | 1.50M | s_init_state((stream_state *)ss, &s_CFD_template, mem); |
948 | 1.50M | s_CFD_template.set_defaults((stream_state *)ss); |
949 | 1.50M | clist_cf_init((stream_CF_state *)ss, width); |
950 | 1.50M | ss->Rows = height; |
951 | 1.50M | s_CFD_template.init((stream_state *)(ss)); |
952 | 1.50M | } |
953 | | |
954 | | /* Initialize RunLength filters. */ |
955 | | void |
956 | | clist_rle_init(stream_RLE_state *ss) |
957 | 843k | { |
958 | 843k | s_init_state((stream_state *)ss, &s_RLE_template, (gs_memory_t *)0); |
959 | 843k | ss->templat->set_defaults((stream_state *)ss); |
960 | 843k | ss->templat->init((stream_state *)ss); |
961 | 843k | } |
962 | | void |
963 | | clist_rld_init(stream_RLD_state *ss) |
964 | 0 | { |
965 | 0 | s_init_state((stream_state *)ss, &s_RLD_template, (gs_memory_t *)0); |
966 | 0 | ss->templat->set_defaults((stream_state *)ss); |
967 | 0 | ss->templat->init((stream_state *)ss); |
968 | 0 | } |
969 | | |
970 | | /* Read a transformation matrix. */ |
971 | | const byte * |
972 | | cmd_read_matrix(gs_matrix * pmat, const byte * cbp) |
973 | 14.8M | { |
974 | 14.8M | stream s; |
975 | | |
976 | 14.8M | s_init(&s, NULL); |
977 | 14.8M | sread_string(&s, cbp, 1 + sizeof(*pmat)); |
978 | 14.8M | sget_matrix(&s, pmat); |
979 | 14.8M | return cbp + stell(&s); |
980 | 14.8M | } |
981 | | |
982 | | /* |
983 | | Some notes on understanding the output of -ZL. |
984 | | |
985 | | The examples here are given from: |
986 | | gs -o out.png -r96 -sDEVICE=png16m -dBandHeight=20 -dMaxBitmap=1000 -ZL examples/tiger.eps |
987 | | |
988 | | Not every line in that output is explained here! |
989 | | |
990 | | When writing a command list, we gather up a list of 'commands' into the |
991 | | clist (cfile). We then have a series of indexes that says which of these |
992 | | commands is needed for each band (bfile). |
993 | | |
994 | | So, while writing, we can be writing for 1 band, or for a range of bands |
995 | | at any given time. Commands that follow one another for the same band |
996 | | (or range of bands) will be crammed together into a single command block. |
997 | | These command blocks are each given an id for debugging purposes. When |
998 | | the set of bands for which we are writing changes, the id changes. |
999 | | |
1000 | | Somewhere towards the top of the output (i.e. within a |
1001 | | hundred lines or so) you should see: |
1002 | | |
1003 | | [L]Resetting: Band range(0,56) |
1004 | | |
1005 | | So, we are writing some commands that will apply to bands 0 to 56. |
1006 | | |
1007 | | [L] id:0+0, put_fill_dcolor(13) |
1008 | | [L] id:0+13, fill_rect 0(5) |
1009 | | |
1010 | | So, for id 0, at 0 bytes offset, we first have a put_fill_dcolor command |
1011 | | that takes 13 bytes. Then, still in id 0, at 13 bytes offset, we have |
1012 | | a fill_rect that takes 5 bytes. |
1013 | | |
1014 | | Then we change the band: |
1015 | | |
1016 | | [L]Change to band=0, align=6 |
1017 | | |
1018 | | When we change the band, we change to a new command block, and the id |
1019 | | changes - so you'll see the subsequent entries listed with id 1. |
1020 | | Subsequent command blocks are aligned, so you'll see some alignment |
1021 | | (padding) bytes used - here 6 bytes. |
1022 | | |
1023 | | [L] id:1+0, set_misc2(6) |
1024 | | [L] id:1+6, begin_clip(1) |
1025 | | [L] id:1+7, fill_rect 0(7) |
1026 | | |
1027 | | Here we see various commands, each for id 1, at the expected offsets |
1028 | | given their respective sizes. Then we get some debugging from elsewhere |
1029 | | in the clist system. |
1030 | | |
1031 | | [L] r6:0,793,0,1123 |
1032 | | |
1033 | | This indicates details about the fill_rect (in particular the way |
1034 | | the fill_rect is encoded, and the parameters it uses). Such lines can |
1035 | | be differentiated fairly easily from the command block writing code |
1036 | | as they do not start with 'id:'. |
1037 | | |
1038 | | We continue with more commands: |
1039 | | |
1040 | | [L] id:1+14, end_clip(1) |
1041 | | [L] id:1+15, put_fill_dcolor(13) |
1042 | | [L] rmoveto:0: 0 0 |
1043 | | [L] id:1+28, rmoveto(5) |
1044 | | [L] rlineto:0: 0 1123 |
1045 | | [L] id:1+33, vlineto(4) |
1046 | | [L] rlineto:0: 793 0 |
1047 | | [L] id:1+37, hlineto(3) |
1048 | | [L] rlineto:0: 0 -1123 |
1049 | | [L] id:1+40, vlineto(4) |
1050 | | [L] closepath:0: |
1051 | | [L] id:1+44, closepath(1) |
1052 | | [L] id:1+45, fill(1) |
1053 | | |
1054 | | Here we note a couple of things. The clist command encoding system |
1055 | | works by first reserving the required number of bytes for a command, |
1056 | | then filling in those bytes. Because lots of parameters vary in length |
1057 | | according to their particular value, we often have to do a lot of the |
1058 | | encoding work twice; once to count how many bytes we need to reserve |
1059 | | and then once to fill in the block. |
1060 | | |
1061 | | The command buffer debug lines (i.e. the ones starting 'id:') are output |
1062 | | at the point the buffer is reserved. Other debug lines for the same |
1063 | | command can happen either before or after these lines. So the 'r6' line |
1064 | | happened after the command reservation that it corresponded to, whereas |
1065 | | the 'rmoveto' (and others) above happen before the command reservation. |
1066 | | This can be confusing. |
1067 | | |
1068 | | Another confusing thing is that the commands can appear to change. The |
1069 | | non-command block debug above mentions 4 rlineto's, but these all |
1070 | | appear in the command list as vlineto or hlineto. This is because |
1071 | | the command block queueing attempts to be smart and to simplify the |
1072 | | sequence of commands. This can mean pulling a command into a previous |
1073 | | one, or (as in this case) realising that a simpler encoding can be |
1074 | | used. |
1075 | | |
1076 | | And we continue... |
1077 | | |
1078 | | [L]Change to band=1, align=2 |
1079 | | [L] id:2+0, set_misc2(6) |
1080 | | [L] id:2+6, begin_clip(1) |
1081 | | |
1082 | | After a while, we move to an output phase where things are actually |
1083 | | written to the file. These come in groups like: |
1084 | | |
1085 | | [l]writing for bands (0,56) at 0 |
1086 | | [L] cmd id=0 at 0 |
1087 | | [L] adding terminator, end_run(1) |
1088 | | |
1089 | | So this is writing out a note that bands 0 to 56 should execute the following |
1090 | | id's. We then write out the id's in question (id 0, goes into cfile at offset 0). |
1091 | | This is then terminated by a single byte 'end_run' marker. |
1092 | | |
1093 | | This repeats, with the file offsets increasing as we go. Some cases have more |
1094 | | than one id, for instance: |
1095 | | |
1096 | | [l]writing for bands (7,7) at 640 |
1097 | | [L] cmd id=8 at 640 |
1098 | | [L] cmd id=194 at 685 |
1099 | | [L] cmd id=215 at 785 |
1100 | | [L] cmd id=712 at 928 |
1101 | | [L] cmd id=720 at 969 |
1102 | | [L] cmd id=726 at 986 |
1103 | | [L] cmd id=732 at 1016 |
1104 | | [L] cmd id=809 at 1046 |
1105 | | [L] cmd id=817 at 1185 |
1106 | | [L] cmd id=822 at 1258 |
1107 | | [L] adding terminator, end_page(1) |
1108 | | |
1109 | | So, by matching up the id's in this section, together with their offsets, |
1110 | | we can find out what command was written there. |
1111 | | |
1112 | | For instance, suppose we hit a problem when reading the cfile at offset 1029. |
1113 | | We can look to see that this is id=732 + 13 bytes. We can look back in the |
1114 | | output to where id:732 was being output, and we see: |
1115 | | |
1116 | | [L] id:732+13, rmoveto(5) |
1117 | | |
1118 | | Most clist bugs tend to involve the reader and writer disagreeing on how |
1119 | | many bytes a given command should be and getting out of step. By looking at |
1120 | | where the writer puts stuff, and the reader is trying to read stuff, we can |
1121 | | hopefully spot this. |
1122 | | |
1123 | | The writing phase ends with: |
1124 | | |
1125 | | [l]writing pseudo band 57 cb pos 92521 |
1126 | | [l]writing 1824 bytes into cfile at 92521 |
1127 | | [l]writing end for bands (-1,-1) at 94345 |
1128 | | |
1129 | | FIXME: Explain the pseudo band. |
1130 | | |
1131 | | The next section of the logging shows the reader reading. For each band |
1132 | | in turn, we'll see a section where we announce what band we are |
1133 | | rendering: |
1134 | | |
1135 | | [l]rendering bands (0,0) |
1136 | | |
1137 | | Then we will read through the different band records that were output |
1138 | | above. |
1139 | | |
1140 | | [l]reading for bands (0,0) at bfile 0, cfile 0, length 0 |
1141 | | [l]reading for bands (0,56) at bfile 16, cfile 0, length 19 |
1142 | | [l]reading for bands (0,0) at bfile 32, cfile 19, length 47 |
1143 | | |
1144 | | If we look back, we can see that the first of these corresponded to an |
1145 | | empty record. The second of these corresponded to the write of |
1146 | | "cmd id=0 at 0", and the third corresponds to the write of |
1147 | | "cmd id=1 at 19". |
1148 | | |
1149 | | When these records have been read in, we actually execute the data. Each |
1150 | | line gives the offset from which the command was read (which allows us |
1151 | | to track it back to what it *should* be in the case of a mismatch), |
1152 | | and is followed by the command name, and a selection of its parameters: |
1153 | | |
1154 | | [L] 0: put_fill_dcolor cmd_opv_ext_put_drawing_color |
1155 | | [L] 13: fill_rect 0 x=0 y=0 w=0 h=0 |
1156 | | [L] 18: end_run |
1157 | | [L] 19: set_misc2 |
1158 | | [L] CJ=-1 AC=1 SA=1 |
1159 | | [L] BM=0 TK=1 OPM=0 OP=0 op=0 RI=1 |
1160 | | [L] 25: begin_clip |
1161 | | [L] 26: fill_rect 0 x=0 y=0 w=793 h=1123 |
1162 | | [L] 33: end_clip |
1163 | | [L] 34: put_fill_dcolor cmd_opv_ext_put_drawing_color |
1164 | | [L] 47: rmoveto (0,0) 0 0 |
1165 | | [L] 52: vlineto 1123 |
1166 | | [L] 56: hlineto 793 |
1167 | | [L] 59: vlineto -1123 |
1168 | | [L] 63: closepath |
1169 | | [L] 64: fill |
1170 | | [L] 65: end_page |
1171 | | |
1172 | | Then we repeat gathering the data for the next band: |
1173 | | |
1174 | | [l]rendering bands (1,1) |
1175 | | [l]reading for bands (0,56) at bfile 16, cfile 0, length 19 |
1176 | | [l]reading for bands (1,1) at bfile 48, cfile 66, length 46 |
1177 | | |
1178 | | and so on. |
1179 | | |
1180 | | */ |