/src/ghostpdl/base/gsshade.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | | /* Constructors for shadings */ |
18 | | #include "gx.h" |
19 | | #include "gscspace.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsstruct.h" |
22 | | #include "gsptype2.h" |
23 | | #include "gxdevcli.h" |
24 | | #include "gxcpath.h" |
25 | | #include "gxcspace.h" |
26 | | #include "gxdcolor.h" /* for filling background rectangle */ |
27 | | #include "gxgstate.h" |
28 | | #include "gxpaint.h" |
29 | | #include "gxpath.h" |
30 | | #include "gxshade.h" |
31 | | #include "gxshade4.h" |
32 | | #include "gzpath.h" |
33 | | #include "gzcpath.h" |
34 | | #include "gsfunc3.h" |
35 | | |
36 | | /* ================ Initialize shadings ================ */ |
37 | | |
38 | | /* ---------------- Generic services ---------------- */ |
39 | | |
40 | | /* GC descriptors */ |
41 | | private_st_shading(); |
42 | | |
43 | | static |
44 | 0 | ENUM_PTRS_WITH(shading_mesh_enum_ptrs, gs_shading_mesh_t *psm) |
45 | 0 | { |
46 | 0 | index -= 2; |
47 | 0 | if (index < st_data_source_max_ptrs) |
48 | 0 | return ENUM_USING(st_data_source, &psm->params.DataSource, |
49 | 0 | sizeof(psm->params.DataSource), index); |
50 | 0 | return ENUM_USING_PREFIX(st_shading, st_data_source_max_ptrs); |
51 | 0 | } |
52 | 0 | ENUM_PTR2(0, gs_shading_mesh_t, params.Function, params.Decode); |
53 | 0 | ENUM_PTRS_END |
54 | | |
55 | | static |
56 | 0 | RELOC_PTRS_WITH(shading_mesh_reloc_ptrs, gs_shading_mesh_t *psm) |
57 | 0 | { |
58 | 0 | RELOC_PREFIX(st_shading); |
59 | 0 | RELOC_USING(st_data_source, &psm->params.DataSource, |
60 | 0 | sizeof(psm->params.DataSource)); |
61 | 0 | RELOC_PTR2(gs_shading_mesh_t, params.Function, params.Decode); |
62 | 0 | } |
63 | 0 | RELOC_PTRS_END |
64 | | |
65 | | /* Check ColorSpace, BBox, and Function (if present). */ |
66 | | /* Free variables: params. */ |
67 | | static int |
68 | | check_CBFD(const gs_shading_params_t * params, |
69 | | const gs_function_t * function, const float *domain, int m) |
70 | 18.2k | { |
71 | 18.2k | int ncomp = gs_color_space_num_components(params->ColorSpace); |
72 | | |
73 | 18.2k | if (ncomp < 0 || |
74 | 18.2k | (params->have_BBox && |
75 | 44 | (params->BBox.p.x > params->BBox.q.x || |
76 | 44 | params->BBox.p.y > params->BBox.q.y)) |
77 | 18.2k | ) |
78 | 0 | return_error(gs_error_rangecheck); |
79 | 18.2k | if (function != 0) { |
80 | 17.1k | if (function->params.m != m || function->params.n != ncomp) |
81 | 6 | return_error(gs_error_rangecheck); |
82 | 17.1k | if (function->head.type == function_type_ArrayedOutput) { |
83 | | /* If the Function member is an array it must contain either n 1-in, 1-out function dictionaries |
84 | | * or (type 1, function-based shadings) n 2-in, 1-out function dictionaries. Either way all the |
85 | | * functions have to have a single output, so we need to check that. |
86 | | */ |
87 | 0 | int i = 0; |
88 | 0 | gs_function_AdOt_params_t *a_params = (gs_function_AdOt_params_t *)&function->params; |
89 | |
|
90 | 0 | for (i = 0; i < a_params->n;i++) { |
91 | 0 | if (a_params->Functions[i]->params.m != m || a_params->Functions[i]->params.n != 1) |
92 | 0 | return_error(gs_error_rangecheck); |
93 | 0 | } |
94 | 0 | } |
95 | | /* |
96 | | * The Adobe documentation says that the function's domain must |
97 | | * be a superset of the domain defined in the shading dictionary. |
98 | | * However, Adobe implementations apparently don't necessarily |
99 | | * check this ahead of time; therefore, we do the same. |
100 | | */ |
101 | 17.1k | } |
102 | 18.2k | return 0; |
103 | 18.2k | } |
104 | | |
105 | | /* Check parameters for a mesh shading. */ |
106 | | static int |
107 | | check_mesh(const gs_shading_mesh_params_t * params) |
108 | 1.44k | { |
109 | 1.44k | const float *domain; |
110 | | |
111 | 1.44k | if (data_source_is_array(params->DataSource)) |
112 | 0 | domain = 0; |
113 | 1.44k | else { |
114 | 1.44k | domain = params->Decode; |
115 | 1.44k | switch (params->BitsPerCoordinate) { |
116 | 4 | case 1: case 2: case 4: case 8: |
117 | 1.44k | case 12: case 16: case 24: case 32: |
118 | 1.44k | break; |
119 | 0 | default: |
120 | 0 | return_error(gs_error_rangecheck); |
121 | 1.44k | } |
122 | 1.44k | switch (params->BitsPerComponent) { |
123 | 723 | case 1: case 2: case 4: case 8: |
124 | 1.44k | case 12: case 16: |
125 | 1.44k | break; |
126 | 0 | default: |
127 | 0 | return_error(gs_error_rangecheck); |
128 | 1.44k | } |
129 | 1.44k | } |
130 | 1.44k | return check_CBFD((const gs_shading_params_t *)params, |
131 | 1.44k | params->Function, domain, 1); |
132 | 1.44k | } |
133 | | |
134 | | /* Check the BitsPerFlag value. Return the value or an error code. */ |
135 | | static int |
136 | | check_BPF(const gs_data_source_t *pds, int bpf) |
137 | 1.16k | { |
138 | 1.16k | if (data_source_is_array(*pds)) |
139 | 0 | return 2; |
140 | 1.16k | switch (bpf) { |
141 | 1.16k | case 2: case 4: case 8: |
142 | 1.16k | return bpf; |
143 | 0 | default: |
144 | 0 | return_error(gs_error_rangecheck); |
145 | 1.16k | } |
146 | 1.16k | } |
147 | | |
148 | | /* Initialize common shading parameters. */ |
149 | | static void |
150 | | shading_params_init(gs_shading_params_t *params) |
151 | 20 | { |
152 | 20 | params->ColorSpace = 0; /* must be set by client */ |
153 | 20 | params->cie_joint_caches = 0; |
154 | 20 | params->Background = 0; |
155 | 20 | params->have_BBox = false; |
156 | 20 | params->AntiAlias = false; |
157 | 20 | } |
158 | | |
159 | | /* Initialize common mesh shading parameters. */ |
160 | | static void |
161 | | mesh_shading_params_init(gs_shading_mesh_params_t *params) |
162 | 0 | { |
163 | 0 | shading_params_init((gs_shading_params_t *)params); |
164 | 0 | data_source_init_floats(¶ms->DataSource, NULL, 0);/* client must set */ |
165 | | /* Client must set BitsPerCoordinate and BitsPerComponent */ |
166 | | /* if DataSource is not an array. */ |
167 | 0 | params->Decode = 0; |
168 | 0 | params->Function = 0; |
169 | 0 | } |
170 | | |
171 | | /* Allocate and initialize a shading. */ |
172 | | #define ALLOC_SHADING(ppsh, psh, mem, sttype, stype, sprocs, cname, params)\ |
173 | 36.4k | BEGIN\ |
174 | 36.4k | psh = gs_alloc_struct(mem, void, sttype, cname);\ |
175 | 36.4k | if ( psh == 0 )\ |
176 | 36.4k | return_error(gs_error_VMerror);\ |
177 | 36.4k | psh->head.type = stype;\ |
178 | 18.2k | psh->head.procs = sprocs;\ |
179 | 18.2k | psh->params = *params;\ |
180 | 18.2k | *ppsh = (gs_shading_t *)psh;\ |
181 | 18.2k | END |
182 | | |
183 | | /* ---------------- Function-based shading ---------------- */ |
184 | | |
185 | | private_st_shading_Fb(); |
186 | | |
187 | | /* Initialize parameters for a Function-based shading. */ |
188 | | void |
189 | | gs_shading_Fb_params_init(gs_shading_Fb_params_t * params) |
190 | 0 | { |
191 | 0 | shading_params_init((gs_shading_params_t *)params); |
192 | 0 | params->Domain[0] = params->Domain[2] = 0; |
193 | 0 | params->Domain[1] = params->Domain[3] = 1; |
194 | 0 | gs_make_identity(¶ms->Matrix); |
195 | 0 | params->Function = 0; /* must be set by client */ |
196 | 0 | } |
197 | | |
198 | | /* Allocate and initialize a Function-based shading. */ |
199 | | static const gs_shading_procs_t shading_Fb_procs = { |
200 | | gs_shading_Fb_fill_rectangle |
201 | | }; |
202 | | int |
203 | | gs_shading_Fb_init(gs_shading_t ** ppsh, |
204 | | const gs_shading_Fb_params_t * params, gs_memory_t * mem) |
205 | 0 | { |
206 | 0 | gs_shading_Fb_t *psh; |
207 | 0 | gs_matrix imat; |
208 | 0 | int code = check_CBFD((const gs_shading_params_t *)params, |
209 | 0 | params->Function, params->Domain, 2); |
210 | |
|
211 | 0 | if (code < 0 || |
212 | 0 | (code = gs_matrix_invert(¶ms->Matrix, &imat)) < 0 |
213 | 0 | ) |
214 | 0 | return code; |
215 | 0 | ALLOC_SHADING(ppsh, psh, mem, &st_shading_Fb, shading_type_Function_based, |
216 | 0 | shading_Fb_procs, "gs_shading_Fb_init", params); |
217 | 0 | return 0; |
218 | 0 | } |
219 | | |
220 | | /* ---------------- Axial shading ---------------- */ |
221 | | |
222 | | private_st_shading_A(); |
223 | | |
224 | | /* Initialize parameters for an Axial shading. */ |
225 | | void |
226 | | gs_shading_A_params_init(gs_shading_A_params_t * params) |
227 | 10 | { |
228 | 10 | shading_params_init((gs_shading_params_t *)params); |
229 | | /* Coords must be set by client */ |
230 | 10 | params->Domain[0] = 0; |
231 | 10 | params->Domain[1] = 1; |
232 | 10 | params->Function = 0; /* must be set by client */ |
233 | 10 | params->Extend[0] = params->Extend[1] = false; |
234 | 10 | } |
235 | | |
236 | | /* Allocate and initialize an Axial shading. */ |
237 | | static const gs_shading_procs_t shading_A_procs = { |
238 | | gs_shading_A_fill_rectangle |
239 | | }; |
240 | | int |
241 | | gs_shading_A_init(gs_shading_t ** ppsh, |
242 | | const gs_shading_A_params_t * params, gs_memory_t * mem) |
243 | 16.5k | { |
244 | 16.5k | gs_shading_A_t *psh; |
245 | 16.5k | int code = check_CBFD((const gs_shading_params_t *)params, |
246 | 16.5k | params->Function, params->Domain, 1); |
247 | | |
248 | 16.5k | if (code < 0) |
249 | 6 | return code; |
250 | 16.5k | ALLOC_SHADING(ppsh, psh, mem, &st_shading_A, shading_type_Axial, |
251 | 16.5k | shading_A_procs, "gs_shading_A_init", params); |
252 | 16.5k | return 0; |
253 | 16.5k | } |
254 | | |
255 | | /* ---------------- Radial shading ---------------- */ |
256 | | |
257 | | private_st_shading_R(); |
258 | | |
259 | | /* Initialize parameters for a Radial shading. */ |
260 | | void |
261 | | gs_shading_R_params_init(gs_shading_R_params_t * params) |
262 | 10 | { |
263 | 10 | shading_params_init((gs_shading_params_t *)params); |
264 | | /* Coords must be set by client */ |
265 | 10 | params->Domain[0] = 0; |
266 | 10 | params->Domain[1] = 1; |
267 | 10 | params->Function = 0; /* must be set by client */ |
268 | 10 | params->Extend[0] = params->Extend[1] = false; |
269 | 10 | } |
270 | | |
271 | | /* Allocate and initialize a Radial shading. */ |
272 | | static const gs_shading_procs_t shading_R_procs = { |
273 | | gs_shading_R_fill_rectangle |
274 | | }; |
275 | | int |
276 | | gs_shading_R_init(gs_shading_t ** ppsh, |
277 | | const gs_shading_R_params_t * params, gs_memory_t * mem) |
278 | 181 | { |
279 | 181 | gs_shading_R_t *psh; |
280 | 181 | int code; |
281 | | |
282 | 181 | if (params == NULL || params->Domain[0] == params->Domain[1] || |
283 | 181 | params->Coords[2] < 0 || params->Coords[5] < 0) |
284 | 0 | return_error(gs_error_rangecheck); |
285 | 181 | code = check_CBFD((const gs_shading_params_t *)params, |
286 | 181 | params->Function, params->Domain, 1); |
287 | | |
288 | 181 | if (code < 0) |
289 | 0 | return code; |
290 | 181 | ALLOC_SHADING(ppsh, psh, mem, &st_shading_R, shading_type_Radial, |
291 | 181 | shading_R_procs, "gs_shading_R_init", params); |
292 | 181 | return 0; |
293 | 181 | } |
294 | | |
295 | | /* ---------------- Free-form Gouraud triangle mesh shading ---------------- */ |
296 | | |
297 | | private_st_shading_FfGt(); |
298 | | |
299 | | /* Initialize parameters for a Free-form Gouraud triangle mesh shading. */ |
300 | | void |
301 | | gs_shading_FfGt_params_init(gs_shading_FfGt_params_t * params) |
302 | 0 | { |
303 | 0 | mesh_shading_params_init((gs_shading_mesh_params_t *)params); |
304 | | /* Client must set BitsPerFlag if DataSource is not an array. */ |
305 | 0 | } |
306 | | |
307 | | /* Allocate and initialize a Free-form Gouraud triangle mesh shading. */ |
308 | | static const gs_shading_procs_t shading_FfGt_procs = { |
309 | | gs_shading_FfGt_fill_rectangle |
310 | | }; |
311 | | int |
312 | | gs_shading_FfGt_init(gs_shading_t ** ppsh, |
313 | | const gs_shading_FfGt_params_t * params, |
314 | | gs_memory_t * mem) |
315 | 285 | { |
316 | 285 | gs_shading_FfGt_t *psh; |
317 | 285 | int code = check_mesh((const gs_shading_mesh_params_t *)params); |
318 | 285 | int bpf = check_BPF(¶ms->DataSource, params->BitsPerFlag); |
319 | | |
320 | 285 | if (code < 0) |
321 | 0 | return code; |
322 | 285 | if (bpf < 0) |
323 | 0 | return bpf; |
324 | 285 | ALLOC_SHADING(ppsh, psh, mem, &st_shading_FfGt, shading_type_Free_form_Gouraud_triangle, |
325 | 285 | shading_FfGt_procs, "gs_shading_FfGt_init", params); |
326 | 285 | psh->params.BitsPerFlag = bpf; |
327 | 285 | return 0; |
328 | 285 | } |
329 | | |
330 | | /* -------------- Lattice-form Gouraud triangle mesh shading -------------- */ |
331 | | |
332 | | private_st_shading_LfGt(); |
333 | | |
334 | | /* Initialize parameters for a Lattice-form Gouraud triangle mesh shading. */ |
335 | | void |
336 | | gs_shading_LfGt_params_init(gs_shading_LfGt_params_t * params) |
337 | 0 | { |
338 | 0 | mesh_shading_params_init((gs_shading_mesh_params_t *)params); |
339 | | /* Client must set VerticesPerRow. */ |
340 | 0 | } |
341 | | |
342 | | /* Allocate and initialize a Lattice-form Gouraud triangle mesh shading. */ |
343 | | static const gs_shading_procs_t shading_LfGt_procs = { |
344 | | gs_shading_LfGt_fill_rectangle |
345 | | }; |
346 | | int |
347 | | gs_shading_LfGt_init(gs_shading_t ** ppsh, |
348 | | const gs_shading_LfGt_params_t * params, gs_memory_t * mem) |
349 | 284 | { |
350 | 284 | gs_shading_LfGt_t *psh; |
351 | 284 | int code = check_mesh((const gs_shading_mesh_params_t *)params); |
352 | | |
353 | 284 | if (code < 0) |
354 | 0 | return code; |
355 | 284 | if (params->VerticesPerRow < 2) |
356 | 0 | return_error(gs_error_rangecheck); |
357 | 284 | ALLOC_SHADING(ppsh, psh, mem, &st_shading_LfGt, shading_type_Lattice_form_Gouraud_triangle, |
358 | 284 | shading_LfGt_procs, "gs_shading_LfGt_init", params); |
359 | 284 | return 0; |
360 | 284 | } |
361 | | |
362 | | /* ---------------- Coons patch mesh shading ---------------- */ |
363 | | |
364 | | private_st_shading_Cp(); |
365 | | |
366 | | /* Initialize parameters for a Coons patch mesh shading. */ |
367 | | void |
368 | | gs_shading_Cp_params_init(gs_shading_Cp_params_t * params) |
369 | 0 | { |
370 | 0 | mesh_shading_params_init((gs_shading_mesh_params_t *)params); |
371 | | /* Client must set BitsPerFlag if DataSource is not an array. */ |
372 | 0 | } |
373 | | |
374 | | /* Allocate and initialize a Coons patch mesh shading. */ |
375 | | static const gs_shading_procs_t shading_Cp_procs = { |
376 | | gs_shading_Cp_fill_rectangle |
377 | | }; |
378 | | int |
379 | | gs_shading_Cp_init(gs_shading_t ** ppsh, |
380 | | const gs_shading_Cp_params_t * params, gs_memory_t * mem) |
381 | 153 | { |
382 | 153 | gs_shading_Cp_t *psh; |
383 | 153 | int code = check_mesh((const gs_shading_mesh_params_t *)params); |
384 | 153 | int bpf = check_BPF(¶ms->DataSource, params->BitsPerFlag); |
385 | | |
386 | 153 | if (code < 0) |
387 | 0 | return code; |
388 | 153 | if (bpf < 0) |
389 | 0 | return bpf; |
390 | 153 | ALLOC_SHADING(ppsh, psh, mem, &st_shading_Cp, shading_type_Coons_patch, |
391 | 153 | shading_Cp_procs, "gs_shading_Cp_init", params); |
392 | 153 | psh->params.BitsPerFlag = bpf; |
393 | 153 | return 0; |
394 | 153 | } |
395 | | |
396 | | /* ---------------- Tensor product patch mesh shading ---------------- */ |
397 | | |
398 | | private_st_shading_Tpp(); |
399 | | |
400 | | /* Initialize parameters for a Tensor product patch mesh shading. */ |
401 | | void |
402 | | gs_shading_Tpp_params_init(gs_shading_Tpp_params_t * params) |
403 | 0 | { |
404 | 0 | mesh_shading_params_init((gs_shading_mesh_params_t *)params); |
405 | | /* Client must set BitsPerFlag if DataSource is not an array. */ |
406 | 0 | } |
407 | | |
408 | | /* Allocate and initialize a Tensor product patch mesh shading. */ |
409 | | static const gs_shading_procs_t shading_Tpp_procs = { |
410 | | gs_shading_Tpp_fill_rectangle |
411 | | }; |
412 | | int |
413 | | gs_shading_Tpp_init(gs_shading_t ** ppsh, |
414 | | const gs_shading_Tpp_params_t * params, gs_memory_t * mem) |
415 | 723 | { |
416 | 723 | gs_shading_Tpp_t *psh; |
417 | 723 | int code = check_mesh((const gs_shading_mesh_params_t *)params); |
418 | 723 | int bpf = check_BPF(¶ms->DataSource, params->BitsPerFlag); |
419 | | |
420 | 723 | if (code < 0) |
421 | 0 | return code; |
422 | 723 | if (bpf < 0) |
423 | 0 | return bpf; |
424 | 723 | ALLOC_SHADING(ppsh, psh, mem, &st_shading_Tpp, shading_type_Tensor_product_patch, |
425 | 723 | shading_Tpp_procs, "gs_shading_Tpp_init", params); |
426 | 723 | psh->params.BitsPerFlag = bpf; |
427 | 723 | return 0; |
428 | 723 | } |
429 | | |
430 | | /* ================ Shading rendering ================ */ |
431 | | |
432 | | /* Add a user-space rectangle to a path. */ |
433 | | int |
434 | | gs_shading_path_add_box(gx_path *ppath, const gs_rect *pbox, |
435 | | const gs_matrix_fixed *pmat) |
436 | 32 | { |
437 | 32 | gs_fixed_point pt; |
438 | 32 | gs_fixed_point pts[3]; |
439 | 32 | int code; |
440 | | |
441 | 32 | if ((code = gs_point_transform2fixed(pmat, pbox->p.x, pbox->p.y, |
442 | 32 | &pt)) < 0 || |
443 | 32 | (code = gx_path_add_point(ppath, pt.x, pt.y)) < 0 || |
444 | 32 | (code = gs_point_transform2fixed(pmat, pbox->q.x, pbox->p.y, |
445 | 32 | &pts[0])) < 0 || |
446 | 32 | (code = gs_point_transform2fixed(pmat, pbox->q.x, pbox->q.y, |
447 | 32 | &pts[1])) < 0 || |
448 | 32 | (code = gs_point_transform2fixed(pmat, pbox->p.x, pbox->q.y, |
449 | 32 | &pts[2])) < 0 || |
450 | 32 | (code = gx_path_add_lines(ppath, pts, 3)) < 0 |
451 | 32 | ) |
452 | 32 | DO_NOTHING; |
453 | 32 | return code; |
454 | 32 | } |
455 | | |
456 | | /* Fill a path with a shading. */ |
457 | | int |
458 | | gs_shading_do_fill_rectangle(const gs_shading_t *psh, |
459 | | const gs_fixed_rect *prect, gx_device *dev, |
460 | | gs_gstate *pgs, bool fill_background) |
461 | 41.1k | { /* If you need to fill a path, clip the output device before calling this function. */ |
462 | 41.1k | const gs_matrix_fixed *pmat = &pgs->ctm; |
463 | 41.1k | gs_fixed_rect path_box; |
464 | 41.1k | gs_rect path_rect; |
465 | 41.1k | gs_rect rect; |
466 | 41.1k | int code = 0; |
467 | | |
468 | 41.1k | dev_proc(dev, get_clipping_box)(dev, &path_box); |
469 | 41.1k | if (prect) |
470 | 41.1k | rect_intersect(path_box, *prect); |
471 | 41.1k | if (psh->params.Background && fill_background) { |
472 | 20.7k | const gs_color_space *pcs = psh->params.ColorSpace; |
473 | 20.7k | gs_client_color cc; |
474 | 20.7k | gx_device_color dev_color; |
475 | | |
476 | 20.7k | cc = *psh->params.Background; |
477 | 20.7k | (*pcs->type->restrict_color)(&cc, pcs); |
478 | 20.7k | code = (*pcs->type->remap_color)(&cc, pcs, &dev_color, pgs, |
479 | 20.7k | dev, gs_color_select_texture); |
480 | | |
481 | | /****** WRONG IF NON-IDEMPOTENT RasterOp ******/ |
482 | 20.7k | if (code >= 0) |
483 | 20.7k | code = gx_shade_background(dev, &path_box, &dev_color, pgs->log_op); |
484 | 20.7k | } |
485 | 41.1k | if (code >= 0) { |
486 | 41.1k | path_rect.p.x = fixed2float(path_box.p.x); |
487 | 41.1k | path_rect.p.y = fixed2float(path_box.p.y); |
488 | 41.1k | path_rect.q.x = fixed2float(path_box.q.x); |
489 | 41.1k | path_rect.q.y = fixed2float(path_box.q.y); |
490 | 41.1k | code = gs_bbox_transform_inverse(&path_rect, (const gs_matrix *)pmat, &rect); |
491 | 41.1k | if (code >= 0) |
492 | 41.0k | code = gs_shading_fill_rectangle(psh, &rect, &path_box, dev, pgs); |
493 | 41.1k | } |
494 | 41.1k | return code; |
495 | 41.1k | } |