123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- /* Copyright (C) 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
- /*$Id: gxclbits.c,v 1.4 2000/11/05 18:44:57 raph Exp $ */
- /* Halftone and bitmap writing for command lists */
- #include "memory_.h"
- #include "gx.h"
- #include "gpcheck.h"
- #include "gserrors.h"
- #include "gsbitops.h"
- #include "gxdevice.h"
- #include "gxdevmem.h" /* must precede gxcldev.h */
- #include "gxcldev.h"
- #include "gxfmap.h"
- /*
- * Define when, if ever, to write character bitmaps in all bands.
- * Set this to:
- * 0 to always write in all bands;
- * N to write in all bands when the character has been seen in N+1
- * bands on a page;
- * max_ushort to never write in all bands.
- */
- #define CHAR_ALL_BANDS_COUNT max_ushort
- /* ------ Writing ------ */
- /*
- * Determine the (possibly unpadded) width in bytes for writing a bitmap,
- * per the algorithm in gxcldev.h. If compression_mask has any of the
- * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
- * Return the total size of the bitmap.
- */
- uint
- clist_bitmap_bytes(uint width_bits, uint height, int compression_mask,
- uint * width_bytes, uint * raster)
- {
- uint full_raster = *raster = bitmap_raster(width_bits);
- uint short_raster = (width_bits + 7) >> 3;
- uint width_bytes_last;
- if (compression_mask & cmd_mask_compress_any)
- *width_bytes = width_bytes_last = full_raster;
- else if (short_raster <= cmd_max_short_width_bytes ||
- height <= 1 ||
- (compression_mask & decompress_spread) != 0
- )
- *width_bytes = width_bytes_last = short_raster;
- else
- *width_bytes = full_raster, width_bytes_last = short_raster;
- return
- (height == 0 ? 0 : *width_bytes * (height - 1) + width_bytes_last);
- }
- /*
- * Compress a bitmap, skipping extra padding bytes at the end of each row if
- * necessary. We require height >= 1, raster >= bitmap_raster(width_bits).
- */
- private int
- cmd_compress_bitmap(stream_state * st, const byte * data, uint width_bits,
- uint raster, uint height, stream_cursor_write * pw)
- {
- uint width_bytes = bitmap_raster(width_bits);
- int status = 0;
- stream_cursor_read r;
- r.ptr = data - 1;
- if (raster == width_bytes) {
- r.limit = r.ptr + raster * height;
- status = (*st->template->process) (st, &r, pw, true);
- } else { /* Compress row-by-row. */
- uint y;
- for (y = 1; (r.limit = r.ptr + width_bytes), y < height; ++y) {
- status = (*st->template->process) (st, &r, pw, false);
- if (status)
- break;
- if (r.ptr != r.limit) { /* We don't attempt to handle compressors that */
- /* require >1 input byte to make progress. */
- status = -1;
- break;
- }
- r.ptr += raster - width_bytes;
- }
- if (status == 0)
- status = (*st->template->process) (st, &r, pw, true);
- }
- if (st->template->release)
- (*st->template->release) (st);
- return status;
- }
- /*
- * Put a bitmap in the buffer, compressing if appropriate.
- * pcls == 0 means put the bitmap in all bands.
- * Return <0 if error, otherwise the compression method.
- * A return value of gs_error_limitcheck means that the bitmap was too big
- * to fit in the command reading buffer.
- * Note that this leaves room for the command and initial arguments,
- * but doesn't fill them in.
- */
- 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)
- {
- uint short_raster, full_raster;
- uint short_size =
- clist_bitmap_bytes(width_bits, height,
- compression_mask & ~cmd_mask_compress_any,
- &short_raster, &full_raster);
- uint uncompressed_raster;
- uint uncompressed_size =
- clist_bitmap_bytes(width_bits, height, compression_mask,
- &uncompressed_raster, &full_raster);
- uint max_size = cbuf_size - op_size;
- gs_memory_t *mem = (cldev->memory ? cldev->memory : &gs_memory_default);
- byte *dp;
- int compress = 0;
- /*
- * See if compressing the bits is possible and worthwhile.
- * Currently we can't compress if the compressed data won't fit in
- * the command reading buffer, or if the decompressed data won't fit
- * in the buffer and decompress_elsewhere isn't set.
- */
- if (short_size >= 50 &&
- (compression_mask & cmd_mask_compress_any) != 0 &&
- (uncompressed_size <= max_size ||
- (compression_mask & decompress_elsewhere) != 0)
- ) {
- union ss_ {
- stream_state ss;
- stream_CFE_state cf;
- stream_RLE_state rl;
- } sstate;
- int code;
- int try_size = op_size + min(uncompressed_size, max_size);
- *psize = try_size;
- code = (pcls != 0 ?
- set_cmd_put_op(dp, cldev, pcls, 0, try_size) :
- set_cmd_put_all_op(dp, cldev, 0, try_size));
- if (code < 0)
- return code;
- cmd_uncount_op(0, try_size);
- /*
- * Note that we currently keep all the padding if we are
- * compressing. This is ridiculous, but it's too hard to
- * change right now.
- */
- if (compression_mask & (1 << cmd_compress_cfe)) {
- /* Try CCITTFax compression. */
- clist_cfe_init(&sstate.cf,
- uncompressed_raster << 3 /*width_bits*/,
- mem);
- compress = cmd_compress_cfe;
- } else if (compression_mask & (1 << cmd_compress_rle)) {
- /* Try RLE compression. */
- clist_rle_init(&sstate.rl);
- compress = cmd_compress_rle;
- }
- if (compress) {
- byte *wbase = dp + (op_size - 1);
- stream_cursor_write w;
- /*
- * We can give up on compressing if we generate too much
- * output to fit in the command reading buffer, or too
- * much to make compression worthwhile.
- */
- uint wmax = min(uncompressed_size, max_size);
- int status;
- w.ptr = wbase;
- w.limit = w.ptr + min(wmax, short_size >> 1);
- status = cmd_compress_bitmap((stream_state *) & sstate, data,
- uncompressed_raster << 3 /*width_bits */ ,
- raster, height, &w);
- if (status == 0) { /* Use compressed representation. */
- uint wcount = w.ptr - wbase;
- cmd_shorten_list_op(cldev,
- (pcls ? &pcls->list : &cldev->band_range_list),
- try_size - (op_size + wcount));
- *psize = op_size + wcount;
- goto out;
- }
- }
- if (uncompressed_size > max_size) {
- /* Shorten to zero, erasing the operation altogether */
- if_debug1 ('L', "[L]Uncompressed bits %u too large for buffer\n",
- uncompressed_size);
- cmd_shorten_list_op(cldev,
- (pcls ? &pcls->list : &cldev->band_range_list),
- try_size);
- return_error(gs_error_limitcheck);
- }
- if (uncompressed_size != short_size) {
- if_debug2 ('L', "[L]Shortening bits from %u to %u\n",
- try_size, op_size + short_size);
- cmd_shorten_list_op(cldev,
- (pcls ? &pcls->list : &cldev->band_range_list),
- try_size - (op_size + short_size));
- *psize = op_size + short_size;
- }
- compress = 0;
- } else if (uncompressed_size > max_size)
- return_error(gs_error_limitcheck);
- else {
- int code;
- *psize = op_size + short_size;
- code = (pcls != 0 ?
- set_cmd_put_op(dp, cldev, pcls, 0, *psize) :
- set_cmd_put_all_op(dp, cldev, 0, *psize));
- if (code < 0)
- return code;
- cmd_uncount_op(0, *psize);
- }
- bytes_copy_rectangle(dp + op_size, short_raster, data, raster,
- short_raster, height);
- out:
- *pdp = dp;
- return compress;
- }
- /* Add a command to set the tile size and depth. */
- private uint
- cmd_size_tile_params(const gx_strip_bitmap * tile)
- {
- return 2 + cmd_size_w(tile->rep_width) + cmd_size_w(tile->rep_height) +
- (tile->rep_width == tile->size.x ? 0 :
- cmd_size_w(tile->size.x / tile->rep_width)) +
- (tile->rep_height == tile->size.y ? 0 :
- cmd_size_w(tile->size.y / tile->rep_height)) +
- (tile->rep_shift == 0 ? 0 : cmd_size_w(tile->rep_shift));
- }
- private void
- cmd_store_tile_params(byte * dp, const gx_strip_bitmap * tile, int depth,
- uint csize)
- {
- byte *p = dp + 2;
- byte bd = depth - 1;
- *dp = cmd_count_op(cmd_opv_set_tile_size, csize);
- p = cmd_put_w(tile->rep_width, p);
- p = cmd_put_w(tile->rep_height, p);
- if (tile->rep_width != tile->size.x) {
- p = cmd_put_w(tile->size.x / tile->rep_width, p);
- bd |= 0x20;
- }
- if (tile->rep_height != tile->size.y) {
- p = cmd_put_w(tile->size.y / tile->rep_height, p);
- bd |= 0x40;
- }
- if (tile->rep_shift != 0) {
- cmd_put_w(tile->rep_shift, p);
- bd |= 0x80;
- }
- dp[1] = bd;
- }
- /* Add a command to set the tile index. */
- /* This is a relatively high-frequency operation, so we declare it `inline'. */
- inline private int
- cmd_put_tile_index(gx_device_clist_writer *cldev, gx_clist_state *pcls,
- uint indx)
- {
- int idelta = indx - pcls->tile_index + 8;
- byte *dp;
- int code;
- if (!(idelta & ~15)) {
- code = set_cmd_put_op(dp, cldev, pcls,
- cmd_op_delta_tile_index + idelta, 1);
- if (code < 0)
- return code;
- } else {
- code = set_cmd_put_op(dp, cldev, pcls,
- cmd_op_set_tile_index + (indx >> 8), 2);
- if (code < 0)
- return code;
- dp[1] = indx & 0xff;
- }
- if_debug2('L', "[L]writing index=%u, offset=%lu\n",
- indx, cldev->tile_table[indx].offset);
- return 0;
- }
- /* If necessary, write out data for a single color map. */
- int
- cmd_put_color_map(gx_device_clist_writer * cldev, cmd_map_index map_index,
- const gx_transfer_map * map, gs_id * pid)
- {
- byte *dp;
- int code;
- if (map == 0) {
- if (pid && *pid == gs_no_id)
- return 0; /* no need to write */
- code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 2);
- if (code < 0)
- return code;
- dp[1] = cmd_set_misc_map + (cmd_map_none << 4) + map_index;
- if (pid)
- *pid = gs_no_id;
- } else {
- if (pid && map->id == *pid)
- return 0; /* no need to write */
- if (map->proc == gs_identity_transfer) {
- code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc, 2);
- if (code < 0)
- return code;
- dp[1] = cmd_set_misc_map + (cmd_map_identity << 4) + map_index;
- } else {
- code = set_cmd_put_all_op(dp, cldev, cmd_opv_set_misc,
- 2 + sizeof(map->values));
- if (code < 0)
- return code;
- dp[1] = cmd_set_misc_map + (cmd_map_other << 4) + map_index;
- memcpy(dp + 2, map->values, sizeof(map->values));
- }
- if (pid)
- *pid = map->id;
- }
- return 0;
- }
- /* ------ Tile cache management ------ */
- /* We want consecutive ids to map to consecutive hash slots if possible, */
- /* so we can use a delta representation when setting the index. */
- /* NB that we cannot emit 'delta' style tile indices if VM error recovery */
- /* is in effect, since reader & writer's tile indices may get out of phase */
- /* as a consequence of error recovery occurring. */
- #define tile_id_hash(id) (id)
- #define tile_hash_next(index) ((index) + 413) /* arbitrary large odd # */
- typedef struct tile_loc_s {
- uint index;
- tile_slot *tile;
- } tile_loc;
- /* Look up a tile or character in the cache. If found, set the index and */
- /* pointer; if not, set the index to the insertion point. */
- private bool
- clist_find_bits(gx_device_clist_writer * cldev, gx_bitmap_id id, tile_loc * ploc)
- {
- uint index = tile_id_hash(id);
- const tile_hash *table = cldev->tile_table;
- uint mask = cldev->tile_hash_mask;
- ulong offset;
- for (; (offset = table[index &= mask].offset) != 0;
- index = tile_hash_next(index)
- ) {
- tile_slot *tile = (tile_slot *) (cldev->data + offset);
- if (tile->id == id) {
- ploc->index = index;
- ploc->tile = tile;
- return true;
- }
- }
- ploc->index = index;
- return false;
- }
- /* Delete a tile from the cache. */
- private void
- clist_delete_tile(gx_device_clist_writer * cldev, tile_slot * slot)
- {
- tile_hash *table = cldev->tile_table;
- uint mask = cldev->tile_hash_mask;
- uint index = slot->index;
- ulong offset;
- if_debug2('L', "[L]deleting index=%u, offset=%lu\n",
- index, (ulong) ((byte *) slot - cldev->data));
- gx_bits_cache_free(&cldev->bits, (gx_cached_bits_head *) slot,
- &cldev->chunk);
- table[index].offset = 0;
- /* Delete the entry from the hash table. */
- /* We'd like to move up any later entries, so that we don't need */
- /* a deleted mark, but it's too difficult to note this in the */
- /* band list, so instead, we just delete any entries that */
- /* would need to be moved. */
- while ((offset = table[index = tile_hash_next(index) & mask].offset) != 0) {
- tile_slot *tile = (tile_slot *) (cldev->data + offset);
- tile_loc loc;
- if (!clist_find_bits(cldev, tile->id, &loc)) { /* We didn't find it, so it should be moved into a slot */
- /* that we just vacated; instead, delete it. */
- if_debug2('L', "[L]move-deleting index=%u, offset=%lu\n",
- index, offset);
- gx_bits_cache_free(&cldev->bits,
- (gx_cached_bits_head *) (cldev->data + offset),
- &cldev->chunk);
- table[index].offset = 0;
- }
- }
- }
- /* Add a tile to the cache. */
- /* tile->raster holds the raster for the replicated tile; */
- /* we pass the raster of the actual data separately. */
- private int
- clist_add_tile(gx_device_clist_writer * cldev, const gx_strip_bitmap * tiles,
- uint sraster, int depth)
- {
- uint raster = tiles->raster;
- uint size_bytes = raster * tiles->size.y;
- uint tsize =
- sizeof(tile_slot) + cldev->tile_band_mask_size + size_bytes;
- gx_cached_bits_head *slot_head;
- #define slot ((tile_slot *)slot_head)
- if (cldev->bits.csize == cldev->tile_max_count) { /* Don't let the hash table get too full: delete an entry. */
- /* Since gx_bits_cache_alloc returns an entry to delete when */
- /* it fails, just force it to fail. */
- gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->chunk.size,
- &slot_head);
- if (slot_head == 0) { /* Wrap around and retry. */
- cldev->bits.cnext = 0;
- gx_bits_cache_alloc(&cldev->bits, (ulong) cldev->chunk.size,
- &slot_head);
- #ifdef DEBUG
- if (slot_head == 0) {
- lprintf("No entry to delete!\n");
- return_error(gs_error_Fatal);
- }
- #endif
- }
- clist_delete_tile(cldev, slot);
- }
- /* Allocate the space for the new entry, deleting entries as needed. */
- while (gx_bits_cache_alloc(&cldev->bits, (ulong) tsize, &slot_head) < 0) {
- if (slot_head == 0) { /* Wrap around. */
- if (cldev->bits.cnext == 0) { /* Too big to fit. We should probably detect this */
- /* sooner, since if we get here, we've cleared the */
- /* cache. */
- return_error(gs_error_limitcheck);
- }
- cldev->bits.cnext = 0;
- } else
- clist_delete_tile(cldev, slot);
- }
- /* Fill in the entry. */
- slot->cb_depth = depth;
- slot->cb_raster = raster;
- slot->width = tiles->rep_width;
- slot->height = tiles->rep_height;
- slot->shift = slot->rep_shift = tiles->rep_shift;
- slot->x_reps = slot->y_reps = 1;
- slot->id = tiles->id;
- memset(ts_mask(slot), 0, cldev->tile_band_mask_size);
- bytes_copy_rectangle(ts_bits(cldev, slot), raster,
- tiles->data, sraster,
- (tiles->rep_width * depth + 7) >> 3,
- tiles->rep_height);
- /* Make the hash table entry. */
- {
- tile_loc loc;
- #ifdef DEBUG
- if (clist_find_bits(cldev, tiles->id, &loc))
- lprintf1("clist_find_bits(0x%lx) should have failed!\n",
- (ulong) tiles->id);
- #else
- clist_find_bits(cldev, tiles->id, &loc); /* always fails */
- #endif
- slot->index = loc.index;
- cldev->tile_table[loc.index].offset =
- (byte *) slot_head - cldev->data;
- if_debug2('L', "[L]adding index=%u, offset=%lu\n",
- loc.index, cldev->tile_table[loc.index].offset);
- }
- slot->num_bands = 0;
- return 0;
- }
- /* ------ Driver procedure support ------ */
- /* Change the tile parameters (size and depth). */
- /* Currently we do this for all bands at once. */
- private void
- clist_new_tile_params(gx_strip_bitmap * new_tile, const gx_strip_bitmap * tiles,
- int depth, const gx_device_clist_writer * cldev)
- { /*
- * Adjust the replication factors. If we can, we replicate
- * the tile in X up to 32 bytes, and then in Y up to 4 copies,
- * as long as we don't exceed a total tile size of 256 bytes,
- * or more than 255 repetitions in X or Y, or make the tile so
- * large that not all possible tiles will fit in the cache.
- * Also, don't attempt Y replication if shifting is required.
- */
- #define max_tile_reps_x 255
- #define max_tile_bytes_x 32
- #define max_tile_reps_y 4
- #define max_tile_bytes 256
- uint rep_width = tiles->rep_width;
- uint rep_height = tiles->rep_height;
- uint rep_width_bits = rep_width * depth;
- uint tile_overhead =
- sizeof(tile_slot) + cldev->tile_band_mask_size;
- uint max_bytes = cldev->chunk.size / (rep_width_bits * rep_height);
- max_bytes -= min(max_bytes, tile_overhead);
- if (max_bytes > max_tile_bytes)
- max_bytes = max_tile_bytes;
- *new_tile = *tiles;
- {
- uint max_bits_x = max_bytes * 8 / rep_height;
- uint reps_x =
- min(max_bits_x, max_tile_bytes_x * 8) / rep_width_bits;
- uint reps_y;
- while (reps_x > max_tile_reps_x)
- reps_x >>= 1;
- new_tile->size.x = max(reps_x, 1) * rep_width;
- new_tile->raster = bitmap_raster(new_tile->size.x * depth);
- if (tiles->shift != 0)
- reps_y = 1;
- else {
- reps_y = max_bytes / (new_tile->raster * rep_height);
- if (reps_y > max_tile_reps_y)
- reps_y = max_tile_reps_y;
- else if (reps_y < 1)
- reps_y = 1;
- }
- new_tile->size.y = reps_y * rep_height;
- }
- #undef max_tile_reps_x
- #undef max_tile_bytes_x
- #undef max_tile_reps_y
- #undef max_tile_bytes
- }
- /* Change tile for clist_tile_rectangle. */
- int
- clist_change_tile(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- const gx_strip_bitmap * tiles, int depth)
- {
- tile_loc loc;
- int code;
- #define tile_params_differ(cldev, tiles, depth)\
- ((tiles)->rep_width != (cldev)->tile_params.rep_width ||\
- (tiles)->rep_height != (cldev)->tile_params.rep_height ||\
- (tiles)->rep_shift != (cldev)->tile_params.rep_shift ||\
- (depth) != (cldev)->tile_depth)
- top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache. Check whether this band */
- /* knows about it. */
- int band_index = pcls - cldev->states;
- byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
- byte bmask = 1 << (band_index & 7);
- if (*bptr & bmask) { /* Already known. Just set the index. */
- if (pcls->tile_index == loc.index)
- return 0;
- if ((code = cmd_put_tile_index(cldev, pcls, loc.index)) < 0)
- return code;
- } else {
- uint extra = 0;
- if tile_params_differ
- (cldev, tiles, depth) { /*
- * We have a cached tile whose parameters differ from
- * the current ones. Because of the way tile IDs are
- * managed, this is currently only possible when mixing
- * Patterns and halftones, but if we didn't generate new
- * IDs each time the main halftone cache needed to be
- * refreshed, this could also happen simply from
- * switching screens.
- */
- int band;
- clist_new_tile_params(&cldev->tile_params, tiles, depth,
- cldev);
- cldev->tile_depth = depth;
- /* No band knows about the new parameters. */
- for (band = cldev->tile_known_min;
- band <= cldev->tile_known_max;
- ++band
- )
- cldev->states[band].known &= ~tile_params_known;
- cldev->tile_known_min = cldev->nbands;
- cldev->tile_known_max = -1;
- }
- if (!(pcls->known & tile_params_known)) { /* We're going to have to write the tile parameters. */
- extra = cmd_size_tile_params(&cldev->tile_params);
- } { /*
- * This band doesn't know this tile yet, so output the
- * bits. Note that the offset we write is the one used by
- * the reading phase, not the writing phase. Note also
- * that the size of the cached and written tile may differ
- * from that of the client's tile. Finally, note that
- * this tile's size parameters are guaranteed to be
- * compatible with those stored in the device
- * (cldev->tile_params).
- */
- ulong offset = (byte *) loc.tile - cldev->chunk.data;
- uint rsize =
- extra + 1 + cmd_size_w(loc.index) + cmd_size_w(offset);
- byte *dp;
- uint csize;
- int code =
- cmd_put_bits(cldev, pcls, ts_bits(cldev, loc.tile),
- tiles->rep_width * depth, tiles->rep_height,
- loc.tile->cb_raster, rsize,
- (cldev->tile_params.size.x > tiles->rep_width ?
- decompress_elsewhere | decompress_spread :
- decompress_elsewhere),
- &dp, &csize);
- if (code < 0)
- return code;
- if (extra) { /* Write the tile parameters before writing the bits. */
- cmd_store_tile_params(dp, &cldev->tile_params, depth,
- extra);
- dp += extra;
- /* This band now knows the parameters. */
- pcls->known |= tile_params_known;
- if (band_index < cldev->tile_known_min)
- cldev->tile_known_min = band_index;
- if (band_index > cldev->tile_known_max)
- cldev->tile_known_max = band_index;
- }
- *dp = cmd_count_op(cmd_opv_set_tile_bits, csize - extra);
- dp++;
- dp = cmd_put_w(loc.index, dp);
- cmd_put_w(offset, dp);
- *bptr |= bmask;
- loc.tile->num_bands++;
- }
- }
- pcls->tile_index = loc.index;
- pcls->tile_id = loc.tile->id;
- return 0;
- }
- /* The tile is not in the cache, add it. */
- {
- gx_strip_bitmap new_tile;
- gx_strip_bitmap *ptile;
- /* Ensure that the tile size is compatible. */
- if (tile_params_differ(cldev, tiles, depth)) { /* We'll reset cldev->tile_params when we write the bits. */
- clist_new_tile_params(&new_tile, tiles, depth, cldev);
- ptile = &new_tile;
- } else {
- cldev->tile_params.id = tiles->id;
- cldev->tile_params.data = tiles->data;
- ptile = &cldev->tile_params;
- }
- code = clist_add_tile(cldev, ptile, tiles->raster, depth);
- if (code < 0)
- return code;
- }
- goto top;
- #undef tile_params_differ
- }
- /* Change "tile" for clist_copy_*. tiles->[rep_]shift must be zero. */
- int
- clist_change_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
- const gx_strip_bitmap * tiles, int depth)
- {
- tile_loc loc;
- int code;
- top:if (clist_find_bits(cldev, tiles->id, &loc)) { /* The bitmap is in the cache. Check whether this band */
- /* knows about it. */
- uint band_index = pcls - cldev->states;
- byte *bptr = ts_mask(loc.tile) + (band_index >> 3);
- byte bmask = 1 << (band_index & 7);
- if (*bptr & bmask) { /* Already known. Just set the index. */
- if (pcls->tile_index == loc.index)
- return 0;
- cmd_put_tile_index(cldev, pcls, loc.index);
- } else { /* Not known yet. Output the bits. */
- /* Note that the offset we write is the one used by */
- /* the reading phase, not the writing phase. */
- ulong offset = (byte *) loc.tile - cldev->chunk.data;
- uint rsize = 2 + cmd_size_w(loc.tile->width) +
- cmd_size_w(loc.tile->height) + cmd_size_w(loc.index) +
- cmd_size_w(offset);
- byte *dp;
- uint csize;
- gx_clist_state *bit_pcls = pcls;
- int code;
- if (loc.tile->num_bands == CHAR_ALL_BANDS_COUNT)
- bit_pcls = NULL;
- code = cmd_put_bits(cldev, bit_pcls, ts_bits(cldev, loc.tile),
- loc.tile->width * depth,
- loc.tile->height, loc.tile->cb_raster,
- rsize,
- (1 << cmd_compress_cfe) | decompress_elsewhere,
- &dp, &csize);
- if (code < 0)
- return code;
- *dp = cmd_count_op(cmd_opv_set_bits, csize);
- dp[1] = (depth << 2) + code;
- dp += 2;
- dp = cmd_put_w(loc.tile->width, dp);
- dp = cmd_put_w(loc.tile->height, dp);
- dp = cmd_put_w(loc.index, dp);
- cmd_put_w(offset, dp);
- if (bit_pcls == NULL) {
- memset(ts_mask(loc.tile), 0xff,
- cldev->tile_band_mask_size);
- loc.tile->num_bands = cldev->nbands;
- } else {
- *bptr |= bmask;
- loc.tile->num_bands++;
- }
- }
- pcls->tile_index = loc.index;
- pcls->tile_id = loc.tile->id;
- return 0;
- }
- /* The tile is not in the cache. */
- code = clist_add_tile(cldev, tiles, tiles->raster, depth);
- if (code < 0)
- return code;
- goto top;
- }
|