xref: /plan9/sys/src/cmd/gs/src/gsshade.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gsshade.c,v 1.17 2005/04/19 12:22:08 igor Exp $ */
18 /* Constructors for shadings */
19 #include "gx.h"
20 #include "gscspace.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gsptype2.h"
24 #include "gxdevcli.h"
25 #include "gxcpath.h"
26 #include "gxcspace.h"
27 #include "gxdcolor.h"		/* for filling background rectangle */
28 #include "gxistate.h"
29 #include "gxpaint.h"
30 #include "gxpath.h"
31 #include "gxshade.h"
32 #include "gxshade4.h"
33 #include "gzpath.h"
34 #include "gzcpath.h"
35 
36 /* ================ Initialize shadings ================ */
37 
38 /* ---------------- Generic services ---------------- */
39 
40 /* GC descriptors */
41 private_st_shading();
42 private_st_shading_mesh();
43 
44 private
ENUM_PTRS_WITH(shading_mesh_enum_ptrs,gs_shading_mesh_t * psm)45 ENUM_PTRS_WITH(shading_mesh_enum_ptrs, gs_shading_mesh_t *psm)
46 {
47     index -= 2;
48     if (index < st_data_source_max_ptrs)
49 	return ENUM_USING(st_data_source, &psm->params.DataSource,
50 			  sizeof(psm->params.DataSource), index);
51     return ENUM_USING_PREFIX(st_shading, st_data_source_max_ptrs);
52 }
53 ENUM_PTR2(0, gs_shading_mesh_t, params.Function, params.Decode);
54 ENUM_PTRS_END
55 
56 private
RELOC_PTRS_WITH(shading_mesh_reloc_ptrs,gs_shading_mesh_t * psm)57 RELOC_PTRS_WITH(shading_mesh_reloc_ptrs, gs_shading_mesh_t *psm)
58 {
59     RELOC_PREFIX(st_shading);
60     RELOC_USING(st_data_source, &psm->params.DataSource,
61 		sizeof(psm->params.DataSource));
62     RELOC_PTR2(gs_shading_mesh_t, params.Function, params.Decode);
63 }
64 RELOC_PTRS_END
65 
66 /* Check ColorSpace, BBox, and Function (if present). */
67 /* Free variables: params. */
68 private int
check_CBFD(const gs_shading_params_t * params,const gs_function_t * function,const float * domain,int m)69 check_CBFD(const gs_shading_params_t * params,
70 	   const gs_function_t * function, const float *domain, int m)
71 {
72     int ncomp = gs_color_space_num_components(params->ColorSpace);
73 
74     if (ncomp < 0 ||
75 	(params->have_BBox &&
76 	 (params->BBox.p.x > params->BBox.q.x ||
77 	  params->BBox.p.y > params->BBox.q.y))
78 	)
79 	return_error(gs_error_rangecheck);
80     if (function != 0) {
81 	if (function->params.m != m || function->params.n != ncomp)
82 	    return_error(gs_error_rangecheck);
83 	/*
84 	 * The Adobe documentation says that the function's domain must
85 	 * be a superset of the domain defined in the shading dictionary.
86 	 * However, Adobe implementations apparently don't necessarily
87 	 * check this ahead of time; therefore, we do the same.
88 	 */
89     }
90     return 0;
91 }
92 
93 /* Check parameters for a mesh shading. */
94 private int
check_mesh(const gs_shading_mesh_params_t * params)95 check_mesh(const gs_shading_mesh_params_t * params)
96 {
97     const float *domain;
98 
99     if (data_source_is_array(params->DataSource))
100 	domain = 0;
101     else {
102 	domain = params->Decode;
103 	switch (params->BitsPerCoordinate) {
104 	    case  1: case  2: case  4: case  8:
105 	    case 12: case 16: case 24: case 32:
106 		break;
107 	    default:
108 		return_error(gs_error_rangecheck);
109 	}
110 	switch (params->BitsPerComponent) {
111 	    case  1: case  2: case  4: case  8:
112 	    case 12: case 16:
113 		break;
114 	    default:
115 		return_error(gs_error_rangecheck);
116 	}
117     }
118     return check_CBFD((const gs_shading_params_t *)params,
119 		      params->Function, domain, 1);
120 }
121 
122 /* Check the BitsPerFlag value.  Return the value or an error code. */
123 private int
check_BPF(const gs_data_source_t * pds,int bpf)124 check_BPF(const gs_data_source_t *pds, int bpf)
125 {
126     if (data_source_is_array(*pds))
127 	return 2;
128     switch (bpf) {
129     case 2: case 4: case 8:
130 	return bpf;
131     default:
132 	return_error(gs_error_rangecheck);
133     }
134 }
135 
136 /* Initialize common shading parameters. */
137 private void
shading_params_init(gs_shading_params_t * params)138 shading_params_init(gs_shading_params_t *params)
139 {
140     params->ColorSpace = 0;	/* must be set by client */
141     params->Background = 0;
142     params->have_BBox = false;
143     params->AntiAlias = false;
144 }
145 
146 /* Initialize common mesh shading parameters. */
147 private void
mesh_shading_params_init(gs_shading_mesh_params_t * params)148 mesh_shading_params_init(gs_shading_mesh_params_t *params)
149 {
150     shading_params_init((gs_shading_params_t *)params);
151     data_source_init_floats(&params->DataSource, NULL, 0);/* client must set */
152     /* Client must set BitsPerCoordinate and BitsPerComponent */
153     /* if DataSource is not an array. */
154     params->Decode = 0;
155     params->Function = 0;
156 }
157 
158 /* Allocate and initialize a shading. */
159 /* Free variables: mem, params, ppsh, psh. */
160 #define ALLOC_SHADING(sttype, stype, sprocs, cname)\
161   BEGIN\
162     psh = gs_alloc_struct(mem, void, sttype, cname);\
163     if ( psh == 0 )\
164       return_error(gs_error_VMerror);\
165     psh->head.type = stype;\
166     psh->head.procs = sprocs;\
167     psh->params = *params;\
168     *ppsh = (gs_shading_t *)psh;\
169   END
170 
171 /* ---------------- Function-based shading ---------------- */
172 
173 private_st_shading_Fb();
174 
175 /* Initialize parameters for a Function-based shading. */
176 void
gs_shading_Fb_params_init(gs_shading_Fb_params_t * params)177 gs_shading_Fb_params_init(gs_shading_Fb_params_t * params)
178 {
179     shading_params_init((gs_shading_params_t *)params);
180     params->Domain[0] = params->Domain[2] = 0;
181     params->Domain[1] = params->Domain[3] = 1;
182     gs_make_identity(&params->Matrix);
183     params->Function = 0;	/* must be set by client */
184 }
185 
186 /* Allocate and initialize a Function-based shading. */
187 private const gs_shading_procs_t shading_Fb_procs = {
188     gs_shading_Fb_fill_rectangle
189 };
190 int
gs_shading_Fb_init(gs_shading_t ** ppsh,const gs_shading_Fb_params_t * params,gs_memory_t * mem)191 gs_shading_Fb_init(gs_shading_t ** ppsh,
192 		   const gs_shading_Fb_params_t * params, gs_memory_t * mem)
193 {
194     gs_shading_Fb_t *psh;
195     gs_matrix imat;
196     int code = check_CBFD((const gs_shading_params_t *)params,
197 			  params->Function, params->Domain, 2);
198 
199     if (code < 0 ||
200 	(code = gs_matrix_invert(&params->Matrix, &imat)) < 0
201 	)
202 	return code;
203     ALLOC_SHADING(&st_shading_Fb, shading_type_Function_based,
204 		  shading_Fb_procs, "gs_shading_Fb_init");
205     return 0;
206 }
207 
208 /* ---------------- Axial shading ---------------- */
209 
210 private_st_shading_A();
211 
212 /* Initialize parameters for an Axial shading. */
213 void
gs_shading_A_params_init(gs_shading_A_params_t * params)214 gs_shading_A_params_init(gs_shading_A_params_t * params)
215 {
216     shading_params_init((gs_shading_params_t *)params);
217     /* Coords must be set by client */
218     params->Domain[0] = 0;
219     params->Domain[1] = 1;
220     params->Function = 0;	/* must be set by client */
221     params->Extend[0] = params->Extend[1] = false;
222 }
223 
224 /* Allocate and initialize an Axial shading. */
225 private const gs_shading_procs_t shading_A_procs = {
226     gs_shading_A_fill_rectangle
227 };
228 int
gs_shading_A_init(gs_shading_t ** ppsh,const gs_shading_A_params_t * params,gs_memory_t * mem)229 gs_shading_A_init(gs_shading_t ** ppsh,
230 		  const gs_shading_A_params_t * params, gs_memory_t * mem)
231 {
232     gs_shading_A_t *psh;
233     int code = check_CBFD((const gs_shading_params_t *)params,
234 			  params->Function, params->Domain, 1);
235 
236     if (code < 0)
237 	return code;
238     ALLOC_SHADING(&st_shading_A, shading_type_Axial,
239 		  shading_A_procs, "gs_shading_A_init");
240     return 0;
241 }
242 
243 /* ---------------- Radial shading ---------------- */
244 
245 private_st_shading_R();
246 
247 /* Initialize parameters for a Radial shading. */
248 void
gs_shading_R_params_init(gs_shading_R_params_t * params)249 gs_shading_R_params_init(gs_shading_R_params_t * params)
250 {
251     shading_params_init((gs_shading_params_t *)params);
252     /* Coords must be set by client */
253     params->Domain[0] = 0;
254     params->Domain[1] = 1;
255     params->Function = 0;	/* must be set by client */
256     params->Extend[0] = params->Extend[1] = false;
257 }
258 
259 /* Allocate and initialize a Radial shading. */
260 private const gs_shading_procs_t shading_R_procs = {
261     gs_shading_R_fill_rectangle
262 };
263 int
gs_shading_R_init(gs_shading_t ** ppsh,const gs_shading_R_params_t * params,gs_memory_t * mem)264 gs_shading_R_init(gs_shading_t ** ppsh,
265 		  const gs_shading_R_params_t * params, gs_memory_t * mem)
266 {
267     gs_shading_R_t *psh;
268     int code = check_CBFD((const gs_shading_params_t *)params,
269 			  params->Function, params->Domain, 1);
270 
271     if (code < 0)
272 	return code;
273     if ((params->Domain != 0 && params->Domain[0] == params->Domain[1]) ||
274 	params->Coords[2] < 0 || params->Coords[5] < 0
275 	)
276 	return_error(gs_error_rangecheck);
277     ALLOC_SHADING(&st_shading_R, shading_type_Radial,
278 		  shading_R_procs, "gs_shading_R_init");
279     return 0;
280 }
281 
282 /* ---------------- Free-form Gouraud triangle mesh shading ---------------- */
283 
284 private_st_shading_FfGt();
285 
286 /* Initialize parameters for a Free-form Gouraud triangle mesh shading. */
287 void
gs_shading_FfGt_params_init(gs_shading_FfGt_params_t * params)288 gs_shading_FfGt_params_init(gs_shading_FfGt_params_t * params)
289 {
290     mesh_shading_params_init((gs_shading_mesh_params_t *)params);
291     /* Client must set BitsPerFlag if DataSource is not an array. */
292 }
293 
294 /* Allocate and initialize a Free-form Gouraud triangle mesh shading. */
295 private const gs_shading_procs_t shading_FfGt_procs = {
296     gs_shading_FfGt_fill_rectangle
297 };
298 int
gs_shading_FfGt_init(gs_shading_t ** ppsh,const gs_shading_FfGt_params_t * params,gs_memory_t * mem)299 gs_shading_FfGt_init(gs_shading_t ** ppsh,
300 		     const gs_shading_FfGt_params_t * params,
301 		     gs_memory_t * mem)
302 {
303     gs_shading_FfGt_t *psh;
304     int code = check_mesh((const gs_shading_mesh_params_t *)params);
305     int bpf = check_BPF(&params->DataSource, params->BitsPerFlag);
306 
307     if (code < 0)
308 	return code;
309     if (bpf < 0)
310 	return bpf;
311     if (params->Decode != 0 && params->Decode[0] == params->Decode[1])
312 	return_error(gs_error_rangecheck);
313     ALLOC_SHADING(&st_shading_FfGt, shading_type_Free_form_Gouraud_triangle,
314 		  shading_FfGt_procs, "gs_shading_FfGt_init");
315     psh->params.BitsPerFlag = bpf;
316     return 0;
317 }
318 
319 /* -------------- Lattice-form Gouraud triangle mesh shading -------------- */
320 
321 private_st_shading_LfGt();
322 
323 /* Initialize parameters for a Lattice-form Gouraud triangle mesh shading. */
324 void
gs_shading_LfGt_params_init(gs_shading_LfGt_params_t * params)325 gs_shading_LfGt_params_init(gs_shading_LfGt_params_t * params)
326 {
327     mesh_shading_params_init((gs_shading_mesh_params_t *)params);
328     /* Client must set VerticesPerRow. */
329 }
330 
331 /* Allocate and initialize a Lattice-form Gouraud triangle mesh shading. */
332 private const gs_shading_procs_t shading_LfGt_procs = {
333     gs_shading_LfGt_fill_rectangle
334 };
335 int
gs_shading_LfGt_init(gs_shading_t ** ppsh,const gs_shading_LfGt_params_t * params,gs_memory_t * mem)336 gs_shading_LfGt_init(gs_shading_t ** ppsh,
337 		 const gs_shading_LfGt_params_t * params, gs_memory_t * mem)
338 {
339     gs_shading_LfGt_t *psh;
340     int code = check_mesh((const gs_shading_mesh_params_t *)params);
341 
342     if (code < 0)
343 	return code;
344     if (params->VerticesPerRow < 2)
345 	return_error(gs_error_rangecheck);
346     ALLOC_SHADING(&st_shading_LfGt, shading_type_Lattice_form_Gouraud_triangle,
347 		  shading_LfGt_procs, "gs_shading_LfGt_init");
348     return 0;
349 }
350 
351 /* ---------------- Coons patch mesh shading ---------------- */
352 
353 private_st_shading_Cp();
354 
355 /* Initialize parameters for a Coons patch mesh shading. */
356 void
gs_shading_Cp_params_init(gs_shading_Cp_params_t * params)357 gs_shading_Cp_params_init(gs_shading_Cp_params_t * params)
358 {
359     mesh_shading_params_init((gs_shading_mesh_params_t *)params);
360     /* Client must set BitsPerFlag if DataSource is not an array. */
361 }
362 
363 /* Allocate and initialize a Coons patch mesh shading. */
364 private const gs_shading_procs_t shading_Cp_procs = {
365     gs_shading_Cp_fill_rectangle
366 };
367 int
gs_shading_Cp_init(gs_shading_t ** ppsh,const gs_shading_Cp_params_t * params,gs_memory_t * mem)368 gs_shading_Cp_init(gs_shading_t ** ppsh,
369 		   const gs_shading_Cp_params_t * params, gs_memory_t * mem)
370 {
371     gs_shading_Cp_t *psh;
372     int code = check_mesh((const gs_shading_mesh_params_t *)params);
373     int bpf = check_BPF(&params->DataSource, params->BitsPerFlag);
374 
375     if (code < 0)
376 	return code;
377     if (bpf < 0)
378 	return bpf;
379     ALLOC_SHADING(&st_shading_Cp, shading_type_Coons_patch,
380 		  shading_Cp_procs, "gs_shading_Cp_init");
381     psh->params.BitsPerFlag = bpf;
382     return 0;
383 }
384 
385 /* ---------------- Tensor product patch mesh shading ---------------- */
386 
387 private_st_shading_Tpp();
388 
389 /* Initialize parameters for a Tensor product patch mesh shading. */
390 void
gs_shading_Tpp_params_init(gs_shading_Tpp_params_t * params)391 gs_shading_Tpp_params_init(gs_shading_Tpp_params_t * params)
392 {
393     mesh_shading_params_init((gs_shading_mesh_params_t *)params);
394     /* Client must set BitsPerFlag if DataSource is not an array. */
395 }
396 
397 /* Allocate and initialize a Tensor product patch mesh shading. */
398 private const gs_shading_procs_t shading_Tpp_procs = {
399     gs_shading_Tpp_fill_rectangle
400 };
401 int
gs_shading_Tpp_init(gs_shading_t ** ppsh,const gs_shading_Tpp_params_t * params,gs_memory_t * mem)402 gs_shading_Tpp_init(gs_shading_t ** ppsh,
403 		  const gs_shading_Tpp_params_t * params, gs_memory_t * mem)
404 {
405     gs_shading_Tpp_t *psh;
406     int code = check_mesh((const gs_shading_mesh_params_t *)params);
407     int bpf = check_BPF(&params->DataSource, params->BitsPerFlag);
408 
409     if (code < 0)
410 	return code;
411     if (bpf < 0)
412 	return bpf;
413     ALLOC_SHADING(&st_shading_Tpp, shading_type_Tensor_product_patch,
414 		  shading_Tpp_procs, "gs_shading_Tpp_init");
415     psh->params.BitsPerFlag = bpf;
416     return 0;
417 }
418 
419 /* ================ Shading rendering ================ */
420 
421 /* Add a user-space rectangle to a path. */
422 private int
shading_path_add_box(gx_path * ppath,const gs_rect * pbox,const gs_matrix_fixed * pmat)423 shading_path_add_box(gx_path *ppath, const gs_rect *pbox,
424 		     const gs_matrix_fixed *pmat)
425 {
426     gs_fixed_point pt;
427     gs_fixed_point pts[3];
428     int code;
429 
430     if ((code = gs_point_transform2fixed(pmat, pbox->p.x, pbox->p.y,
431 					 &pt)) < 0 ||
432 	(code = gx_path_add_point(ppath, pt.x, pt.y)) < 0 ||
433 	(code = gs_point_transform2fixed(pmat, pbox->q.x, pbox->p.y,
434 					 &pts[0])) < 0 ||
435 	(code = gs_point_transform2fixed(pmat, pbox->q.x, pbox->q.y,
436 					 &pts[1])) < 0 ||
437 	(code = gs_point_transform2fixed(pmat, pbox->p.x, pbox->q.y,
438 					 &pts[2])) < 0 ||
439 	(code = gx_path_add_lines(ppath, pts, 3)) < 0
440 	)
441 	DO_NOTHING;
442     return code;
443 }
444 
445 /* Fill a path with a shading. */
446 private int
gs_shading_fill_path(const gs_shading_t * psh,gx_path * ppath,const gs_fixed_rect * prect,gx_device * orig_dev,gs_imager_state * pis,bool fill_background)447 gs_shading_fill_path(const gs_shading_t *psh, /*const*/ gx_path *ppath,
448 		     const gs_fixed_rect *prect, gx_device *orig_dev,
449 		     gs_imager_state *pis, bool fill_background)
450 {
451     gs_memory_t *mem = pis->memory;
452     const gs_matrix_fixed *pmat = &pis->ctm;
453     gx_device *dev = orig_dev;
454     gs_fixed_rect path_box;
455     gs_rect rect;
456     gx_clip_path *path_clip = 0;
457     bool path_clip_set = false;
458     gx_device_clip path_dev;
459     int code = 0;
460 
461     if ((*dev_proc(dev, pattern_manage))(dev,
462 			gs_no_id, NULL, pattern_manage__shading_area) == 0) {
463 	path_clip = gx_cpath_alloc(mem, "shading_fill_path(path_clip)");
464 	if (path_clip == 0) {
465 	    code = gs_note_error(gs_error_VMerror);
466 	    goto out;
467 	}
468 	dev_proc(dev, get_clipping_box)(dev, &path_box);
469 	if (prect)
470 	    rect_intersect(path_box, *prect);
471 	if (psh->params.have_BBox) {
472 	    gs_fixed_rect bbox_fixed;
473 
474 	    if ((is_xxyy(pmat) || is_xyyx(pmat)) &&
475 		(code = gx_dc_pattern2_shade_bbox_transform2fixed(&psh->params.BBox, pis,
476 						&bbox_fixed)) >= 0
477 		) {
478 		/* We can fold BBox into the clipping rectangle. */
479 		rect_intersect(path_box, bbox_fixed);
480 	    } else
481 		{
482 		gx_path *box_path;
483 
484 		if (path_box.p.x >= path_box.q.x || path_box.p.y >= path_box.q.y)
485 		    goto out;		/* empty rectangle */
486 		box_path = gx_path_alloc(mem, "shading_fill_path(box_path)");
487 		if (box_path == 0) {
488 		    code = gs_note_error(gs_error_VMerror);
489 		    goto out;
490 		}
491 		if ((code = gx_cpath_from_rectangle(path_clip, &path_box)) < 0 ||
492 		    (code = shading_path_add_box(box_path, &psh->params.BBox,
493 						pmat)) < 0 ||
494 		    (code = gx_cpath_intersect(path_clip, box_path,
495 					    gx_rule_winding_number, pis)) < 0
496 		    )
497 		    DO_NOTHING;
498 		gx_path_free(box_path, "shading_fill_path(box_path)");
499 		if (code < 0)
500 		    goto out;
501 		path_clip_set = true;
502 	    }
503 	}
504 	if (!path_clip_set) {
505 	    if (path_box.p.x >= path_box.q.x || path_box.p.y >= path_box.q.y)
506 		goto out;		/* empty rectangle */
507 	    if ((code = gx_cpath_from_rectangle(path_clip, &path_box)) < 0)
508 		goto out;
509 	}
510 	if (ppath &&
511 	    (code =
512 	    gx_cpath_intersect(path_clip, ppath, gx_rule_winding_number, pis)) < 0
513 	    )
514 	    goto out;
515 	gx_make_clip_device(&path_dev, &path_clip->rect_list->list);
516 	path_dev.target = dev;
517 	path_dev.HWResolution[0] = dev->HWResolution[0];
518 	path_dev.HWResolution[1] = dev->HWResolution[1];
519 	dev = (gx_device *)&path_dev;
520 	dev_proc(dev, open_device)(dev);
521     }
522 #if 0 /* doesn't work for 478-01.ps, which sets a big smoothness :
523          makes an assymmetrix domain, and the patch decomposition
524 	 becomes highly irregular. */
525     {	gs_fixed_rect r;
526 
527 	dev_proc(dev, get_clipping_box)(dev, &r);
528 	rect_intersect(path_box, r);
529     }
530 #else
531     dev_proc(dev, get_clipping_box)(dev, &path_box);
532 #endif
533     if (psh->params.Background && fill_background) {
534 	const gs_color_space *pcs = psh->params.ColorSpace;
535 	gs_client_color cc;
536 	gx_device_color dev_color;
537 
538 	cc = *psh->params.Background;
539 	(*pcs->type->restrict_color)(&cc, pcs);
540 	(*pcs->type->remap_color)(&cc, pcs, &dev_color, pis,
541 				  dev, gs_color_select_texture);
542 
543 	/****** WRONG IF NON-IDEMPOTENT RasterOp ******/
544 	code = gx_shade_background(dev, &path_box, &dev_color, pis->log_op);
545 	if (code < 0)
546 	    goto out;
547     }
548     {
549 	gs_rect path_rect;
550 
551 	path_rect.p.x = fixed2float(path_box.p.x);
552 	path_rect.p.y = fixed2float(path_box.p.y);
553 	path_rect.q.x = fixed2float(path_box.q.x);
554 	path_rect.q.y = fixed2float(path_box.q.y);
555 	gs_bbox_transform_inverse(&path_rect, (const gs_matrix *)pmat, &rect);
556     }
557     code = gs_shading_fill_rectangle(psh, &rect, &path_box, dev, pis);
558 out:
559     if (path_clip)
560 	gx_cpath_free(path_clip, "shading_fill_path(path_clip)");
561     return code;
562 }
563 
564 int
gs_shading_fill_path_adjusted(const gs_shading_t * psh,gx_path * ppath,const gs_fixed_rect * prect,gx_device * orig_dev,gs_imager_state * pis,bool fill_background)565 gs_shading_fill_path_adjusted(const gs_shading_t *psh, /*const*/ gx_path *ppath,
566 		     const gs_fixed_rect *prect, gx_device *orig_dev,
567 		     gs_imager_state *pis, bool fill_background)
568 {
569     return  gs_shading_fill_path(psh, ppath, prect, orig_dev, pis, fill_background);
570 }
571 
572