xref: /plan9/sys/src/cmd/gs/src/gdevdbit.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 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: gdevdbit.c,v 1.11 2004/08/05 17:02:36 stefan Exp $ */
18 /* Default device bitmap copying implementation */
19 #include "gx.h"
20 #include "gpcheck.h"
21 #include "gserrors.h"
22 #include "gsbittab.h"
23 #include "gsrect.h"
24 #include "gsropt.h"
25 #include "gxdcolor.h"
26 #include "gxdevice.h"
27 #include "gxdevmem.h"
28 #include "gdevmem.h"
29 #undef mdev
30 #include "gxcpath.h"
31 
32 /* By default, implement tile_rectangle using strip_tile_rectangle. */
33 int
gx_default_tile_rectangle(gx_device * dev,const gx_tile_bitmap * tile,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1,int px,int py)34 gx_default_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
35    int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
36 			  int px, int py)
37 {
38     gx_strip_bitmap tiles;
39 
40     *(gx_tile_bitmap *) & tiles = *tile;
41     tiles.shift = tiles.rep_shift = 0;
42     return (*dev_proc(dev, strip_tile_rectangle))
43 	(dev, &tiles, x, y, w, h, color0, color1, px, py);
44 }
45 
46 /* Implement copy_mono by filling lots of small rectangles. */
47 /* This is very inefficient, but it works as a default. */
48 int
gx_default_copy_mono(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)49 gx_default_copy_mono(gx_device * dev, const byte * data,
50 	    int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
51 		     gx_color_index zero, gx_color_index one)
52 {
53     bool invert;
54     gx_color_index color;
55     gx_device_color devc;
56 
57     fit_copy(dev, data, dx, raster, id, x, y, w, h);
58     if (one != gx_no_color_index) {
59 	invert = false;
60 	color = one;
61 	if (zero != gx_no_color_index) {
62 	    int code = (*dev_proc(dev, fill_rectangle))
63 	    (dev, x, y, w, h, zero);
64 
65 	    if (code < 0)
66 		return code;
67 	}
68     } else {
69 	invert = true;
70 	color = zero;
71     }
72     set_nonclient_dev_color(&devc, color);
73     return gx_dc_default_fill_masked
74 	(&devc, data, dx, raster, id, x, y, w, h, dev, rop3_T, invert);
75 }
76 
77 /* Implement copy_color by filling lots of small rectangles. */
78 /* This is very inefficient, but it works as a default. */
79 int
gx_default_copy_color(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h)80 gx_default_copy_color(gx_device * dev, const byte * data,
81 		      int dx, int raster, gx_bitmap_id id,
82 		      int x, int y, int w, int h)
83 {
84     int depth = dev->color_info.depth;
85     byte mask;
86 
87     dev_proc_fill_rectangle((*fill));
88     const byte *row;
89     int iy;
90 
91     if (depth == 1)
92 	return (*dev_proc(dev, copy_mono)) (dev, data, dx, raster, id,
93 					    x, y, w, h,
94 				    (gx_color_index) 0, (gx_color_index) 1);
95     fit_copy(dev, data, dx, raster, id, x, y, w, h);
96     fill = dev_proc(dev, fill_rectangle);
97     mask = (byte) ((1 << depth) - 1);
98     for (row = data, iy = 0; iy < h; row += raster, ++iy) {
99 	int ix;
100 	gx_color_index c0 = gx_no_color_index;
101 	const byte *ptr = row + ((dx * depth) >> 3);
102 	int i0;
103 
104 	for (i0 = ix = 0; ix < w; ++ix) {
105 	    gx_color_index color;
106 
107 	    if (depth >= 8) {
108 		color = *ptr++;
109 		switch (depth) {
110 		    case 64:
111 			color = (color << 8) + *ptr++;
112 		    case 56:
113 			color = (color << 8) + *ptr++;
114 		    case 48:
115 			color = (color << 8) + *ptr++;
116 		    case 40:
117 			color = (color << 8) + *ptr++;
118 		    case 32:
119 			color = (color << 8) + *ptr++;
120 		    case 24:
121 			color = (color << 8) + *ptr++;
122 		    case 16:
123 			color = (color << 8) + *ptr++;
124 		}
125 	    } else {
126 		uint dbit = (-(ix + dx + 1) * depth) & 7;
127 
128 		color = (*ptr >> dbit) & mask;
129 		if (dbit == 0)
130 		    ptr++;
131 	    }
132 	    if (color != c0) {
133 		if (ix > i0) {
134 		    int code = (*fill)
135 		    (dev, i0 + x, iy + y, ix - i0, 1, c0);
136 
137 		    if (code < 0)
138 			return code;
139 		}
140 		c0 = color;
141 		i0 = ix;
142 	    }
143 	}
144 	if (ix > i0) {
145 	    int code = (*fill) (dev, i0 + x, iy + y, ix - i0, 1, c0);
146 
147 	    if (code < 0)
148 		return code;
149 	}
150     }
151     return 0;
152 }
153 
154 int
gx_no_copy_alpha(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color,int depth)155 gx_no_copy_alpha(gx_device * dev, const byte * data, int data_x,
156 	   int raster, gx_bitmap_id id, int x, int y, int width, int height,
157 		 gx_color_index color, int depth)
158 {
159     return_error(gs_error_unknownerror);
160 }
161 
162 int
gx_default_copy_alpha(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color,int depth)163 gx_default_copy_alpha(gx_device * dev, const byte * data, int data_x,
164 	   int raster, gx_bitmap_id id, int x, int y, int width, int height,
165 		      gx_color_index color, int depth)
166 {				/* This might be called with depth = 1.... */
167     if (depth == 1)
168 	return (*dev_proc(dev, copy_mono)) (dev, data, data_x, raster, id,
169 					    x, y, width, height,
170 					    gx_no_color_index, color);
171     /*
172      * Simulate alpha by weighted averaging of RGB values.
173      * This is very slow, but functionally correct.
174      */
175     {
176 	const byte *row;
177 	gs_memory_t *mem = dev->memory;
178 	int bpp = dev->color_info.depth;
179 	int ncomps = dev->color_info.num_components;
180 	uint in_size = gx_device_raster(dev, false);
181 	byte *lin;
182 	uint out_size;
183 	byte *lout;
184 	int code = 0;
185 	gx_color_value color_cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
186 	int ry;
187 
188 	fit_copy(dev, data, data_x, raster, id, x, y, width, height);
189 	row = data;
190 	out_size = bitmap_raster(width * bpp);
191 	lin = gs_alloc_bytes(mem, in_size, "copy_alpha(lin)");
192 	lout = gs_alloc_bytes(mem, out_size, "copy_alpha(lout)");
193 	if (lin == 0 || lout == 0) {
194 	    code = gs_note_error(gs_error_VMerror);
195 	    goto out;
196 	}
197 	(*dev_proc(dev, decode_color)) (dev, color, color_cv);
198 	for (ry = y; ry < y + height; row += raster, ++ry) {
199 	    byte *line;
200 	    int sx, rx;
201 
202 	    DECLARE_LINE_ACCUM_COPY(lout, bpp, x);
203 
204 	    code = (*dev_proc(dev, get_bits)) (dev, ry, lin, &line);
205 	    if (code < 0)
206 		break;
207 	    for (sx = data_x, rx = x; sx < data_x + width; ++sx, ++rx) {
208 		gx_color_index previous = gx_no_color_index;
209 		gx_color_index composite;
210 		int alpha2, alpha;
211 
212 		if (depth == 2)	/* map 0 - 3 to 0 - 15 */
213 		    alpha = ((row[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 5;
214 		else
215 		    alpha2 = row[sx >> 1],
216 			alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4);
217 	      blend:if (alpha == 15) {	/* Just write the new color. */
218 		    composite = color;
219 		} else {
220 		    if (previous == gx_no_color_index) {	/* Extract the old color. */
221 			if (bpp < 8) {
222 			    const uint bit = rx * bpp;
223 			    const byte *src = line + (bit >> 3);
224 
225 			    previous =
226 				(*src >> (8 - ((bit & 7) + bpp))) &
227 				((1 << bpp) - 1);
228 			} else {
229 			    const byte *src = line + (rx * (bpp >> 3));
230 
231 			    previous = 0;
232 			    switch (bpp >> 3) {
233 				case 8:
234 				    previous += (gx_color_index) * src++
235 					<< sample_bound_shift(previous, 56);
236 				case 7:
237 				    previous += (gx_color_index) * src++
238 					<< sample_bound_shift(previous, 48);
239 				case 6:
240 				    previous += (gx_color_index) * src++
241 					<< sample_bound_shift(previous, 40);
242 				case 5:
243 				    previous += (gx_color_index) * src++
244 					<< sample_bound_shift(previous, 32);
245 				case 4:
246 				    previous += (gx_color_index) * src++ << 24;
247 				case 3:
248 				    previous += (gx_color_index) * src++ << 16;
249 				case 2:
250 				    previous += (gx_color_index) * src++ << 8;
251 				case 1:
252 				    previous += *src++;
253 			    }
254 			}
255 		    }
256 		    if (alpha == 0) {	/* Just write the old color. */
257 			composite = previous;
258 		    } else {	/* Blend values. */
259 			gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
260 			int i;
261 
262 			(*dev_proc(dev, decode_color)) (dev, previous, cv);
263 #if arch_ints_are_short
264 #  define b_int long
265 #else
266 #  define b_int int
267 #endif
268 #define make_shade(old, clr, alpha, amax) \
269   (old) + (((b_int)(clr) - (b_int)(old)) * (alpha) / (amax))
270 			for (i=0; i<ncomps; i++)
271 			    cv[i] = make_shade(cv[i], color_cv[i], alpha, 15);
272 #undef b_int
273 #undef make_shade
274 			composite =
275 			    (*dev_proc(dev, encode_color)) (dev, cv);
276 			if (composite == gx_no_color_index) {	/* The device can't represent this color. */
277 			    /* Move the alpha value towards 0 or 1. */
278 			    if (alpha == 7)	/* move 1/2 towards 1 */
279 				++alpha;
280 			    alpha = (alpha & 8) | (alpha >> 1);
281 			    goto blend;
282 			}
283 		    }
284 		}
285 		LINE_ACCUM(composite, bpp);
286 	    }
287 	    LINE_ACCUM_COPY(dev, lout, bpp, x, rx, raster, ry);
288 	}
289       out:gs_free_object(mem, lout, "copy_alpha(lout)");
290 	gs_free_object(mem, lin, "copy_alpha(lin)");
291 	return code;
292     }
293 }
294 
295 int
gx_no_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_tile_bitmap * texture,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop)296 gx_no_copy_rop(gx_device * dev,
297 	     const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
298 	       const gx_color_index * scolors,
299 	     const gx_tile_bitmap * texture, const gx_color_index * tcolors,
300 	       int x, int y, int width, int height,
301 	       int phase_x, int phase_y, gs_logical_operation_t lop)
302 {
303     return_error(gs_error_unknownerror);	/* not implemented */
304 }
305 
306 int
gx_default_fill_mask(gx_device * orig_dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)307 gx_default_fill_mask(gx_device * orig_dev,
308 		     const byte * data, int dx, int raster, gx_bitmap_id id,
309 		     int x, int y, int w, int h,
310 		     const gx_drawing_color * pdcolor, int depth,
311 		     gs_logical_operation_t lop, const gx_clip_path * pcpath)
312 {
313     gx_device *dev;
314     gx_device_clip cdev;
315 
316     if (pcpath != 0) {
317 	gx_make_clip_path_device(&cdev, pcpath);
318 	cdev.target = orig_dev;
319 	dev = (gx_device *) & cdev;
320 	(*dev_proc(dev, open_device)) (dev);
321     } else
322 	dev = orig_dev;
323     if (depth > 1) {
324 	/****** CAN'T DO ROP OR HALFTONE WITH ALPHA ******/
325 	return (*dev_proc(dev, copy_alpha))
326 	    (dev, data, dx, raster, id, x, y, w, h,
327 	     gx_dc_pure_color(pdcolor), depth);
328     } else
329         return pdcolor->type->fill_masked(pdcolor, data, dx, raster, id,
330 				          x, y, w, h, dev, lop, false);
331 }
332 
333 /* Default implementation of strip_tile_rectangle */
334 int
gx_default_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1,int px,int py)335 gx_default_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
336    int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
337 				int px, int py)
338 {				/* Fill the rectangle in chunks. */
339     int width = tiles->size.x;
340     int height = tiles->size.y;
341     int raster = tiles->raster;
342     int rwidth = tiles->rep_width;
343     int rheight = tiles->rep_height;
344     int shift = tiles->shift;
345     gs_id tile_id = tiles->id;
346 
347     fit_fill_xy(dev, x, y, w, h);
348 
349 #ifdef DEBUG
350     if (gs_debug_c('t')) {
351 	int ptx, pty;
352 	const byte *ptp = tiles->data;
353 
354 	dlprintf4("[t]tile %dx%d raster=%d id=%lu;",
355 		  tiles->size.x, tiles->size.y, tiles->raster, tiles->id);
356 	dlprintf6(" x,y=%d,%d w,h=%d,%d p=%d,%d\n",
357 		  x, y, w, h, px, py);
358 	dlputs("");
359 	for (pty = 0; pty < tiles->size.y; pty++) {
360 	    dprintf("   ");
361 	    for (ptx = 0; ptx < tiles->raster; ptx++)
362 		dprintf1("%3x", *ptp++);
363 	}
364 	dputc('\n');
365     }
366 #endif
367 
368     if (dev_proc(dev, tile_rectangle) != gx_default_tile_rectangle) {
369 	if (shift == 0) {	/*
370 				 * Temporarily patch the tile_rectangle procedure in the
371 				 * device so we don't get into a recursion loop if the
372 				 * device has a tile_rectangle procedure that conditionally
373 				 * calls the strip_tile_rectangle procedure.
374 				 */
375 	    dev_proc_tile_rectangle((*tile_proc)) =
376 		dev_proc(dev, tile_rectangle);
377 	    int code;
378 
379 	    set_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle);
380 	    code = (*tile_proc)
381 		(dev, (const gx_tile_bitmap *)tiles, x, y, w, h,
382 		 color0, color1, px, py);
383 	    set_dev_proc(dev, tile_rectangle, tile_proc);
384 	    return code;
385 	}
386 	/* We should probably optimize this case too, for the benefit */
387 	/* of window systems, but we don't yet. */
388     } {				/*
389 				 * Note: we can't do the following computations until after
390 				 * the fit_fill_xy.
391 				 */
392 	int xoff =
393 	(shift == 0 ? px :
394 	 px + (y + py) / rheight * tiles->rep_shift);
395 	int irx = ((rwidth & (rwidth - 1)) == 0 ?	/* power of 2 */
396 		   (x + xoff) & (rwidth - 1) :
397 		   (x + xoff) % rwidth);
398 	int ry = ((rheight & (rheight - 1)) == 0 ?	/* power of 2 */
399 		  (y + py) & (rheight - 1) :
400 		  (y + py) % rheight);
401 	int icw = width - irx;
402 	int ch = height - ry;
403 	byte *row = tiles->data + ry * raster;
404 
405 	dev_proc_copy_mono((*proc_mono));
406 	dev_proc_copy_color((*proc_color));
407 	int code;
408 
409 	if (color0 == gx_no_color_index && color1 == gx_no_color_index)
410 	    proc_color = dev_proc(dev, copy_color), proc_mono = 0;
411 	else
412 	    proc_color = 0, proc_mono = dev_proc(dev, copy_mono);
413 
414 #define real_copy_tile(srcx, tx, ty, tw, th, id)\
415   code =\
416     (proc_color != 0 ?\
417      (*proc_color)(dev, row, srcx, raster, id, tx, ty, tw, th) :\
418      (*proc_mono)(dev, row, srcx, raster, id, tx, ty, tw, th, color0, color1));\
419   if (code < 0) return_error(code);\
420   return_if_interrupt(dev->memory)
421 #ifdef DEBUG
422 #define copy_tile(srcx, tx, ty, tw, th, tid)\
423   if_debug6('t', "   copy id=%lu sx=%d => x=%d y=%d w=%d h=%d\n",\
424 	    tid, srcx, tx, ty, tw, th);\
425   real_copy_tile(srcx, tx, ty, tw, th, tid)
426 #else
427 #define copy_tile(srcx, tx, ty, tw, th, id)\
428   real_copy_tile(srcx, tx, ty, tw, th, id)
429 #endif
430 	if (ch >= h) {		/* Shallow operation */
431 	    if (icw >= w) {	/* Just one (partial) tile to transfer. */
432 		copy_tile(irx, x, y, w, h,
433 			  (w == width && h == height ? tile_id :
434 			   gs_no_bitmap_id));
435 	    } else {
436 		int ex = x + w;
437 		int fex = ex - width;
438 		int cx = x + icw;
439 		ulong id = (h == height ? tile_id : gs_no_bitmap_id);
440 
441 		copy_tile(irx, x, y, icw, h, gs_no_bitmap_id);
442 		while (cx <= fex) {
443 		    copy_tile(0, cx, y, width, h, id);
444 		    cx += width;
445 		}
446 		if (cx < ex) {
447 		    copy_tile(0, cx, y, ex - cx, h, gs_no_bitmap_id);
448 		}
449 	    }
450 	} else if (icw >= w && shift == 0) {
451 	    /* Narrow operation, no shift */
452 	    int ey = y + h;
453 	    int fey = ey - height;
454 	    int cy = y + ch;
455 	    ulong id = (w == width ? tile_id : gs_no_bitmap_id);
456 
457 	    copy_tile(irx, x, y, w, ch, (ch == height ? id : gs_no_bitmap_id));
458 	    row = tiles->data;
459 	    do {
460 		ch = (cy > fey ? ey - cy : height);
461 		copy_tile(irx, x, cy, w, ch,
462 			  (ch == height ? id : gs_no_bitmap_id));
463 	    }
464 	    while ((cy += ch) < ey);
465 	} else {
466 	    /* Full operation.  If shift != 0, some scan lines */
467 	    /* may be narrow.  We could test shift == 0 in advance */
468 	    /* and use a slightly faster loop, but right now */
469 	    /* we don't bother. */
470 	    int ex = x + w, ey = y + h;
471 	    int fex = ex - width, fey = ey - height;
472 	    int cx, cy;
473 
474 	    for (cy = y;;) {
475 		ulong id = (ch == height ? tile_id : gs_no_bitmap_id);
476 
477 		if (icw >= w) {
478 		    copy_tile(irx, x, cy, w, ch,
479 			      (w == width ? id : gs_no_bitmap_id));
480 		} else {
481 		    copy_tile(irx, x, cy, icw, ch, gs_no_bitmap_id);
482 		    cx = x + icw;
483 		    while (cx <= fex) {
484 			copy_tile(0, cx, cy, width, ch, id);
485 			cx += width;
486 		    }
487 		    if (cx < ex) {
488 			copy_tile(0, cx, cy, ex - cx, ch, gs_no_bitmap_id);
489 		    }
490 		}
491 		if ((cy += ch) >= ey)
492 		    break;
493 		ch = (cy > fey ? ey - cy : height);
494 		if ((irx += shift) >= rwidth)
495 		    irx -= rwidth;
496 		icw = width - irx;
497 		row = tiles->data;
498 	    }
499 	}
500 #undef copy_tile
501 #undef real_copy_tile
502     }
503     return 0;
504 }
505 
506 int
gx_no_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop)507 gx_no_strip_copy_rop(gx_device * dev,
508 	     const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
509 		     const gx_color_index * scolors,
510 	   const gx_strip_bitmap * textures, const gx_color_index * tcolors,
511 		     int x, int y, int width, int height,
512 		     int phase_x, int phase_y, gs_logical_operation_t lop)
513 {
514     return_error(gs_error_unknownerror);	/* not implemented */
515 }
516 
517 /* ---------------- Unaligned copy operations ---------------- */
518 
519 /*
520  * Implementing unaligned operations in terms of the standard aligned
521  * operations requires adjusting the bitmap origin and/or the raster to be
522  * aligned.  Adjusting the origin is simple; adjusting the raster requires
523  * doing the operation one scan line at a time.
524  */
525 int
gx_copy_mono_unaligned(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)526 gx_copy_mono_unaligned(gx_device * dev, const byte * data,
527 	    int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
528 		       gx_color_index zero, gx_color_index one)
529 {
530     dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono);
531     uint offset = ALIGNMENT_MOD(data, align_bitmap_mod);
532     int step = raster & (align_bitmap_mod - 1);
533 
534     /* Adjust the origin. */
535     data -= offset;
536     dx += offset << 3;
537 
538     /* Adjust the raster. */
539     if (!step) {		/* No adjustment needed. */
540 	return (*copy_mono) (dev, data, dx, raster, id,
541 			     x, y, w, h, zero, one);
542     }
543     /* Do the transfer one scan line at a time. */
544     {
545 	const byte *p = data;
546 	int d = dx;
547 	int code = 0;
548 	int i;
549 
550 	for (i = 0; i < h && code >= 0;
551 	     ++i, p += raster - step, d += step << 3
552 	    )
553 	    code = (*copy_mono) (dev, p, d, raster, gx_no_bitmap_id,
554 				 x, y + i, w, 1, zero, one);
555 	return code;
556     }
557 }
558 
559 int
gx_copy_color_unaligned(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height)560 gx_copy_color_unaligned(gx_device * dev, const byte * data,
561 			int data_x, int raster, gx_bitmap_id id,
562 			int x, int y, int width, int height)
563 {
564     dev_proc_copy_color((*copy_color)) = dev_proc(dev, copy_color);
565     int depth = dev->color_info.depth;
566     uint offset = (uint) (data - (const byte *)0) & (align_bitmap_mod - 1);
567     int step = raster & (align_bitmap_mod - 1);
568 
569     /*
570      * Adjust the origin.
571      * We have to do something very special for 24-bit data,
572      * because that is the only depth that doesn't divide
573      * align_bitmap_mod exactly.  In particular, we need to find
574      * M*B + R == 0 mod 3, where M is align_bitmap_mod, R is the
575      * offset value just calculated, and B is an integer unknown;
576      * the new value of offset will be M*B + R.
577      */
578     if (depth == 24)
579 	offset += (offset % 3) *
580 	    (align_bitmap_mod * (3 - (align_bitmap_mod % 3)));
581     data -= offset;
582     data_x += (offset << 3) / depth;
583 
584     /* Adjust the raster. */
585     if (!step) {		/* No adjustment needed. */
586 	return (*copy_color) (dev, data, data_x, raster, id,
587 			      x, y, width, height);
588     }
589     /* Do the transfer one scan line at a time. */
590     {
591 	const byte *p = data;
592 	int d = data_x;
593 	int dstep = (step << 3) / depth;
594 	int code = 0;
595 	int i;
596 
597 	for (i = 0; i < height && code >= 0;
598 	     ++i, p += raster - step, d += dstep
599 	    )
600 	    code = (*copy_color) (dev, p, d, raster, gx_no_bitmap_id,
601 				  x, y + i, width, 1);
602 	return code;
603     }
604 }
605 
606 int
gx_copy_alpha_unaligned(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color,int depth)607 gx_copy_alpha_unaligned(gx_device * dev, const byte * data, int data_x,
608 	   int raster, gx_bitmap_id id, int x, int y, int width, int height,
609 			gx_color_index color, int depth)
610 {
611     dev_proc_copy_alpha((*copy_alpha)) = dev_proc(dev, copy_alpha);
612     uint offset = (uint) (data - (const byte *)0) & (align_bitmap_mod - 1);
613     int step = raster & (align_bitmap_mod - 1);
614 
615     /* Adjust the origin. */
616     data -= offset;
617     data_x += (offset << 3) / depth;
618 
619     /* Adjust the raster. */
620     if (!step) {		/* No adjustment needed. */
621 	return (*copy_alpha) (dev, data, data_x, raster, id,
622 			      x, y, width, height, color, depth);
623     }
624     /* Do the transfer one scan line at a time. */
625     {
626 	const byte *p = data;
627 	int d = data_x;
628 	int dstep = (step << 3) / depth;
629 	int code = 0;
630 	int i;
631 
632 	for (i = 0; i < height && code >= 0;
633 	     ++i, p += raster - step, d += dstep
634 	    )
635 	    code = (*copy_alpha) (dev, p, d, raster, gx_no_bitmap_id,
636 				  x, y + i, width, 1, color, depth);
637 	return code;
638     }
639 }
640