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