1 /* Copyright (C) 1998, 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: gxclipm.c,v 1.13 2004/06/24 05:03:36 dan Exp $ */
18 /* Mask clipping device */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gsbittab.h"
22 #include "gxdevice.h"
23 #include "gxdevmem.h"
24 #include "gxclipm.h"
25
26 /* Device procedures */
27 private dev_proc_fill_rectangle(mask_clip_fill_rectangle);
28 private dev_proc_copy_mono(mask_clip_copy_mono);
29 private dev_proc_copy_color(mask_clip_copy_color);
30 private dev_proc_copy_alpha(mask_clip_copy_alpha);
31 private dev_proc_strip_tile_rectangle(mask_clip_strip_tile_rectangle);
32 private dev_proc_strip_copy_rop(mask_clip_strip_copy_rop);
33 private dev_proc_get_clipping_box(mask_clip_get_clipping_box);
34
35 /* The device descriptor. */
36 const gx_device_mask_clip gs_mask_clip_device =
37 {std_device_std_body_open(gx_device_mask_clip, 0, "mask clipper",
38 0, 0, 1, 1),
39 {gx_default_open_device,
40 gx_forward_get_initial_matrix,
41 gx_default_sync_output,
42 gx_default_output_page,
43 gx_default_close_device,
44 gx_forward_map_rgb_color,
45 gx_forward_map_color_rgb,
46 mask_clip_fill_rectangle,
47 gx_default_tile_rectangle,
48 mask_clip_copy_mono,
49 mask_clip_copy_color,
50 gx_default_draw_line,
51 gx_forward_get_bits,
52 gx_forward_get_params,
53 gx_forward_put_params,
54 gx_forward_map_cmyk_color,
55 gx_forward_get_xfont_procs,
56 gx_forward_get_xfont_device,
57 gx_forward_map_rgb_alpha_color,
58 gx_forward_get_page_device,
59 gx_forward_get_alpha_bits,
60 mask_clip_copy_alpha,
61 gx_forward_get_band,
62 gx_default_copy_rop,
63 gx_default_fill_path,
64 gx_default_stroke_path,
65 gx_default_fill_mask,
66 gx_default_fill_trapezoid,
67 gx_default_fill_parallelogram,
68 gx_default_fill_triangle,
69 gx_default_draw_thin_line,
70 gx_default_begin_image,
71 gx_default_image_data,
72 gx_default_end_image,
73 mask_clip_strip_tile_rectangle,
74 mask_clip_strip_copy_rop,
75 mask_clip_get_clipping_box,
76 gx_default_begin_typed_image,
77 gx_forward_get_bits_rectangle,
78 gx_forward_map_color_rgb_alpha,
79 gx_no_create_compositor,
80 gx_forward_get_hardware_params,
81 gx_default_text_begin,
82 gx_default_finish_copydevice,
83 NULL, /* begin_transparency_group */
84 NULL, /* end_transparency_group */
85 NULL, /* begin_transparency_mask */
86 NULL, /* end_transparency_mask */
87 NULL, /* discard_transparency_layer */
88 gx_forward_get_color_mapping_procs,
89 gx_forward_get_color_comp_index,
90 gx_forward_encode_color,
91 gx_forward_decode_color,
92 gx_forward_pattern_manage,
93 gx_forward_fill_rectangle_hl_color,
94 gx_forward_include_color_space,
95 gx_forward_fill_linear_color_scanline,
96 gx_forward_fill_linear_color_trapezoid,
97 gx_forward_fill_linear_color_triangle,
98 gx_forward_update_spot_equivalent_colors
99 }
100 };
101
102 /* Fill a rectangle by painting through the mask. */
103 private int
mask_clip_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)104 mask_clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
105 gx_color_index color)
106 {
107 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
108 gx_device *tdev = cdev->target;
109
110 /* Clip the rectangle to the region covered by the mask. */
111 int mx0 = x + cdev->phase.x, my0 = y + cdev->phase.y;
112 int mx1 = mx0 + w, my1 = my0 + h;
113
114 if (mx0 < 0)
115 mx0 = 0;
116 if (my0 < 0)
117 my0 = 0;
118 if (mx1 > cdev->tiles.size.x)
119 mx1 = cdev->tiles.size.x;
120 if (my1 > cdev->tiles.size.y)
121 my1 = cdev->tiles.size.y;
122 return (*dev_proc(tdev, copy_mono))
123 (tdev, cdev->tiles.data + my0 * cdev->tiles.raster, mx0,
124 cdev->tiles.raster, cdev->tiles.id,
125 mx0 - cdev->phase.x, my0 - cdev->phase.y,
126 mx1 - mx0, my1 - my0, gx_no_color_index, color);
127 }
128
129 /*
130 * Clip the rectangle for a copy operation.
131 * Sets m{x,y}{0,1} to the region in the mask coordinate system;
132 * subtract cdev->phase.{x,y} to get target coordinates.
133 * Sets sdata, sx to adjusted values of data, sourcex.
134 * References cdev, data, sourcex, raster, x, y, w, h.
135 */
136 #define DECLARE_MASK_COPY\
137 const byte *sdata;\
138 int sx, mx0, my0, mx1, my1
139 #define FIT_MASK_COPY(data, sourcex, raster, vx, vy, vw, vh)\
140 BEGIN\
141 sdata = data, sx = sourcex;\
142 mx0 = vx + cdev->phase.x, my0 = vy + cdev->phase.y;\
143 mx1 = mx0 + vw, my1 = my0 + vh;\
144 if ( mx0 < 0 )\
145 sx -= mx0, mx0 = 0;\
146 if ( my0 < 0 )\
147 sdata -= my0 * raster, my0 = 0;\
148 if ( mx1 > cdev->tiles.size.x )\
149 mx1 = cdev->tiles.size.x;\
150 if ( my1 > cdev->tiles.size.y )\
151 my1 = cdev->tiles.size.y;\
152 END
153
154 /* Copy a monochrome bitmap by playing Boolean games. */
155 private int
mask_clip_copy_mono(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)156 mask_clip_copy_mono(gx_device * dev,
157 const byte * data, int sourcex, int raster, gx_bitmap_id id,
158 int x, int y, int w, int h,
159 gx_color_index color0, gx_color_index color1)
160 {
161 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
162 gx_device *tdev = cdev->target;
163 gx_color_index color, mcolor0, mcolor1;
164
165 DECLARE_MASK_COPY;
166 int cy, ny;
167 int code;
168
169 setup_mask_copy_mono(cdev, color, mcolor0, mcolor1);
170 FIT_MASK_COPY(data, sourcex, raster, x, y, w, h);
171 for (cy = my0; cy < my1; cy += ny) {
172 int ty = cy - cdev->phase.y;
173 int cx, nx;
174
175 ny = my1 - cy;
176 if (ny > cdev->mdev.height)
177 ny = cdev->mdev.height;
178 for (cx = mx0; cx < mx1; cx += nx) {
179 int tx = cx - cdev->phase.x;
180
181 nx = mx1 - cx; /* also should be min */
182 /* Copy a tile slice to the memory device buffer. */
183 memcpy(cdev->buffer.bytes,
184 cdev->tiles.data + cy * cdev->tiles.raster,
185 cdev->tiles.raster * ny);
186 /* Intersect the tile with the source data. */
187 /* mcolor0 and mcolor1 invert the data if needed. */
188 /* This call can't fail. */
189 (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev,
190 sdata + (ty - y) * raster, sx + tx - x,
191 raster, gx_no_bitmap_id,
192 cx, 0, nx, ny, mcolor0, mcolor1);
193 /* Now copy the color through the double mask. */
194 code = (*dev_proc(tdev, copy_mono)) (cdev->target,
195 cdev->buffer.bytes, cx, cdev->tiles.raster,
196 gx_no_bitmap_id,
197 tx, ty, nx, ny, gx_no_color_index, color);
198 if (code < 0)
199 return code;
200 }
201 }
202 return 0;
203 }
204
205 /*
206 * Define the run enumerator for the other copying operations. We can't use
207 * the BitBlt tricks: we have to scan for runs of 1s. There are obvious
208 * ways to speed this up; we'll implement some if we need to.
209 */
210 private int
clip_runs_enumerate(gx_device_mask_clip * cdev,int (* process)(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec),clip_callback_data_t * pccd)211 clip_runs_enumerate(gx_device_mask_clip * cdev,
212 int (*process) (clip_callback_data_t * pccd, int xc, int yc, int xec, int yec),
213 clip_callback_data_t * pccd)
214 {
215 DECLARE_MASK_COPY;
216 int cy;
217 const byte *tile_row;
218 gs_int_rect prev;
219 int code;
220
221 FIT_MASK_COPY(pccd->data, pccd->sourcex, pccd->raster,
222 pccd->x, pccd->y, pccd->w, pccd->h);
223 tile_row = cdev->tiles.data + my0 * cdev->tiles.raster + (mx0 >> 3);
224 prev.p.x = 0; /* arbitrary */
225 prev.q.x = prev.p.x - 1; /* an impossible rectangle */
226 prev.p.y = prev.q.y = -1; /* arbitrary */
227 for (cy = my0; cy < my1; cy++) {
228 int cx = mx0;
229 const byte *tp = tile_row;
230
231 if_debug1('B', "[B]clip runs y=%d:", cy - cdev->phase.y);
232 while (cx < mx1) {
233 int len;
234 int tx1, tx, ty;
235
236 /* Skip a run of 0s. */
237 len = byte_bit_run_length[cx & 7][*tp ^ 0xff];
238 if (len < 8) {
239 cx += len;
240 if (cx >= mx1)
241 break;
242 } else {
243 cx += len - 8;
244 tp++;
245 while (cx < mx1 && *tp == 0)
246 cx += 8, tp++;
247 if (cx >= mx1)
248 break;
249 cx += byte_bit_run_length_0[*tp ^ 0xff];
250 if (cx >= mx1)
251 break;
252 }
253 tx1 = cx - cdev->phase.x;
254 /* Scan a run of 1s. */
255 len = byte_bit_run_length[cx & 7][*tp];
256 if (len < 8) {
257 cx += len;
258 if (cx > mx1)
259 cx = mx1;
260 } else {
261 cx += len - 8;
262 tp++;
263 while (cx < mx1 && *tp == 0xff)
264 cx += 8, tp++;
265 if (cx > mx1)
266 cx = mx1;
267 else {
268 cx += byte_bit_run_length_0[*tp];
269 if (cx > mx1)
270 cx = mx1;
271 }
272 }
273 tx = cx - cdev->phase.x;
274 if_debug2('B', " %d-%d,", tx1, tx);
275 ty = cy - cdev->phase.y;
276 /* Detect vertical rectangles. */
277 if (prev.p.x == tx1 && prev.q.x == tx && prev.q.y == ty)
278 prev.q.y = ty + 1;
279 else {
280 if (prev.q.y > prev.p.y) {
281 code = (*process)(pccd, tx1, ty, tx, ty + 1);
282 if (code < 0)
283 return code;
284 }
285 prev.p.x = tx1;
286 prev.p.y = ty;
287 prev.q.x = tx;
288 prev.q.y = ty + 1;
289 }
290 }
291 if_debug0('B', "\n");
292 tile_row += cdev->tiles.raster;
293 }
294 if (prev.q.y > prev.p.y) {
295 code = (*process)(pccd, prev.p.x, prev.p.y, prev.q.x, prev.q.y);
296 if (code < 0)
297 return code;
298 }
299 return 0;
300 }
301
302 /* Copy a color rectangle */
303 private int
mask_clip_copy_color(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)304 mask_clip_copy_color(gx_device * dev,
305 const byte * data, int sourcex, int raster, gx_bitmap_id id,
306 int x, int y, int w, int h)
307 {
308 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
309 clip_callback_data_t ccdata;
310
311 ccdata.tdev = cdev->target;
312 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
313 ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
314 return clip_runs_enumerate(cdev, clip_call_copy_color, &ccdata);
315 }
316
317 /* Copy a rectangle with alpha */
318 private int
mask_clip_copy_alpha(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color,int depth)319 mask_clip_copy_alpha(gx_device * dev,
320 const byte * data, int sourcex, int raster, gx_bitmap_id id,
321 int x, int y, int w, int h, gx_color_index color, int depth)
322 {
323 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
324 clip_callback_data_t ccdata;
325
326 ccdata.tdev = cdev->target;
327 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
328 ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
329 ccdata.color[0] = color, ccdata.depth = depth;
330 return clip_runs_enumerate(cdev, clip_call_copy_alpha, &ccdata);
331 }
332
333 private int
mask_clip_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 phase_x,int phase_y)334 mask_clip_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
335 int x, int y, int w, int h,
336 gx_color_index color0, gx_color_index color1,
337 int phase_x, int phase_y)
338 {
339 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
340 clip_callback_data_t ccdata;
341
342 ccdata.tdev = cdev->target;
343 ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
344 ccdata.tiles = tiles;
345 ccdata.color[0] = color0, ccdata.color[1] = color1;
346 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
347 return clip_runs_enumerate(cdev, clip_call_strip_tile_rectangle, &ccdata);
348 }
349
350 private int
mask_clip_strip_copy_rop(gx_device * dev,const byte * data,int sourcex,uint raster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int w,int h,int phase_x,int phase_y,gs_logical_operation_t lop)351 mask_clip_strip_copy_rop(gx_device * dev,
352 const byte * data, int sourcex, uint raster, gx_bitmap_id id,
353 const gx_color_index * scolors,
354 const gx_strip_bitmap * textures, const gx_color_index * tcolors,
355 int x, int y, int w, int h,
356 int phase_x, int phase_y, gs_logical_operation_t lop)
357 {
358 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
359 clip_callback_data_t ccdata;
360
361 ccdata.tdev = cdev->target;
362 ccdata.x = x, ccdata.y = y, ccdata.w = w, ccdata.h = h;
363 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
364 ccdata.scolors = scolors, ccdata.textures = textures,
365 ccdata.tcolors = tcolors;
366 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
367 return clip_runs_enumerate(cdev, clip_call_strip_copy_rop, &ccdata);
368 }
369
370 private void
mask_clip_get_clipping_box(gx_device * dev,gs_fixed_rect * pbox)371 mask_clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
372 {
373 gx_device_mask_clip *cdev = (gx_device_mask_clip *) dev;
374 gx_device *tdev = cdev->target;
375 gs_fixed_rect tbox;
376
377 (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
378 pbox->p.x = tbox.p.x - cdev->phase.x;
379 pbox->p.y = tbox.p.y - cdev->phase.y;
380 pbox->q.x = tbox.q.x - cdev->phase.x;
381 pbox->q.y = tbox.q.y - cdev->phase.y;
382 }
383