xref: /plan9/sys/src/cmd/gs/src/gxshade.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1998, 1999 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: gxshade.c,v 1.22 2005/01/31 03:08:43 igor Exp $ */
18 /* Shading rendering support */
19 #include "math_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsrect.h"
23 #include "gxcspace.h"
24 #include "gscindex.h"
25 #include "gscie.h"		/* requires gscspace.h */
26 #include "gxdevcli.h"
27 #include "gxistate.h"
28 #include "gxdht.h"		/* for computing # of different colors */
29 #include "gxpaint.h"
30 #include "gxshade.h"
31 #include "gxshade4.h"
32 #include "gsicc.h"
33 
34 /* Define a maximum smoothness value. */
35 /* smoothness > 0.2 produces severely blocky output. */
36 #define MAX_SMOOTHNESS 0.2
37 
38 /* ================ Packed coordinate streams ================ */
39 
40 /* Forward references */
41 private int cs_next_packed_value(shade_coord_stream_t *, int, uint *);
42 private int cs_next_array_value(shade_coord_stream_t *, int, uint *);
43 private int cs_next_packed_decoded(shade_coord_stream_t *, int,
44 				   const float[2], float *);
45 private int cs_next_array_decoded(shade_coord_stream_t *, int,
46 				  const float[2], float *);
47 private bool cs_eod(const shade_coord_stream_t * cs);
48 
49 /* Initialize a packed value stream. */
50 void
shade_next_init(shade_coord_stream_t * cs,const gs_shading_mesh_params_t * params,const gs_imager_state * pis)51 shade_next_init(shade_coord_stream_t * cs,
52 		const gs_shading_mesh_params_t * params,
53 		const gs_imager_state * pis)
54 {
55     cs->params = params;
56     cs->pctm = &pis->ctm;
57     if (data_source_is_stream(params->DataSource)) {
58 	/*
59 	 * Reset the data stream iff it is reusable -- either a reusable
60 	 * file or a reusable string.
61 	 */
62 	stream *s = cs->s = params->DataSource.data.strm;
63 
64 	if ((s->file != 0 && s->file_limit != max_long) ||
65 	    (s->file == 0 && s->strm == 0)
66 	    )
67 	    sreset(s);
68     } else {
69 	sread_string(&cs->ds, params->DataSource.data.str.data,
70 		     params->DataSource.data.str.size);
71 	cs->s = &cs->ds;
72     }
73     if (data_source_is_array(params->DataSource)) {
74 	cs->get_value = cs_next_array_value;
75 	cs->get_decoded = cs_next_array_decoded;
76     } else {
77 	cs->get_value = cs_next_packed_value;
78 	cs->get_decoded = cs_next_packed_decoded;
79     }
80     cs->is_eod = cs_eod;
81     cs->left = 0;
82     cs->ds_EOF = false;
83 }
84 
85 /* Check for the End-Of-Data state form a stream. */
86 private bool
cs_eod(const shade_coord_stream_t * cs)87 cs_eod(const shade_coord_stream_t * cs)
88 {
89     return cs->ds_EOF;
90 }
91 
92 /* Get the next (integer) value from a packed value stream. */
93 /* 1 <= num_bits <= sizeof(uint) * 8. */
94 private int
cs_next_packed_value(shade_coord_stream_t * cs,int num_bits,uint * pvalue)95 cs_next_packed_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue)
96 {
97     uint bits = cs->bits;
98     int left = cs->left;
99 
100     if (left >= num_bits) {
101 	/* We can satisfy this request with the current buffered bits. */
102 	cs->left = left -= num_bits;
103 	*pvalue = (bits >> left) & ((1 << num_bits) - 1);
104     } else {
105 	/* We need more bits. */
106 	int needed = num_bits - left;
107 	uint value = bits & ((1 << left) - 1);	/* all the remaining bits */
108 
109 	for (; needed >= 8; needed -= 8) {
110 	    int b = sgetc(cs->s);
111 
112 	    if (b < 0) {
113 	        cs->ds_EOF = true;
114 		return_error(gs_error_rangecheck);
115 	    }
116 	    value = (value << 8) + b;
117 	}
118 	if (needed == 0) {
119 	    cs->left = 0;
120 	    *pvalue = value;
121 	} else {
122 	    int b = sgetc(cs->s);
123 
124 	    if (b < 0) {
125 	        cs->ds_EOF = true;
126 		return_error(gs_error_rangecheck);
127 	    }
128 	    cs->bits = b;
129 	    cs->left = left = 8 - needed;
130 	    *pvalue = (value << needed) + (b >> left);
131 	}
132     }
133     return 0;
134 }
135 
136 /*
137  * Get the next (integer) value from an unpacked array.  Note that
138  * num_bits may be 0 if we are reading a coordinate or color value.
139  */
140 private int
cs_next_array_value(shade_coord_stream_t * cs,int num_bits,uint * pvalue)141 cs_next_array_value(shade_coord_stream_t * cs, int num_bits, uint * pvalue)
142 {
143     float value;
144     uint read;
145 
146     if (sgets(cs->s, (byte *)&value, sizeof(float), &read) < 0 ||
147 	read != sizeof(float)) {
148 	cs->ds_EOF = true;
149 	return_error(gs_error_rangecheck);
150     }
151     if (value < 0 || (num_bits != 0 && num_bits < sizeof(uint) * 8 &&
152 	 value >= (1 << num_bits)) ||
153 	value != (uint)value
154 	)
155 	return_error(gs_error_rangecheck);
156     *pvalue = (uint) value;
157     return 0;
158 }
159 
160 /* Get the next decoded floating point value. */
161 private int
cs_next_packed_decoded(shade_coord_stream_t * cs,int num_bits,const float decode[2],float * pvalue)162 cs_next_packed_decoded(shade_coord_stream_t * cs, int num_bits,
163 		       const float decode[2], float *pvalue)
164 {
165     uint value;
166     int code = cs->get_value(cs, num_bits, &value);
167 #if ARCH_CAN_SHIFT_FULL_LONG
168     double max_value = (double)(uint) ((1 << num_bits) - 1);
169 #else
170     double max_value = (double)(uint)
171 	(num_bits == sizeof(uint) * 8 ? ~0 : ((1 << num_bits) - 1));
172 #endif
173 
174     if (code < 0)
175 	return code;
176     *pvalue =
177 	(decode == 0 ? value / max_value :
178 	 decode[0] + value * (decode[1] - decode[0]) / max_value);
179     return 0;
180 }
181 
182 /* Get the next floating point value from an array, without decoding. */
183 private int
cs_next_array_decoded(shade_coord_stream_t * cs,int num_bits,const float decode[2],float * pvalue)184 cs_next_array_decoded(shade_coord_stream_t * cs, int num_bits,
185 		      const float decode[2], float *pvalue)
186 {
187     float value;
188     uint read;
189 
190     if (sgets(cs->s, (byte *)&value, sizeof(float), &read) < 0 ||
191 	read != sizeof(float)
192     ) {
193 	cs->ds_EOF = true;
194 	return_error(gs_error_rangecheck);
195     }
196     *pvalue = value;
197     return 0;
198 }
199 
200 /* Get the next flag value. */
201 /* Note that this always starts a new data byte. */
202 int
shade_next_flag(shade_coord_stream_t * cs,int BitsPerFlag)203 shade_next_flag(shade_coord_stream_t * cs, int BitsPerFlag)
204 {
205     uint flag;
206     int code;
207 
208     cs->left = 0;		/* start a new byte if packed */
209     code = cs->get_value(cs, BitsPerFlag, &flag);
210     return (code < 0 ? code : flag);
211 }
212 
213 /* Get one or more coordinate pairs. */
214 int
shade_next_coords(shade_coord_stream_t * cs,gs_fixed_point * ppt,int num_points)215 shade_next_coords(shade_coord_stream_t * cs, gs_fixed_point * ppt,
216 		  int num_points)
217 {
218     int num_bits = cs->params->BitsPerCoordinate;
219     const float *decode = cs->params->Decode;
220     int code = 0;
221     int i;
222 
223     for (i = 0; i < num_points; ++i) {
224 	float x, y;
225 
226 	if ((code = cs->get_decoded(cs, num_bits, decode, &x)) < 0 ||
227 	    (code = cs->get_decoded(cs, num_bits, decode + 2, &y)) < 0 ||
228 	    (code = gs_point_transform2fixed(cs->pctm, x, y, &ppt[i])) < 0
229 	    )
230 	    break;
231     }
232     return code;
233 }
234 
235 /* Get a color.  Currently all this does is look up Indexed colors. */
236 int
shade_next_color(shade_coord_stream_t * cs,float * pc)237 shade_next_color(shade_coord_stream_t * cs, float *pc)
238 {
239     const float *decode = cs->params->Decode + 4;	/* skip coord decode */
240     const gs_color_space *pcs = cs->params->ColorSpace;
241     gs_color_space_index index = gs_color_space_get_index(pcs);
242     int num_bits = cs->params->BitsPerComponent;
243 
244     if (index == gs_color_space_index_Indexed) {
245 	int ncomp = gs_color_space_num_components(gs_cspace_base_space(pcs));
246 	uint ci;
247 	int code = cs->get_value(cs, num_bits, &ci);
248 	gs_client_color cc;
249 	int i;
250 
251 	if (code < 0)
252 	    return code;
253 	if (ci >= gs_cspace_indexed_num_entries(pcs))
254 	    return_error(gs_error_rangecheck);
255 	code = gs_cspace_indexed_lookup(&pcs->params.indexed, (int)ci, &cc);
256 	if (code < 0)
257 	    return code;
258 	for (i = 0; i < ncomp; ++i)
259 	    pc[i] = cc.paint.values[i];
260     } else {
261 	int i, code;
262 	int ncomp = (cs->params->Function != 0 ? 1 :
263 		     gs_color_space_num_components(pcs));
264 
265 	for (i = 0; i < ncomp; ++i)
266 	    if ((code = cs->get_decoded(cs, num_bits, decode + i * 2, &pc[i])) < 0)
267 		return code;
268     }
269     return 0;
270 }
271 
272 /* Get the next vertex for a mesh element. */
273 int
shade_next_vertex(shade_coord_stream_t * cs,shading_vertex_t * vertex)274 shade_next_vertex(shade_coord_stream_t * cs, shading_vertex_t * vertex)
275 {
276     int code = shade_next_coords(cs, &vertex->p, 1);
277 
278     vertex->c.cc.paint.values[1] = 0; /* safety. (patch_fill may assume 2 arguments) */
279     if (code >= 0)
280 	code = shade_next_color(cs, vertex->c.cc.paint.values);
281     return code;
282 }
283 
284 /* ================ Shading rendering ================ */
285 
286 /* Initialize the common parts of the recursion state. */
287 void
shade_init_fill_state(shading_fill_state_t * pfs,const gs_shading_t * psh,gx_device * dev,gs_imager_state * pis)288 shade_init_fill_state(shading_fill_state_t * pfs, const gs_shading_t * psh,
289 		      gx_device * dev, gs_imager_state * pis)
290 {
291     const gs_color_space *pcs = psh->params.ColorSpace;
292     float max_error = min(pis->smoothness, MAX_SMOOTHNESS);
293     /*
294      * There's no point in trying to achieve smoothness beyond what
295      * the device can implement, i.e., the number of representable
296      * colors times the number of halftone levels.
297      */
298     long num_colors =
299 	max(dev->color_info.max_gray, dev->color_info.max_color) + 1;
300     const gs_range *ranges = 0;
301     int ci;
302 
303     pfs->dev = dev;
304     pfs->pis = pis;
305 top:
306     pfs->direct_space = pcs;
307     pfs->num_components = gs_color_space_num_components(pcs);
308     switch ( gs_color_space_get_index(pcs) )
309 	{
310 	case gs_color_space_index_Indexed:
311 	    pcs = gs_cspace_base_space(pcs);
312 	    goto top;
313 	case gs_color_space_index_CIEDEFG:
314 	    ranges = pcs->params.defg->RangeDEFG.ranges;
315 	    break;
316 	case gs_color_space_index_CIEDEF:
317 	    ranges = pcs->params.def->RangeDEF.ranges;
318 	    break;
319 	case gs_color_space_index_CIEABC:
320 	    ranges = pcs->params.abc->RangeABC.ranges;
321 	    break;
322 	case gs_color_space_index_CIEA:
323 	    ranges = &pcs->params.a->RangeA;
324 	    break;
325         case gs_color_space_index_CIEICC:
326             ranges = pcs->params.icc.picc_info->Range.ranges;
327 	default:
328 	    break;
329 	}
330     if (num_colors <= 32) {
331 	gx_ht_order_component *components = pis->dev_ht->components;
332 	if (components && components[0].corder.wts)
333 	    num_colors = 256;
334 	else
335 	    /****** WRONG FOR MULTI-PLANE HALFTONES ******/
336 	    num_colors *= pis->dev_ht->components[0].corder.num_levels;
337     }
338     if (psh->head.type == 2 || psh->head.type == 3) {
339 	max_error *= 0.25;
340 	num_colors *= 2;
341     }
342     if (max_error < 1.0 / num_colors)
343 	max_error = 1.0 / num_colors;
344     for (ci = 0; ci < pfs->num_components; ++ci)
345 	pfs->cc_max_error[ci] =
346 	    (ranges == 0 ? max_error :
347 	     max_error * (ranges[ci].rmax - ranges[ci].rmin));
348 }
349 
350 /* Fill one piece of a shading. */
351 int
shade_fill_path(const shading_fill_state_t * pfs,gx_path * ppath,gx_device_color * pdevc,const gs_fixed_point * fill_adjust)352 shade_fill_path(const shading_fill_state_t * pfs, gx_path * ppath,
353 		gx_device_color * pdevc, const gs_fixed_point *fill_adjust)
354 {
355     gx_fill_params params;
356 
357     params.rule = -1;		/* irrelevant */
358     params.adjust = *fill_adjust;
359     params.flatness = 0;	/* irrelevant */
360     params.fill_zero_width = false;
361     return (*dev_proc(pfs->dev, fill_path)) (pfs->dev, pfs->pis, ppath,
362 					     &params, pdevc, NULL);
363 }
364