1 /* Copyright (C) 1995, 1996, 1997, 1998, 1999 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: gxclbits.c,v 1.9 2004/08/04 19:36:12 stefan Exp $ */
18 /* Halftone and bitmap writing for command lists */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gpcheck.h"
22 #include "gserrors.h"
23 #include "gsbitops.h"
24 #include "gxdevice.h"
25 #include "gxdevmem.h" /* must precede gxcldev.h */
26 #include "gxcldev.h"
27 #include "gxfmap.h"
28
29 /*
30 * Define when, if ever, to write character bitmaps in all bands.
31 * Set this to:
32 * 0 to always write in all bands;
33 * N to write in all bands when the character has been seen in N+1
34 * bands on a page;
35 * max_ushort to never write in all bands.
36 */
37 #define CHAR_ALL_BANDS_COUNT max_ushort
38
39 /* ------ Writing ------ */
40
41 /*
42 * Determine the (possibly unpadded) width in bytes for writing a bitmap,
43 * per the algorithm in gxcldev.h. If compression_mask has any of the
44 * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
45 * Return the total size of the bitmap.
46 */
47 uint
clist_bitmap_bytes(uint width_bits,uint height,int compression_mask,uint * width_bytes,uint * raster)48 clist_bitmap_bytes(uint width_bits, uint height, int compression_mask,
49 uint * width_bytes, uint * raster)
50 {
51 uint full_raster = *raster = bitmap_raster(width_bits);
52 uint short_raster = (width_bits + 7) >> 3;
53 uint width_bytes_last;
54
55 if (compression_mask & cmd_mask_compress_any)
56 *width_bytes = width_bytes_last = full_raster;
57 else if (short_raster <= cmd_max_short_width_bytes ||
58 height <= 1 ||
59 (compression_mask & decompress_spread) != 0
60 )
61 *width_bytes = width_bytes_last = short_raster;
62 else
63 *width_bytes = full_raster, width_bytes_last = short_raster;
64 return
65 (height == 0 ? 0 : *width_bytes * (height - 1) + width_bytes_last);
66 }
67
68 /*
69 * Compress a bitmap, skipping extra padding bytes at the end of each row if
70 * necessary. We require height >= 1, raster >= bitmap_raster(width_bits).
71 */
72 private int
cmd_compress_bitmap(stream_state * st,const byte * data,uint width_bits,uint raster,uint height,stream_cursor_write * pw)73 cmd_compress_bitmap(stream_state * st, const byte * data, uint width_bits,
74 uint raster, uint height, stream_cursor_write * pw)
75 {
76 uint width_bytes = bitmap_raster(width_bits);
77 int status = 0;
78 stream_cursor_read r;
79
80 r.ptr = data - 1;
81 if (raster == width_bytes) {
82 r.limit = r.ptr + raster * height;
83 status = (*st->template->process) (st, &r, pw, true);
84 } else { /* Compress row-by-row. */
85 uint y;
86
87 for (y = 1; (r.limit = r.ptr + width_bytes), y < height; ++y) {
88 status = (*st->template->process) (st, &r, pw, false);
89 if (status)
90 break;
91 if (r.ptr != r.limit) { /* We don't attempt to handle compressors that */
92 /* require >1 input byte to make progress. */
93 status = -1;
94 break;
95 }
96 r.ptr += raster - width_bytes;
97 }
98 if (status == 0)
99 status = (*st->template->process) (st, &r, pw, true);
100 }
101 if (st->template->release)
102 (*st->template->release) (st);
103 return status;
104 }
105
106 /*
107 * Put a bitmap in the buffer, compressing if appropriate.
108 * pcls == 0 means put the bitmap in all bands.
109 * Return <0 if error, otherwise the compression method.
110 * A return value of gs_error_limitcheck means that the bitmap was too big
111 * to fit in the command reading buffer.
112 * Note that this leaves room for the command and initial arguments,
113 * but doesn't fill them in.
114 */
115 int
cmd_put_bits(gx_device_clist_writer * cldev,gx_clist_state * pcls,const byte * data,uint width_bits,uint height,uint raster,int op_size,int compression_mask,byte ** pdp,uint * psize)116 cmd_put_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
117 const byte * data, uint width_bits, uint height, uint raster, int op_size,
118 int compression_mask, byte ** pdp, uint * psize)
119 {
120 uint short_raster, full_raster;
121 uint short_size =
122 clist_bitmap_bytes(width_bits, height,
123 compression_mask & ~cmd_mask_compress_any,
124 &short_raster, &full_raster);
125 uint uncompressed_raster;
126 uint uncompressed_size =
127 clist_bitmap_bytes(width_bits, height, compression_mask,
128 &uncompressed_raster, &full_raster);
129 uint max_size = cbuf_size - op_size;
130 gs_memory_t *mem = cldev->memory;
131 byte *dp;
132 int compress = 0;
133
134 /*
135 * See if compressing the bits is possible and worthwhile.
136 * Currently we can't compress if the compressed data won't fit in
137 * the command reading buffer, or if the decompressed data won't fit
138 * in the buffer and decompress_elsewhere isn't set.
139 */
140 if (short_size >= 50 &&
141 (compression_mask & cmd_mask_compress_any) != 0 &&
142 (uncompressed_size <= max_size ||
143 (compression_mask & decompress_elsewhere) != 0)
144 ) {
145 union ss_ {
146 stream_state ss;
147 stream_CFE_state cf;
148 stream_RLE_state rl;
149 } sstate;
150 int code;
151 int try_size = op_size + min(uncompressed_size, max_size);
152
153 *psize = try_size;
154 code = (pcls != 0 ?
155 set_cmd_put_op(dp, cldev, pcls, 0, try_size) :
156 set_cmd_put_all_op(dp, cldev, 0, try_size));
157 if (code < 0)
158 return code;
159 cmd_uncount_op(0, try_size);
160 /*
161 * Note that we currently keep all the padding if we are
162 * compressing. This is ridiculous, but it's too hard to
163 * change right now.
164 */
165 if (compression_mask & (1 << cmd_compress_cfe)) {
166 /* Try CCITTFax compression. */
167 clist_cfe_init(&sstate.cf,
168 uncompressed_raster << 3 /*width_bits*/,
169 mem);
170 compress = cmd_compress_cfe;
171 } else if (compression_mask & (1 << cmd_compress_rle)) {
172 /* Try RLE compression. */
173 clist_rle_init(&sstate.rl);
174 compress = cmd_compress_rle;
175 }
176 if (compress) {
177 byte *wbase = dp + (op_size - 1);
178 stream_cursor_write w;
179
180 /*
181 * We can give up on compressing if we generate too much
182 * output to fit in the command reading buffer, or too
183 * much to make compression worthwhile.
184 */
185 uint wmax = min(uncompressed_size, max_size);
186 int status;
187
188 w.ptr = wbase;
189 w.limit = w.ptr + min(wmax, short_size >> 1);
190 status = cmd_compress_bitmap((stream_state *) & sstate, data,
191 uncompressed_raster << 3 /*width_bits */ ,
192 raster, height, &w);
193 if (status == 0) { /* Use compressed representation. */
194 uint wcount = w.ptr - wbase;
195
196 cmd_shorten_list_op(cldev,
197 (pcls ? &pcls->list : &cldev->band_range_list),
198 try_size - (op_size + wcount));
199 *psize = op_size + wcount;
200 goto out;
201 }
202 }
203 if (uncompressed_size > max_size) {
204 /* Shorten to zero, erasing the operation altogether */
205 if_debug1 ('L', "[L]Uncompressed bits %u too large for buffer\n",
206 uncompressed_size);
207 cmd_shorten_list_op(cldev,
208 (pcls ? &pcls->list : &cldev->band_range_list),
209 try_size);
210 return_error(gs_error_limitcheck);
211 }
212 if (uncompressed_size != short_size) {
213 if_debug2 ('L', "[L]Shortening bits from %u to %u\n",
214 try_size, op_size + short_size);
215 cmd_shorten_list_op(cldev,
216 (pcls ? &pcls->list : &cldev->band_range_list),
217 try_size - (op_size + short_size));
218 *psize = op_size + short_size;
219 }
220 compress = 0;
221 } else if (uncompressed_size > max_size)
222 return_error(gs_error_limitcheck);
223 else {
224 int code;
225
226 *psize = op_size + short_size;
227 code = (pcls != 0 ?
228 set_cmd_put_op(dp, cldev, pcls, 0, *psize) :
229 set_cmd_put_all_op(dp, cldev, 0, *psize));
230 if (code < 0)
231 return code;
232 cmd_uncount_op(0, *psize);
233 }
234 bytes_copy_rectangle(dp + op_size, short_raster, data, raster,
235 short_raster, height);
236 out:
237 *pdp = dp;
238 return compress;
239 }
240
241 /* Add a command to set the tile size and depth. */
242 private uint
cmd_size_tile_params(const gx_strip_bitmap * tile)243 cmd_size_tile_params(const gx_strip_bitmap * tile)
244 {
245 return 2 + cmd_size_w(tile->rep_width) + cmd_size_w(tile->rep_height) +
246 (tile->rep_width == tile->size.x ? 0 :
247 cmd_size_w(tile->size.x / tile->rep_width)) +
248 (tile->rep_height == tile->size.y ? 0 :
249 cmd_size_w(tile->size.y / tile->rep_height)) +
250 (tile->rep_shift == 0 ? 0 : cmd_size_w(tile->rep_shift));
251 }
252 private void
cmd_store_tile_params(byte * dp,const gx_strip_bitmap * tile,int depth,uint csize)253 cmd_store_tile_params(byte * dp, const gx_strip_bitmap * tile, int depth,
254 uint csize)
255 {
256 byte *p = dp + 2;
257 byte bd = cmd_depth_to_code(depth);
258
259 *dp = cmd_count_op(cmd_opv_set_tile_size, csize);
260 p = cmd_put_w(tile->rep_width, p);
261 p = cmd_put_w(tile->rep_height, p);
262 if (tile->rep_width != tile->size.x) {
263 p = cmd_put_w(tile->size.x / tile->rep_width, p);
264 bd |= 0x20;
265 }
266 if (tile->rep_height != tile->size.y) {
267 p = cmd_put_w(tile->size.y / tile->rep_height, p);
268 bd |= 0x40;
269 }
270 if (tile->rep_shift != 0) {
271 cmd_put_w(tile->rep_shift, p);
272 bd |= 0x80;
273 }
274 dp[1] = bd;
275 }
276
277 /* Add a command to set the tile index. */
278 /* This is a relatively high-frequency operation, so we declare it `inline'. */
279 inline private int
cmd_put_tile_index(gx_device_clist_writer * cldev,gx_clist_state * pcls,uint indx)280 cmd_put_tile_index(gx_device_clist_writer *cldev, gx_clist_state *pcls,
281 uint indx)
282 {
283 int idelta = indx - pcls->tile_index + 8;
284 byte *dp;
285 int code;
286
287 if (!(idelta & ~15)) {
288 code = set_cmd_put_op(dp, cldev, pcls,
289 cmd_op_delta_tile_index + idelta, 1);
290 if (code < 0)
291 return code;
292 } else {
293 code = set_cmd_put_op(dp, cldev, pcls,
294 cmd_op_set_tile_index + (indx >> 8), 2);
295 if (code < 0)
296 return code;
297 dp[1] = indx & 0xff;
298 }
299 if_debug2('L', "[L]writing index=%u, offset=%lu\n",
300 indx, cldev->tile_table[indx].offset);
301 return 0;
302 }
303
304 /* If necessary, write out data for a single color map. */
305 int
cmd_put_color_map(gx_device_clist_writer * cldev,cmd_map_index map_index,int comp_num,const gx_transfer_map * map,gs_id * pid)306 cmd_put_color_map(gx_device_clist_writer * cldev, cmd_map_index map_index,
307 int comp_num, const gx_transfer_map * map, gs_id * pid)
308 {
309 byte *dp;
310 int code;
311
312 if (map == 0) {
313 if (pid && *pid == gs_no_id)
314 return 0; /* no need to write */
315 code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 3);
316 if (code < 0)
317 return code;
318 dp[1] = cmd_set_misc_map + (cmd_map_none << 4) + map_index;
319 dp[2] = comp_num;
320 if (pid)
321 *pid = gs_no_id;
322 } else {
323 if (pid && map->id == *pid)
324 return 0; /* no need to write */
325 if (map->proc == gs_identity_transfer) {
326 code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 3);
327 if (code < 0)
328 return code;
329 dp[1] = cmd_set_misc_map + (cmd_map_identity << 4) + map_index;
330 dp[2] = comp_num;
331 } else {
332 code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
333 3 + sizeof(map->values));
334 if (code < 0)
335 return code;
336 dp[1] = cmd_set_misc_map + (cmd_map_other << 4) + map_index;
337 dp[2] = comp_num;
338 memcpy(dp + 3, map->values, sizeof(map->values));
339 }
340 if (pid)
341 *pid = map->id;
342 }
343 return 0;
344 }
345
346 /* ------ Tile cache management ------ */
347
348 /* We want consecutive ids to map to consecutive hash slots if possible, */
349 /* so we can use a delta representation when setting the index. */
350 /* NB that we cannot emit 'delta' style tile indices if VM error recovery */
351 /* is in effect, since reader & writer's tile indices may get out of phase */
352 /* as a consequence of error recovery occurring. */
353 #define tile_id_hash(id) (id)
354 #define tile_hash_next(index) ((index) + 413) /* arbitrary large odd # */
355 typedef struct tile_loc_s {
356 uint index;
357 tile_slot *tile;
358 } tile_loc;
359
360 /* Look up a tile or character in the cache. If found, set the index and */
361 /* pointer; if not, set the index to the insertion point. */
362 private bool
clist_find_bits(gx_device_clist_writer * cldev,gx_bitmap_id id,tile_loc * ploc)363 clist_find_bits(gx_device_clist_writer * cldev, gx_bitmap_id id, tile_loc * ploc)
364 {
365 uint index = tile_id_hash(id);
366 const tile_hash *table = cldev->tile_table;
367 uint mask = cldev->tile_hash_mask;
368 ulong offset;
369
370 for (; (offset = table[index &= mask].offset) != 0;
371 index = tile_hash_next(index)
372 ) {
373 tile_slot *tile = (tile_slot *) (cldev->data + offset);
374
375 if (tile->id == id) {
376 ploc->index = index;
377 ploc->tile = tile;
378 return true;
379 }
380 }
381 ploc->index = index;
382 return false;
383 }
384
385 /* Delete a tile from the cache. */
386 private void
clist_delete_tile(gx_device_clist_writer * cldev,tile_slot * slot)387 clist_delete_tile(gx_device_clist_writer * cldev, tile_slot * slot)
388 {
389 tile_hash *table = cldev->tile_table;
390 uint mask = cldev->tile_hash_mask;
391 uint index = slot->index;
392 ulong offset;
393
394 if_debug2('L', "[L]deleting index=%u, offset=%lu\n",
395 index, (ulong) ((byte *) slot - cldev->data));
396 gx_bits_cache_free(&cldev->bits, (gx_cached_bits_head *) slot,
397 &cldev->chunk);
398 table[index].offset = 0;
399 /* Delete the entry from the hash table. */
400 /* We'd like to move up any later entries, so that we don't need */
401 /* a deleted mark, but it's too difficult to note this in the */
402 /* band list, so instead, we just delete any entries that */
403 /* would need to be moved. */
404 while ((offset = table[index = tile_hash_next(index) & mask].offset) != 0) {
405 tile_slot *tile = (tile_slot *) (cldev->data + offset);
406 tile_loc loc;
407
408 if (!clist_find_bits(cldev, tile->id, &loc)) { /* We didn't find it, so it should be moved into a slot */
409 /* that we just vacated; instead, delete it. */
410 if_debug2('L', "[L]move-deleting index=%u, offset=%lu\n",
411 index, offset);
412 gx_bits_cache_free(&cldev->bits,
413 (gx_cached_bits_head *) (cldev->data + offset),
414 &cldev->chunk);
415 table[index].offset = 0;
416 }
417 }
418 }
419
420 /* Add a tile to the cache. */
421 /* tile->raster holds the raster for the replicated tile; */
422 /* we pass the raster of the actual data separately. */
423 private int
clist_add_tile(gx_device_clist_writer * cldev,const gx_strip_bitmap * tiles,uint sraster,int depth)424 clist_add_tile(gx_device_clist_writer * cldev, const gx_strip_bitmap * tiles,
425 uint sraster, int depth)
426 {
427 uint raster = tiles->raster;
428 uint size_bytes = raster * tiles->size.y;
429 uint tsize =
430 sizeof(tile_slot) + cldev->tile_band_mask_size + size_bytes;
431 gx_cached_bits_head *slot_head;
432
433 #define slot ((tile_slot *)slot_head)
434
435 if (cldev->bits.csize == cldev->tile_max_count) { /* Don't let the hash table get too full: delete an entry. */
436 /* Since gx_bits_cache_alloc returns an entry to delete when */
437 /* it fails, just force it to fail. */
438 gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->chunk.size,
439 &slot_head);
440 if (slot_head == 0) { /* Wrap around and retry. */
441 cldev->bits.cnext = 0;
442 gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->chunk.size,
443 &slot_head);
444 #ifdef DEBUG
445 if (slot_head == 0) {
446 lprintf("No entry to delete!\n");
447 return_error(gs_error_Fatal);
448 }
449 #endif
450 }
451 clist_delete_tile(cldev, slot);
452 }
453 /* Allocate the space for the new entry, deleting entries as needed. */
454 while (gx_bits_cache_alloc(&cldev->bits, (ulong) tsize, &slot_head) < 0) {
455 if (slot_head == 0) { /* Wrap around. */
456 if (cldev->bits.cnext == 0) { /* Too big to fit. We should probably detect this */
457 /* sooner, since if we get here, we've cleared the */
458 /* cache. */
459 return_error(gs_error_limitcheck);
460 }
461 cldev->bits.cnext = 0;
462 } else
463 clist_delete_tile(cldev, slot);
464 }
465 /* Fill in the entry. */
466 slot->cb_depth = depth;
467 slot->cb_raster = raster;
468 slot->width = tiles->rep_width;
469 slot->height = tiles->rep_height;
470 slot->shift = slot->rep_shift = tiles->rep_shift;
471 slot->x_reps = slot->y_reps = 1;
472 slot->id = tiles->id;
473 memset(ts_mask(slot), 0, cldev->tile_band_mask_size);
474 bytes_copy_rectangle(ts_bits(cldev, slot), raster,
475 tiles->data, sraster,
476 (tiles->rep_width * depth + 7) >> 3,
477 tiles->rep_height);
478 /* Make the hash table entry. */
479 {
480 tile_loc loc;
481
482 #ifdef DEBUG
483 if (clist_find_bits(cldev, tiles->id, &loc))
484 lprintf1("clist_find_bits(0x%lx) should have failed!\n",
485 (ulong) tiles->id);
486 #else
487 clist_find_bits(cldev, tiles->id, &loc); /* always fails */
488 #endif
489 slot->index = loc.index;
490 cldev->tile_table[loc.index].offset =
491 (byte *) slot_head - cldev->data;
492 if_debug2('L', "[L]adding index=%u, offset=%lu\n",
493 loc.index, cldev->tile_table[loc.index].offset);
494 }
495 slot->num_bands = 0;
496 return 0;
497 }
498
499 /* ------ Driver procedure support ------ */
500
501 /* Change the tile parameters (size and depth). */
502 /* Currently we do this for all bands at once. */
503 private void
clist_new_tile_params(gx_strip_bitmap * new_tile,const gx_strip_bitmap * tiles,int depth,const gx_device_clist_writer * cldev)504 clist_new_tile_params(gx_strip_bitmap * new_tile, const gx_strip_bitmap * tiles,
505 int depth, const gx_device_clist_writer * cldev)
506 { /*
507 * Adjust the replication factors. If we can, we replicate
508 * the tile in X up to 32 bytes, and then in Y up to 4 copies,
509 * as long as we don't exceed a total tile size of 256 bytes,
510 * or more than 255 repetitions in X or Y, or make the tile so
511 * large that not all possible tiles will fit in the cache.
512 * Also, don't attempt Y replication if shifting is required.
513 */
514 #define max_tile_reps_x 255
515 #define max_tile_bytes_x 32
516 #define max_tile_reps_y 4
517 #define max_tile_bytes 256
518 uint rep_width = tiles->rep_width;
519 uint rep_height = tiles->rep_height;
520 uint rep_width_bits = rep_width * depth;
521 uint tile_overhead =
522 sizeof(tile_slot) + cldev->tile_band_mask_size;
523 uint max_bytes = cldev->chunk.size / (rep_width_bits * rep_height);
524
525 max_bytes -= min(max_bytes, tile_overhead);
526 if (max_bytes > max_tile_bytes)
527 max_bytes = max_tile_bytes;
528 *new_tile = *tiles;
529 {
530 uint max_bits_x = max_bytes * 8 / rep_height;
531 uint reps_x =
532 min(max_bits_x, max_tile_bytes_x * 8) / rep_width_bits;
533 uint reps_y;
534
535 while (reps_x > max_tile_reps_x)
536 reps_x >>= 1;
537 new_tile->size.x = max(reps_x, 1) * rep_width;
538 new_tile->raster = bitmap_raster(new_tile->size.x * depth);
539 if (tiles->shift != 0)
540 reps_y = 1;
541 else {
542 reps_y = max_bytes / (new_tile->raster * rep_height);
543 if (reps_y > max_tile_reps_y)
544 reps_y = max_tile_reps_y;
545 else if (reps_y < 1)
546 reps_y = 1;
547 }
548 new_tile->size.y = reps_y * rep_height;
549 }
550 #undef max_tile_reps_x
551 #undef max_tile_bytes_x
552 #undef max_tile_reps_y
553 #undef max_tile_bytes
554 }
555
556 /* Change tile for clist_tile_rectangle. */
557 int
clist_change_tile(gx_device_clist_writer * cldev,gx_clist_state * pcls,const gx_strip_bitmap * tiles,int depth)558 clist_change_tile(gx_device_clist_writer * cldev, gx_clist_state * pcls,
559 const gx_strip_bitmap * tiles, int depth)
560 {
561 tile_loc loc;
562 int code;
563
564 #define tile_params_differ(cldev, tiles, depth)\
565 ((tiles)->rep_width != (cldev)->tile_params.rep_width ||\
566 (tiles)->rep_height != (cldev)->tile_params.rep_height ||\
567 (tiles)->rep_shift != (cldev)->tile_params.rep_shift ||\
568 (depth) != (cldev)->tile_depth)
569
570 top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache. Check whether this band */
571 /* knows about it. */
572 int band_index = pcls - cldev->states;
573 byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
574 byte bmask = 1 << (band_index & 7);
575
576 if (*bptr & bmask) { /* Already known. Just set the index. */
577 if (pcls->tile_index == loc.index)
578 return 0;
579 if ((code = cmd_put_tile_index(cldev, pcls, loc.index)) < 0)
580 return code;
581 } else {
582 uint extra = 0;
583
584 if tile_params_differ
585 (cldev, tiles, depth) { /*
586 * We have a cached tile whose parameters differ from
587 * the current ones. Because of the way tile IDs are
588 * managed, this is currently only possible when mixing
589 * Patterns and halftones, but if we didn't generate new
590 * IDs each time the main halftone cache needed to be
591 * refreshed, this could also happen simply from
592 * switching screens.
593 */
594 int band;
595
596 clist_new_tile_params(&cldev->tile_params, tiles, depth,
597 cldev);
598 cldev->tile_depth = depth;
599 /* No band knows about the new parameters. */
600 for (band = cldev->tile_known_min;
601 band <= cldev->tile_known_max;
602 ++band
603 )
604 cldev->states[band].known &= ~tile_params_known;
605 cldev->tile_known_min = cldev->nbands;
606 cldev->tile_known_max = -1;
607 }
608 if (!(pcls->known & tile_params_known)) { /* We're going to have to write the tile parameters. */
609 extra = cmd_size_tile_params(&cldev->tile_params);
610 } { /*
611 * This band doesn't know this tile yet, so output the
612 * bits. Note that the offset we write is the one used by
613 * the reading phase, not the writing phase. Note also
614 * that the size of the cached and written tile may differ
615 * from that of the client's tile. Finally, note that
616 * this tile's size parameters are guaranteed to be
617 * compatible with those stored in the device
618 * (cldev->tile_params).
619 */
620 ulong offset = (byte *) loc.tile - cldev->chunk.data;
621 uint rsize =
622 extra + 1 + cmd_size_w(loc.index) + cmd_size_w(offset);
623 byte *dp;
624 uint csize;
625 int code =
626 cmd_put_bits(cldev, pcls, ts_bits(cldev, loc.tile),
627 tiles->rep_width * depth, tiles->rep_height,
628 loc.tile->cb_raster, rsize,
629 (cldev->tile_params.size.x > tiles->rep_width ?
630 decompress_elsewhere | decompress_spread :
631 decompress_elsewhere),
632 &dp, &csize);
633
634 if (code < 0)
635 return code;
636 if (extra) { /* Write the tile parameters before writing the bits. */
637 cmd_store_tile_params(dp, &cldev->tile_params, depth,
638 extra);
639 dp += extra;
640 /* This band now knows the parameters. */
641 pcls->known |= tile_params_known;
642 if (band_index < cldev->tile_known_min)
643 cldev->tile_known_min = band_index;
644 if (band_index > cldev->tile_known_max)
645 cldev->tile_known_max = band_index;
646 }
647 *dp = cmd_count_op(cmd_opv_set_tile_bits, csize - extra);
648 dp++;
649 dp = cmd_put_w(loc.index, dp);
650 cmd_put_w(offset, dp);
651 *bptr |= bmask;
652 loc.tile->num_bands++;
653 }
654 }
655 pcls->tile_index = loc.index;
656 pcls->tile_id = loc.tile->id;
657 return 0;
658 }
659 /* The tile is not in the cache, add it. */
660 {
661 gx_strip_bitmap new_tile;
662 gx_strip_bitmap *ptile;
663
664 /* Ensure that the tile size is compatible. */
665 if (tile_params_differ(cldev, tiles, depth)) { /* We'll reset cldev->tile_params when we write the bits. */
666 clist_new_tile_params(&new_tile, tiles, depth, cldev);
667 ptile = &new_tile;
668 } else {
669 cldev->tile_params.id = tiles->id;
670 cldev->tile_params.data = tiles->data;
671 ptile = &cldev->tile_params;
672 }
673 code = clist_add_tile(cldev, ptile, tiles->raster, depth);
674 if (code < 0)
675 return code;
676 }
677 goto top;
678 #undef tile_params_differ
679 }
680
681 /* Change "tile" for clist_copy_*. tiles->[rep_]shift must be zero. */
682 int
clist_change_bits(gx_device_clist_writer * cldev,gx_clist_state * pcls,const gx_strip_bitmap * tiles,int depth)683 clist_change_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
684 const gx_strip_bitmap * tiles, int depth)
685 {
686 tile_loc loc;
687 int code;
688
689 top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache. Check whether this band */
690 /* knows about it. */
691 uint band_index = pcls - cldev->states;
692 byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
693 byte bmask = 1 << (band_index & 7);
694
695 if (*bptr & bmask) { /* Already known. Just set the index. */
696 if (pcls->tile_index == loc.index)
697 return 0;
698 cmd_put_tile_index(cldev, pcls, loc.index);
699 } else { /* Not known yet. Output the bits. */
700 /* Note that the offset we write is the one used by */
701 /* the reading phase, not the writing phase. */
702 ulong offset = (byte *) loc.tile - cldev->chunk.data;
703 uint rsize = 2 + cmd_size_w(loc.tile->width) +
704 cmd_size_w(loc.tile->height) + cmd_size_w(loc.index) +
705 cmd_size_w(offset);
706 byte *dp;
707 uint csize;
708 gx_clist_state *bit_pcls = pcls;
709 int code;
710
711 if (loc.tile->num_bands == CHAR_ALL_BANDS_COUNT)
712 bit_pcls = NULL;
713 code = cmd_put_bits(cldev, bit_pcls, ts_bits(cldev, loc.tile),
714 loc.tile->width * depth,
715 loc.tile->height, loc.tile->cb_raster,
716 rsize,
717 (1 << cmd_compress_cfe) | decompress_elsewhere,
718 &dp, &csize);
719
720 if (code < 0)
721 return code;
722 *dp = cmd_count_op(cmd_opv_set_bits, csize);
723 dp[1] = (depth << 2) + code;
724 dp += 2;
725 dp = cmd_put_w(loc.tile->width, dp);
726 dp = cmd_put_w(loc.tile->height, dp);
727 dp = cmd_put_w(loc.index, dp);
728 cmd_put_w(offset, dp);
729 if (bit_pcls == NULL) {
730 memset(ts_mask(loc.tile), 0xff,
731 cldev->tile_band_mask_size);
732 loc.tile->num_bands = cldev->nbands;
733 } else {
734 *bptr |= bmask;
735 loc.tile->num_bands++;
736 }
737 }
738 pcls->tile_index = loc.index;
739 pcls->tile_id = loc.tile->id;
740 return 0;
741 }
742 /* The tile is not in the cache. */
743 code = clist_add_tile(cldev, tiles, tiles->raster, depth);
744 if (code < 0)
745 return code;
746 goto top;
747 }
748