Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
}