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