1 /* Copyright (C) 1993, 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: gxclip2.c,v 1.11 2004/06/24 05:03:36 dan Exp $ */
18 /* Mask clipping for patterns */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gxdevice.h"
24 #include "gxdevmem.h"
25 #include "gxclip2.h"
26
27 private_st_device_tile_clip();
28
29 /* Device procedures */
30 private dev_proc_fill_rectangle(tile_clip_fill_rectangle);
31 private dev_proc_copy_mono(tile_clip_copy_mono);
32 private dev_proc_copy_color(tile_clip_copy_color);
33 private dev_proc_copy_alpha(tile_clip_copy_alpha);
34 private dev_proc_strip_copy_rop(tile_clip_strip_copy_rop);
35
36 /* The device descriptor. */
37 private const gx_device_tile_clip gs_tile_clip_device =
38 {std_device_std_body_open(gx_device_tile_clip, 0, "tile clipper",
39 0, 0, 1, 1),
40 {gx_default_open_device,
41 gx_forward_get_initial_matrix,
42 gx_default_sync_output,
43 gx_default_output_page,
44 gx_default_close_device,
45 gx_forward_map_rgb_color,
46 gx_forward_map_color_rgb,
47 tile_clip_fill_rectangle,
48 gx_default_tile_rectangle,
49 tile_clip_copy_mono,
50 tile_clip_copy_color,
51 gx_default_draw_line,
52 gx_forward_get_bits,
53 gx_forward_get_params,
54 gx_forward_put_params,
55 gx_forward_map_cmyk_color,
56 gx_forward_get_xfont_procs,
57 gx_forward_get_xfont_device,
58 gx_forward_map_rgb_alpha_color,
59 gx_forward_get_page_device,
60 gx_forward_get_alpha_bits,
61 tile_clip_copy_alpha,
62 gx_forward_get_band,
63 gx_default_copy_rop,
64 gx_default_fill_path,
65 gx_default_stroke_path,
66 gx_default_fill_mask,
67 gx_default_fill_trapezoid,
68 gx_default_fill_parallelogram,
69 gx_default_fill_triangle,
70 gx_default_draw_thin_line,
71 gx_default_begin_image,
72 gx_default_image_data,
73 gx_default_end_image,
74 gx_default_strip_tile_rectangle,
75 tile_clip_strip_copy_rop,
76 gx_forward_get_clipping_box,
77 gx_default_begin_typed_image,
78 gx_forward_get_bits_rectangle,
79 gx_forward_map_color_rgb_alpha,
80 gx_no_create_compositor,
81 gx_forward_get_hardware_params,
82 gx_default_text_begin,
83 gx_default_finish_copydevice,
84 NULL, /* begin_transparency_group */
85 NULL, /* end_transparency_group */
86 NULL, /* begin_transparency_mask */
87 NULL, /* end_transparency_mask */
88 NULL, /* discard_transparency_layer */
89 gx_forward_get_color_mapping_procs,
90 gx_forward_get_color_comp_index,
91 gx_forward_encode_color,
92 gx_forward_decode_color,
93 gx_forward_pattern_manage,
94 gx_forward_fill_rectangle_hl_color,
95 gx_forward_include_color_space,
96 gx_forward_fill_linear_color_scanline,
97 gx_forward_fill_linear_color_trapezoid,
98 gx_forward_fill_linear_color_triangle,
99 gx_forward_update_spot_equivalent_colors
100 }
101 };
102
103 /* Initialize a tile clipping device from a mask. */
104 int
tile_clip_initialize(gx_device_tile_clip * cdev,const gx_strip_bitmap * tiles,gx_device * tdev,int px,int py,gs_memory_t * mem)105 tile_clip_initialize(gx_device_tile_clip * cdev, const gx_strip_bitmap * tiles,
106 gx_device * tdev, int px, int py, gs_memory_t *mem)
107 {
108 int code =
109 gx_mask_clip_initialize(cdev, &gs_tile_clip_device,
110 (const gx_bitmap *)tiles,
111 tdev, 0, 0, mem); /* phase will be reset */
112
113 if (code >= 0) {
114 cdev->tiles = *tiles;
115 tile_clip_set_phase(cdev, px, py);
116 }
117 return code;
118 }
119
120 /* Set the phase of the tile. */
121 void
tile_clip_set_phase(gx_device_tile_clip * cdev,int px,int py)122 tile_clip_set_phase(gx_device_tile_clip * cdev, int px, int py)
123 {
124 cdev->phase.x = px;
125 cdev->phase.y = py;
126 }
127
128 /* Fill a rectangle by tiling with the mask. */
129 private int
tile_clip_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)130 tile_clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
131 gx_color_index color)
132 {
133 gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
134 gx_device *tdev = cdev->target;
135
136 return (*dev_proc(tdev, strip_tile_rectangle)) (tdev, &cdev->tiles,
137 x, y, w, h,
138 gx_no_color_index, color, cdev->phase.x, cdev->phase.y);
139 }
140
141 /* Calculate the X offset corresponding to a given Y, taking the phase */
142 /* and shift into account. */
143 #define x_offset(ty, cdev)\
144 ((cdev)->phase.x + (((ty) + (cdev)->phase.y) / (cdev)->tiles.rep_height) *\
145 (cdev)->tiles.rep_shift)
146
147 /* Copy a monochrome bitmap. We divide it up into maximal chunks */
148 /* that line up with a single tile, and then do the obvious Boolean */
149 /* combination of the tile mask and the source. */
150 private int
tile_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)151 tile_clip_copy_mono(gx_device * dev,
152 const byte * data, int sourcex, int raster, gx_bitmap_id id,
153 int x, int y, int w, int h,
154 gx_color_index color0, gx_color_index color1)
155 {
156 gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
157 gx_color_index color, mcolor0, mcolor1;
158 int ty, ny;
159 int code;
160
161 setup_mask_copy_mono(cdev, color, mcolor0, mcolor1);
162 for (ty = y; ty < y + h; ty += ny) {
163 int tx, nx;
164 int cy = (ty + cdev->phase.y) % cdev->tiles.rep_height;
165 int xoff = x_offset(ty, cdev);
166
167 ny = min(y + h - ty, cdev->tiles.size.y - cy);
168 if (ny > cdev->mdev.height)
169 ny = cdev->mdev.height;
170 for (tx = x; tx < x + w; tx += nx) {
171 int cx = (tx + xoff) % cdev->tiles.rep_width;
172
173 nx = min(x + w - tx, cdev->tiles.size.x - cx);
174 /* Copy a tile slice to the memory device buffer. */
175 memcpy(cdev->buffer.bytes,
176 cdev->tiles.data + cy * cdev->tiles.raster,
177 cdev->tiles.raster * ny);
178 /* Intersect the tile with the source data. */
179 /* mcolor0 and mcolor1 invert the data if needed. */
180 /* This call can't fail. */
181 (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev,
182 data + (ty - y) * raster, sourcex + tx - x,
183 raster, gx_no_bitmap_id,
184 cx, 0, nx, ny, mcolor0, mcolor1);
185 /* Now copy the color through the double mask. */
186 code = (*dev_proc(cdev->target, copy_mono)) (cdev->target,
187 cdev->buffer.bytes, cx, cdev->tiles.raster,
188 gx_no_bitmap_id,
189 tx, ty, nx, ny, gx_no_color_index, color);
190 if (code < 0)
191 return code;
192 }
193 }
194 return 0;
195 }
196
197 /*
198 * Define the skeleton for the other copying operations. We can't use the
199 * BitBlt tricks: we have to scan for runs of 1s. There are many obvious
200 * ways to speed this up; we'll implement some if we need to. The schema
201 * is:
202 * FOR_RUNS(data_row, tx1, tx, ty) {
203 * ... process the run ([tx1,tx),ty) ...
204 * } END_FOR_RUNS();
205 * Free variables: cdev, data, sourcex, raster, x, y, w, h.
206 */
207 #define t_next(tx)\
208 BEGIN {\
209 if ( ++cx == cdev->tiles.size.x )\
210 cx = 0, tp = tile_row, tbit = 0x80;\
211 else if ( (tbit >>= 1) == 0 )\
212 tp++, tbit = 0x80;\
213 tx++;\
214 } END
215 #define FOR_RUNS(data_row, tx1, tx, ty)\
216 const byte *data_row = data;\
217 int cy = (y + cdev->phase.y) % cdev->tiles.rep_height;\
218 const byte *tile_row = cdev->tiles.data + cy * cdev->tiles.raster;\
219 int ty;\
220 \
221 for ( ty = y; ty < y + h; ty++, data_row += raster ) {\
222 int cx = (x + x_offset(ty, cdev)) % cdev->tiles.rep_width;\
223 const byte *tp = tile_row + (cx >> 3);\
224 byte tbit = 0x80 >> (cx & 7);\
225 int tx;\
226 \
227 for ( tx = x; tx < x + w; ) {\
228 int tx1;\
229 \
230 /* Skip a run of 0s. */\
231 while ( tx < x + w && (*tp & tbit) == 0 )\
232 t_next(tx);\
233 if ( tx == x + w )\
234 break;\
235 /* Scan a run of 1s. */\
236 tx1 = tx;\
237 do {\
238 t_next(tx);\
239 } while ( tx < x + w && (*tp & tbit) != 0 );\
240 if_debug3('T', "[T]run x=(%d,%d), y=%d\n", tx1, tx, ty);
241 /* (body goes here) */
242 #define END_FOR_RUNS()\
243 }\
244 if ( ++cy == cdev->tiles.size.y )\
245 cy = 0, tile_row = cdev->tiles.data;\
246 else\
247 tile_row += cdev->tiles.raster;\
248 }
249
250 /* Copy a color rectangle. */
251 private int
tile_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)252 tile_clip_copy_color(gx_device * dev,
253 const byte * data, int sourcex, int raster, gx_bitmap_id id,
254 int x, int y, int w, int h)
255 {
256 gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
257
258 FOR_RUNS(data_row, txrun, tx, ty) {
259 /* Copy the run. */
260 int code = (*dev_proc(cdev->target, copy_color))
261 (cdev->target, data_row, sourcex + txrun - x, raster,
262 gx_no_bitmap_id, txrun, ty, tx - txrun, 1);
263
264 if (code < 0)
265 return code;
266 }
267 END_FOR_RUNS();
268 return 0;
269 }
270
271 /* Copy an alpha rectangle similarly. */
272 private int
tile_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)273 tile_clip_copy_alpha(gx_device * dev,
274 const byte * data, int sourcex, int raster, gx_bitmap_id id,
275 int x, int y, int w, int h, gx_color_index color, int depth)
276 {
277 gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
278
279 FOR_RUNS(data_row, txrun, tx, ty) {
280 /* Copy the run. */
281 int code = (*dev_proc(cdev->target, copy_alpha))
282 (cdev->target, data_row, sourcex + txrun - x, raster,
283 gx_no_bitmap_id, txrun, ty, tx - txrun, 1, color, depth);
284
285 if (code < 0)
286 return code;
287 }
288 END_FOR_RUNS();
289 return 0;
290 }
291
292 /* Copy a RasterOp rectangle similarly. */
293 private int
tile_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)294 tile_clip_strip_copy_rop(gx_device * dev,
295 const byte * data, int sourcex, uint raster, gx_bitmap_id id,
296 const gx_color_index * scolors,
297 const gx_strip_bitmap * textures, const gx_color_index * tcolors,
298 int x, int y, int w, int h,
299 int phase_x, int phase_y, gs_logical_operation_t lop)
300 {
301 gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
302
303 FOR_RUNS(data_row, txrun, tx, ty) {
304 /* Copy the run. */
305 int code = (*dev_proc(cdev->target, strip_copy_rop))
306 (cdev->target, data_row, sourcex + txrun - x, raster,
307 gx_no_bitmap_id, scolors, textures, tcolors,
308 txrun, ty, tx - txrun, 1, phase_x, phase_y, lop);
309
310 if (code < 0)
311 return code;
312 }
313 END_FOR_RUNS();
314 return 0;
315 }
316