386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / gxclist.c
CommitLineData
9792d40a
WJ
1/* Copyright (C) 1991, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* gxclist.c */
21/* Command list 'device' for Ghostscript. */
22#include "memory_.h"
23#include "gx.h"
24#include "gserrors.h"
25#include "gxdevice.h"
26#include "gxdevmem.h" /* must precede gxclist.h */
27#include "gxclist.h"
28
29/* Patch a couple of things possibly missing from stdio.h. */
30#ifndef SEEK_SET
31# define SEEK_SET 0
32#endif
33#ifndef SEEK_END
34# define SEEK_END 2
35#endif
36
37#define cdev ((gx_device_clist *)dev)
38
39/* Forward declarations of procedures */
40private dev_proc_open_device(clist_open);
41private dev_proc_get_initial_matrix(clist_get_initial_matrix);
42private dev_proc_output_page(clist_output_page);
43private dev_proc_map_rgb_color(clist_map_rgb_color);
44private dev_proc_map_color_rgb(clist_map_color_rgb);
45private dev_proc_fill_rectangle(clist_fill_rectangle);
46private dev_proc_tile_rectangle(clist_tile_rectangle);
47private dev_proc_copy_mono(clist_copy_mono);
48private dev_proc_copy_color(clist_copy_color);
49private dev_proc_get_bits(clist_get_bits);
50private dev_proc_get_props(clist_get_props);
51private dev_proc_put_props(clist_put_props);
52
53/* The device descriptor */
54private gx_device_procs clist_procs =
55{ clist_open,
56 clist_get_initial_matrix,
57 gx_default_sync_output,
58 clist_output_page,
59 gx_default_close_device,
60 clist_map_rgb_color,
61 clist_map_color_rgb,
62 clist_fill_rectangle,
63 clist_tile_rectangle,
64 clist_copy_mono,
65 clist_copy_color,
66 gx_default_draw_line,
67 clist_get_bits,
68 clist_get_props,
69 clist_put_props
70};
71gx_device_clist gs_clist_device =
72{ sizeof(gx_device_clist),
73 &clist_procs,
74 "command list",
75 0, 0, 1, 1, no_margins, dci_black_and_white, 0, /* generic */
76 NULL, NULL, 0
77};
78
79/* ------ Define the command set and syntax ------ */
80
81/* A command always consists of an operation followed by operands. */
82/* The operands are implicit in the procedural code. */
83typedef enum {
84 cmd_op_misc = 0x00, /* (see below) */
85 cmd_opv_end_run = 0x00, /* (nothing) */
86 cmd_opv_set_tile_size = 0x01, /* width, height */
87 cmd_opv_set_tile_phase = 0x02, /* x, y */
88 cmd_op_set_color0 = 0x10, /* color+2 in op byte, [color] */
89 cmd_op_set_color1 = 0x20, /* color+2 in op byte, [color] */
90 cmd_op_set_tile_index = 0x30, /* index */
91 cmd_op_fill_rect = 0x40, /* rect */
92 cmd_op_fill_rect_short = 0x50, /* dh in op byte,dx,dw | rect_short */
93 cmd_op_fill_rect_tiny = 0x60, /* dw in op byte, rect_tiny */
94 cmd_op_tile_rect = 0x70, /* rect */
95 cmd_op_tile_rect_short = 0x80, /* dh in op byte,dx,dw | rect_short */
96 cmd_op_tile_rect_tiny = 0x90, /* dw in op byte, rect_tiny */
97 cmd_op_copy_mono = 0xa0, /* rect, data_x, raster | */
98 /* d_x+1 in op byte, x, y, w, h */
99 cmd_op_copy_color = 0xb0, /* rect, data_x, raster */
100 cmd_op_set_tile_bits = 0xc0, /* index, <bits> */
101 cmd_op_delta_tile_bits = 0xd0, /* n-1 in op byte, n x <offset, bits> */
102 cmd_op_end
103} gx_cmd_op;
104/* Define the size of the largest command, */
105/* not counting any bitmap. */
106#define w sizeof(short) /* size of coordinate */
107#define d 3 /* size of tile delta */
108private uint cmd_largest_size =
109 max(1 + 6 * sizeof(short) /* copy_mono */, 2 + 16 * d /* delta_tile 15 */);
110#undef d
111#undef w
112#ifdef DEBUG
113private char *cmd_op_names[16] = {
114 "misc", "set_color_0", "set_color_1", "set_tile",
115 "fill_rect", "fill_rect_short", "fill_rect_tiny", "tile_rect",
116 "tile_rect_short", "tile_rect_tiny", "copy_mono", "copy_color",
117 "set_tile_bits", "delta_tile_bits", "?e0?", "?f0?"
118};
119private char *cmd_misc_op_names[16] = {
120 "end_run", "set_tile_size", "set_tile_phase", "?03?",
121 "?04?", "?05?", "?06?", "?07?",
122 "?08?", "?09?", "?0a?", "?0b?",
123 "?0c?", "?0d?", "?0e?", "?0f?"
124};
125private ulong cmd_op_counts[256];
126private ulong cmd_tile_count, cmd_copy_count, cmd_delta_tile_count;
127private ulong cmd_tile_reset, cmd_tile_found, cmd_tile_added;
128private int
129count_op(int op)
130{ ++cmd_op_counts[op];
131if ( gs_debug['L'] )
132 dprintf2(", %s %d\n", cmd_op_names[op >> 4], op & 0xf),
133 fflush(dstderr);
134 return op;
135}
136# define count_add(v, n) (v += (n))
137#else
138# define count_op(store_op) store_op
139# define count_add(v, n) 0
140#endif
141#define count_add1(v) count_add(v, 1)
142
143typedef struct {
144 short x, y, width, height;
145} gx_cmd_rect;
146typedef struct {
147 byte dx, dwidth, dy, dheight; /* dy and dheight are optional */
148} gx_cmd_rect_short;
149#define cmd_min_short (-128)
150#define cmd_max_short 127
151typedef struct {
152 unsigned dx : 4;
153 unsigned dy : 4;
154} gx_cmd_rect_tiny;
155#define cmd_min_tiny (-8)
156#define cmd_max_tiny 7
157
158/* Define the prefix on each command run in the writing buffer. */
159typedef struct cmd_prefix_s cmd_prefix;
160struct cmd_prefix_s {
161 cmd_prefix *next;
162 uint size;
163};
164
165/* Define the entries in the block file. */
166typedef struct cmd_block_s {
167 int band;
168 long pos; /* starting position in cfile */
169} cmd_block;
170
171/* Remember the current state of one band when writing or reading. */
172struct gx_clist_state_s {
173 gx_color_index color0, color1; /* most recent colors */
174 tile_slot *tile; /* most recent tile */
175 gs_int_point tile_phase; /* most recent tile phase */
176 gx_cmd_rect rect; /* most recent rectangle */
177 /* Following are only used when writing */
178 cmd_prefix *head, *tail; /* list of commands for band */
179};
180private tile_slot no_tile = { ~0L };
181
182/* The initial values for a band state */
183private gx_clist_state cls_initial =
184 { gx_no_color_index, gx_no_color_index, &no_tile,
185 { 0, 0 }, { 0, 0, 0, 0 },
186 0, 0
187 };
188
189/* Define the size of the command buffer used for reading. */
190/* This is needed to split up very large copy_ operations. */
191#define cbuf_size 500
192
193/* Initialize the device state */
194private void clist_init_tiles(P1(gx_device_clist *));
195private int
196clist_open(gx_device *dev)
197{ /*
198 * The buffer area (data, data_size) holds a tile cache and a
199 * set of block range bit masks when both writing and reading.
200 * The rest of the space is used for
201 * the command buffer and band state bookkeeping when writing,
202 * and for the rendering buffer (image device) when reading.
203 * For the moment, we divide the space up arbitrarily.
204 */
205 byte *data = cdev->data;
206 uint size = cdev->data_size;
207#define alloc_data(n) data += (n), size -= (n)
208 gx_device *target = cdev->target;
209 int raster, nbands, band;
210 gx_clist_state *states;
211 uint state_size;
212 cdev->ymin = cdev->ymax = -1; /* render_init not done yet */
213 cdev->tile_data = data;
214 cdev->tile_data_size = (size / 5) & -4; /* arbitrary! */
215 alloc_data(cdev->tile_data_size);
216 raster = (((target->width * target->color_info.depth + 31) >> 5) << 2) + sizeof(byte *);
217 cdev->band_height = size / (uint)raster;
218 nbands = target->height / cdev->band_height + 1;
219 cdev->nbands = nbands;
220#ifdef DEBUG
221if ( gs_debug['l'] | gs_debug['L'] )
222 dprintf4("[l]width=%d, raster=%d, band_height=%d, nbands=%d\n",
223 target->width, raster, cdev->band_height, cdev->nbands);
224#endif
225 state_size = nbands * sizeof(gx_clist_state);
226 if ( state_size > size / 2 )
227 return -1; /* not enough room */
228 cdev->mdev.base = data;
229 cdev->states = states = (gx_clist_state *)data;
230 alloc_data(state_size);
231 cdev->cbuf = data;
232 cdev->cnext = data;
233 cdev->cend = data + size;
234 cdev->ccls = 0;
235 for ( band = 0; band < nbands; band++, states++ )
236 *states = cls_initial;
237#undef alloc_data
238 cdev->tile_band_mask_size = (nbands + 31) / 32 * 4;
239 cdev->tile_max_size = cdev->tile_data_size -
240 (sizeof(tile_hash) * 2 + sizeof(tile_slot) +
241 cdev->tile_band_mask_size);
242 clist_init_tiles(cdev);
243 return 0;
244}
245
246/* (Re)initialize the tile cache. */
247private void
248clist_init_tiles(register gx_device_clist *cldev)
249{ gx_clist_state *pcls;
250 int i, hc;
251 cldev->tile_slot_size =
252 sizeof(tile_slot) + cldev->tile_band_mask_size +
253 cldev->tile.raster * cldev->tile.size.y;
254 cldev->tile_max_count = cldev->tile_data_size /
255 (sizeof(tile_hash) * 3 /*(worst case)*/ + cldev->tile_slot_size);
256 hc = (cldev->tile_max_count - 1) * 2;
257 while ( (hc + 1) & hc ) hc |= hc >> 1; /* make mask */
258 if ( hc >= cldev->tile_max_count * 3 ) hc >>= 1;
259 if ( hc > 255 ) /* slot index in set_tile is only 1 byte */
260 { hc = 255;
261 if ( cldev->tile_max_count > 200 )
262 cldev->tile_max_count = 200;
263 }
264 cldev->tile_hash_mask = hc;
265 hc++; /* make actual size */
266#ifdef DEBUG
267if ( gs_debug['l'] | gs_debug['L'] )
268 dprintf5("[l]tile.size=%dx%d, slot_size=%d, max_count=%d, hc=%d\n",
269 cldev->tile.size.x, cldev->tile.size.y,
270 cldev->tile_slot_size, cldev->tile_max_count, hc);
271#endif
272 cldev->tile_hash_table =
273 (tile_hash *)(cldev->tile_data + cldev->tile_data_size) - hc;
274 cldev->tile_count = 0;
275 memset(cldev->tile_data, 0, cldev->tile_data_size);
276 memset(cldev->tile_hash_table, -1, hc * sizeof(tile_hash));
277 for ( i = 0, pcls = cldev->states; i < cldev->nbands; i++, pcls++ )
278 pcls->tile = &no_tile;
279 count_add1(cmd_tile_reset);
280}
281
282/* Forward the non-displaying operations to the target device. */
283private void
284clist_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
285{ (*cdev->target->procs->get_initial_matrix)(dev, pmat);
286}
287private gx_color_index
288clist_map_rgb_color(gx_device *dev, gx_color_value red, gx_color_value green,
289 gx_color_value blue)
290{ return (*cdev->target->procs->map_rgb_color)(dev, red, green, blue);
291}
292private int
293clist_map_color_rgb(gx_device *dev, gx_color_index color,
294 gx_color_value rgb[3])
295{ return (*cdev->target->procs->map_color_rgb)(dev, color, rgb);
296}
297private int
298clist_get_props(gx_device *dev, gs_prop_item *plist)
299{ gx_device *tdev = cdev->target;
300 return (*tdev->procs->get_props)(tdev, plist);
301}
302private int
303clist_put_props(gx_device *dev, gs_prop_item *plist, int count)
304{ gx_device *tdev = cdev->target;
305 return (*tdev->procs->put_props)(tdev, plist, count);
306}
307
308/* Print a bitmap for tracing */
309#ifdef DEBUG
310private void
311cmd_print_bits(byte *data, int height, int raster)
312{ int i, j;
313 for ( i = 0; i < height; i++ )
314 { byte *row = data + i * raster;
315 dprintf("[L]");
316 for ( j = 0; j < raster; j++ )
317 dprintf1(" %02x", row[j]);
318 dputc('\n');
319 }
320}
321#else
322# define cmd_print_bits(data, height, raster)
323#endif
324
325/* ------ Writing ------ */
326
327/* Utilities */
328
329#define cmd_set_rect(rect)\
330 ((rect).x = x, (rect).y = y,\
331 (rect).width = width, (rect).height = height)
332
333#define clist_write(f, str, len)\
334 fwrite(str, 1, len, f)
335
336/* Write out the buffered commands, and reset the buffer. */
337private void
338cmd_write_buffer(gx_device_clist *cldev)
339{ FILE *cfile = cldev->cfile;
340 FILE *bfile = cldev->bfile;
341 int nbands = cldev->nbands;
342 gx_clist_state *pcls;
343 int band;
344 for ( band = 0, pcls = cldev->states; band < nbands; band++, pcls++ )
345 { cmd_prefix *cp = pcls->head;
346 if ( cp != 0 )
347 { cmd_block cb;
348 cb.band = band;
349 cb.pos = ftell(cfile);
350#ifdef DEBUG
351if ( gs_debug['l'] | gs_debug['L'] )
352 dprintf2("[l]writing for band %d at %ld\n",
353 band, cb.pos);
354#endif
355 clist_write(bfile, (byte *)&cb, sizeof(cb));
356 for ( ; cp != 0; cp = cp->next )
357 clist_write(cfile, (byte *)(cp + 1), cp->size);
358 pcls->head = pcls->tail = 0;
359 fputc(cmd_opv_end_run, cfile);
360 }
361 }
362 cldev->cnext = cldev->cbuf;
363 cldev->ccls = 0;
364}
365
366/* Add a command to the appropriate band list, */
367/* and allocate space for its data. */
368/* Return the pointer to the data area. */
369private byte *
370cmd_put_op(gx_device_clist *cldev, gx_clist_state *pcls, uint size)
371{ byte *dp = cldev->cnext;
372#ifdef DEBUG
373if ( gs_debug['L'] )
374 dprintf3("[L]band %d: size=%u, left=%d",
375 (int)(pcls - cldev->states), size, (int)(cldev->cend - dp));
376#endif
377 if ( size + (sizeof(cmd_prefix) + 4) > cldev->cend - dp )
378 { cmd_write_buffer(cldev);
379 return cmd_put_op(cldev, pcls, size);
380 }
381 if ( cldev->ccls == pcls )
382 { /* We're adding another command for the same band. */
383 /* Tack it onto the end of the previous one. */
384 pcls->tail->size += size;
385 }
386 else
387 { cmd_prefix *cp = (cmd_prefix *)(dp + (((byte *)0 - dp) & 3));
388 dp = (byte *)(cp + 1);
389 if ( pcls->tail != 0 ) pcls->tail->next = cp;
390 else pcls->head = cp;
391 pcls->tail = cp;
392 cldev->ccls = pcls;
393 cp->next = 0;
394 cp->size = size;
395 }
396 cldev->cnext = dp + size;
397 return dp;
398}
399
400/* We store all short quantities little-endian. */
401/* This is OK, because we read them back little-endian explicitly. */
402#define cmd_putw(w, dp)\
403 (*dp = (w) & 0xff, dp[1] = (w) >> 8, dp += 2)
404
405/* Write a short bitmap. 1 <= bwidth <= 3. */
406private void
407cmd_put_short_bits(register byte *dp, register byte *data,
408 int raster, register int bwidth, register int height)
409{ while ( --height >= 0 )
410 { switch ( bwidth )
411 {
412 case 3: dp[2] = data[2];
413 case 2: dp[1] = data[1];
414 case 1: dp[0] = data[0];
415 }
416 dp += bwidth, data += raster;
417 }
418}
419
420private int
421cmd_write_rect_cmd(gx_device *dev, gx_clist_state *pcls,
422 int op, int x, int y, int width, int height)
423{ int dx = x - pcls->rect.x;
424 int dy = y - pcls->rect.y;
425 int dwidth = width - pcls->rect.width;
426 int dheight = height - pcls->rect.height;
427#define check_ranges_1()\
428 ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
429 (unsigned)(dy - rmin) <= (rmax - rmin) &&\
430 (unsigned)(dwidth - rmin) <= (rmax - rmin))
431#define check_ranges()\
432 (check_ranges_1() &&\
433 (unsigned)(dheight - rmin) <= (rmax - rmin))
434#define rmin cmd_min_tiny
435#define rmax cmd_max_tiny
436 cmd_set_rect(pcls->rect);
437 if ( dheight == 0 && check_ranges_1() )
438 { byte *dp = cmd_put_op(cdev, pcls, 2);
439 count_op(*dp = op + 0x20 + dwidth - rmin);
440 dp[1] = (dx << 4) + dy - (rmin * 0x11);
441 }
442#undef rmin
443#undef rmax
444#define rmin cmd_min_short
445#define rmax cmd_max_short
446 else if ( check_ranges() )
447 { int dh = dheight - cmd_min_tiny;
448 byte *dp;
449 if ( (unsigned)dh <= cmd_max_tiny - cmd_min_tiny && dh != 0 &&
450 dy == 0
451 )
452 { op += dh;
453 dp = cmd_put_op(cdev, pcls, 3);
454 }
455 else
456 { dp = cmd_put_op(cdev, pcls, 5);
457 dp[3] = dy - rmin;
458 dp[4] = dheight - rmin;
459 }
460 count_op(*dp = op + 0x10);
461 dp[1] = dx - rmin;
462 dp[2] = dwidth - rmin;
463 }
464 else
465 { byte *dp = cmd_put_op(cdev, pcls, 1 + sizeof(pcls->rect));
466 count_op(*dp = op);
467 memcpy(dp + 1, &pcls->rect, sizeof(pcls->rect));
468 }
469 return 0;
470}
471
472private void
473cmd_put_color(gx_device *dev, gx_clist_state *pcls,
474 int op, gx_color_index color)
475{ if ( (long)color >= -1 && (long)color <= 13 )
476 count_op(*cmd_put_op(cdev, pcls, 1) = op + (int)color + 2);
477 else
478 { byte *dp = cmd_put_op(cdev, pcls, 1 + sizeof(color));
479 count_op(*dp = op);
480 memcpy(dp + 1, &color, sizeof(color));
481 }
482}
483private void
484cmd_set_colors(gx_device *dev, gx_clist_state *pcls,
485 gx_color_index color0, gx_color_index color1)
486{ if ( color0 != pcls->color0 )
487 { cmd_put_color(dev, pcls, cmd_op_set_color0, color0);
488 pcls->color0 = color0;
489 }
490 if ( color1 != pcls->color1 )
491 { cmd_put_color(dev, pcls, cmd_op_set_color1, color1);
492 pcls->color1 = color1;
493 }
494}
495
496/* Driver interface */
497
498/* Macros for dividing up a single call into bands */
499#define BEGIN_RECT\
500 { int yend = y + height;\
501 int band_height = cdev->band_height;\
502 do\
503 { int band = y / band_height;\
504 gx_clist_state *pcls = cdev->states + band;\
505 height = band_height - y % band_height;\
506 if ( yend - y < height ) height = yend - y;\
507 {
508#define END_RECT\
509 }\
510 y += height;\
511 }\
512 while ( y < yend );\
513 }
514
515private int
516clist_fill_rectangle(gx_device *dev, int x, int y, int width, int height,
517 gx_color_index color)
518{ BEGIN_RECT
519 if ( color != pcls->color1 )
520 cmd_set_colors(dev, pcls, pcls->color0, color);
521 cmd_write_rect_cmd(dev, pcls, cmd_op_fill_rect, x, y, width, height);
522 END_RECT
523 return 0;
524}
525
526/* Compare unequal tiles. Return -1 if unrelated, */
527/* or 2<=N<=50 for the size of the delta encoding. */
528private int
529tile_diff(byte *old_data, byte *new_data, uint tsize, byte _ss *delta)
530{ register ushort *old2, *new2;
531 register ushort diff;
532 int count;
533 register int i;
534 byte _ss *pd;
535 if ( tsize > 128 ) return -1;
536 old2 = (ushort *)old_data;
537 new2 = (ushort *)new_data;
538 count = 0;
539 pd = delta + 2; /* skip slot index */
540 for ( i = 0; i < tsize; i += 2, old2++, new2++ )
541 if ( (diff = *new2 ^ *old2) != 0 )
542#if arch_is_big_endian
543# define i_hi 0
544# define b_0(w) ((w) >> 8)
545# define b_1(w) ((byte)(w))
546#else
547# define i_hi 1
548# define b_0(w) ((byte)(w))
549# define b_1(w) ((w) >> 8)
550#endif
551 { if ( count == 16 ) return -1;
552 if ( diff & 0xff00 )
553 { if ( diff & 0xff )
554 *pd++ = 0x80 + i,
555 *pd++ = b_0(diff),
556 *pd++ = b_1(diff);
557 else
558 *pd++ = i + i_hi, *pd++ = diff >> 8;
559 }
560 else /* know diff != 0 */
561 *pd++ = i + (1 - i_hi), *pd++ = (byte)diff;
562 count++;
563 }
564#undef b_0
565#undef b_1
566#undef i_hi
567 delta[0] = (byte)cmd_op_delta_tile_bits + count - 1;
568 return pd - delta;
569}
570
571/* Handle changing tiles for clist_tile_rectangle. */
572/* We put this in a separate routine, even though it is called only once, */
573/* to avoid cluttering up the main-line case of tile_rectangle. */
574private int
575clist_change_tile(gx_device_clist *cldev, gx_clist_state *pcls,
576 gx_bitmap *tile)
577{ uint tile_size = tile->raster * tile->size.y;
578 tile_slot *old_tile, *new_tile;
579 int slot_index;
580 /* Look up the tile in the cache. */
581top: { gx_bitmap_id id = tile->id;
582 uint probe = (uint)(id >> 16) + (uint)(id);
583 old_tile = pcls->tile;
584 for ( ; ; probe += 25 /* semi-random odd # */ )
585 { tile_hash *hptr = cldev->tile_hash_table +
586 (probe & cldev->tile_hash_mask);
587 if ( (slot_index = hptr->slot_index) < 0 ) /* empty entry */
588 { /* Must change tiles. Check whether the */
589 /* tile size has changed. */
590 if ( tile->size.x != cldev->tile.size.x ||
591 tile->size.y != cldev->tile.size.y
592 )
593 { if ( tile->raster !=
594 ((tile->size.x + 31) >> 5) << 2 ||
595 tile_size > cldev->tile_max_size
596 )
597 return -1;
598 cldev->tile = *tile; /* reset size, raster */
599 clist_init_tiles(cldev);
600 goto top;
601 }
602 if ( cldev->tile_count == cldev->tile_max_count )
603 { /* Punt. */
604 clist_init_tiles(cldev);
605 goto top;
606 }
607 hptr->slot_index = slot_index =
608 cldev->tile_count++;
609 new_tile = tile_slot_ptr(cldev, slot_index);
610 new_tile->id = id;
611 memcpy(ts_bits(cldev, new_tile), tile->data, tile_size);
612 count_add1(cmd_tile_added);
613#ifdef DEBUG
614if ( gs_debug['L'] )
615 dprintf3("[L]adding tile %d, hash=%d, id=%lx\n",
616 slot_index,
617 (int)(hptr - cldev->tile_hash_table),
618 id);
619#endif
620 break;
621 }
622 new_tile = tile_slot_ptr(cldev, slot_index);
623 if ( new_tile->id == id )
624 { count_add1(cmd_tile_found);
625#ifdef DEBUG
626if ( gs_debug['L'] )
627 dprintf1("[L]found tile %d\n", slot_index);
628#endif
629 break;
630 }
631 }
632 }
633 /* Check whether this band knows about this tile yet. */
634 { int band_index = pcls - cldev->states;
635 byte pmask = 1 << (band_index & 7);
636 byte *ppresent = ts_mask(new_tile) + (band_index >> 3);
637 if ( *ppresent & pmask )
638 { /* Tile is known, just put out the index. */
639 byte *dp = cmd_put_op(cldev, pcls, 2);
640 count_op(*dp = cmd_op_set_tile_index);
641 dp[1] = slot_index;
642 }
643 else
644 { /* Tile is not known, put out the bits. Use a */
645 /* delta encoding or a short encoding if possible. */
646 byte *new_data = ts_bits(cldev, new_tile);
647 byte *dp;
648 byte delta[2+16*3];
649 int diff;
650 *ppresent |= pmask;
651 if ( old_tile != &no_tile &&
652 (diff = tile_diff(ts_bits(cldev, old_tile), new_data, tile_size, delta)) >= 0
653 )
654 { /* Use delta representation */
655 dp = cmd_put_op(cldev, pcls, diff);
656 count_op(delta[0]);
657 delta[1] = slot_index;
658 memcpy(dp, delta, diff);
659 count_add(cmd_delta_tile_count, diff - 2);
660 }
661 else
662 { if ( old_tile == &no_tile )
663 { byte *dp = cmd_put_op(cldev, pcls,
664 1 + sizeof(cldev->tile.size));
665 count_op(*dp = (byte)cmd_opv_set_tile_size);
666 memcpy(dp + 1, &cldev->tile.size,
667 sizeof(cldev->tile.size));
668 }
669 if ( tile->size.x <= 16 )
670 { dp = cmd_put_op(cldev, pcls, 2 + (tile_size >> 1));
671 cmd_put_short_bits(dp + 2, new_data, tile->raster, 2, tile->size.y);
672 count_add(cmd_tile_count, tile_size >> 1);
673 }
674 else
675 { dp = cmd_put_op(cldev, pcls, 2 + tile_size);
676 memcpy(dp + 2, new_data, tile_size);
677 count_add(cmd_tile_count, tile_size);
678 }
679 count_op(*dp = (byte)cmd_op_set_tile_bits);
680 dp[1] = slot_index;
681 }
682 }
683 }
684 pcls->tile = new_tile;
685 return 0;
686}
687private int
688clist_tile_rectangle(gx_device *dev, gx_bitmap *tile, int x, int y,
689 int width, int height, gx_color_index color0, gx_color_index color1,
690 int px, int py)
691{ BEGIN_RECT
692 if ( tile->id != pcls->tile->id )
693 { if ( clist_change_tile(cdev, pcls, tile) < 0 )
694 return gx_default_tile_rectangle(dev, tile, x, y, width, height, color0, color1, px, py);
695 }
696 if ( color0 != pcls->color0 || color1 != pcls->color1 )
697 cmd_set_colors(dev, pcls, color0, color1);
698 if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
699 { byte *dp = cmd_put_op(cdev, pcls, 1 + sizeof(pcls->tile_phase));
700 count_op(*dp = (byte)cmd_opv_set_tile_phase);
701 pcls->tile_phase.x = px;
702 pcls->tile_phase.y = py;
703 memcpy(dp + 1, &pcls->tile_phase, sizeof(pcls->tile_phase));
704 }
705 cmd_write_rect_cmd(dev, pcls, cmd_op_tile_rect, x, y, width, height);
706 END_RECT
707 return 0;
708}
709
710private int
711clist_copy_mono(gx_device *dev,
712 byte *data, int data_x, int raster, gx_bitmap_id id,
713 int x, int y, int width, int height,
714 gx_color_index color0, gx_color_index color1)
715{ int y0 = y;
716 BEGIN_RECT
717 gx_cmd_rect rect;
718 uint dsize;
719 int bwidth;
720 byte *row = data + (y - y0) * raster;
721 byte *dp;
722 if ( color0 != pcls->color0 || color1 != pcls->color1 )
723 cmd_set_colors(dev, pcls, color0, color1);
724 cmd_set_rect(rect);
725 if ( width >= 2 && (bwidth = (width + (data_x & 7) + 7) >> 3) <= 3 &&
726 height <= min(255, (cbuf_size - (1 + 2 * 2 + 2)) / bwidth)
727 )
728 { dsize = height * bwidth;
729 dp = cmd_put_op(cdev, pcls, 1 + 2 * 2 + 2 + dsize);
730 count_op(*dp++ = (byte)cmd_op_copy_mono + (data_x & 7) + 1);
731 cmd_putw(x, dp);
732 cmd_putw(y, dp);
733 *dp++ = width;
734 *dp++ = height;
735 row += data_x >> 3;
736 cmd_put_short_bits(dp, row, raster, bwidth, height);
737 }
738 else
739 { dsize = height * raster;
740 if ( dsize > cbuf_size )
741 { /* We have to split it into pieces. */
742 if ( height > 1 )
743 { int h2 = height >> 1;
744 clist_copy_mono(dev, data, data_x, raster,
745 gx_no_bitmap_id, x, y, width, h2,
746 color0, color1);
747 return clist_copy_mono(dev, data + h2 * raster,
748 data_x, raster, gx_no_bitmap_id,
749 x, y + h2, width, height - h2,
750 color0, color1);
751 }
752 /* Split a single (very long) row. */
753 { int w2 = width >> 1;
754 clist_copy_mono(dev, data, data_x, raster,
755 gx_no_bitmap_id, x, y, w2, 1,
756 color0, color1);
757 return clist_copy_mono(dev, data, data_x + w2,
758 raster, gx_no_bitmap_id, x + w2, y,
759 width - w2, 1, color0, color1);
760 }
761 }
762 dp = cmd_put_op(cdev, pcls, 1 + sizeof(rect) + 4 + dsize);
763 count_op(*dp++ = (byte)cmd_op_copy_mono);
764 memcpy(dp, (byte *)&rect, sizeof(rect));
765 dp += sizeof(rect);
766 cmd_putw(data_x, dp);
767 cmd_putw(raster, dp);
768 memcpy(dp, row, dsize);
769 }
770 pcls->rect = rect;
771 count_add(cmd_copy_count, dsize);
772 END_RECT
773 return 0;
774}
775
776private int
777clist_copy_color(gx_device *dev,
778 byte *data, int data_x, int raster, gx_bitmap_id id,
779 int x, int y, int width, int height)
780{ int y0 = y;
781 BEGIN_RECT
782 gx_cmd_rect rect;
783 uint dsize = height * raster;
784 byte *dp;
785 if ( dsize > cbuf_size )
786 { /* We have to split it into pieces. */
787 if ( height > 1 )
788 { int h2 = height >> 1;
789 clist_copy_color(dev, data, data_x, raster,
790 gx_no_bitmap_id, x, y, width, h2);
791 return clist_copy_color(dev, data + h2 * raster, gx_no_bitmap_id,
792 data_x, raster, x, y + h2, width, height - h2);
793 }
794 /* Split a single (very long) row. */
795 { int w2 = width >> 1;
796 clist_copy_color(dev, data, data_x, raster,
797 gx_no_bitmap_id, x, y, w2, 1);
798 return clist_copy_color(dev, data, data_x + w2,
799 raster, gx_no_bitmap_id, x + w2, y,
800 width - w2, 1);
801 }
802
803 }
804 cmd_set_rect(rect);
805 dp = cmd_put_op(cdev, pcls, 1 + sizeof(rect) + 4 + dsize);
806 count_op(*dp++ = (byte)cmd_op_copy_color);
807 memcpy(dp, (byte *)&rect, sizeof(rect));
808 pcls->rect = rect;
809 dp += sizeof(rect);
810 cmd_putw(data_x, dp);
811 cmd_putw(raster, dp);
812 memcpy(dp, data + (y - y0) * raster, dsize);
813 END_RECT
814 return 0;
815}
816
817/* ------ Reading/rendering ------ */
818
819/* Clean up after rendering a page. */
820private int
821clist_output_page(gx_device *dev, int num_copies, int flush)
822{ if ( flush )
823 { rewind(cdev->cfile);
824 rewind(cdev->bfile);
825 cdev->bfile_end_pos = 0;
826 }
827 else
828 { fseek(cdev->cfile, 0L, SEEK_END);
829 fseek(cdev->bfile, 0L, SEEK_END);
830 }
831 return clist_open(dev); /* reinitialize */
832}
833
834private int clist_render_init(P1(gx_device_clist *));
835private int clist_render(P3(gx_device_clist *, gx_device *, int));
836
837/* Copy scan lines to the client. This is where rendering gets done. */
838private int
839clist_get_bits(gx_device *dev, int start_y,
840 byte *str, uint size, int pad_to_word)
841{ int y = start_y;
842 byte *dest = str;
843 gx_device_memory *mdev = &cdev->mdev;
844 uint bytes_per_line;
845 uint count, left;
846 /* Initialize for rendering if we haven't done so yet. */
847 if ( cdev->ymin < 0 )
848 clist_render_init(cdev);
849 bytes_per_line = gx_device_bytes_per_scan_line((gx_device *)mdev,
850 pad_to_word);
851 count = min(size / bytes_per_line,
852 cdev->target->height - start_y);
853 /* Render bands and copy them incrementally. */
854 for ( left = count; left; )
855 { int n;
856 if ( !(y >= cdev->ymin && y < cdev->ymax) )
857 { int band = y / mdev->height;
858 int code;
859 rewind(cdev->bfile);
860 (*mdev->procs->open_device)((gx_device *)mdev); /* reinitialize */
861 code = clist_render(cdev, (gx_device *)mdev, band);
862 if ( code < 0 ) return code;
863 cdev->ymin = band * mdev->height;
864 cdev->ymax = cdev->ymin + mdev->height;
865 }
866 n = min(cdev->ymax - y, left);
867 (*mdev->procs->get_bits)((gx_device *)mdev,
868 y - cdev->ymin, dest,
869 bytes_per_line * n, pad_to_word);
870 y += n, dest += bytes_per_line * n, left -= n;
871 }
872 return count;
873}
874
875#undef cdev
876
877/* Initialize for reading. */
878private int
879clist_render_init(gx_device_clist *cdev)
880{ gx_device *target = cdev->target;
881 byte *base = cdev->mdev.base; /* save */
882 int depth = target->color_info.depth;
883 uint raster = ((target->width * depth + 31) >> 5) << 2;
884 gx_device_memory *mdev = gdev_mem_device_for_bits(depth);
885 if ( mdev == 0 )
886 return_error(gs_error_rangecheck);
887 cmd_write_buffer(cdev); /* flush buffer */
888 /* Write the terminating entry in the block file. */
889 /* Note that because of copypage, there may be many such entries. */
890 { cmd_block cb;
891 cb.band = -1;
892 cb.pos = ftell(cdev->cfile);
893 clist_write(cdev->bfile, (byte *)&cb, sizeof(cb));
894 cdev->bfile_end_pos = ftell(cdev->bfile);
895 }
896 cdev->mdev = *mdev;
897 cdev->mdev.base = base; /* restore */
898 (*target->procs->get_initial_matrix)(target, &cdev->mdev.initial_matrix);
899 cdev->mdev.width = target->width;
900 cdev->mdev.height = cdev->band_height;
901 cdev->mdev.raster = raster;
902 cdev->ymin = cdev->ymax = 0;
903#ifdef DEBUG
904if ( gs_debug['l'] | gs_debug['L'] )
905 { int ci, cj;
906 dprintf3("[l]counts: tile = %ld, copy = %ld, delta = %ld\n",
907 cmd_tile_count, cmd_copy_count, cmd_delta_tile_count);
908 dprintf3(" reset = %ld, found = %ld, added = %ld\n",
909 cmd_tile_reset, cmd_tile_found, cmd_tile_added);
910 for ( ci = 0; ci < 0x100; ci += 0x10 )
911 { dprintf1("[l] %s =", cmd_op_names[ci >> 4]);
912 for ( cj = ci; cj < ci + 0x10; cj++ )
913 dprintf1(" %ld", cmd_op_counts[cj]);
914 dputs("\n");
915 }
916 }
917#endif
918 return 0;
919}
920
921/* Render one band to a specified target device. */
922#define assign_getw(var, p)\
923 (var = *p + ((uint)p[1] << 8), p += 2)
924typedef byte _ss *cb_ptr;
925private void clist_read(P3(FILE *, byte *, uint));
926private cb_ptr clist_read_short_bits(P6(FILE *, byte *, int, int, cb_ptr, cb_ptr));
927private int
928clist_render(gx_device_clist *cdev, gx_device *tdev, int band)
929{ byte cbuf[cbuf_size];
930 byte bits[4 * 255]; /* for short copy_mono bits */
931 register cb_ptr cbp;
932 cb_ptr cb_limit;
933 cb_ptr cb_end;
934 FILE *file = cdev->cfile;
935 FILE *bfile = cdev->bfile;
936 int y0 = band * cdev->band_height;
937 gx_clist_state state;
938 gx_bitmap state_tile;
939 uint tile_bits_size; /* size of bits of each tile */
940 gs_int_point tile_phase;
941 cmd_block b_this;
942 long pos;
943 uint left;
944#define cmd_read_var(ptr, cbp)\
945 memcpy(ptr, cbp, sizeof(*ptr)),\
946 cbp += sizeof(*ptr)
947#define cmd_read(ptr, vsize, cbp)\
948 if ( cb_end - cbp >= vsize )\
949 memcpy(ptr, cbp, vsize), cbp += vsize;\
950 else\
951 { uint cleft = cb_end - cbp;\
952 memcpy(ptr, cbp, cleft); vsize -= cleft;\
953 clist_read(file, ptr + cleft, vsize);\
954 cbp = cb_end;\
955 }
956#define cmd_read_short_bits(ptr, bw, ht, cbp)\
957 cbp = clist_read_short_bits(file, ptr, bw, ht, cbp, cb_end)
958 state = cls_initial;
959 state_tile.id = 0;
960 tile_phase.x = tile_phase.y = 0;
961trd: clist_read(bfile, (byte *)&b_this, sizeof(b_this));
962top: /* Find the next run of commands for this band. */
963 if ( b_this.band < 0 && ftell(bfile) == cdev->bfile_end_pos )
964 return 0; /* end of bfile */
965 if ( b_this.band != band ) goto trd;
966 pos = b_this.pos;
967 clist_read(bfile, (byte *)&b_this, sizeof(b_this));
968 fseek(file, pos, SEEK_SET);
969 left = (uint)(b_this.pos - pos);
970 cb_limit = cbuf + (cbuf_size - cmd_largest_size);
971 cb_end = cbuf + cbuf_size;
972 cbp = cb_end;
973 for ( ; ; )
974 { int op;
975 uint bytes;
976 int data_x, raster;
977 int code;
978 cb_ptr source;
979 gx_color_index _ss *pcolor;
980 /* Make sure the buffer contains a full command. */
981 if ( cbp > cb_limit )
982 { uint nread;
983 memcpy(cbuf, cbp, cb_end - cbp);
984 cbp = cbuf + (cb_end - cbp);
985 nread = cb_end - cbp;
986 if ( nread > left ) nread = left;
987 clist_read(file, cbp, nread);
988 cb_end = cbp + nread;
989 cbp = cbuf;
990 left -= nread;
991 if ( cb_limit > cb_end ) cb_limit = cb_end;
992 }
993 op = *cbp++;
994#ifdef DEBUG
995if ( gs_debug['L'] )
996 dprintf2("[L]%s %d:\n", cmd_op_names[op >> 4], op & 0xf);
997#endif
998 switch ( op >> 4 )
999 {
1000 case cmd_op_misc >> 4:
1001 switch ( op )
1002 {
1003 case cmd_opv_end_run:
1004 goto top;
1005 case cmd_opv_set_tile_size:
1006 cmd_read_var(&state_tile.size, cbp);
1007 state_tile.raster = ((state_tile.size.x + 31) >> 5) << 2;
1008 /* We can't actually know the rep_size, */
1009 /* so we play it safe. */
1010 state_tile.rep_width = state_tile.size.x;
1011 state_tile.rep_height = state_tile.size.y;
1012 cdev->tile_slot_size = tile_bits_size =
1013 state_tile.raster * state_tile.size.y;
1014 break;
1015 case cmd_opv_set_tile_phase:
1016 cmd_read_var(&state.tile_phase, cbp);
1017 break;
1018 default:
1019 goto bad_op;
1020 }
1021 tile_phase.x = state.tile_phase.x % state_tile.size.x;
1022 tile_phase.y = (state.tile_phase.y + y0) % state_tile.size.y;
1023 continue;
1024 case cmd_op_set_color0 >> 4:
1025 pcolor = &state.color0;
1026 goto set_color;
1027 case cmd_op_set_color1 >> 4:
1028 pcolor = &state.color1;
1029set_color: if ( op & 0xf )
1030 *pcolor = (gx_color_index)(long)((op & 0xf) - 2);
1031 else
1032 cmd_read_var(pcolor, cbp);
1033 continue;
1034 case cmd_op_set_tile_index >> 4:
1035 state_tile.data = (byte *)tile_slot_ptr(cdev, *cbp);
1036 cbp++;
1037 continue;
1038 case cmd_op_copy_mono >> 4:
1039 if ( op & 0xf )
1040 { assign_getw(state.rect.x, cbp);
1041 assign_getw(state.rect.y, cbp);
1042 state.rect.width = *cbp++;
1043 state.rect.height = *cbp++;
1044 break;
1045 }
1046 /* falls through */
1047 case cmd_op_fill_rect >> 4:
1048 case cmd_op_tile_rect >> 4:
1049 case cmd_op_copy_color >> 4:
1050 cmd_read_var(&state.rect, cbp);
1051 break;
1052 case cmd_op_fill_rect_short >> 4:
1053 case cmd_op_tile_rect_short >> 4:
1054 state.rect.x += *cbp + cmd_min_short;
1055 state.rect.width += cbp[1] + cmd_min_short;
1056 if ( op & 0xf )
1057 { state.rect.height += (op & 0xf) + cmd_min_tiny;
1058 cbp += 2;
1059 }
1060 else
1061 { state.rect.y += cbp[2] + cmd_min_short;
1062 state.rect.height += cbp[3] + cmd_min_short;
1063 cbp += 4;
1064 }
1065 break;
1066 case cmd_op_fill_rect_tiny >> 4:
1067 case cmd_op_tile_rect_tiny >> 4:
1068 { int txy = *cbp++;
1069 state.rect.x += (txy >> 4) + cmd_min_tiny;
1070 state.rect.y += (txy & 0xf) + cmd_min_tiny;
1071 state.rect.width += (op & 0xf) + cmd_min_tiny;
1072 } break;
1073 case cmd_op_set_tile_bits >> 4:
1074 state_tile.data = (byte *)tile_slot_ptr(cdev, *cbp);
1075 cbp++;
1076 if ( state_tile.size.x <= 16 )
1077 { cmd_read_short_bits(state_tile.data, 2, state_tile.size.y, cbp);
1078 }
1079 else
1080 { bytes = tile_bits_size;
1081 cmd_read(state_tile.data, bytes, cbp);
1082 }
1083#ifdef DEBUG
1084if ( gs_debug['L'] )
1085 cmd_print_bits(state_tile.data, state_tile.size.y,
1086 state_tile.raster);
1087#endif
1088 continue;
1089 case cmd_op_delta_tile_bits >> 4:
1090 { byte *new_data = (byte *)tile_slot_ptr(cdev, *cbp);
1091 cbp++;
1092 memcpy(new_data, state_tile.data, tile_bits_size);
1093 state_tile.data = new_data;
1094 do
1095 { uint offset = *cbp;
1096 if ( offset < 0x80 )
1097 new_data[offset] ^= cbp[1],
1098 cbp += 2;
1099 else
1100 offset -= 0x80,
1101 new_data[offset] ^= cbp[1],
1102 new_data[offset + 1] ^= cbp[2],
1103 cbp += 3;
1104 }
1105 while ( op-- & 0xf );
1106 } continue;
1107 default:
1108bad_op: printf/*lprintf5*/("Bad op %02x band %d file pos %ld buf pos %d/%d\n",
1109 op, band, ftell(file), (int)(cbp - cbuf), (int)(cb_end - cbuf));
1110 { cb_ptr pp;
1111 for ( pp = cbuf; pp < cb_end; pp += 10 )
1112 printf/*lprintf10*/(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1113 pp[0], pp[1], pp[2], pp[3], pp[4],
1114 pp[5], pp[6], pp[7], pp[8], pp[9]);
1115 }
1116
1117 gs_exit(1);
1118 return -1;
1119 }
1120#ifdef DEBUG
1121if ( gs_debug['L'] )
1122 dprintf4("[L] x=%d y=%d w=%d h=%d\n",
1123 state.rect.x, state.rect.y, state.rect.width,
1124 state.rect.height);
1125#endif
1126 switch ( op >> 4 )
1127 {
1128 case cmd_op_fill_rect >> 4:
1129 case cmd_op_fill_rect_short >> 4:
1130 case cmd_op_fill_rect_tiny >> 4:
1131 code = (*tdev->procs->fill_rectangle)
1132 (tdev, state.rect.x, state.rect.y - y0,
1133 state.rect.width, state.rect.height, state.color1);
1134 break;
1135 case cmd_op_tile_rect >> 4:
1136 case cmd_op_tile_rect_short >> 4:
1137 case cmd_op_tile_rect_tiny >> 4:
1138 code = (*tdev->procs->tile_rectangle)
1139 (tdev, &state_tile,
1140 state.rect.x, state.rect.y - y0,
1141 state.rect.width, state.rect.height,
1142 state.color0, state.color1,
1143 tile_phase.x, tile_phase.y);
1144 break;
1145 case cmd_op_copy_mono >> 4:
1146 if ( op & 0xf )
1147 { data_x = (op & 0xf) - 1;
1148 raster = 4;
1149 cmd_read_short_bits(bits, (data_x + state.rect.width + 7) >> 3, state.rect.height, cbp);
1150 source = bits;
1151 goto copy;
1152 }
1153 /* falls through */
1154 case cmd_op_copy_color >> 4:
1155 assign_getw(data_x, cbp);
1156 assign_getw(raster, cbp);
1157 bytes = state.rect.height * raster;
1158 /* copy_mono and copy_color have ensured that */
1159 /* the bits will fit in a single buffer. */
1160 cmd_read(cbuf, bytes, cbp);
1161 source = cbuf;
1162copy:
1163#ifdef DEBUG
1164if ( gs_debug['L'] )
1165 { dprintf2("[L] data_x=%d raster=%d\n",
1166 data_x, raster);
1167 cmd_print_bits(source, state.rect.height, raster);
1168 }
1169#endif
1170 code = (op >> 4 == (byte)cmd_op_copy_mono >> 4 ?
1171 (*tdev->procs->copy_mono)
1172 (tdev, source, data_x, raster, gx_no_bitmap_id,
1173 state.rect.x, state.rect.y - y0,
1174 state.rect.width, state.rect.height,
1175 state.color0, state.color1) :
1176 (*tdev->procs->copy_color)
1177 (tdev, source, data_x, raster, gx_no_bitmap_id,
1178 state.rect.x, state.rect.y - y0,
1179 state.rect.width, state.rect.height));
1180 break;
1181 }
1182 if ( code < 0 ) return_error(code);
1183 }
1184}
1185/* The typical implementations of fread and fseek */
1186/* are extremely inefficient for small counts, */
1187/* so we use loops instead. */
1188private void
1189clist_read(FILE *f, byte *str, uint len)
1190{ switch ( len )
1191 {
1192 default: fread(str, 1, len, f); break;
1193 case 8: *str++ = (byte)getc(f);
1194 case 7: *str++ = (byte)getc(f);
1195 case 6: *str++ = (byte)getc(f);
1196 case 5: *str++ = (byte)getc(f);
1197 case 4: *str++ = (byte)getc(f);
1198 case 3: *str++ = (byte)getc(f);
1199 case 2: *str++ = (byte)getc(f);
1200 case 1: *str = (byte)getc(f);
1201 }
1202}
1203/* Read a short bitmap */
1204private cb_ptr
1205clist_read_short_bits(FILE *file, byte *data, register int bwidth, int height,
1206 cb_ptr cbp, cb_ptr cb_end)
1207{ uint bytes = bwidth * height;
1208 byte *pdata = data + bytes;
1209 byte *udata = data + (height << 2);
1210 cmd_read(data, bytes, cbp);
1211 while ( --height > 0 ) /* first row is in place already */
1212 { udata -= 4, pdata -= bwidth;
1213 switch ( bwidth )
1214 {
1215 case 3: udata[2] = pdata[2];
1216 case 2: udata[1] = pdata[1];
1217 case 1: udata[0] = pdata[0];
1218 }
1219 }
1220 return cbp;
1221}