home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1991 Aladdin Enterprises. All rights reserved.
- Distributed by Free Software Foundation, Inc.
-
- This file is part of Ghostscript.
-
- Ghostscript is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- to anyone for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing. Refer
- to the Ghostscript General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- Ghostscript, but only under the conditions described in the Ghostscript
- General Public License. A copy of this license is supposed to have been
- given to you along with Ghostscript so you can know your rights and
- responsibilities. It should be in a file named COPYING. Among other
- things, the copyright notice and this notice must be preserved on all
- copies. */
-
- /* gxclist.c */
- /* Command list 'device' for Ghostscript. */
- #include "memory_.h"
- #include "gx.h"
- #include "gserrors.h"
- #include "gxbitmap.h"
- #include "gsmatrix.h" /* for gxdevice.h */
- #include "gxdevice.h"
- #include "gxdevmem.h" /* must precede gxclist.h */
- #include "gxclist.h"
-
- /* Patch a couple of things possibly missing from stdio.h. */
- #ifndef SEEK_SET
- # define SEEK_SET 0
- #endif
- #ifndef SEEK_CUR
- # define SEEK_CUR 1
- #endif
-
- /*
- * The implementation here is somewhat lazy in that it requires the entire
- * bitmap argument to copy_mono/color (in fact, all the scan lines involved)
- * to fit into the tile_data buffer at once.
- */
-
- #define cdev ((gx_device_clist *)dev)
-
- /* Forward declarations of procedures */
- private dev_proc_open_device(clist_open);
- private dev_proc_get_initial_matrix(clist_get_initial_matrix);
- private dev_proc_map_rgb_color(clist_map_rgb_color);
- private dev_proc_map_color_rgb(clist_map_color_rgb);
- private dev_proc_fill_rectangle(clist_fill_rectangle);
- private dev_proc_tile_rectangle(clist_tile_rectangle);
- private dev_proc_copy_mono(clist_copy_mono);
- private dev_proc_copy_color(clist_copy_color);
-
- /* The device descriptor */
- private gx_device_procs clist_procs =
- { clist_open,
- clist_get_initial_matrix,
- gx_default_sync_output,
- gx_default_output_page,
- gx_default_close_device,
- clist_map_rgb_color,
- clist_map_color_rgb,
- clist_fill_rectangle,
- clist_tile_rectangle,
- clist_copy_mono,
- clist_copy_color,
- gx_default_draw_line,
- gx_default_fill_trapezoid,
- gx_default_tile_trapezoid
- };
- gx_device_clist gs_clist_device =
- { sizeof(gx_device_clist),
- &clist_procs,
- "command list",
- 0, 0, 1, 1, no_margins, 0, 0, 0, 0, /* generic */
- NULL, NULL, 0
- };
-
- /* ------ Define the command set and syntax ------ */
-
- /* A command always consists of an operation followed by operands. */
- /* The operands are implicit in the procedural code. */
- typedef enum {
- cmd_op_set_color0 = 0, /* color+2 in op byte, [color] */
- cmd_op_set_color1 = 0x10, /* color+2 in op byte, [color] */
- cmd_op_set_tile = 0x20, /* raster, width, height, <bits> */
- cmd_op_set_phase = 0x30, /* x, y */
- cmd_op_fill_rect = 0x40, /* rect */
- cmd_op_fill_rect_short = 0x50, /* dh|0 in op byte, rect_short,[dh] */
- cmd_op_fill_rect_tiny = 0x60, /* dw in op byte, rect_tiny */
- cmd_op_tile_rect = 0x70, /* rect */
- cmd_op_tile_rect_short = 0x80, /* dh|0 in op byte, rect_short,[dh] */
- cmd_op_tile_rect_tiny = 0x90, /* dw in op byte, rect_tiny */
- cmd_op_copy_mono = 0xa0, /* rect, data_x, raster */
- cmd_op_copy_color = 0xb0, /* rect, data_x, raster */
- cmd_op_end_run = 0xc0, /* (nothing) */
- cmd_op_end
- } gx_cmd_op;
- #ifdef DEBUG
- private char *cmd_op_names[16] = {
- "set_color_0", "set_color_1", "set_tile", "set_phase",
- "fill_rect", "fill_rect_short", "fill_rect_tiny", "tile_rect",
- "tile_rect_short", "tile_rect_tiny", "copy_mono", "copy_color",
- "end_run", "?d0?", "?e0?", "?f0?"
- };
- private ulong cmd_op_counts[256];
- private ulong cmd_tile_count, cmd_copy_count;
- private int
- count_op(int op)
- { ++cmd_op_counts[op];
- #ifdef DEBUG
- if ( gs_debug['L'] )
- dprintf2(", %s %d\n", cmd_op_names[op >> 4], op & 0xf);
- #endif
- return op;
- }
- #else
- # define count_op(store_op) store_op
- #endif
-
- typedef struct {
- short x, y, width, height;
- } gx_cmd_rect;
- typedef struct {
- byte dx, dy, dwidth, dheight; /* dheight is optional */
- } gx_cmd_rect_short;
- #define cmd_min_short (-128)
- #define cmd_max_short 127
- typedef struct {
- unsigned dx : 4;
- unsigned dy : 4;
- } gx_cmd_rect_tiny;
- #define cmd_min_tiny (-8)
- #define cmd_max_tiny 7
- /* Define the size of the largest command, */
- /* not counting any bitmap. */
- #define cmd_largest_size (1 + sizeof(gx_cmd_rect) + 4)
-
- /* Define the prefix on each command in the buffer for writing. */
- typedef struct cmd_prefix_s cmd_prefix;
- struct cmd_prefix_s {
- cmd_prefix *next;
- uint size;
- };
-
- /* Remember the current state of one band when writing or reading. */
- struct gx_clist_state_s {
- gx_color_index color0, color1; /* most recent colors */
- gx_bitmap tile; /* most recent tile */
- gs_int_point phase; /* most recent tile phase */
- gx_cmd_rect rect; /* most recent rectangle */
- /* Following are only used when writing */
- uint size; /* total size of buffered commands */
- /* for this band */
- uint band; /* band number */
- cmd_prefix *head, *tail; /* list of commands for band */
- };
-
- /* The initial values for a band state */
- private gx_clist_state cls_initial =
- { gx_no_color_index, gx_no_color_index,
- { 0, 0, 0, 0 }, { 0, 0 }, { 0, 0, 0, 0 },
- 1, 0, 0, 0
- };
-
- /* Initialize the device state */
- private int
- clist_open(gx_device *dev)
- { /*
- * The buffer area (data, data_size) holds a tile cache when
- * both writing and reading. The rest of the space is used for
- * the command buffer and band state bookkeeping when writing,
- * and for the rendering buffer (image device) when reading.
- * For the moment, we divide the space up arbitrarily.
- */
- byte *data = cdev->data;
- uint size = cdev->data_size;
- #define alloc_data(n) data += (n), size -= (n)
- gx_device *target = cdev->target;
- int raster, nbands, band;
- gx_clist_state *states;
- uint state_size;
- cdev->ymin = cdev->ymax = -1; /* render_init not done yet */
- cdev->tile_data = data;
- cdev->tile_size = (size / 5) & -4; /* arbitrary! */
- alloc_data(cdev->tile_size);
- raster = (((target->width * target->bits_per_color_pixel + 31) >> 5) << 2) + sizeof(byte *);
- cdev->band_height = size / (uint)raster;
- cdev->nbands = nbands = target->height / cdev->band_height + 1;
- #ifdef DEBUG
- if ( gs_debug['l'] | gs_debug['L'] )
- dprintf4("[l]width=%d, raster=%d, band_height=%d, nbands=%d\n",
- target->width, raster, cdev->band_height, cdev->nbands);
- #endif
- state_size = nbands * sizeof(gx_clist_state);
- if ( state_size > size / 2 )
- return -1; /* not enough room */
- cdev->mdev.base = data;
- cdev->states = states = (gx_clist_state *)data;
- alloc_data(state_size);
- cdev->cbuf = data;
- cdev->cnext = data;
- cdev->cend = data + size;
- cdev->ccls = 0;
- for ( band = 0; band < nbands; band++, states++ )
- *states = cls_initial, states->band = band;
- #undef alloc_data
- return 0;
- }
-
- /* Forward the non-displaying operations to the target device. */
- private void
- clist_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
- { (*cdev->target->procs->get_initial_matrix)(dev, pmat);
- }
- private gx_color_index
- clist_map_rgb_color(gx_device *dev, ushort red, ushort green, ushort blue)
- { return (*cdev->target->procs->map_rgb_color)(dev, red, green, blue);
- }
- private int
- clist_map_color_rgb(gx_device *dev, gx_color_index color, ushort rgb[3])
- { return (*cdev->target->procs->map_color_rgb)(dev, color, rgb);
- }
-
- /* Print a bitmap for tracing */
- #ifdef DEBUG
- private void
- cmd_print_bits(byte *data, int height, int raster)
- { int i, j;
- for ( i = 0; i < height; i++ )
- { byte *row = data + i * raster;
- dprintf("[L]");
- for ( j = 0; j < raster; j++ )
- dprintf1(" %02x", row[j]);
- dputc('\n');
- }
- }
- #else
- # define cmd_print_bits(data, height, raster)
- #endif
-
- /* ------ Writing ------ */
-
- /* Utilities */
-
- #define cmd_set_rect(rect)\
- ((rect).x = x, (rect).y = y,\
- (rect).width = width, (rect).height = height)
-
- private void
- clist_write(FILE *f, byte *str, uint len)
- { fwrite(str, 1, len, f);
- }
-
- /* Write out the buffered commands, and reset the buffer. */
- private void
- cmd_write_buffer(gx_device *dev)
- { FILE *file = cdev->file;
- int nbands = cdev->nbands;
- gx_clist_state *pcls;
- uint size = 0;
- int band;
- for ( band = 0, pcls = cdev->states; band < nbands; band++, pcls++ )
- size += pcls->size;
- #ifdef DEBUG
- if ( gs_debug['l'] | gs_debug['L'] )
- dprintf1("[l]write_buffer %d\n", size);
- #endif
- if ( size == 0 ) return; /* nothing to write */
- clist_write(file, (byte *)&size, sizeof(size));
- size = 0;
- for ( band = 0, pcls = cdev->states; band < nbands; band++, pcls++ )
- { clist_write(file, (byte *)&size, sizeof(size));
- size += pcls->size;
- }
- clist_write(file, (byte *)&size, sizeof(size));
- for ( band = 0, pcls = cdev->states; band < nbands; band++, pcls++ )
- { cmd_prefix *cp = pcls->head;
- for ( ; cp != 0; cp = cp->next )
- clist_write(file, (byte *)(cp + 1), cp->size);
- pcls->size = 1;
- pcls->head = pcls->tail = 0;
- fputc(cmd_op_end_run, file);
- }
- cdev->cnext = cdev->cbuf;
- cdev->ccls = 0;
- }
-
- /* Add a command to the appropriate band list, */
- /* and allocate space for its data. */
- /* Return the pointer to the data area. */
- private byte *
- cmd_put_op(gx_device *dev, gx_clist_state *pcls, uint size)
- { byte *dp = cdev->cnext;
- #ifdef DEBUG
- if ( gs_debug['L'] )
- dprintf3("[L]band %d: size=%d, left=%d",
- pcls->band, size, (int)(cdev->cend - dp));
- #endif
- if ( size + (sizeof(cmd_prefix) + 4) > cdev->cend - dp )
- { cmd_write_buffer(dev);
- return cmd_put_op(dev, pcls, size);
- }
- if ( cdev->ccls == pcls )
- { /* We're adding another command for the same band. */
- /* Tack it onto the end of the previous one. */
- pcls->tail->size += size;
- }
- else
- { cmd_prefix *cp = (cmd_prefix *)(dp + (((byte *)0 - dp) & 3));
- dp = (byte *)(cp + 1);
- if ( pcls->tail != 0 ) pcls->tail->next = cp;
- else pcls->head = cp;
- pcls->tail = cp;
- cdev->ccls = pcls;
- cp->next = 0;
- cp->size = size;
- }
- cdev->cnext = dp + size;
- pcls->size += size;
- return dp;
- }
-
- /* We store all short quantities little-endian. */
- /* This is OK, because we read them back little-endian explicitly. */
- #define cmd_putw(w, dp) (*dp = (w) & 0xff, dp[1] = (w) >> 8, dp += 2)
-
- private int
- cmd_write_rect_cmd(gx_device *dev, gx_clist_state *pcls,
- int op, int x, int y, int width, int height)
- { int dx = x - pcls->rect.x;
- int dy = y - pcls->rect.y;
- int dwidth = width - pcls->rect.width;
- int dheight = height - pcls->rect.height;
- #define check_ranges_1()\
- ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
- (unsigned)(dy - rmin) <= (rmax - rmin) &&\
- (unsigned)(dwidth - rmin) <= (rmax - rmin))
- #define check_ranges()\
- (check_ranges_1() &&\
- (unsigned)(dheight - rmin) <= (rmax - rmin))
- #define rmin cmd_min_tiny
- #define rmax cmd_max_tiny
- cmd_set_rect(pcls->rect);
- if ( dheight == 0 && check_ranges_1() )
- { byte *dp = cmd_put_op(dev, pcls, 2);
- count_op(*dp = op + 0x20 + dwidth - rmin);
- dp[1] = (dx << 4) + dy - (rmin * 0x11);
- }
- #undef rmin
- #undef rmax
- #define rmin cmd_min_short
- #define rmax cmd_max_short
- else if ( check_ranges() )
- { int dh = dheight - cmd_min_tiny;
- byte *dp;
- if ( (unsigned)dh <= cmd_max_tiny - cmd_min_tiny && dh != 0 )
- { op += dh;
- dp = cmd_put_op(dev, pcls, 4);
- }
- else
- { dp = cmd_put_op(dev, pcls, 5);
- dp[4] = dheight - rmin;
- }
- count_op(*dp = op + 0x10);
- dp[1] = dx - rmin;
- dp[2] = dy - rmin;
- dp[3] = dwidth - rmin;
- }
- else
- { byte *dp = cmd_put_op(dev, pcls, 1 + sizeof(pcls->rect));
- count_op(*dp = op);
- memcpy(dp + 1, &pcls->rect, sizeof(pcls->rect));
- }
- return 0;
- }
-
- private void
- cmd_put_color(gx_device *dev, gx_clist_state *pcls,
- int op, gx_color_index color)
- { if ( (long)color >= -1 && (long)color <= 13 )
- count_op(*cmd_put_op(dev, pcls, 1) = op + (int)color + 2);
- else
- { byte *dp = cmd_put_op(dev, pcls, 1 + sizeof(color));
- count_op(*dp = op);
- memcpy(dp + 1, &color, sizeof(color));
- }
- }
- private void
- cmd_set_colors(gx_device *dev, gx_clist_state *pcls,
- gx_color_index color0, gx_color_index color1)
- { if ( color0 != pcls->color0 )
- { cmd_put_color(dev, pcls, cmd_op_set_color0, color0);
- pcls->color0 = color0;
- }
- if ( color1 != pcls->color1 )
- { cmd_put_color(dev, pcls, cmd_op_set_color1, color1);
- pcls->color1 = color1;
- }
- }
-
- /* Driver interface */
-
- /* Macros for dividing up a single call into bands */
- #define BEGIN_RECT\
- { int yend = y + height;\
- int band_height = cdev->band_height;\
- do\
- { int band = y / band_height;\
- gx_clist_state *pcls = cdev->states + band;\
- height = band_height - y % band_height;\
- if ( yend - y < height ) height = yend - y;\
- {
- #define END_RECT\
- }\
- y += height;\
- }\
- while ( y < yend );\
- }
-
- private int
- clist_fill_rectangle(gx_device *dev, int x, int y, int width, int height,
- gx_color_index color)
- { BEGIN_RECT
- if ( color != pcls->color1 )
- cmd_set_colors(dev, pcls, pcls->color0, color);
- cmd_write_rect_cmd(dev, pcls, cmd_op_fill_rect, x, y, width, height);
- END_RECT
- return 0;
- }
-
- private int
- tile_eq(gx_bitmap *tile, gx_clist_state *pcls)
- { return
- (tile->data == pcls->tile.data &&
- tile->raster == pcls->tile.raster &&
- tile->width == pcls->tile.width &&
- tile->height == pcls->tile.height);
- }
- private int
- clist_tile_rectangle(gx_device *dev, gx_bitmap *tile, int x, int y,
- int width, int height, gx_color_index color0, gx_color_index color1,
- int px, int py)
- { uint tile_size = tile->raster * tile->height;
- BEGIN_RECT
- if ( color0 != pcls->color0 || color1 != pcls->color1 )
- cmd_set_colors(dev, pcls, color0, color1);
- if ( px != pcls->phase.x || py != pcls->phase.y )
- { byte *dp = cmd_put_op(dev, pcls, 1 + sizeof(pcls->phase));
- count_op(*dp = (byte)cmd_op_set_phase);
- pcls->phase.x = px;
- pcls->phase.y = py;
- memcpy(dp + 1, &pcls->phase, sizeof(pcls->phase));
- }
- if ( !tile_eq(tile, pcls) ||
- memcmp(tile->data, cdev->tile_data, tile_size)
- )
- { byte *dp = cmd_put_op(dev, pcls, 1 + 6 + tile_size);
- count_op(*dp++ = (byte)cmd_op_set_tile);
- cmd_putw(tile->raster, dp);
- cmd_putw(tile->width, dp);
- cmd_putw(tile->height, dp);
- if ( tile_size <= cdev->tile_size )
- { /* Clear the tile records of all the other bands. */
- { gx_clist_state *tcls = cdev->states;
- int i;
- for ( i = 0; i < cdev->nbands; i++, tcls++ )
- tcls->tile.data = 0;
- }
- pcls->tile = *tile;
- memcpy(cdev->tile_data, tile->data, tile_size);
- }
- memcpy(dp, tile->data, tile_size);
- #ifdef DEBUG
- cmd_tile_count += tile_size;
- #endif
- }
- cmd_write_rect_cmd(dev, pcls, cmd_op_tile_rect, x, y, width, height);
- END_RECT
- return 0;
- }
-
- private int
- clist_copy_mono(gx_device *dev, byte *data, int data_x, int raster,
- int x, int y, int width, int height,
- gx_color_index color0, gx_color_index color1)
- { int y0 = y;
- BEGIN_RECT
- gx_cmd_rect rect;
- uint dsize = height * raster;
- byte *dp;
- if ( color0 != pcls->color0 || color1 != pcls->color1 )
- cmd_set_colors(dev, pcls, color0, color1);
- cmd_set_rect(rect);
- dp = cmd_put_op(dev, pcls, 1 + sizeof(rect) + 4 + dsize);
- count_op(*dp++ = (byte)cmd_op_copy_mono);
- memcpy(dp, (byte *)&rect, sizeof(rect));
- pcls->rect = rect;
- dp += sizeof(rect);
- cmd_putw(data_x, dp);
- cmd_putw(raster, dp);
- memcpy(dp, data + (y - y0) * raster, dsize);
- #ifdef DEBUG
- cmd_copy_count += dsize;
- #endif
- END_RECT
- return 0;
- }
-
- private int
- clist_copy_color(gx_device *dev, byte *data, int data_x, int raster,
- int x, int y, int width, int height)
- { int y0 = y;
- BEGIN_RECT
- gx_cmd_rect rect;
- uint dsize = height * raster;
- byte *dp;
- cmd_set_rect(rect);
- dp = cmd_put_op(dev, pcls, 1 + sizeof(rect) + 4 + dsize);
- count_op(*dp++ = (byte)cmd_op_copy_color);
- memcpy(dp, (byte *)&rect, sizeof(rect));
- pcls->rect = rect;
- dp += sizeof(rect);
- cmd_putw(data_x, dp);
- cmd_putw(raster, dp);
- memcpy(dp, data + (y - y0) * raster, dsize);
- END_RECT
- return 0;
- }
-
- /* ------ Reading/rendering ------ */
-
- #undef cdev
-
- private int clist_render(P3(gx_device_clist *, gx_device *, int));
-
- /* Initialize for reading. */
- int
- clist_render_init(gx_device_clist *cdev)
- { gx_device *target = cdev->target;
- byte *base = cdev->mdev.base; /* save */
- int bpp = target->bits_per_color_pixel;
- uint raster = ((target->width * bpp + 31) >> 5) << 2;
- gx_device_memory *mdev;
- cmd_write_buffer((gx_device *)cdev); /* flush buffer */
- switch ( bpp )
- {
- case 1: mdev = &mem_mono_device; break;
- case 8: mdev = &mem_mapped8_color_device; break;
- case 24: mdev = &mem_true24_color_device; break;
- case 32: mdev = &mem_true32_color_device; break;
- default: return_error(gs_error_rangecheck);
- }
- cdev->mdev = *mdev;
- cdev->mdev.base = base; /* restore */
- (*target->procs->get_initial_matrix)(target, &cdev->mdev.initial_matrix);
- cdev->mdev.width = target->width;
- cdev->mdev.height = cdev->band_height;
- cdev->mdev.raster = raster;
- cdev->ymin = cdev->ymax = 0;
- #ifdef DEBUG
- if ( gs_debug['l'] | gs_debug['L'] )
- { int ci, cj;
- dprintf2("[l]counts: tile = %ld, copy = %ld\n",
- cmd_tile_count, cmd_copy_count);
- for ( ci = 0; ci < 0x100; ci += 0x10 )
- { dprintf1("[l] %s =", cmd_op_names[ci >> 4]);
- for ( cj = ci; cj < ci + 0x10; cj++ )
- dprintf1(" %ld", cmd_op_counts[cj]);
- dputs("\n");
- }
- }
- #endif
- return 0;
- }
-
- /* Copy scan lines to the client. This is where rendering gets done. */
- int
- clist_copy_scan_lines(gx_device_clist *cdev, int start_y,
- byte *str, uint size)
- { gx_device_memory *mdev = &cdev->mdev;
- uint bytes_per_line = gdev_mem_bytes_per_scan_line((gx_device *)mdev);
- uint count = min(size / bytes_per_line,
- cdev->target->height - start_y);
- int y = start_y;
- uint left = count;
- byte *dest = str;
- /* Render bands and copy them incrementally. */
- while ( left )
- { int n;
- if ( !(y >= cdev->ymin && y < cdev->ymax) )
- { int band = y / mdev->height;
- rewind(cdev->file);
- (*mdev->procs->open_device)((gx_device *)mdev); /* reinitialize */
- clist_render(cdev, (gx_device *)mdev, band);
- gdev_mem_ensure_byte_order(mdev);
- cdev->ymin = band * mdev->height;
- cdev->ymax = cdev->ymin + mdev->height;
- }
- n = min(cdev->ymax - y, left);
- gdev_mem_copy_scan_lines(mdev, y - cdev->ymin, dest,
- bytes_per_line * n);
- y += n, dest += bytes_per_line * n, left -= n;
- }
- return count;
- }
-
- /* Render one band to a specified target device. */
- #define assign_getw(var, p)\
- (var = *p + ((uint)p[1] << 8), p += 2)
- #define cbuf_size 500
- private void clist_read(P3(FILE *, byte *, uint));
- private void clist_skip(P2(FILE *, uint));
- private int
- clist_render(gx_device_clist *cdev, gx_device *tdev, int band)
- { byte cbuf[cbuf_size];
- register byte _ss *cbp;
- byte _ss *cb_limit;
- byte _ss *cb_end;
- FILE *file = cdev->file;
- int y0 = band * cdev->band_height;
- gx_clist_state state;
- gs_int_point tile_phase;
- long end_run;
- uint left;
- #define cmd_read_var(ptr, cbp)\
- memcpy(ptr, cbp, sizeof(*ptr)),\
- cbp += sizeof(*ptr)
- #define cmd_read(ptr, vsize, cbp)\
- if ( cb_end - cbp >= vsize )\
- memcpy(ptr, cbp, vsize), cbp += vsize;\
- else\
- { uint cleft = cb_end - cbp;\
- memcpy(ptr, cbp, cleft); vsize -= cleft;\
- clist_read(file, ptr + cleft, vsize);\
- cbp = cb_end;\
- }
- state = cls_initial;
- tile_phase.x = tile_phase.y = 0;
- state.tile.data = cdev->tile_data;
- state.tile.width = state.tile.height = 1; /* so set_phase works */
- #ifdef DEBUG
- if ( gs_debug['l'] | gs_debug['L'] )
- dprintf1("[l]render band %d\n", band);
- #endif
- /* Read the header of a block of buffered commands, */
- /* and skip to the correct run for this band. */
- top: { uint block_size, start[2];
- clist_read(file, (byte *)&block_size, sizeof(block_size));
- #ifdef DEBUG
- if ( gs_debug['l'] | gs_debug['L'] )
- dprintf2("[l]block at %ld, size=%d\n",
- ftell(file), block_size);
- #endif
- if ( feof(file) ) return 0; /* all done */
- end_run = ftell(file) + (cdev->nbands + 1) * sizeof(uint) +
- (ulong)block_size;
- clist_skip(file, band * sizeof(uint));
- clist_read(file, (byte *)start, sizeof(start));
- left = start[1] - start[0];
- clist_skip(file, (cdev->nbands - band - 1) * sizeof(uint) + start[0]);
- #ifdef DEBUG
- if ( gs_debug['l'] | gs_debug['L'] )
- dprintf4("[l]start=%d,%d run=%ld, end_run=%ld\n",
- start[0], start[1], ftell(file), end_run);
- #endif
- }
- cb_limit = cbuf + (cbuf_size - cmd_largest_size);
- cb_end = cbuf + cbuf_size;
- cbp = cb_end;
- for ( ; ; )
- { int op;
- uint bytes;
- int code;
- gx_color_index _ss *pcolor;
- /* Make sure the buffer contains a full command. */
- if ( cbp > cb_limit )
- { uint nread;
- memcpy(cbuf, cbp, cb_end - cbp);
- cbp = cbuf + (cb_end - cbp);
- nread = cb_end - cbp;
- if ( nread > left ) nread = left;
- clist_read(file, cbp, nread);
- cb_end = cbp + nread;
- cbp = cbuf;
- left -= nread;
- if ( cb_limit > cb_end ) cb_limit = cb_end;
- }
- op = *cbp++;
- #ifdef DEBUG
- if ( gs_debug['L'] )
- dprintf2("[L]%s %d:\n", cmd_op_names[op >> 4], op & 0xf);
- #endif
- switch ( op >> 4 )
- {
- case cmd_op_set_color0 >> 4:
- pcolor = &state.color0;
- goto set_color;
- case cmd_op_set_color1 >> 4:
- pcolor = &state.color1;
- set_color: if ( op & 0xf )
- *pcolor = (gx_color_index)(long)((op & 0xf) - 2);
- else
- cmd_read_var(pcolor, cbp);
- continue;
- case cmd_op_set_tile >> 4:
- assign_getw(state.tile.raster, cbp);
- assign_getw(state.tile.width, cbp);
- assign_getw(state.tile.height, cbp);
- bytes = state.tile.height * state.tile.raster;
- cmd_read(state.tile.data, bytes, cbp);
- #ifdef DEBUG
- if ( gs_debug['L'] )
- cmd_print_bits(state.tile.data, state.tile.height,
- state.tile.raster);
- #endif
- goto set_phase;
- case cmd_op_set_phase >> 4:
- cmd_read_var(&state.phase, cbp);
- set_phase: tile_phase.x = state.phase.x % state.tile.width;
- tile_phase.y = (state.phase.y + y0) % state.tile.height;
- continue;
- case cmd_op_fill_rect >> 4:
- case cmd_op_tile_rect >> 4:
- case cmd_op_copy_mono >> 4:
- case cmd_op_copy_color >> 4:
- cmd_read_var(&state.rect, cbp);
- break;
- case cmd_op_fill_rect_short >> 4:
- case cmd_op_tile_rect_short >> 4:
- state.rect.x += *cbp + cmd_min_short;
- state.rect.y += cbp[1] + cmd_min_short;
- state.rect.width += cbp[2] + cmd_min_short;
- state.rect.height +=
- (op & 0xf ? (op & 0xf) + cmd_min_tiny :
- (++cbp)[2] + cmd_min_short);
- cbp += 3;
- break;
- case cmd_op_fill_rect_tiny >> 4:
- case cmd_op_tile_rect_tiny >> 4:
- { int txy = *cbp++;
- state.rect.x += (txy >> 4) + cmd_min_tiny;
- state.rect.y += (txy & 0xf) + cmd_min_tiny;
- state.rect.width += (op & 0xf) + cmd_min_tiny;
- } break;
- case cmd_op_end_run >> 4:
- fseek(file, end_run, SEEK_SET); /* skip rest of block */
- goto top;
- default:
- lprintf5("Bad op %02x band %d file pos %ld buf pos %d/%d\n",
- op, band, ftell(file), (int)(cbp - cbuf), (int)(cb_end - cbuf));
- return -1;
- }
- #ifdef DEBUG
- if ( gs_debug['L'] )
- dprintf4("[L] x=%d y=%d w=%d h=%d\n",
- state.rect.x, state.rect.y, state.rect.width,
- state.rect.height);
- #endif
- switch ( op >> 4 )
- {
- case cmd_op_fill_rect >> 4:
- case cmd_op_fill_rect_short >> 4:
- case cmd_op_fill_rect_tiny >> 4:
- code = (*tdev->procs->fill_rectangle)
- (tdev, state.rect.x, state.rect.y - y0,
- state.rect.width, state.rect.height, state.color1);
- break;
- case cmd_op_tile_rect >> 4:
- case cmd_op_tile_rect_short >> 4:
- case cmd_op_tile_rect_tiny >> 4:
- code = (*tdev->procs->tile_rectangle)
- (tdev, &state.tile,
- state.rect.x, state.rect.y - y0,
- state.rect.width, state.rect.height,
- state.color0, state.color1,
- tile_phase.x, tile_phase.y);
- break;
- case cmd_op_copy_mono >> 4:
- case cmd_op_copy_color >> 4:
- { int data_x, raster;
- assign_getw(data_x, cbp);
- assign_getw(raster, cbp);
- #ifdef DEBUG
- if ( gs_debug['L'] )
- dprintf2("[L] data_x=%d raster=%d\n",
- data_x, raster);
- #endif
- bytes = state.rect.height * raster;
- /* The following doesn't work for very large */
- /* bitmaps, but it's good enough for now. */
- cmd_read(cbuf, bytes, cbp);
- #ifdef DEBUG
- if ( gs_debug['L'] )
- cmd_print_bits(cbuf, state.rect.height, raster);
- #endif
- code = (op >> 4 == (byte)cmd_op_copy_mono >> 4 ?
- (*tdev->procs->copy_mono)
- (tdev, cbuf, data_x, raster,
- state.rect.x, state.rect.y - y0,
- state.rect.width, state.rect.height,
- state.color0, state.color1) :
- (*tdev->procs->copy_color)
- (tdev, cbuf, data_x, raster,
- state.rect.x, state.rect.y - y0,
- state.rect.width, state.rect.height));
- } break;
- }
- if ( code < 0 ) return code;
- }
- }
- /* The typical implementations of fread and fseek */
- /* are extremely inefficient for small counts, */
- /* so we use loops instead. */
- private void
- clist_read(FILE *f, byte *str, uint len)
- { switch ( len )
- {
- default: fread(str, 1, len, f); break;
- case 8: *str++ = (char)getc(f);
- case 7: *str++ = (char)getc(f);
- case 6: *str++ = (char)getc(f);
- case 5: *str++ = (char)getc(f);
- case 4: *str++ = (char)getc(f);
- case 3: *str++ = (char)getc(f);
- case 2: *str++ = (char)getc(f);
- case 1: *str = (char)getc(f);
- }
- }
- private void
- clist_skip(FILE *f, uint len)
- { if ( len <= 10 )
- { register int i;
- for ( i = 0; i < len; i++ ) getc(f);
- }
- else
- fseek(f, (long)len, SEEK_CUR);
- }
-