1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 /* $Id: gdevabuf.c 8250 2007-09-25 13:31:24Z giles $ */
14 /* Alpha-buffering memory devices */
15 #include "memory_.h"
16 #include "gx.h"
17 #include "gserrors.h"
18 #include "gxdevice.h"
19 #include "gxdevmem.h"		/* semi-public definitions */
20 #include "gdevmem.h"		/* private definitions */
21 
22 /* ================ Alpha devices ================ */
23 
24 /*
25  * These devices store 2 or 4 bits of alpha.  They are a hybrid of a
26  * monobit device (for color mapping) and a 2- or 4-bit device (for painting).
27  * Currently, we only use them for character rasterizing, but they might be
28  * useful for other things someday.
29  */
30 
31 /* We can't initialize the device descriptor statically very well, */
32 /* so we patch up the image2 or image4 descriptor. */
33 static dev_proc_map_rgb_color(mem_alpha_map_rgb_color);
34 static dev_proc_map_color_rgb(mem_alpha_map_color_rgb);
35 static dev_proc_map_rgb_alpha_color(mem_alpha_map_rgb_alpha_color);
36 static dev_proc_copy_alpha(mem_alpha_copy_alpha);
37 
38 void
gs_make_mem_alpha_device(gx_device_memory * adev,gs_memory_t * mem,gx_device * target,int alpha_bits)39 gs_make_mem_alpha_device(gx_device_memory * adev, gs_memory_t * mem,
40 			 gx_device * target, int alpha_bits)
41 {
42     gs_make_mem_device(adev, gdev_mem_device_for_bits(alpha_bits),
43 		       mem, 0, target);
44     /* This is a black-and-white device ... */
45     adev->color_info = gdev_mem_device_for_bits(1)->color_info;
46     /* ... but it has multiple bits per pixel ... */
47     adev->color_info.depth = alpha_bits;
48     /* ... and different color mapping. */
49     set_dev_proc(adev, map_rgb_color, mem_alpha_map_rgb_color);
50     set_dev_proc(adev, map_color_rgb, mem_alpha_map_color_rgb);
51     set_dev_proc(adev, map_rgb_alpha_color, mem_alpha_map_rgb_alpha_color);
52     set_dev_proc(adev, copy_alpha, mem_alpha_copy_alpha);
53 }
54 
55 /* Reimplement color mapping. */
56 static gx_color_index
mem_alpha_map_rgb_color(gx_device * dev,const gx_color_value cv[])57 mem_alpha_map_rgb_color(gx_device * dev, const gx_color_value cv[])
58 {
59     gx_device_memory * const mdev = (gx_device_memory *)dev;
60     gx_color_index color = gx_forward_map_rgb_color(dev, cv);
61 
62     return (color == 0 || color == gx_no_color_index ? color :
63 	    (gx_color_index) ((1 << mdev->log2_alpha_bits) - 1));
64 }
65 static int
mem_alpha_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])66 mem_alpha_map_color_rgb(gx_device * dev, gx_color_index color,
67 			gx_color_value prgb[3])
68 {
69     return
70 	gx_forward_map_color_rgb(dev,
71 				 (color == 0 ? color : (gx_color_index) 1),
72 				 prgb);
73 }
74 static gx_color_index
mem_alpha_map_rgb_alpha_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b,gx_color_value alpha)75 mem_alpha_map_rgb_alpha_color(gx_device * dev, gx_color_value r,
76 		   gx_color_value g, gx_color_value b, gx_color_value alpha)
77 {
78     gx_device_memory * const mdev = (gx_device_memory *)dev;
79     gx_color_index color;
80     gx_color_value cv[3];
81 
82     cv[0] = r; cv[1] = g; cv[2] = b;
83     color = gx_forward_map_rgb_color(dev, cv);
84 
85     return (color == 0 || color == gx_no_color_index ? color :
86 	    (gx_color_index) (alpha >> (gx_color_value_bits -
87 					mdev->log2_alpha_bits)));
88 }
89 /* Implement alpha copying. */
90 static int
mem_alpha_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)91 mem_alpha_copy_alpha(gx_device * dev, const byte * data, int data_x,
92 	   int raster, gx_bitmap_id id, int x, int y, int width, int height,
93 		     gx_color_index color, int depth)
94 {				/* Just use copy_color. */
95     return (color == 0 ?
96 	    (*dev_proc(dev, fill_rectangle)) (dev, x, y, width, height,
97 					      color) :
98 	    (*dev_proc(dev, copy_color)) (dev, data, data_x, raster, id,
99 					  x, y, width, height));
100 }
101 
102 /* ================ Alpha-buffer device ================ */
103 
104 /*
105  * This device converts graphics sampled at a higher resolution to
106  * alpha values at a lower resolution.  It does this by accumulating
107  * the bits of a band and then converting the band to alphas.
108  * In order to make this work, the client of the device must promise
109  * only to visit each band at most once, except possibly for a single
110  * scan line overlapping the adjacent band, and must promise only to write
111  * a single color into the output.  In particular, this works
112  * within a single call on gx_fill_path (if the fill loop is constrained
113  * to process bands of limited height on each pass) or a single masked image
114  * scanned in Y order, but not across such calls and not for other
115  * kinds of painting operations.
116  *
117  * We implement this device as a subclass of a monobit memory device.
118  * (We put its state in the definition of gx_device_memory just because
119  * actual subclassing introduces a lot of needless boilerplate.)
120  * We only allocate enough bits for one band.  The height of the band
121  * must be a multiple of the Y scale factor; the minimum height
122  * of the band is twice the Y scale factor.
123  *
124  * The bits in storage are actually a sliding window on the true
125  * oversampled image.  To avoid having to copy the bits around when we
126  * move the window, we adjust the mapping between the client's Y values
127  * and our own, as follows:
128  *      Client          Stored
129  *      ------          ------
130  *      y0..y0+m-1      n-m..n-1
131  *      y0+m..y0+n-1    0..n-m-1
132  * where n and m are multiples of the Y scale factor and 0 <= m <= n <=
133  * the height of the band.  (In the device structure, m is called
134  * mapped_start and n is called mapped_height.)  This allows us to slide
135  * the window incrementally in either direction without copying any bits.
136  */
137 
138 /* Procedures */
139 static dev_proc_close_device(mem_abuf_close);
140 static dev_proc_copy_mono(mem_abuf_copy_mono);
141 static dev_proc_fill_rectangle(mem_abuf_fill_rectangle);
142 static dev_proc_get_clipping_box(mem_abuf_get_clipping_box);
143 
144 /* The device descriptor. */
145 static const gx_device_memory mem_alpha_buffer_device =
146 mem_device("image(alpha buffer)", 0, 1,
147 	   gx_forward_map_rgb_color, gx_forward_map_color_rgb,
148 	 mem_abuf_copy_mono, gx_default_copy_color, mem_abuf_fill_rectangle,
149 	   gx_no_strip_copy_rop);
150 
151 /* Make an alpha-buffer memory device. */
152 /* We use abuf instead of alpha_buffer because */
153 /* gcc under VMS only retains 23 characters of procedure names. */
154 void
gs_make_mem_abuf_device(gx_device_memory * adev,gs_memory_t * mem,gx_device * target,const gs_log2_scale_point * pscale,int alpha_bits,int mapped_x)155 gs_make_mem_abuf_device(gx_device_memory * adev, gs_memory_t * mem,
156 		     gx_device * target, const gs_log2_scale_point * pscale,
157 			int alpha_bits, int mapped_x)
158 {
159     gs_make_mem_device(adev, &mem_alpha_buffer_device, mem, 0, target);
160     adev->max_fill_band = 1 << pscale->y;
161     adev->log2_scale = *pscale;
162     adev->log2_alpha_bits = alpha_bits >> 1;	/* works for 1,2,4 */
163     adev->mapped_x = mapped_x;
164     set_dev_proc(adev, close_device, mem_abuf_close);
165     set_dev_proc(adev, get_clipping_box, mem_abuf_get_clipping_box);
166     adev->color_info.anti_alias.text_bits =
167       adev->color_info.anti_alias.graphics_bits =
168 	alpha_bits;
169 }
170 
171 /* Test whether a device is an alpha-buffering device. */
172 bool
gs_device_is_abuf(const gx_device * dev)173 gs_device_is_abuf(const gx_device * dev)
174 {				/* We can't just compare the procs, or even an individual proc, */
175     /* because we might be tracing.  Instead, check the identity of */
176     /* the device name. */
177     return dev->dname == mem_alpha_buffer_device.dname;
178 }
179 
180 /* Internal routine to flush a block of the buffer. */
181 /* A block is a group of scan lines whose initial Y is a multiple */
182 /* of the Y scale and whose height is equal to the Y scale. */
183 static int
abuf_flush_block(gx_device_memory * adev,int y)184 abuf_flush_block(gx_device_memory * adev, int y)
185 {
186     gx_device *target = adev->target;
187     int block_height = 1 << adev->log2_scale.y;
188     int alpha_bits = 1 << adev->log2_alpha_bits;
189     int ddepth =
190     (adev->width >> adev->log2_scale.x) << adev->log2_alpha_bits;
191     uint draster = bitmap_raster(ddepth);
192     int buffer_y = y - adev->mapped_y + adev->mapped_start;
193     byte *bits;
194 
195     if (buffer_y >= adev->height)
196 	buffer_y -= adev->height;
197     bits = scan_line_base(adev, buffer_y);
198     {				/*
199 				 * Many bits are typically zero.  Save time by computing
200 				 * an accurate X bounding box before compressing.
201 				 * Unfortunately, in order to deal with alpha nibble swapping
202 				 * (see gsbitops.c), we can't expand the box only to pixel
203 				 * boundaries:
204 				 int alpha_mask = -1 << adev->log2_alpha_bits;
205 				 * Instead, we must expand it to byte boundaries,
206 				 */
207 	int alpha_mask = ~7;
208 	gs_int_rect bbox;
209 	int width;
210 
211 	bits_bounding_box(bits, block_height, adev->raster, &bbox);
212 	bbox.p.x &= alpha_mask;
213 	bbox.q.x = (bbox.q.x + ~alpha_mask) & alpha_mask;
214 	width = bbox.q.x - bbox.p.x;
215 	bits_compress_scaled(bits, bbox.p.x, width, block_height,
216 			     adev->raster, bits, draster, &adev->log2_scale,
217 			     adev->log2_alpha_bits);
218 	return (*dev_proc(target, copy_alpha)) (target,
219 					  bits, 0, draster, gx_no_bitmap_id,
220 					      (adev->mapped_x + bbox.p.x) >>
221 						adev->log2_scale.x,
222 						y >> adev->log2_scale.y,
223 					     width >> adev->log2_scale.x, 1,
224 					      adev->save_color, alpha_bits);
225     }
226 }
227 /* Flush the entire buffer. */
228 static int
abuf_flush(gx_device_memory * adev)229 abuf_flush(gx_device_memory * adev)
230 {
231     int y, code = 0;
232     int block_height = 1 << adev->log2_scale.y;
233 
234     for (y = 0; y < adev->mapped_height; y += block_height)
235 	if ((code = abuf_flush_block(adev, adev->mapped_y + y)) < 0)
236 	    return code;
237     adev->mapped_height = adev->mapped_start = 0;
238     return 0;
239 }
240 
241 /* Close the device, flushing the buffer. */
242 static int
mem_abuf_close(gx_device * dev)243 mem_abuf_close(gx_device * dev)
244 {
245     gx_device_memory * const mdev = (gx_device_memory *)dev;
246     int code = abuf_flush(mdev);
247 
248     if (code < 0)
249 	return code;
250     return mem_close(dev);
251 }
252 
253 /*
254  * Framework for mapping a requested imaging operation to the buffer.
255  * For now, we assume top-to-bottom transfers and use a very simple algorithm.
256  */
257 typedef struct y_transfer_s {
258     int y_next;
259     int height_left;
260     int transfer_y;
261     int transfer_height;
262 } y_transfer;
263 static void
y_transfer_init(y_transfer * pyt,gx_device * dev,int ty,int th)264 y_transfer_init(y_transfer * pyt, gx_device * dev, int ty, int th)
265 {
266     gx_device_memory * const mdev = (gx_device_memory *)dev;
267     int bh = 1 << mdev->log2_scale.y;
268 
269     if (ty < mdev->mapped_y || ty > mdev->mapped_y + mdev->mapped_height) {
270 	abuf_flush(mdev);
271 	mdev->mapped_y = ty & -bh;
272 	mdev->mapped_height = bh;
273 	memset(scan_line_base(mdev, 0), 0, bh * mdev->raster);
274     }
275     pyt->y_next = ty;
276     pyt->height_left = th;
277     pyt->transfer_height = 0;
278 }
279 /* while ( yt.height_left > 0 ) { y_transfer_next(&yt, mdev); ... } */
280 static int
y_transfer_next(y_transfer * pyt,gx_device * dev)281 y_transfer_next(y_transfer * pyt, gx_device * dev)
282 {
283     gx_device_memory * const mdev = (gx_device_memory *)dev;
284     int my = mdev->mapped_y, mh = mdev->mapped_height;
285     int ms = mdev->mapped_start;
286     int ty = pyt->y_next += pyt->transfer_height;
287     int th = pyt->height_left;
288     int bh = 1 << mdev->log2_scale.y;
289 
290     /* From here on, we know that my <= ty <= my + mh. */
291     int tby, tbh;
292 
293     if (ty == my + mh) {	/* Add a new block at my1. */
294 	if (mh == mdev->height) {
295 	    int code = abuf_flush_block(mdev, my);
296 
297 	    if (code < 0)
298 		return code;
299 	    mdev->mapped_y = my += bh;
300 	    if ((mdev->mapped_start = ms += bh) == mh)
301 		mdev->mapped_start = ms = 0;
302 	} else {		/* Because we currently never extend backwards, */
303 	    /* we know we can't wrap around in this case. */
304 	    mdev->mapped_height = mh += bh;
305 	}
306 	memset(scan_line_base(mdev, (ms == 0 ? mh : ms) - bh),
307 	       0, bh * mdev->raster);
308     }
309     /* Now we know that my <= ty < my + mh. */
310     tby = ty - my + ms;
311     if (tby < mdev->height) {
312 	tbh = mdev->height - ms;
313 	if (tbh > mh)
314 	    tbh = mh;
315 	tbh -= tby - ms;
316     } else {			/* wrap around */
317 	tby -= mdev->height;
318 	tbh = ms + mh - dev->height - tby;
319     }
320     if_debug7('V',
321 	      "[V]abuf: my=%d, mh=%d, ms=%d, ty=%d, th=%d, tby=%d, tbh=%d\n",
322 	      my, mh, ms, ty, th, tby, tbh);
323     if (tbh > th)
324 	tbh = th;
325     pyt->height_left = th - tbh;
326     pyt->transfer_y = tby;
327     pyt->transfer_height = tbh;
328     return 0;
329 }
330 
331 /* Copy a monobit image. */
332 static int
mem_abuf_copy_mono(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)333 mem_abuf_copy_mono(gx_device * dev,
334 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
335 	int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
336 {
337     gx_device_memory * const mdev = (gx_device_memory *)dev;
338     y_transfer yt;
339 
340     if (zero != gx_no_color_index || one == gx_no_color_index)
341 	return_error(gs_error_undefinedresult);
342     x -= mdev->mapped_x;
343     fit_copy_xyw(dev, base, sourcex, sraster, id, x, y, w, h);	/* don't limit h */
344     if (w <= 0 || h <= 0)
345 	return 0;
346     mdev->save_color = one;
347     y_transfer_init(&yt, dev, y, h);
348     while (yt.height_left > 0) {
349 	int code = y_transfer_next(&yt, dev);
350 
351 	if (code < 0)
352 	    return code;
353 	(*dev_proc(&mem_mono_device, copy_mono)) (dev,
354 					   base + (yt.y_next - y) * sraster,
355 					  sourcex, sraster, gx_no_bitmap_id,
356 				    x, yt.transfer_y, w, yt.transfer_height,
357 				     gx_no_color_index, (gx_color_index) 1);
358     }
359     return 0;
360 }
361 
362 /* Fill a rectangle. */
363 static int
mem_abuf_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)364 mem_abuf_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
365 			gx_color_index color)
366 {
367     gx_device_memory * const mdev = (gx_device_memory *)dev;
368     y_transfer yt;
369 
370     x -= mdev->mapped_x;
371     fit_fill_xy(dev, x, y, w, h);
372     fit_fill_w(dev, x, w);	/* don't limit h */
373     /* or check w <= 0, h <= 0 */
374     mdev->save_color = color;
375     y_transfer_init(&yt, dev, y, h);
376     while (yt.height_left > 0) {
377 	int code = y_transfer_next(&yt, dev);
378 
379 	if (code < 0)
380 	    return code;
381 	(*dev_proc(&mem_mono_device, fill_rectangle)) (dev,
382 				    x, yt.transfer_y, w, yt.transfer_height,
383 						       (gx_color_index) 1);
384     }
385     return 0;
386 }
387 
388 /* Get the clipping box.  We must scale this up by the number of alpha bits. */
389 static void
mem_abuf_get_clipping_box(gx_device * dev,gs_fixed_rect * pbox)390 mem_abuf_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
391 {
392     gx_device_memory * const mdev = (gx_device_memory *)dev;
393     gx_device *tdev = mdev->target;
394 
395     (*dev_proc(tdev, get_clipping_box)) (tdev, pbox);
396     pbox->p.x <<= mdev->log2_scale.x;
397     pbox->p.y <<= mdev->log2_scale.y;
398     pbox->q.x <<= mdev->log2_scale.x;
399     pbox->q.y <<= mdev->log2_scale.y;
400 }
401