/src/ghostpdl/base/gxclip2.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Mask clipping for patterns */ |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gpcheck.h" |
21 | | #include "gserrors.h" |
22 | | #include "gsstruct.h" |
23 | | #include "gxdevice.h" |
24 | | #include "gxdevmem.h" |
25 | | #include "gxclip2.h" |
26 | | #include "gxdcolor.h" |
27 | | #include "gdevmpla.h" |
28 | | |
29 | | private_st_device_tile_clip(); |
30 | | |
31 | | /* Device procedures */ |
32 | | static dev_proc_fill_rectangle(tile_clip_fill_rectangle); |
33 | | static dev_proc_fill_rectangle_hl_color(tile_clip_fill_rectangle_hl_color); |
34 | | static dev_proc_copy_mono(tile_clip_copy_mono); |
35 | | static dev_proc_copy_color(tile_clip_copy_color); |
36 | | static dev_proc_copy_planes(tile_clip_copy_planes); |
37 | | static dev_proc_copy_alpha(tile_clip_copy_alpha); |
38 | | static dev_proc_copy_alpha_hl_color(tile_clip_copy_alpha_hl_color); |
39 | | static dev_proc_strip_copy_rop2(tile_clip_strip_copy_rop2); |
40 | | |
41 | | /* The device descriptor. */ |
42 | | static void |
43 | | tile_clipper_initialize_device_procs(gx_device *dev) |
44 | 246k | { |
45 | 246k | set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix); |
46 | 246k | set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color); |
47 | 246k | set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb); |
48 | 246k | set_dev_proc(dev, fill_rectangle, tile_clip_fill_rectangle); |
49 | 246k | set_dev_proc(dev, copy_mono, tile_clip_copy_mono); |
50 | 246k | set_dev_proc(dev, copy_color, tile_clip_copy_color); |
51 | 246k | set_dev_proc(dev, get_params, gx_forward_get_params); |
52 | 246k | set_dev_proc(dev, put_params, gx_forward_put_params); |
53 | 246k | set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color); |
54 | 246k | set_dev_proc(dev, get_page_device, gx_forward_get_page_device); |
55 | 246k | set_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits); |
56 | 246k | set_dev_proc(dev, copy_alpha, tile_clip_copy_alpha); |
57 | 246k | set_dev_proc(dev, get_clipping_box, gx_forward_get_clipping_box); |
58 | 246k | set_dev_proc(dev, get_bits_rectangle, gx_forward_get_bits_rectangle); |
59 | 246k | set_dev_proc(dev, composite, gx_no_composite); |
60 | 246k | set_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params); |
61 | 246k | set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs); |
62 | 246k | set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index); |
63 | 246k | set_dev_proc(dev, encode_color, gx_forward_encode_color); |
64 | 246k | set_dev_proc(dev, decode_color, gx_forward_decode_color); |
65 | 246k | set_dev_proc(dev, fill_rectangle_hl_color, tile_clip_fill_rectangle_hl_color); |
66 | 246k | set_dev_proc(dev, include_color_space, gx_forward_include_color_space); |
67 | 246k | set_dev_proc(dev, fill_linear_color_scanline, gx_forward_fill_linear_color_scanline); |
68 | 246k | set_dev_proc(dev, fill_linear_color_trapezoid, gx_forward_fill_linear_color_trapezoid); |
69 | 246k | set_dev_proc(dev, fill_linear_color_triangle, gx_forward_fill_linear_color_triangle); |
70 | 246k | set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); |
71 | 246k | set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); |
72 | 246k | set_dev_proc(dev, fillpage, gx_forward_fillpage); |
73 | 246k | set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op); |
74 | 246k | set_dev_proc(dev, copy_planes, tile_clip_copy_planes); |
75 | 246k | set_dev_proc(dev, strip_copy_rop2, tile_clip_strip_copy_rop2); |
76 | 246k | set_dev_proc(dev, copy_alpha_hl_color, tile_clip_copy_alpha_hl_color); |
77 | | |
78 | | /* Ideally the following defaults would be set up for us, but this |
79 | | * does not currently work. */ |
80 | 246k | set_dev_proc(dev, open_device, gx_default_open_device); |
81 | 246k | set_dev_proc(dev, sync_output, gx_default_sync_output); |
82 | 246k | set_dev_proc(dev, output_page, gx_default_output_page); |
83 | 246k | set_dev_proc(dev, close_device, gx_default_close_device); |
84 | 246k | set_dev_proc(dev, fill_path, gx_default_fill_path); |
85 | 246k | set_dev_proc(dev, stroke_path, gx_default_stroke_path); |
86 | 246k | set_dev_proc(dev, fill_mask, gx_default_fill_mask); |
87 | 246k | set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid); |
88 | 246k | set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram); |
89 | 246k | set_dev_proc(dev, fill_triangle, gx_default_fill_triangle); |
90 | 246k | set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line); |
91 | 246k | set_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle); |
92 | 246k | set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image); |
93 | 246k | set_dev_proc(dev, text_begin, gx_default_text_begin); |
94 | 246k | set_dev_proc(dev, strip_tile_rect_devn, gx_default_strip_tile_rect_devn); |
95 | 246k | } |
96 | | |
97 | | static const gx_device_tile_clip gs_tile_clip_device = |
98 | | {std_device_std_body_open(gx_device_tile_clip, |
99 | | tile_clipper_initialize_device_procs, |
100 | | "tile clipper", |
101 | | 0, 0, 1, 1) |
102 | | }; |
103 | | |
104 | | /* Initialize a tile clipping device from a mask. */ |
105 | | int |
106 | | tile_clip_initialize(gx_device_tile_clip * cdev, const gx_strip_bitmap * tiles, |
107 | | gx_device * tdev, int px, int py) |
108 | 246k | { |
109 | 246k | int code = |
110 | 246k | gx_mask_clip_initialize(cdev, &gs_tile_clip_device, |
111 | 246k | (const gx_bitmap *)tiles, |
112 | 246k | tdev, 0, 0, NULL); /* phase will be reset */ |
113 | | |
114 | 246k | if (code >= 0) { |
115 | 246k | cdev->tiles = *tiles; |
116 | 246k | tile_clip_set_phase(cdev, px, py); |
117 | 246k | } |
118 | 246k | return code; |
119 | 246k | } |
120 | | |
121 | | void |
122 | | tile_clip_free(gx_device_tile_clip *cdev) |
123 | 246k | { |
124 | | /* release the target reference */ |
125 | 246k | if(cdev->finalize) |
126 | 246k | cdev->finalize((gx_device *)cdev); /* this also sets the target to NULL */ |
127 | 246k | gs_free_object(cdev->memory, cdev, "tile_clip_free(cdev)"); |
128 | 246k | } |
129 | | |
130 | | /* Set the phase of the tile. */ |
131 | | void |
132 | | tile_clip_set_phase(gx_device_tile_clip * cdev, int px, int py) |
133 | 4.50M | { |
134 | 4.50M | cdev->phase.x = px; |
135 | 4.50M | cdev->phase.y = py; |
136 | 4.50M | } |
137 | | |
138 | | /* Fill a rectangle with high level devn color by tiling with the mask. */ |
139 | | static int |
140 | | tile_clip_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect, |
141 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, |
142 | | const gx_clip_path *pcpath) |
143 | 5.83k | { |
144 | 5.83k | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
145 | 5.83k | gx_device *tdev = cdev->target; |
146 | 5.83k | int x, y, w, h; |
147 | 5.83k | gx_device_color dcolor0, dcolor1; |
148 | 5.83k | int k; |
149 | | |
150 | | /* Have to pack the no color index into the pure device type */ |
151 | 5.83k | dcolor0.type = gx_dc_type_pure; |
152 | 5.83k | dcolor0.colors.pure = gx_no_color_index; |
153 | | /* Have to set the dcolor1 to a non mask type */ |
154 | 5.83k | dcolor1.type = gx_dc_type_devn; |
155 | 379k | for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) { |
156 | 373k | dcolor1.colors.devn.values[k] = pdcolor->colors.devn.values[k]; |
157 | 373k | } |
158 | 5.83k | x = fixed2int(rect->p.x); |
159 | 5.83k | y = fixed2int(rect->p.y); |
160 | 5.83k | w = fixed2int(rect->q.x) - x; |
161 | 5.83k | h = fixed2int(rect->q.y) - y; |
162 | 5.83k | return (*dev_proc(tdev, strip_tile_rect_devn))(tdev, &cdev->tiles, |
163 | 5.83k | x, y, w, h, &dcolor0, &dcolor1, |
164 | 5.83k | cdev->phase.x, cdev->phase.y); |
165 | 5.83k | } |
166 | | |
167 | | /* Fill a rectangle by tiling with the mask. */ |
168 | | static int |
169 | | tile_clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h, |
170 | | gx_color_index color) |
171 | 45.0k | { |
172 | 45.0k | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
173 | 45.0k | gx_device *tdev = cdev->target; |
174 | | |
175 | 45.0k | return (*dev_proc(tdev, strip_tile_rectangle)) (tdev, &cdev->tiles, |
176 | 45.0k | x, y, w, h, |
177 | 45.0k | gx_no_color_index, color, cdev->phase.x, cdev->phase.y); |
178 | 45.0k | } |
179 | | |
180 | | /* Calculate the X offset corresponding to a given Y, taking the phase */ |
181 | | /* and shift into account. */ |
182 | | #define x_offset(ty, cdev)\ |
183 | 6.91M | ((cdev)->phase.x + (((ty) + (cdev)->phase.y) / (cdev)->tiles.rep_height) *\ |
184 | 6.91M | (cdev)->tiles.rep_shift) |
185 | | |
186 | | /* Copy a monochrome bitmap. We divide it up into maximal chunks */ |
187 | | /* that line up with a single tile, and then do the obvious Boolean */ |
188 | | /* combination of the tile mask and the source. */ |
189 | | static int |
190 | | tile_clip_copy_mono(gx_device * dev, |
191 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
192 | | int x, int y, int w, int h, |
193 | | gx_color_index color0, gx_color_index color1) |
194 | 229 | { |
195 | 229 | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
196 | 229 | gx_color_index color, mcolor0, mcolor1; |
197 | 229 | int ty, ny; |
198 | 229 | int code; |
199 | | |
200 | 229 | setup_mask_copy_mono(cdev, color, mcolor0, mcolor1); |
201 | 458 | for (ty = y; ty < y + h; ty += ny) { |
202 | 229 | int tx, nx; |
203 | 229 | int cy; |
204 | 229 | int xoff; |
205 | | |
206 | 229 | if (cdev->tiles.rep_height == 0 || cdev->tiles.rep_width == 0) |
207 | 0 | return 0; |
208 | | |
209 | 229 | cy = (ty + cdev->phase.y) % cdev->tiles.rep_height; |
210 | 229 | xoff = x_offset(ty, cdev); |
211 | | |
212 | 229 | ny = min(y + h - ty, cdev->tiles.size.y - cy); |
213 | 229 | if (ny > cdev->mdev.height) |
214 | 0 | ny = cdev->mdev.height; |
215 | 458 | for (tx = x; tx < x + w; tx += nx) { |
216 | 229 | int cx = (tx + xoff) % cdev->tiles.rep_width; |
217 | | |
218 | 229 | nx = min(x + w - tx, cdev->tiles.size.x - cx); |
219 | | /* Copy a tile slice to the memory device buffer. */ |
220 | 229 | memcpy(cdev->buffer.bytes, |
221 | 229 | cdev->tiles.data + cy * cdev->tiles.raster, |
222 | 229 | (size_t)cdev->tiles.raster * ny); |
223 | | /* Intersect the tile with the source data. */ |
224 | | /* mcolor0 and mcolor1 invert the data if needed. */ |
225 | | /* This call can't fail. */ |
226 | 229 | (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev, |
227 | 229 | data + (ty - y) * raster, sourcex + tx - x, |
228 | 229 | raster, gx_no_bitmap_id, |
229 | 229 | cx, 0, nx, ny, mcolor0, mcolor1); |
230 | | /* Now copy the color through the double mask. */ |
231 | 229 | code = (*dev_proc(cdev->target, copy_mono)) (cdev->target, |
232 | 229 | cdev->buffer.bytes, cx, cdev->tiles.raster, |
233 | 229 | gx_no_bitmap_id, |
234 | 229 | tx, ty, nx, ny, gx_no_color_index, color); |
235 | 229 | if (code < 0) |
236 | 0 | return code; |
237 | 229 | } |
238 | 229 | } |
239 | 229 | return 0; |
240 | 229 | } |
241 | | |
242 | | /* |
243 | | * Define the skeleton for the other copying operations. We can't use the |
244 | | * BitBlt tricks: we have to scan for runs of 1s. There are many obvious |
245 | | * ways to speed this up; we'll implement some if we need to. The schema |
246 | | * is: |
247 | | * FOR_RUNS(data_row, tx1, tx, ty) { |
248 | | * ... process the run ([tx1,tx),ty) ... |
249 | | * } END_FOR_RUNS(); |
250 | | * Free variables: cdev, data, sourcex, raster, x, y, w, h. |
251 | | */ |
252 | | #define t_next(tx)\ |
253 | 5.89G | BEGIN {\ |
254 | 5.89G | if ( ++cx == cdev->tiles.size.x )\ |
255 | 5.89G | cx = 0, tp = tile_row, tbit = 0x80;\ |
256 | 5.89G | else if ( (tbit >>= 1) == 0 )\ |
257 | 2.99G | tp++, tbit = 0x80;\ |
258 | 5.89G | tx++;\ |
259 | 5.89G | } END |
260 | | #define FOR_RUNS(data_row, tx1, tx, ty)\ |
261 | 4.20M | const byte *data_row = data;\ |
262 | 4.20M | int cy;\ |
263 | 4.20M | byte *tile_row;\ |
264 | 4.20M | int ty;\ |
265 | 4.20M | \ |
266 | 4.20M | if (cdev->tiles.rep_height == 0 || cdev->tiles.rep_width == 0)\ |
267 | 4.20M | return 0;\ |
268 | 4.20M | cy = imod(y + cdev->phase.y, cdev->tiles.rep_height);\ |
269 | 4.20M | tile_row = cdev->tiles.data + cy * cdev->tiles.raster;\ |
270 | 4.20M | \ |
271 | 11.1M | for ( ty = y; ty < y + h; ty++, data_row += raster ) {\ |
272 | 6.91M | int cx = imod(x + x_offset(ty, cdev), cdev->tiles.rep_width);\ |
273 | 6.91M | const byte *tp = tile_row + (cx >> 3);\ |
274 | 6.91M | byte tbit = 0x80 >> (cx & 7);\ |
275 | 6.91M | int tx;\ |
276 | 6.91M | \ |
277 | 8.35M | for ( tx = x; tx < x + w; ) {\ |
278 | 7.89M | int tx1;\ |
279 | 7.89M | \ |
280 | 7.89M | /* Skip a run of 0s. */\ |
281 | 2.90G | while ( tx < x + w && (*tp & tbit) == 0 )\ |
282 | 7.89M | t_next(tx);\ |
283 | 7.89M | if ( tx == x + w )\ |
284 | 7.89M | break;\ |
285 | 7.89M | /* Scan a run of 1s. */\ |
286 | 7.89M | tx1 = tx;\ |
287 | 93.7M | do {\ |
288 | 93.7M | t_next(tx);\ |
289 | 93.7M | } while ( tx < x + w && (*tp & tbit) != 0 );\ |
290 | 4.20M | if_debug3m('T', cdev->memory, "[T]run x=(%d,%d), y=%d\n", tx1, tx, ty); |
291 | | /* (body goes here) */ |
292 | | #define END_FOR_RUNS()\ |
293 | 1.43M | }\ |
294 | 11.1M | if ( ++cy == cdev->tiles.size.y )\ |
295 | 6.91M | cy = 0, tile_row = cdev->tiles.data;\ |
296 | 6.91M | else\ |
297 | 6.91M | tile_row += cdev->tiles.raster;\ |
298 | 6.91M | } |
299 | | |
300 | | /* Copy a color rectangle. */ |
301 | | static int |
302 | | tile_clip_copy_color(gx_device * dev, |
303 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
304 | | int x, int y, int w, int h) |
305 | 3.48M | { |
306 | 3.48M | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
307 | | |
308 | 3.48M | fit_copy(dev, data, sourcex, raster, id, x, y, w, h); |
309 | 3.42M | { |
310 | 13.5M | FOR_RUNS(data_row, txrun, tx, ty) { |
311 | | /* Copy the run. */ |
312 | 13.5M | int code = (*dev_proc(cdev->target, copy_color)) |
313 | 13.5M | (cdev->target, data_row, sourcex + txrun - x, raster, |
314 | 13.5M | gx_no_bitmap_id, txrun, ty, tx - txrun, 1); |
315 | | |
316 | 13.5M | if (code < 0) |
317 | 0 | return code; |
318 | 13.5M | } |
319 | 13.5M | END_FOR_RUNS(); |
320 | 3.42M | } |
321 | 0 | return 0; |
322 | 3.42M | } |
323 | | |
324 | | /* Copy a color rectangle. */ |
325 | | static int |
326 | | tile_clip_copy_planes(gx_device * dev, |
327 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
328 | | int x, int y, int w, int h, int plane_height) |
329 | 781k | { |
330 | 781k | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
331 | | |
332 | 781k | fit_copy(dev, data, sourcex, raster, id, x, y, w, h); |
333 | 774k | { |
334 | 2.68M | FOR_RUNS(data_row, txrun, tx, ty) { |
335 | | /* Copy the run. */ |
336 | 2.68M | int code = (*dev_proc(cdev->target, copy_planes)) |
337 | 2.68M | (cdev->target, data_row, sourcex + txrun - x, raster, |
338 | 2.68M | gx_no_bitmap_id, txrun, ty, tx - txrun, 1, plane_height); |
339 | | |
340 | 2.68M | if (code < 0) |
341 | 0 | return code; |
342 | 2.68M | } |
343 | 2.68M | END_FOR_RUNS(); |
344 | 774k | } |
345 | 0 | return 0; |
346 | 774k | } |
347 | | |
348 | | |
349 | | /* Copy an alpha rectangle similarly. */ |
350 | | static int |
351 | | tile_clip_copy_alpha(gx_device * dev, |
352 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
353 | | int x, int y, int w, int h, gx_color_index color, int depth) |
354 | 0 | { |
355 | 0 | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
356 | |
|
357 | 0 | fit_copy(dev, data, sourcex, raster, id, x, y, w, h); |
358 | 0 | { |
359 | 0 | FOR_RUNS(data_row, txrun, tx, ty) { |
360 | | /* Copy the run. */ |
361 | 0 | int code = (*dev_proc(cdev->target, copy_alpha)) |
362 | 0 | (cdev->target, data_row, sourcex + txrun - x, raster, |
363 | 0 | gx_no_bitmap_id, txrun, ty, tx - txrun, 1, color, depth); |
364 | |
|
365 | 0 | if (code < 0) |
366 | 0 | return code; |
367 | 0 | } |
368 | 0 | END_FOR_RUNS(); |
369 | 0 | } |
370 | 0 | return 0; |
371 | 0 | } |
372 | | |
373 | | static int |
374 | | tile_clip_copy_alpha_hl_color(gx_device * dev, |
375 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
376 | | int x, int y, int w, int h, const gx_drawing_color *pdcolor, |
377 | | int depth) |
378 | 0 | { |
379 | 0 | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
380 | |
|
381 | 0 | fit_copy(dev, data, sourcex, raster, id, x, y, w, h); |
382 | 0 | { |
383 | 0 | FOR_RUNS(data_row, txrun, tx, ty) { |
384 | | /* Copy the run. */ |
385 | 0 | int code = (*dev_proc(cdev->target, copy_alpha_hl_color)) |
386 | 0 | (cdev->target, data_row, sourcex + txrun - x, raster, |
387 | 0 | gx_no_bitmap_id, txrun, ty, tx - txrun, 1, pdcolor, depth); |
388 | |
|
389 | 0 | if (code < 0) |
390 | 0 | return code; |
391 | 0 | } |
392 | 0 | END_FOR_RUNS(); |
393 | 0 | } |
394 | 0 | return 0; |
395 | 0 | } |
396 | | |
397 | | static int |
398 | | tile_clip_strip_copy_rop2(gx_device * dev, |
399 | | const byte * data, int sourcex, uint raster, gx_bitmap_id id, |
400 | | const gx_color_index * scolors, |
401 | | const gx_strip_bitmap * textures, const gx_color_index * tcolors, |
402 | | int x, int y, int w, int h, |
403 | | int phase_x, int phase_y, gs_logical_operation_t lop, |
404 | | uint planar_height) |
405 | 0 | { |
406 | 0 | gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev; |
407 | |
|
408 | 0 | fit_copy(dev, data, sourcex, raster, id, x, y, w, h); |
409 | 0 | { |
410 | 0 | FOR_RUNS(data_row, txrun, tx, ty) { |
411 | | /* Copy the run. */ |
412 | 0 | int code = (*dev_proc(cdev->target, strip_copy_rop2)) |
413 | 0 | (cdev->target, data_row, sourcex + txrun - x, raster, |
414 | 0 | gx_no_bitmap_id, scolors, textures, tcolors, |
415 | 0 | txrun, ty, tx - txrun, 1, phase_x, phase_y, lop, |
416 | 0 | planar_height); |
417 | |
|
418 | 0 | if (code < 0) |
419 | 0 | return code; |
420 | 0 | } |
421 | 0 | END_FOR_RUNS(); |
422 | 0 | } |
423 | 0 | return 0; |
424 | 0 | } |