2 |
- |
1 |
/* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: gxclutil.c,v 1.12 2005/03/14 18:08:36 dan Exp $ */
|
|
|
18 |
/* Command list writing utilities. */
|
|
|
19 |
|
|
|
20 |
#include "memory_.h"
|
|
|
21 |
#include "string_.h"
|
|
|
22 |
#include "gx.h"
|
|
|
23 |
#include "gp.h"
|
|
|
24 |
#include "gpcheck.h"
|
|
|
25 |
#include "gserrors.h"
|
|
|
26 |
#include "gxdevice.h"
|
|
|
27 |
#include "gxdevmem.h" /* must precede gxcldev.h */
|
|
|
28 |
#include "gxcldev.h"
|
|
|
29 |
#include "gxclpath.h"
|
|
|
30 |
#include "gsparams.h"
|
|
|
31 |
|
|
|
32 |
/* ---------------- Statistics ---------------- */
|
|
|
33 |
|
|
|
34 |
#ifdef DEBUG
|
|
|
35 |
const char *const cmd_op_names[16] =
|
|
|
36 |
{cmd_op_name_strings};
|
|
|
37 |
private const char *const cmd_misc_op_names[16] =
|
|
|
38 |
{cmd_misc_op_name_strings};
|
|
|
39 |
private const char *const cmd_misc2_op_names[16] =
|
|
|
40 |
{cmd_misc2_op_name_strings};
|
|
|
41 |
private const char *const cmd_segment_op_names[16] =
|
|
|
42 |
{cmd_segment_op_name_strings};
|
|
|
43 |
private const char *const cmd_path_op_names[16] =
|
|
|
44 |
{cmd_path_op_name_strings};
|
|
|
45 |
const char *const *const cmd_sub_op_names[16] =
|
|
|
46 |
{cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
|
|
|
47 |
0, 0, 0, 0,
|
|
|
48 |
0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names
|
|
|
49 |
};
|
|
|
50 |
struct stats_cmd_s {
|
|
|
51 |
ulong op_counts[256];
|
|
|
52 |
ulong op_sizes[256];
|
|
|
53 |
ulong tile_reset, tile_found, tile_added;
|
|
|
54 |
ulong same_band, other_band;
|
|
|
55 |
} stats_cmd;
|
|
|
56 |
extern ulong stats_cmd_diffs[5]; /* in gxclpath.c */
|
|
|
57 |
int
|
|
|
58 |
cmd_count_op(int op, uint size)
|
|
|
59 |
{
|
|
|
60 |
stats_cmd.op_counts[op]++;
|
|
|
61 |
stats_cmd.op_sizes[op] += size;
|
|
|
62 |
if (gs_debug_c('L')) {
|
|
|
63 |
const char *const *sub = cmd_sub_op_names[op >> 4];
|
|
|
64 |
|
|
|
65 |
if (sub)
|
|
|
66 |
dlprintf2(", %s(%u)\n", sub[op & 0xf], size);
|
|
|
67 |
else
|
|
|
68 |
dlprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf,
|
|
|
69 |
size);
|
|
|
70 |
dflush();
|
|
|
71 |
}
|
|
|
72 |
return op;
|
|
|
73 |
}
|
|
|
74 |
void
|
|
|
75 |
cmd_uncount_op(int op, uint size)
|
|
|
76 |
{
|
|
|
77 |
stats_cmd.op_counts[op]--;
|
|
|
78 |
stats_cmd.op_sizes[op] -= size;
|
|
|
79 |
}
|
|
|
80 |
#endif
|
|
|
81 |
|
|
|
82 |
/* Print statistics. */
|
|
|
83 |
#ifdef DEBUG
|
|
|
84 |
void
|
|
|
85 |
cmd_print_stats(void)
|
|
|
86 |
{
|
|
|
87 |
int ci, cj;
|
|
|
88 |
|
|
|
89 |
dlprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
|
|
|
90 |
stats_cmd.tile_reset, stats_cmd.tile_found,
|
|
|
91 |
stats_cmd.tile_added);
|
|
|
92 |
dlprintf5(" diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
|
|
|
93 |
stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2],
|
|
|
94 |
stats_cmd_diffs[3], stats_cmd_diffs[4]);
|
|
|
95 |
dlprintf2(" same_band = %lu, other_band = %lu\n",
|
|
|
96 |
stats_cmd.same_band, stats_cmd.other_band);
|
|
|
97 |
for (ci = 0; ci < 0x100; ci += 0x10) {
|
|
|
98 |
const char *const *sub = cmd_sub_op_names[ci >> 4];
|
|
|
99 |
|
|
|
100 |
if (sub != 0) {
|
|
|
101 |
dlprintf1("[l] %s =", cmd_op_names[ci >> 4]);
|
|
|
102 |
for (cj = ci; cj < ci + 0x10; cj += 2)
|
|
|
103 |
dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
|
|
|
104 |
sub[cj - ci],
|
|
|
105 |
stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj],
|
|
|
106 |
sub[cj - ci + 1],
|
|
|
107 |
stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]);
|
|
|
108 |
} else {
|
|
|
109 |
ulong tcounts = 0, tsizes = 0;
|
|
|
110 |
|
|
|
111 |
for (cj = ci; cj < ci + 0x10; cj++)
|
|
|
112 |
tcounts += stats_cmd.op_counts[cj],
|
|
|
113 |
tsizes += stats_cmd.op_sizes[cj];
|
|
|
114 |
dlprintf3("[l] %s (%lu,%lu) =\n\t",
|
|
|
115 |
cmd_op_names[ci >> 4], tcounts, tsizes);
|
|
|
116 |
for (cj = ci; cj < ci + 0x10; cj++)
|
|
|
117 |
if (stats_cmd.op_counts[cj] == 0)
|
|
|
118 |
dputs(" -");
|
|
|
119 |
else
|
|
|
120 |
dprintf2(" %lu(%lu)", stats_cmd.op_counts[cj],
|
|
|
121 |
stats_cmd.op_sizes[cj]);
|
|
|
122 |
}
|
|
|
123 |
dputs("\n");
|
|
|
124 |
}
|
|
|
125 |
}
|
|
|
126 |
#endif /* DEBUG */
|
|
|
127 |
|
|
|
128 |
/* ---------------- Writing utilities ---------------- */
|
|
|
129 |
|
|
|
130 |
/* Write the commands for one band or band range. */
|
|
|
131 |
private int /* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
|
|
|
132 |
cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
|
|
|
133 |
cmd_list * pcl, byte cmd_end)
|
|
|
134 |
{
|
|
|
135 |
const cmd_prefix *cp = pcl->head;
|
|
|
136 |
int code_b = 0;
|
|
|
137 |
int code_c = 0;
|
|
|
138 |
|
|
|
139 |
if (cp != 0 || cmd_end != cmd_opv_end_run) {
|
|
|
140 |
clist_file_ptr cfile = cldev->page_cfile;
|
|
|
141 |
clist_file_ptr bfile = cldev->page_bfile;
|
|
|
142 |
cmd_block cb;
|
|
|
143 |
byte end = cmd_count_op(cmd_end, 1);
|
|
|
144 |
|
|
|
145 |
if (cfile == 0 || bfile == 0)
|
|
|
146 |
return_error(gs_error_ioerror);
|
|
|
147 |
cb.band_min = band_min;
|
|
|
148 |
cb.band_max = band_max;
|
|
|
149 |
cb.pos = clist_ftell(cfile);
|
|
|
150 |
if_debug3('l', "[l]writing for bands (%d,%d) at %ld\n",
|
|
|
151 |
band_min, band_max, cb.pos);
|
|
|
152 |
clist_fwrite_chars(&cb, sizeof(cb), bfile);
|
|
|
153 |
if (cp != 0) {
|
|
|
154 |
pcl->tail->next = 0; /* terminate the list */
|
|
|
155 |
for (; cp != 0; cp = cp->next) {
|
|
|
156 |
#ifdef DEBUG
|
|
|
157 |
if ((const byte *)cp < cldev->cbuf ||
|
|
|
158 |
(const byte *)cp >= cldev->cend ||
|
|
|
159 |
cp->size > cldev->cend - (const byte *)cp
|
|
|
160 |
) {
|
|
|
161 |
lprintf1("cmd_write_band error at 0x%lx\n", (ulong) cp);
|
|
|
162 |
return_error(gs_error_Fatal);
|
|
|
163 |
}
|
|
|
164 |
#endif
|
|
|
165 |
clist_fwrite_chars(cp + 1, cp->size, cfile);
|
|
|
166 |
}
|
|
|
167 |
pcl->head = pcl->tail = 0;
|
|
|
168 |
}
|
|
|
169 |
clist_fwrite_chars(&end, 1, cfile);
|
|
|
170 |
process_interrupts(cldev->memory);
|
|
|
171 |
code_b = clist_ferror_code(bfile);
|
|
|
172 |
code_c = clist_ferror_code(cfile);
|
|
|
173 |
if (code_b < 0)
|
|
|
174 |
return_error(code_b);
|
|
|
175 |
if (code_c < 0)
|
|
|
176 |
return_error(code_c);
|
|
|
177 |
}
|
|
|
178 |
return code_b | code_c;
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
/* Write out the buffered commands, and reset the buffer. */
|
|
|
182 |
int /* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
|
|
|
183 |
cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
|
|
|
184 |
{
|
|
|
185 |
int nbands = cldev->nbands;
|
|
|
186 |
gx_clist_state *pcls;
|
|
|
187 |
int band;
|
|
|
188 |
int code = cmd_write_band(cldev, cldev->band_range_min,
|
|
|
189 |
cldev->band_range_max,
|
|
|
190 |
&cldev->band_range_list, cmd_opv_end_run);
|
|
|
191 |
int warning = code;
|
|
|
192 |
|
|
|
193 |
for (band = 0, pcls = cldev->states;
|
|
|
194 |
code >= 0 && band < nbands; band++, pcls++
|
|
|
195 |
) {
|
|
|
196 |
code = cmd_write_band(cldev, band, band, &pcls->list, cmd_end);
|
|
|
197 |
warning |= code;
|
|
|
198 |
}
|
|
|
199 |
/* If an error occurred, finish cleaning up the pointers. */
|
|
|
200 |
for (; band < nbands; band++, pcls++)
|
|
|
201 |
pcls->list.head = pcls->list.tail = 0;
|
|
|
202 |
cldev->cnext = cldev->cbuf;
|
|
|
203 |
cldev->ccl = 0;
|
|
|
204 |
#ifdef DEBUG
|
|
|
205 |
if (gs_debug_c('l'))
|
|
|
206 |
cmd_print_stats();
|
|
|
207 |
#endif
|
|
|
208 |
return_check_interrupt(cldev->memory, code != 0 ? code : warning);
|
|
|
209 |
}
|
|
|
210 |
|
|
|
211 |
/*
|
|
|
212 |
* Add a command to the appropriate band list, and allocate space for its
|
|
|
213 |
* data. Return the pointer to the data area. If an error or (low-memory
|
|
|
214 |
* warning) occurs, set cldev->error_code and return 0.
|
|
|
215 |
*/
|
|
|
216 |
#define cmd_headroom (sizeof(cmd_prefix) + arch_align_ptr_mod)
|
|
|
217 |
byte *
|
|
|
218 |
cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size)
|
|
|
219 |
{
|
|
|
220 |
byte *dp = cldev->cnext;
|
|
|
221 |
|
|
|
222 |
if (size + cmd_headroom > cldev->cend - dp) {
|
|
|
223 |
if ((cldev->error_code =
|
|
|
224 |
cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
|
|
|
225 |
if (cldev->error_code < 0)
|
|
|
226 |
cldev->error_is_retryable = 0; /* hard error */
|
|
|
227 |
else {
|
|
|
228 |
/* upgrade lo-mem warning into an error */
|
|
|
229 |
if (!cldev->ignore_lo_mem_warnings)
|
|
|
230 |
cldev->error_code = gs_note_error(gs_error_VMerror);
|
|
|
231 |
cldev->error_is_retryable = 1;
|
|
|
232 |
}
|
|
|
233 |
return 0;
|
|
|
234 |
}
|
|
|
235 |
else
|
|
|
236 |
return cmd_put_list_op(cldev, pcl, size);
|
|
|
237 |
}
|
|
|
238 |
if (cldev->ccl == pcl) { /* We're adding another command for the same band. */
|
|
|
239 |
/* Tack it onto the end of the previous one. */
|
|
|
240 |
cmd_count_add1(stats_cmd.same_band);
|
|
|
241 |
#ifdef DEBUG
|
|
|
242 |
if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) {
|
|
|
243 |
lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong) pcl->tail);
|
|
|
244 |
}
|
|
|
245 |
#endif
|
|
|
246 |
pcl->tail->size += size;
|
|
|
247 |
} else {
|
|
|
248 |
/* Skip to an appropriate alignment boundary. */
|
|
|
249 |
/* (We assume the command buffer itself is aligned.) */
|
|
|
250 |
cmd_prefix *cp = (cmd_prefix *)
|
|
|
251 |
(dp + ((cldev->cbuf - dp) & (arch_align_ptr_mod - 1)));
|
|
|
252 |
|
|
|
253 |
cmd_count_add1(stats_cmd.other_band);
|
|
|
254 |
dp = (byte *) (cp + 1);
|
|
|
255 |
if (pcl->tail != 0) {
|
|
|
256 |
#ifdef DEBUG
|
|
|
257 |
if (pcl->tail < pcl->head ||
|
|
|
258 |
pcl->tail->size > dp - (byte *) (pcl->tail + 1)
|
|
|
259 |
) {
|
|
|
260 |
lprintf1("cmd_put_list_op error at 0x%lx\n",
|
|
|
261 |
(ulong) pcl->tail);
|
|
|
262 |
}
|
|
|
263 |
#endif
|
|
|
264 |
pcl->tail->next = cp;
|
|
|
265 |
} else
|
|
|
266 |
pcl->head = cp;
|
|
|
267 |
pcl->tail = cp;
|
|
|
268 |
cldev->ccl = pcl;
|
|
|
269 |
cp->size = size;
|
|
|
270 |
}
|
|
|
271 |
cldev->cnext = dp + size;
|
|
|
272 |
return dp;
|
|
|
273 |
}
|
|
|
274 |
#ifdef DEBUG
|
|
|
275 |
byte *
|
|
|
276 |
cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
|
|
|
277 |
{
|
|
|
278 |
if_debug3('L', "[L]band %d: size=%u, left=%u",
|
|
|
279 |
(int)(pcls - cldev->states),
|
|
|
280 |
size, 0);
|
|
|
281 |
return cmd_put_list_op(cldev, &pcls->list, size);
|
|
|
282 |
}
|
|
|
283 |
#endif
|
|
|
284 |
|
|
|
285 |
/* Add a command for a range of bands. */
|
|
|
286 |
byte *
|
|
|
287 |
cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max,
|
|
|
288 |
uint size)
|
|
|
289 |
{
|
|
|
290 |
if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
|
|
|
291 |
band_min, band_max, size, 0);
|
|
|
292 |
if (cldev->ccl != 0 &&
|
|
|
293 |
(cldev->ccl != &cldev->band_range_list ||
|
|
|
294 |
band_min != cldev->band_range_min ||
|
|
|
295 |
band_max != cldev->band_range_max)
|
|
|
296 |
) {
|
|
|
297 |
if ((cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
|
|
|
298 |
if (cldev->error_code < 0)
|
|
|
299 |
cldev->error_is_retryable = 0; /* hard error */
|
|
|
300 |
else {
|
|
|
301 |
/* upgrade lo-mem warning into an error */
|
|
|
302 |
cldev->error_code = gs_error_VMerror;
|
|
|
303 |
cldev->error_is_retryable = 1;
|
|
|
304 |
}
|
|
|
305 |
return 0;
|
|
|
306 |
}
|
|
|
307 |
cldev->band_range_min = band_min;
|
|
|
308 |
cldev->band_range_max = band_max;
|
|
|
309 |
}
|
|
|
310 |
return cmd_put_list_op(cldev, &cldev->band_range_list, size);
|
|
|
311 |
}
|
|
|
312 |
|
|
|
313 |
/* Write a variable-size positive integer. */
|
|
|
314 |
int
|
|
|
315 |
cmd_size_w(register uint w)
|
|
|
316 |
{
|
|
|
317 |
register int size = 1;
|
|
|
318 |
|
|
|
319 |
while (w > 0x7f)
|
|
|
320 |
w >>= 7, size++;
|
|
|
321 |
return size;
|
|
|
322 |
}
|
|
|
323 |
byte *
|
|
|
324 |
cmd_put_w(register uint w, register byte * dp)
|
|
|
325 |
{
|
|
|
326 |
while (w > 0x7f)
|
|
|
327 |
*dp++ = w | 0x80, w >>= 7;
|
|
|
328 |
*dp = w;
|
|
|
329 |
return dp + 1;
|
|
|
330 |
}
|
|
|
331 |
|
|
|
332 |
|
|
|
333 |
/*
|
|
|
334 |
* This next two arrays are used for the 'delta' mode of placing a color
|
|
|
335 |
* in the clist. These arrays are indexed by the number of bytes in the
|
|
|
336 |
* color value (the depth).
|
|
|
337 |
*
|
|
|
338 |
* Delta values are calculated by subtracting the old value for the color
|
|
|
339 |
* from the desired new value. Then each byte of the differenece is
|
|
|
340 |
* examined. For most bytes, if the difference fits into 4 bits (signed)
|
|
|
341 |
* then those bits are packed into the clist along with an opcode. If
|
|
|
342 |
* the size of the color (the depth) is an odd number of bytes then instead
|
|
|
343 |
* of four bits per byte, extra bits are used for the upper three bytes
|
|
|
344 |
* of the color. In this case, five bits are used for the first byte,
|
|
|
345 |
* six bits for the second byte, and five bits for third byte. This
|
|
|
346 |
* maximizes the chance that the 'delta' mode can be used for placing
|
|
|
347 |
* colors in the clist.
|
|
|
348 |
*/
|
|
|
349 |
/*
|
|
|
350 |
* Depending upon the compiler and user choices, the size of a gx_color_index
|
|
|
351 |
* may be 4 to 8 bytes. We will define table entries for up to 8 bytes.
|
|
|
352 |
* This macro is being used to prevent compiler warnings if gx_color_index is
|
|
|
353 |
* only 4 bytes.
|
|
|
354 |
*/
|
|
|
355 |
#define tab_entry(x) ((x) & (~((gx_color_index) 0)))
|
|
|
356 |
|
|
|
357 |
const gx_color_index cmd_delta_offsets[] = {
|
|
|
358 |
tab_entry(0),
|
|
|
359 |
tab_entry(0),
|
|
|
360 |
tab_entry(0x0808),
|
|
|
361 |
tab_entry(0x102010),
|
|
|
362 |
tab_entry(0x08080808),
|
|
|
363 |
tab_entry(0x1020100808),
|
|
|
364 |
tab_entry(0x080808080808),
|
|
|
365 |
tab_entry(0x10201008080808),
|
|
|
366 |
tab_entry(0x0808080808080808),
|
|
|
367 |
};
|
|
|
368 |
|
|
|
369 |
private const gx_color_index cmd_delta_masks[] = {
|
|
|
370 |
tab_entry(0),
|
|
|
371 |
tab_entry(0),
|
|
|
372 |
tab_entry(0x0f0f),
|
|
|
373 |
tab_entry(0x1f3f1f),
|
|
|
374 |
tab_entry(0x0f0f0f0f),
|
|
|
375 |
tab_entry(0x1f3f1f0f0f),
|
|
|
376 |
tab_entry(0x0f0f0f0f0f0f),
|
|
|
377 |
tab_entry(0x1f3f1f0f0f0f0f),
|
|
|
378 |
tab_entry(0x0f0f0f0f0f0f0f0f),
|
|
|
379 |
};
|
|
|
380 |
|
|
|
381 |
#undef tab_entry
|
|
|
382 |
|
|
|
383 |
/*
|
|
|
384 |
* There are currently only four different color "types" that can be placed
|
|
|
385 |
* into the clist. These are called "color0", "color1", and "tile_color0",
|
|
|
386 |
* and "tile_color1". There are separate command codes for color0 versus
|
|
|
387 |
* color1, both for the full value and delta commands - see cmd_put_color.
|
|
|
388 |
* Tile colors are preceded by a cmd_opv_set_tile_color command.
|
|
|
389 |
*/
|
|
|
390 |
const clist_select_color_t
|
|
|
391 |
clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 0},
|
|
|
392 |
clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 0},
|
|
|
393 |
clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 1},
|
|
|
394 |
clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 1};
|
|
|
395 |
|
|
|
396 |
/*
|
|
|
397 |
* This routine is used to place a color into the clist. Colors, in the
|
|
|
398 |
* clist, can be specified either as by a full value or by a "delta" value.
|
|
|
399 |
*
|
|
|
400 |
* See the comments before cmd_delta_offsets[] for a description of the
|
|
|
401 |
* 'delta' mode. The delta mode may allow for a smaller command in the clist.
|
|
|
402 |
*
|
|
|
403 |
* For the full value mode, values are sent as a cmd code plus n bytes of
|
|
|
404 |
* data. To minimize the number of bytes, a count is made of any low order
|
|
|
405 |
* bytes which are zero. This count is packed into the low order 4 bits
|
|
|
406 |
* of the cmd code. The data for these bytes are not sent.
|
|
|
407 |
*
|
|
|
408 |
* The gx_no_color_index value is treated as a special case. This is done
|
|
|
409 |
* because it is both a commonly sent value and because it may require
|
|
|
410 |
* more bytes then the other color values.
|
|
|
411 |
*
|
|
|
412 |
* Parameters:
|
|
|
413 |
* cldev - Pointer to clist device
|
|
|
414 |
* pcls - Pointer to clist state
|
|
|
415 |
* select - Descriptor record for type of color being sent. See comments
|
|
|
416 |
* by clist_select_color_t.
|
|
|
417 |
* color - The new color value.
|
|
|
418 |
* pcolor - Pointer to previous color value. (If the color value is the
|
|
|
419 |
* same as the previous value then nothing is placed into the clist.)
|
|
|
420 |
*
|
|
|
421 |
* Returns:
|
|
|
422 |
* Error code
|
|
|
423 |
* clist and pcls and cldev may be updated.
|
|
|
424 |
*/
|
|
|
425 |
int
|
|
|
426 |
cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
427 |
const clist_select_color_t * select,
|
|
|
428 |
gx_color_index color, gx_color_index * pcolor)
|
|
|
429 |
{
|
|
|
430 |
byte * dp; /* This is manipulated by the set_cmd_put_op macro */
|
|
|
431 |
gx_color_index diff = color - *pcolor;
|
|
|
432 |
byte op, op_delta;
|
|
|
433 |
int code;
|
|
|
434 |
|
|
|
435 |
if (diff == 0)
|
|
|
436 |
return 0;
|
|
|
437 |
|
|
|
438 |
/* If this is a tile color then send tile color type */
|
|
|
439 |
if (select->tile_color) {
|
|
|
440 |
code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
|
|
|
441 |
if (code < 0)
|
|
|
442 |
return code;
|
|
|
443 |
}
|
|
|
444 |
op = select->set_op;
|
|
|
445 |
op_delta = select->delta_op;
|
|
|
446 |
if (color == gx_no_color_index) {
|
|
|
447 |
/*
|
|
|
448 |
* We must handle this specially, because it may take more
|
|
|
449 |
* bytes than the color depth.
|
|
|
450 |
*/
|
|
|
451 |
code = set_cmd_put_op(dp, cldev, pcls, op + cmd_no_color_index, 1);
|
|
|
452 |
if (code < 0)
|
|
|
453 |
return code;
|
|
|
454 |
} else {
|
|
|
455 |
/* Check if the "delta" mode command can be used. */
|
|
|
456 |
int num_bytes = (cldev->color_info.depth + 7) >> 3;
|
|
|
457 |
int delta_bytes = (num_bytes + 1) / 2;
|
|
|
458 |
gx_color_index delta_offset = cmd_delta_offsets[num_bytes];
|
|
|
459 |
gx_color_index delta_mask = cmd_delta_masks[num_bytes];
|
|
|
460 |
gx_color_index delta = (diff + delta_offset) & delta_mask;
|
|
|
461 |
bool use_delta = (color == (*pcolor + delta - delta_offset));
|
|
|
462 |
int bytes_dropped = 0;
|
|
|
463 |
gx_color_index data = color;
|
|
|
464 |
|
|
|
465 |
/*
|
|
|
466 |
* If we use the full value mode, we do not send low order bytes
|
|
|
467 |
* which are zero. Determine how many low order bytes are zero.
|
|
|
468 |
*/
|
|
|
469 |
if (color == 0) {
|
|
|
470 |
bytes_dropped = num_bytes;
|
|
|
471 |
}
|
|
|
472 |
else {
|
|
|
473 |
while ((data & 0xff) == 0) {
|
|
|
474 |
bytes_dropped++;
|
|
|
475 |
data >>= 8;
|
|
|
476 |
}
|
|
|
477 |
}
|
|
|
478 |
|
|
|
479 |
/* Now send one of the two command forms */
|
|
|
480 |
if (use_delta && delta_bytes < num_bytes - bytes_dropped) {
|
|
|
481 |
code = set_cmd_put_op(dp, cldev, pcls,
|
|
|
482 |
op_delta, delta_bytes + 1);
|
|
|
483 |
if (code < 0)
|
|
|
484 |
return code;
|
|
|
485 |
/*
|
|
|
486 |
* If we have an odd number of bytes then use extra bits for
|
|
|
487 |
* the high order three bytes of the color.
|
|
|
488 |
*/
|
|
|
489 |
if ((num_bytes >= 3) && (num_bytes & 1)) {
|
|
|
490 |
data = delta >> ((num_bytes - 3) * 8);
|
|
|
491 |
dp[delta_bytes--] = (byte)(((data >> 13) & 0xf8) + ((data >> 11) & 0x07));
|
|
|
492 |
dp[delta_bytes--] = (byte)(((data >> 3) & 0xe0) + (data & 0x1f));
|
|
|
493 |
}
|
|
|
494 |
for(; delta_bytes>0; delta_bytes--) {
|
|
|
495 |
dp[delta_bytes] = (byte)((delta >> 4) + delta);
|
|
|
496 |
delta >>= 16;
|
|
|
497 |
}
|
|
|
498 |
}
|
|
|
499 |
else {
|
|
|
500 |
num_bytes -= bytes_dropped;
|
|
|
501 |
code = set_cmd_put_op(dp, cldev, pcls,
|
|
|
502 |
(byte)(op + bytes_dropped), num_bytes + 1);
|
|
|
503 |
if (code < 0)
|
|
|
504 |
return code;
|
|
|
505 |
for(; num_bytes>0; num_bytes--) {
|
|
|
506 |
dp[num_bytes] = (byte)data;
|
|
|
507 |
data >>= 8;
|
|
|
508 |
}
|
|
|
509 |
}
|
|
|
510 |
}
|
|
|
511 |
*pcolor = color;
|
|
|
512 |
return 0;
|
|
|
513 |
}
|
|
|
514 |
|
|
|
515 |
|
|
|
516 |
/* Put out a command to set the tile colors. */
|
|
|
517 |
int
|
|
|
518 |
cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
519 |
gx_color_index color0, gx_color_index color1)
|
|
|
520 |
{
|
|
|
521 |
int code = 0;
|
|
|
522 |
|
|
|
523 |
if (color0 != pcls->tile_colors[0]) {
|
|
|
524 |
code = cmd_put_color(cldev, pcls,
|
|
|
525 |
&clist_select_tile_color0,
|
|
|
526 |
color0, &pcls->tile_colors[0]);
|
|
|
527 |
if (code != 0)
|
|
|
528 |
return code;
|
|
|
529 |
}
|
|
|
530 |
if (color1 != pcls->tile_colors[1])
|
|
|
531 |
code = cmd_put_color(cldev, pcls,
|
|
|
532 |
&clist_select_tile_color1,
|
|
|
533 |
color1, &pcls->tile_colors[1]);
|
|
|
534 |
return code;
|
|
|
535 |
}
|
|
|
536 |
|
|
|
537 |
/* Put out a command to set the tile phase. */
|
|
|
538 |
int
|
|
|
539 |
cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
540 |
int px, int py)
|
|
|
541 |
{
|
|
|
542 |
int pcsize;
|
|
|
543 |
byte *dp;
|
|
|
544 |
int code;
|
|
|
545 |
|
|
|
546 |
pcsize = 1 + cmd_size2w(px, py);
|
|
|
547 |
code =
|
|
|
548 |
set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
|
|
|
549 |
if (code < 0)
|
|
|
550 |
return code;
|
|
|
551 |
++dp;
|
|
|
552 |
pcls->tile_phase.x = px;
|
|
|
553 |
pcls->tile_phase.y = py;
|
|
|
554 |
cmd_putxy(pcls->tile_phase, dp);
|
|
|
555 |
return 0;
|
|
|
556 |
}
|
|
|
557 |
|
|
|
558 |
/* Write a command to enable or disable the logical operation. */
|
|
|
559 |
int
|
|
|
560 |
cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
561 |
int enable)
|
|
|
562 |
{
|
|
|
563 |
byte *dp;
|
|
|
564 |
int code = set_cmd_put_op(dp, cldev, pcls,
|
|
|
565 |
(byte)(enable ? cmd_opv_enable_lop :
|
|
|
566 |
cmd_opv_disable_lop),
|
|
|
567 |
1);
|
|
|
568 |
|
|
|
569 |
if (code < 0)
|
|
|
570 |
return code;
|
|
|
571 |
pcls->lop_enabled = enable;
|
|
|
572 |
return 0;
|
|
|
573 |
}
|
|
|
574 |
|
|
|
575 |
/* Write a command to enable or disable clipping. */
|
|
|
576 |
/* This routine is only called if the path extensions are included. */
|
|
|
577 |
int
|
|
|
578 |
cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
579 |
int enable)
|
|
|
580 |
{
|
|
|
581 |
byte *dp;
|
|
|
582 |
int code = set_cmd_put_op(dp, cldev, pcls,
|
|
|
583 |
(byte)(enable ? cmd_opv_enable_clip :
|
|
|
584 |
cmd_opv_disable_clip),
|
|
|
585 |
1);
|
|
|
586 |
|
|
|
587 |
if (code < 0)
|
|
|
588 |
return code;
|
|
|
589 |
pcls->clip_enabled = enable;
|
|
|
590 |
return 0;
|
|
|
591 |
}
|
|
|
592 |
|
|
|
593 |
/* Write a command to set the logical operation. */
|
|
|
594 |
int
|
|
|
595 |
cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
596 |
gs_logical_operation_t lop)
|
|
|
597 |
{
|
|
|
598 |
byte *dp;
|
|
|
599 |
uint lop_msb = lop >> 6;
|
|
|
600 |
int code = set_cmd_put_op(dp, cldev, pcls,
|
|
|
601 |
cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
|
|
|
602 |
|
|
|
603 |
if (code < 0)
|
|
|
604 |
return code;
|
|
|
605 |
dp[1] = cmd_set_misc_lop + (lop & 0x3f);
|
|
|
606 |
cmd_put_w(lop_msb, dp + 2);
|
|
|
607 |
pcls->lop = lop;
|
|
|
608 |
return 0;
|
|
|
609 |
}
|
|
|
610 |
|
|
|
611 |
/* Disable (if default) or enable the logical operation, setting it if */
|
|
|
612 |
/* needed. */
|
|
|
613 |
int
|
|
|
614 |
cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
|
|
|
615 |
gs_logical_operation_t lop)
|
|
|
616 |
{
|
|
|
617 |
int code;
|
|
|
618 |
|
|
|
619 |
if (lop == lop_default)
|
|
|
620 |
return cmd_disable_lop(cldev, pcls);
|
|
|
621 |
code = cmd_set_lop(cldev, pcls, lop);
|
|
|
622 |
if (code < 0)
|
|
|
623 |
return code;
|
|
|
624 |
return cmd_enable_lop(cldev, pcls);
|
|
|
625 |
}
|
|
|
626 |
|
|
|
627 |
/* Write a parameter list */
|
|
|
628 |
int /* ret 0 all ok, -ve error */
|
|
|
629 |
cmd_put_params(gx_device_clist_writer *cldev,
|
|
|
630 |
gs_param_list *param_list) /* NB open for READ */
|
|
|
631 |
{
|
|
|
632 |
byte *dp;
|
|
|
633 |
int code;
|
|
|
634 |
byte local_buf[512]; /* arbitrary */
|
|
|
635 |
int param_length;
|
|
|
636 |
|
|
|
637 |
/* Get serialized list's length + try to get it into local var if it fits. */
|
|
|
638 |
param_length = code =
|
|
|
639 |
gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
|
|
|
640 |
if (param_length > 0) {
|
|
|
641 |
/* Get cmd buffer space for serialized */
|
|
|
642 |
code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend,
|
|
|
643 |
2 + sizeof(unsigned) + param_length);
|
|
|
644 |
if (code < 0)
|
|
|
645 |
return code;
|
|
|
646 |
|
|
|
647 |
/* write param list to cmd list: needs to all fit in cmd buffer */
|
|
|
648 |
if_debug1('l', "[l]put_params, length=%d\n", param_length);
|
|
|
649 |
dp[1] = cmd_opv_ext_put_params;
|
|
|
650 |
dp += 2;
|
|
|
651 |
memcpy(dp, ¶m_length, sizeof(unsigned));
|
|
|
652 |
dp += sizeof(unsigned);
|
|
|
653 |
if (param_length > sizeof(local_buf)) {
|
|
|
654 |
int old_param_length = param_length;
|
|
|
655 |
|
|
|
656 |
param_length = code =
|
|
|
657 |
gs_param_list_serialize(param_list, dp, old_param_length);
|
|
|
658 |
if (param_length >= 0)
|
|
|
659 |
code = (old_param_length != param_length ?
|
|
|
660 |
gs_note_error(gs_error_unknownerror) : 0);
|
|
|
661 |
if (code < 0) {
|
|
|
662 |
/* error serializing: back out by writing a 0-length parm list */
|
|
|
663 |
memset(dp - sizeof(unsigned), 0, sizeof(unsigned));
|
|
|
664 |
cmd_shorten_list_op(cldev, &cldev->band_range_list,
|
|
|
665 |
old_param_length);
|
|
|
666 |
}
|
|
|
667 |
} else
|
|
|
668 |
memcpy(dp, local_buf, param_length); /* did this when computing length */
|
|
|
669 |
}
|
|
|
670 |
return code;
|
|
|
671 |
}
|
|
|
672 |
|
|
|
673 |
/* Initialize CCITTFax filters. */
|
|
|
674 |
private void
|
|
|
675 |
clist_cf_init(stream_CF_state *ss, int width)
|
|
|
676 |
{
|
|
|
677 |
ss->K = -1;
|
|
|
678 |
ss->Columns = width;
|
|
|
679 |
ss->EndOfBlock = false;
|
|
|
680 |
ss->BlackIs1 = true;
|
|
|
681 |
ss->DecodedByteAlign = align_bitmap_mod;
|
|
|
682 |
}
|
|
|
683 |
void
|
|
|
684 |
clist_cfe_init(stream_CFE_state *ss, int width, gs_memory_t *mem)
|
|
|
685 |
{
|
|
|
686 |
s_init_state((stream_state *)ss, &s_CFE_template, mem);
|
|
|
687 |
s_CFE_set_defaults_inline(ss);
|
|
|
688 |
clist_cf_init((stream_CF_state *)ss, width);
|
|
|
689 |
s_CFE_template.init((stream_state *)(ss));
|
|
|
690 |
}
|
|
|
691 |
void
|
|
|
692 |
clist_cfd_init(stream_CFD_state *ss, int width, int height, gs_memory_t *mem)
|
|
|
693 |
{
|
|
|
694 |
s_init_state((stream_state *)ss, &s_CFD_template, mem);
|
|
|
695 |
s_CFD_template.set_defaults((stream_state *)ss);
|
|
|
696 |
clist_cf_init((stream_CF_state *)ss, width);
|
|
|
697 |
ss->Rows = height;
|
|
|
698 |
s_CFD_template.init((stream_state *)(ss));
|
|
|
699 |
}
|
|
|
700 |
|
|
|
701 |
/* Initialize RunLength filters. */
|
|
|
702 |
void
|
|
|
703 |
clist_rle_init(stream_RLE_state *ss)
|
|
|
704 |
{
|
|
|
705 |
s_init_state((stream_state *)ss, &s_RLE_template, (gs_memory_t *)0);
|
|
|
706 |
s_RLE_set_defaults_inline(ss);
|
|
|
707 |
s_RLE_init_inline(ss);
|
|
|
708 |
}
|
|
|
709 |
void
|
|
|
710 |
clist_rld_init(stream_RLD_state *ss)
|
|
|
711 |
{
|
|
|
712 |
s_init_state((stream_state *)ss, &s_RLD_template, (gs_memory_t *)0);
|
|
|
713 |
s_RLD_set_defaults_inline(ss);
|
|
|
714 |
s_RLD_init_inline(ss);
|
|
|
715 |
}
|