/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 | 2.01k | { |
40 | 2.01k | int code; |
41 | 2.01k | code = shade_init_fill_state((shading_fill_state_t *) pfs, |
42 | 2.01k | (const gs_shading_t *)psh, dev, pgs); |
43 | 2.01k | if (code < 0) |
44 | 0 | return code; |
45 | 2.01k | pfs->pshm = psh; |
46 | 2.01k | pfs->rect = *rect_clip; |
47 | 2.01k | return 0; |
48 | 2.01k | } |
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 | 2.23M | { |
56 | 2.23M | int code = shade_next_vertex(cs, vertex, c); |
57 | 2.23M | if (code < 0) |
58 | 369 | return code; |
59 | | |
60 | 2.23M | if (psh->params.Function) { |
61 | 2.17M | c->t[0] = c->cc.paint.values[0]; |
62 | 2.17M | c->t[1] = 0; |
63 | | /* Decode the color with the function. */ |
64 | 2.17M | code = gs_function_evaluate(psh->params.Function, c->t, |
65 | 2.17M | c->cc.paint.values); |
66 | 2.17M | } else |
67 | 63.7k | psh->params.ColorSpace->type->restrict_color(&c->cc, psh->params.ColorSpace); |
68 | 2.23M | return code; |
69 | 2.23M | } |
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 | 3.92M | { |
75 | 3.92M | int code = 0; |
76 | | |
77 | 3.92M | if (INTERPATCH_PADDING) { |
78 | 3.92M | code = mesh_padding(pfs, &va->p, &vb->p, va->c, vb->c); |
79 | 3.92M | if (code >= 0) |
80 | 3.92M | code = mesh_padding(pfs, &vb->p, &vc->p, vb->c, vc->c); |
81 | 3.92M | if (code >= 0) |
82 | 3.92M | code = mesh_padding(pfs, &vc->p, &va->p, vc->c, va->c); |
83 | 3.92M | } |
84 | 3.92M | if (code >= 0) |
85 | 3.92M | code = mesh_triangle(pfs, va, vb, vc); |
86 | 3.92M | return code; |
87 | 3.92M | } |
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 | 376 | { |
94 | 376 | const gs_shading_FfGt_t * const psh = (const gs_shading_FfGt_t *)psh0; |
95 | 376 | patch_fill_state_t pfs; |
96 | 376 | const gs_shading_mesh_t *pshm = (const gs_shading_mesh_t *)psh; |
97 | 376 | shade_coord_stream_t cs; |
98 | 376 | int num_bits = psh->params.BitsPerFlag; |
99 | 376 | int flag; |
100 | 376 | shading_vertex_t va, vb, vc; |
101 | 376 | 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 | 376 | int code; |
104 | | |
105 | 376 | code = shade_init_fill_state((shading_fill_state_t *)&pfs, |
106 | 376 | (const gs_shading_t *)psh, dev, pgs); |
107 | 376 | if (code < 0) |
108 | 0 | return code; |
109 | 376 | pfs.Function = pshm->params.Function; |
110 | 376 | pfs.rect = *rect_clip; |
111 | 376 | code = init_patch_fill_state(&pfs); |
112 | 376 | if (code < 0) { |
113 | 0 | if (pfs.icclink != NULL) gsicc_release_link(pfs.icclink); |
114 | 0 | return code; |
115 | 0 | } |
116 | 376 | reserve_colors(&pfs, C, 3); /* Can't fail */ |
117 | 376 | va.c = ca = C[0]; |
118 | 376 | vb.c = cb = C[1]; |
119 | 376 | vc.c = cc = C[2]; |
120 | 376 | shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, |
121 | 376 | pgs); |
122 | | /* CET 09-47J.PS SpecialTestI04Test01 does not need the color data alignment. */ |
123 | 21.3k | while ((flag = shade_next_flag(&cs, num_bits)) >= 0) { |
124 | 21.2k | switch (flag) { |
125 | 208 | default: |
126 | 208 | code = gs_note_error(gs_error_rangecheck); |
127 | 208 | goto error; |
128 | 21.0k | case 0: |
129 | 21.0k | if ((code = Gt_next_vertex(pshm, &cs, &va, ca)) < 0 || |
130 | 21.0k | (code = shade_next_flag(&cs, num_bits)) < 0 || |
131 | 21.0k | (code = Gt_next_vertex(pshm, &cs, &vb, cb)) < 0 || |
132 | 21.0k | (code = shade_next_flag(&cs, num_bits)) < 0 |
133 | 21.0k | ) |
134 | 3 | break; |
135 | 21.0k | goto v2; |
136 | 21.0k | case 1: |
137 | 5 | c = ca; |
138 | 5 | va = vb; |
139 | 5 | ca = cb; |
140 | 5 | vb.c = cb = c; |
141 | | /* fall through */ |
142 | 5 | case 2: |
143 | 5 | c = cb; |
144 | 5 | vb = vc; |
145 | 5 | cb = cc; |
146 | 5 | vc.c = cc = c; |
147 | 21.0k | v2: if ((code = Gt_next_vertex(pshm, &cs, &vc, cc)) < 0) |
148 | 2 | break; |
149 | 21.0k | if ((code = Gt_fill_triangle(&pfs, &va, &vb, &vc)) < 0) |
150 | 17 | break; |
151 | 21.2k | } |
152 | 21.0k | cs.align(&cs, 8); /* Debugged with 12-14O.PS page 2. */ |
153 | 21.0k | } |
154 | 376 | error: |
155 | 376 | release_colors(&pfs, pfs.color_stack, 3); |
156 | 376 | if (pfs.icclink != NULL) gsicc_release_link(pfs.icclink); |
157 | 376 | if (term_patch_fill_state(&pfs)) |
158 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
159 | 376 | if (!cs.is_eod(&cs)) |
160 | 208 | return_error(gs_error_rangecheck); |
161 | 168 | return code; |
162 | 376 | } |
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 | 402 | { |
169 | 402 | const gs_shading_LfGt_t * const psh = (const gs_shading_LfGt_t *)psh0; |
170 | 402 | patch_fill_state_t pfs; |
171 | 402 | const gs_shading_mesh_t *pshm = (const gs_shading_mesh_t *)psh; |
172 | 402 | shade_coord_stream_t cs; |
173 | 402 | shading_vertex_t *vertex = NULL; |
174 | 402 | byte *color_buffer = NULL; |
175 | 402 | patch_color_t **color_buffer_ptrs = NULL; /* non-const access to vertex[i].c */ |
176 | 402 | shading_vertex_t next; |
177 | 402 | int per_row = psh->params.VerticesPerRow; |
178 | 402 | patch_color_t *c, *cn; /* cn == next.c always, provides a non-contst access. */ |
179 | 402 | int i, code; |
180 | | |
181 | 402 | code = shade_init_fill_state((shading_fill_state_t *)&pfs, |
182 | 402 | (const gs_shading_t *)psh, dev, pgs); |
183 | 402 | if (code < 0) |
184 | 0 | return code; |
185 | 402 | pfs.Function = pshm->params.Function; |
186 | 402 | pfs.rect = *rect_clip; |
187 | 402 | code = init_patch_fill_state(&pfs); |
188 | 402 | if (code < 0) |
189 | 0 | goto out; |
190 | 402 | reserve_colors(&pfs, &cn, 1); /* Can't fail. */ |
191 | 402 | next.c = cn; |
192 | 402 | shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params, |
193 | 402 | pgs); |
194 | 402 | vertex = (shading_vertex_t *) |
195 | 402 | gs_alloc_byte_array(pgs->memory, per_row, sizeof(*vertex), |
196 | 402 | "gs_shading_LfGt_render"); |
197 | 402 | if (vertex == NULL) { |
198 | 0 | code = gs_note_error(gs_error_VMerror); |
199 | 0 | goto out; |
200 | 0 | } |
201 | 402 | color_buffer = gs_alloc_bytes(pgs->memory, |
202 | 402 | (size_t)pfs.color_stack_step * per_row, |
203 | 402 | "gs_shading_LfGt_fill_rectangle"); |
204 | 402 | if (color_buffer == NULL) { |
205 | 0 | code = gs_note_error(gs_error_VMerror); |
206 | 0 | goto out; |
207 | 0 | } |
208 | 402 | color_buffer_ptrs = (patch_color_t **)gs_alloc_bytes(pgs->memory, |
209 | 402 | sizeof(patch_color_t *) * per_row, "gs_shading_LfGt_fill_rectangle"); |
210 | 402 | 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 | 4.27k | for (i = 0; i < per_row; ++i) { |
216 | 3.89k | color_buffer_ptrs[i] = (patch_color_t *)(color_buffer + pfs.color_stack_step * i); |
217 | 3.89k | vertex[i].c = color_buffer_ptrs[i]; |
218 | 3.89k | if ((code = Gt_next_vertex(pshm, &cs, &vertex[i], color_buffer_ptrs[i])) < 0) |
219 | 17 | goto out; |
220 | 3.89k | } |
221 | 217k | while (!seofp(cs.s)) { |
222 | 217k | code = Gt_next_vertex(pshm, &cs, &next, cn); |
223 | 217k | if (code < 0) |
224 | 43 | goto out; |
225 | 2.17M | for (i = 1; i < per_row; ++i) { |
226 | 1.95M | code = Gt_fill_triangle(&pfs, &vertex[i - 1], &vertex[i], &next); |
227 | 1.95M | if (code < 0) |
228 | 0 | goto out; |
229 | 1.95M | c = color_buffer_ptrs[i - 1]; |
230 | 1.95M | vertex[i - 1] = next; |
231 | 1.95M | color_buffer_ptrs[i - 1] = cn; |
232 | 1.95M | next.c = cn = c; |
233 | 1.95M | code = Gt_next_vertex(pshm, &cs, &next, cn); |
234 | 1.95M | if (code < 0) |
235 | 304 | goto out; |
236 | 1.95M | code = Gt_fill_triangle(&pfs, &vertex[i], &vertex[i - 1], &next); |
237 | 1.95M | if (code < 0) |
238 | 0 | goto out; |
239 | 1.95M | } |
240 | 216k | c = color_buffer_ptrs[per_row - 1]; |
241 | 216k | vertex[per_row - 1] = next; |
242 | 216k | color_buffer_ptrs[per_row - 1] = cn; |
243 | 216k | next.c = cn = c; |
244 | 216k | } |
245 | 402 | out: |
246 | 402 | gs_free_object(pgs->memory, vertex, "gs_shading_LfGt_render"); |
247 | 402 | gs_free_object(pgs->memory, color_buffer, "gs_shading_LfGt_render"); |
248 | 402 | gs_free_object(pgs->memory, color_buffer_ptrs, "gs_shading_LfGt_render"); |
249 | 402 | release_colors(&pfs, pfs.color_stack, 1); |
250 | 402 | if (pfs.icclink != NULL) gsicc_release_link(pfs.icclink); |
251 | 402 | if (term_patch_fill_state(&pfs)) |
252 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
253 | 402 | return code; |
254 | 402 | } |