/src/ghostpdl/base/gximask.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 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 | | /* Functions for masked fill optimization. */ |
18 | | #include "gx.h" |
19 | | #include "memory_.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsptype1.h" |
22 | | #include "gsptype2.h" |
23 | | #include "gxdevice.h" |
24 | | #include "gxdcolor.h" |
25 | | #include "gxcpath.h" |
26 | | #include "gximask.h" |
27 | | #include "gzacpath.h" |
28 | | #include "gzcpath.h" |
29 | | #include "gxdevsop.h" |
30 | | |
31 | | /* Functions for masked fill optimization. */ |
32 | | /* Imagemask with a shading color would paint entire shading for each rectangle of the mask. |
33 | | These functions convert the mask into a clipping path and then render entire shading |
34 | | at once through it. |
35 | | */ |
36 | | |
37 | | int |
38 | | gx_image_fill_masked_start(gx_device *dev, const gx_device_color *pdevc, bool transpose, |
39 | | const gx_clip_path *pcpath, gs_memory_t *mem, gs_logical_operation_t lop, |
40 | | gx_device **cdev) |
41 | 90.1M | { |
42 | 90.1M | if ((lop == lop_default) && (gx_dc_is_pattern2_color(pdevc) || gx_dc_is_pattern1_color_clist_based(pdevc))) { |
43 | 5.21k | if (!dev_proc(dev, dev_spec_op)(dev, gxdso_pattern_can_accum, NULL, gs_no_id)) { |
44 | 5.19k | extern_st(st_device_cpath_accum); |
45 | 5.19k | gx_device_cpath_accum *pcdev; |
46 | 5.19k | gs_fixed_rect cbox; |
47 | | |
48 | 5.19k | if (pcpath == NULL) |
49 | 0 | return_error(gs_error_nocurrentpoint); /* close enough if no clip path */ |
50 | 5.19k | pcdev = gs_alloc_struct(mem, |
51 | 5.19k | gx_device_cpath_accum, &st_device_cpath_accum, "gx_image_fill_masked_start"); |
52 | 5.19k | if (pcdev == NULL) |
53 | 0 | return_error(gs_error_VMerror); |
54 | 5.19k | gx_cpath_accum_begin(pcdev, mem, transpose); |
55 | 5.19k | gx_cpath_outer_box(pcpath, &cbox); |
56 | 5.19k | gx_cpath_accum_set_cbox(pcdev, &cbox); |
57 | 5.19k | pcdev->rc.memory = mem; |
58 | 5.19k | pcdev->width = dev->width; /* For gx_default_copy_mono. */ |
59 | 5.19k | pcdev->height = dev->height; /* For gx_default_copy_mono. */ |
60 | 5.19k | gx_device_retain((gx_device *)pcdev, true); |
61 | 5.19k | *cdev = (gx_device *)pcdev; |
62 | 5.19k | } else{ |
63 | 15 | *cdev = dev; |
64 | 15 | } |
65 | 5.21k | } else |
66 | 90.0M | *cdev = dev; |
67 | 90.1M | return 0; |
68 | 90.1M | } |
69 | | |
70 | | int |
71 | | gx_image_fill_masked_end(gx_device *dev, gx_device *tdev, const gx_device_color *pdevc) |
72 | 5.14k | { |
73 | 5.14k | gx_device_cpath_accum *pcdev = (gx_device_cpath_accum *)dev; |
74 | 5.14k | gx_clip_path cpath; |
75 | 5.14k | gx_clip_path cpath_with_shading_bbox; |
76 | 5.14k | const gx_clip_path *pcpath1 = &cpath; |
77 | 5.14k | gx_device_clip cdev; |
78 | 5.14k | int code, code1; |
79 | | |
80 | 5.14k | gx_cpath_init_local(&cpath, pcdev->memory); |
81 | 5.14k | code = gx_cpath_accum_end(pcdev, &cpath); |
82 | 5.14k | if (code >= 0) |
83 | 5.14k | code = gx_dc_pattern2_clip_with_bbox(pdevc, tdev, &cpath_with_shading_bbox, &pcpath1); |
84 | 5.14k | gx_make_clip_device_on_stack(&cdev, pcpath1, tdev); |
85 | 5.14k | if (code >= 0 && pcdev->bbox.p.x < pcdev->bbox.q.x) { |
86 | 4.14k | code1 = gx_device_color_fill_rectangle(pdevc, |
87 | 4.14k | pcdev->bbox.p.x, pcdev->bbox.p.y, |
88 | 4.14k | pcdev->bbox.q.x - pcdev->bbox.p.x, |
89 | 4.14k | pcdev->bbox.q.y - pcdev->bbox.p.y, |
90 | 4.14k | (gx_device *)&cdev, lop_default, 0); |
91 | 4.14k | if (code == 0) |
92 | 4.14k | code = code1; |
93 | 4.14k | } |
94 | 5.14k | gx_destroy_clip_device_on_stack(&cdev); |
95 | 5.14k | if (pcpath1 == &cpath_with_shading_bbox) |
96 | 0 | gx_cpath_free(&cpath_with_shading_bbox, "s_image_cleanup"); |
97 | 5.14k | gx_device_retain((gx_device *)pcdev, false); |
98 | 5.14k | gx_cpath_free(&cpath, "s_image_cleanup"); |
99 | 5.14k | return code; |
100 | 5.14k | } |
101 | | |
102 | | int |
103 | | gx_image_fill_masked(gx_device *dev, |
104 | | const byte *data, int data_x, int raster, gx_bitmap_id id, |
105 | | int x, int y, int width, int height, |
106 | | const gx_device_color *pdc, int depth, |
107 | | gs_logical_operation_t lop, const gx_clip_path *pcpath) |
108 | 89.1M | { |
109 | 89.1M | gx_device *cdev = dev; |
110 | 89.1M | int code; |
111 | | |
112 | 89.1M | if ((code = gx_image_fill_masked_start(dev, pdc, false, pcpath, dev->memory, lop, &cdev)) < 0) |
113 | 0 | return code; |
114 | | |
115 | 89.1M | if (cdev == dev) |
116 | 89.1M | code = (*dev_proc(cdev, fill_mask))(cdev, data, data_x, raster, id, |
117 | 89.1M | x, y, width, height, pdc, depth, lop, pcpath); |
118 | 4.30k | else { |
119 | | /* cdev != dev means that a cpath_accum device was inserted */ |
120 | 4.30k | gx_device_color dc_temp; /* if fill_masked_start did cpath_accum, use pure color */ |
121 | | |
122 | 4.30k | set_nonclient_dev_color(&dc_temp, 1); /* arbitrary color since cpath_accum doesn't use it */ |
123 | 4.30k | if ((code = (*dev_proc(cdev, fill_mask))(cdev, data, data_x, raster, id, |
124 | 4.30k | x, y, width, height, &dc_temp, depth, lop, pcpath)) < 0) |
125 | 0 | return code; |
126 | 4.30k | code = gx_image_fill_masked_end(cdev, dev, pdc); /* fill with the actual device color */ |
127 | 4.30k | } |
128 | 89.1M | return code; |
129 | 89.1M | } |