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