/src/ghostpdl/base/gxshade4.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 | | /* Rendering for Gouraud triangle shadings */ |
18 | | #include "math_.h" |
19 | | #include "memory_.h" |
20 | | #include "gx.h" |
21 | | #include "gserrors.h" |
22 | | #include "gsmatrix.h" /* for gscoord.h */ |
23 | | #include "gscoord.h" |
24 | | #include "gsptype2.h" |
25 | | #include "gxcspace.h" |
26 | | #include "gxdcolor.h" |
27 | | #include "gxdevcli.h" |
28 | | #include "gxgstate.h" |
29 | | #include "gxpath.h" |
30 | | #include "gxshade.h" |
31 | | #include "gxshade4.h" |
32 | | #include "gsicc_cache.h" |
33 | | |
34 | | /* Initialize the fill state for triangle shading. */ |
35 | | int |
36 | | mesh_init_fill_state(mesh_fill_state_t * pfs, const gs_shading_mesh_t * psh, |
37 | | const gs_fixed_rect * rect_clip, gx_device * dev, |
38 | | gs_gstate * pgs) |
39 | 204 | { |
40 | 204 | int code; |
41 | 204 | code = shade_init_fill_state((shading_fill_state_t *) pfs, |
42 | 204 | (const gs_shading_t *)psh, dev, pgs); |
43 | 204 | if (code < 0) |
44 | 0 | return code; |
45 | 204 | pfs->pshm = psh; |
46 | 204 | pfs->rect = *rect_clip; |
47 | 204 | return 0; |
48 | 204 | } |
49 | | |
50 | | /* ---------------- Gouraud triangle shadings ---------------- */ |
51 | | |
52 | | static int |
53 | | Gt_next_vertex(const gs_shading_mesh_t * psh, shade_coord_stream_t * cs, |
54 | | shading_vertex_t * vertex, patch_color_t *c) |
55 | 509k | { |
56 | 509k | int code = shade_next_vertex(cs, vertex, c); |
57 | 509k | if (code < 0) |
58 | 85 | return code; |
59 | | |
60 | 509k | if (psh->params.Function) { |
61 | 499k | c->t[0] = c->cc.paint.values[0]; |
62 | 499k | c->t[1] = 0; |
63 | | /* Decode the color with the function. */ |
64 | 499k | code = gs_function_evaluate(psh->params.Function, c->t, |
65 | 499k | c->cc.paint.values); |
66 | 499k | } else |
67 | 10.3k | psh->params.ColorSpace->type->restrict_color(&c->cc, psh->params.ColorSpace); |
68 | 509k | return code; |
69 | 509k | } |
70 | | |
71 | | static inline int |
72 | | Gt_fill_triangle(patch_fill_state_t * pfs, const shading_vertex_t * va, |
73 | | const shading_vertex_t * vb, const shading_vertex_t * vc) |
74 | 900k | { |
75 | 900k | int code = 0; |
76 | | |
77 | 900k | if (INTERPATCH_PADDING) { |
78 | 900k | code = mesh_padding(pfs, &va->p, &vb->p, va->c, vb->c); |
79 | 900k | if (code >= 0) |
80 | 900k | code = mesh_padding(pfs, &vb->p, &vc->p, vb->c, vc->c); |
81 | 900k | if (code >= 0) |
82 | 900k | code = mesh_padding(pfs, &vc->p, &va->p, vc->c, va->c); |
83 | 900k | } |
84 | 900k | if (code >= 0) |
85 | 900k | code = mesh_triangle(pfs, va, vb, vc); |
86 | 900k | return code; |
87 | 900k | } |
88 | | |
89 | | int |
90 | | gs_shading_FfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect, |
91 | | const gs_fixed_rect * rect_clip, |
92 | | gx_device * dev, gs_gstate * pgs) |
93 | 53 | { |
94 | 53 | const gs_shading_FfGt_t * const psh = (const gs_shading_FfGt_t *)psh0; |
95 | 53 | patch_fill_state_t pfs; |
96 | 53 | const gs_shading_mesh_t *pshm = (const gs_shading_mesh_t *)psh; |
97 | 53 | shade_coord_stream_t cs; |
98 | 53 | int num_bits = psh->params.BitsPerFlag; |
99 | 53 | int flag; |
100 | 53 | shading_vertex_t va, vb, vc; |
101 | 53 | patch_color_t *c, *C[3], *ca, *cb, *cc; /* va.c == ca && vb.c == cb && vc.c == cc always, |
102 | | provides a non-const access. */ |
103 | 53 | int code; |
104 | | |
105 | 53 | code = shade_init_fill_state((shading_fill_state_t *)&pfs, |
106 | 53 | (const gs_shading_t *)psh, dev, pgs); |
107 | 53 | if (code < 0) |
108 | 0 | return code; |
109 | 53 | pfs.Function = pshm->params.Function; |
110 | 53 | pfs.rect = *rect_clip; |
111 | 53 | code = init_patch_fill_state(&pfs); |
112 | 53 | if (code < 0) { |
113 | 0 | if (pfs.icclink != NULL) gsicc_release_link(pfs.icclink); |
114 | 0 | return code; |
115 | 0 | } |
116 | 53 | reserve_colors(&pfs, C, 3); /* Can't fail */ |
117 | 53 | va.c = ca = C[0]; |
118 | 53 | vb.c = cb = C[1]; |
119 | 53 | vc.c = cc = C[2]; |
120 | 53 | shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, |
121 | 53 | pgs); |
122 | | /* CET 09-47J.PS SpecialTestI04Test01 does not need the color data alignment. */ |
123 | 3.47k | while ((flag = shade_next_flag(&cs, num_bits)) >= 0) { |
124 | 3.45k | switch (flag) { |
125 | 31 | default: |
126 | 31 | code = gs_note_error(gs_error_rangecheck); |
127 | 31 | goto error; |
128 | 3.42k | case 0: |
129 | 3.42k | if ((code = Gt_next_vertex(pshm, &cs, &va, ca)) < 0 || |
130 | 3.42k | (code = shade_next_flag(&cs, num_bits)) < 0 || |
131 | 3.42k | (code = Gt_next_vertex(pshm, &cs, &vb, cb)) < 0 || |
132 | 3.42k | (code = shade_next_flag(&cs, num_bits)) < 0 |
133 | 3.42k | ) |
134 | 1 | break; |
135 | 3.42k | goto v2; |
136 | 3.42k | case 1: |
137 | 1 | c = ca; |
138 | 1 | va = vb; |
139 | 1 | ca = cb; |
140 | 1 | vb.c = cb = c; |
141 | | /* fall through */ |
142 | 1 | case 2: |
143 | 1 | c = cb; |
144 | 1 | vb = vc; |
145 | 1 | cb = cc; |
146 | 1 | vc.c = cc = c; |
147 | 3.42k | v2: if ((code = Gt_next_vertex(pshm, &cs, &vc, cc)) < 0) |
148 | 1 | break; |
149 | 3.42k | if ((code = Gt_fill_triangle(&pfs, &va, &vb, &vc)) < 0) |
150 | 0 | break; |
151 | 3.45k | } |
152 | 3.42k | cs.align(&cs, 8); /* Debugged with 12-14O.PS page 2. */ |
153 | 3.42k | } |
154 | 53 | error: |
155 | 53 | release_colors(&pfs, pfs.color_stack, 3); |
156 | 53 | if (pfs.icclink != NULL) gsicc_release_link(pfs.icclink); |
157 | 53 | if (term_patch_fill_state(&pfs)) |
158 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
159 | 53 | if (!cs.is_eod(&cs)) |
160 | 31 | return_error(gs_error_rangecheck); |
161 | 22 | return code; |
162 | 53 | } |
163 | | |
164 | | int |
165 | | gs_shading_LfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect, |
166 | | const gs_fixed_rect * rect_clip, |
167 | | gx_device * dev, gs_gstate * pgs) |
168 | 91 | { |
169 | 91 | const gs_shading_LfGt_t * const psh = (const gs_shading_LfGt_t *)psh0; |
170 | 91 | patch_fill_state_t pfs; |
171 | 91 | const gs_shading_mesh_t *pshm = (const gs_shading_mesh_t *)psh; |
172 | 91 | shade_coord_stream_t cs; |
173 | 91 | shading_vertex_t *vertex = NULL; |
174 | 91 | byte *color_buffer = NULL; |
175 | 91 | patch_color_t **color_buffer_ptrs = NULL; /* non-const access to vertex[i].c */ |
176 | 91 | shading_vertex_t next; |
177 | 91 | int per_row = psh->params.VerticesPerRow; |
178 | 91 | patch_color_t *c, *cn; /* cn == next.c always, provides a non-contst access. */ |
179 | 91 | int i, code; |
180 | | |
181 | 91 | code = shade_init_fill_state((shading_fill_state_t *)&pfs, |
182 | 91 | (const gs_shading_t *)psh, dev, pgs); |
183 | 91 | if (code < 0) |
184 | 0 | return code; |
185 | 91 | pfs.Function = pshm->params.Function; |
186 | 91 | pfs.rect = *rect_clip; |
187 | 91 | code = init_patch_fill_state(&pfs); |
188 | 91 | if (code < 0) |
189 | 0 | goto out; |
190 | 91 | reserve_colors(&pfs, &cn, 1); /* Can't fail. */ |
191 | 91 | next.c = cn; |
192 | 91 | shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, |
193 | 91 | pgs); |
194 | 91 | vertex = (shading_vertex_t *) |
195 | 91 | gs_alloc_byte_array(pgs->memory, per_row, sizeof(*vertex), |
196 | 91 | "gs_shading_LfGt_render"); |
197 | 91 | if (vertex == NULL) { |
198 | 0 | code = gs_note_error(gs_error_VMerror); |
199 | 0 | goto out; |
200 | 0 | } |
201 | 91 | color_buffer = gs_alloc_bytes(pgs->memory, |
202 | 91 | (size_t)pfs.color_stack_step * per_row, |
203 | 91 | "gs_shading_LfGt_fill_rectangle"); |
204 | 91 | if (color_buffer == NULL) { |
205 | 0 | code = gs_note_error(gs_error_VMerror); |
206 | 0 | goto out; |
207 | 0 | } |
208 | 91 | color_buffer_ptrs = (patch_color_t **)gs_alloc_bytes(pgs->memory, |
209 | 91 | sizeof(patch_color_t *) * per_row, "gs_shading_LfGt_fill_rectangle"); |
210 | 91 | if (color_buffer_ptrs == NULL) { |
211 | 0 | code = gs_note_error(gs_error_VMerror); |
212 | 0 | goto out; |
213 | 0 | } |
214 | | /* CET 09-47K.PS SpecialTestJ02Test05 needs the color data alignment. */ |
215 | 976 | for (i = 0; i < per_row; ++i) { |
216 | 888 | color_buffer_ptrs[i] = (patch_color_t *)(color_buffer + pfs.color_stack_step * i); |
217 | 888 | vertex[i].c = color_buffer_ptrs[i]; |
218 | 888 | if ((code = Gt_next_vertex(pshm, &cs, &vertex[i], color_buffer_ptrs[i])) < 0) |
219 | 3 | goto out; |
220 | 888 | } |
221 | 49.8k | while (!seofp(cs.s)) { |
222 | 49.8k | code = Gt_next_vertex(pshm, &cs, &next, cn); |
223 | 49.8k | if (code < 0) |
224 | 12 | goto out; |
225 | 498k | for (i = 1; i < per_row; ++i) { |
226 | 448k | code = Gt_fill_triangle(&pfs, &vertex[i - 1], &vertex[i], &next); |
227 | 448k | if (code < 0) |
228 | 0 | goto out; |
229 | 448k | c = color_buffer_ptrs[i - 1]; |
230 | 448k | vertex[i - 1] = next; |
231 | 448k | color_buffer_ptrs[i - 1] = cn; |
232 | 448k | next.c = cn = c; |
233 | 448k | code = Gt_next_vertex(pshm, &cs, &next, cn); |
234 | 448k | if (code < 0) |
235 | 68 | goto out; |
236 | 448k | code = Gt_fill_triangle(&pfs, &vertex[i], &vertex[i - 1], &next); |
237 | 448k | if (code < 0) |
238 | 0 | goto out; |
239 | 448k | } |
240 | 49.8k | c = color_buffer_ptrs[per_row - 1]; |
241 | 49.8k | vertex[per_row - 1] = next; |
242 | 49.8k | color_buffer_ptrs[per_row - 1] = cn; |
243 | 49.8k | next.c = cn = c; |
244 | 49.8k | } |
245 | 91 | out: |
246 | 91 | gs_free_object(pgs->memory, vertex, "gs_shading_LfGt_render"); |
247 | 91 | gs_free_object(pgs->memory, color_buffer, "gs_shading_LfGt_render"); |
248 | 91 | gs_free_object(pgs->memory, color_buffer_ptrs, "gs_shading_LfGt_render"); |
249 | 91 | release_colors(&pfs, pfs.color_stack, 1); |
250 | 91 | if (pfs.icclink != NULL) gsicc_release_link(pfs.icclink); |
251 | 91 | if (term_patch_fill_state(&pfs)) |
252 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
253 | 91 | return code; |
254 | 91 | } |