xref: /plan9/sys/src/cmd/gs/src/gsfunc3.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: gsfunc3.c,v 1.26 2005/05/03 10:50:48 igor Exp $ */
18 /* Implementation of LL3 Functions */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsfunc3.h"
24 #include "gsparam.h"
25 #include "gxfunc.h"
26 #include "stream.h"
27 
28 /* ---------------- Utilities ---------------- */
29 
30 #define MASK1 ((uint)(~0) / 3)
31 
32 /*
33  * Free an array of subsidiary Functions.  Note that this may be called
34  * before the Functions array has been fully initialized.  Note also that
35  * its argument conforms to the Functions array in the parameter structure,
36  * but it (necessarily) deconstifies it.
37  */
38 private void
fn_free_functions(const gs_function_t * const * Functions,int count,gs_memory_t * mem)39 fn_free_functions(const gs_function_t *const * Functions, int count,
40 		  gs_memory_t * mem)
41 {
42     int i;
43 
44     for (i = count; --i >= 0;)
45 	if (Functions[i])
46 	    gs_function_free((gs_function_t *)Functions[i], true, mem);
47     gs_free_const_object(mem, Functions, "Functions");
48 }
49 
50 /*
51  * Scale an array of subsidiary functions.  Note that the scale may either
52  * be propagated unchanged (step_ranges = false) or divided among the
53  * (1-output) subfunctions (step_ranges = true).
54  */
55 private int
fn_scale_functions(gs_function_t *** ppsfns,const gs_function_t * const * pfns,int count,const gs_range_t * pranges,bool step_ranges,gs_memory_t * mem)56 fn_scale_functions(gs_function_t ***ppsfns, const gs_function_t *const *pfns,
57 		   int count, const gs_range_t *pranges, bool step_ranges,
58 		   gs_memory_t *mem)
59 {
60     gs_function_t **psfns;
61     int code = alloc_function_array(count, &psfns, mem);
62     const gs_range_t *ranges = pranges;
63     int i;
64 
65     if (code < 0)
66 	return code;
67     for (i = 0; i < count; ++i) {
68 	int code = gs_function_make_scaled(pfns[i], &psfns[i], ranges, mem);
69 
70 	if (code < 0) {
71 	    fn_free_functions((const gs_function_t *const *)psfns, count, mem);
72 	    return code;
73 	}
74 	if (step_ranges)
75 	    ++ranges;
76     }
77     *ppsfns = psfns;
78     return 0;
79 }
80 
81 /* ---------------- Exponential Interpolation functions ---------------- */
82 
83 typedef struct gs_function_ElIn_s {
84     gs_function_head_t head;
85     gs_function_ElIn_params_t params;
86 } gs_function_ElIn_t;
87 
88 private_st_function_ElIn();
89 
90 /* Evaluate an Exponential Interpolation function. */
91 private int
fn_ElIn_evaluate(const gs_function_t * pfn_common,const float * in,float * out)92 fn_ElIn_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
93 {
94     const gs_function_ElIn_t *const pfn =
95 	(const gs_function_ElIn_t *)pfn_common;
96     double arg = in[0], raised;
97     int i;
98 
99     if (arg < pfn->params.Domain[0])
100 	arg = pfn->params.Domain[0];
101     else if (arg > pfn->params.Domain[1])
102 	arg = pfn->params.Domain[1];
103     raised = pow(arg, pfn->params.N);
104     for (i = 0; i < pfn->params.n; ++i) {
105 	float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
106 	float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
107 	double value = v0 + raised * (v1 - v0);
108 
109 	if (pfn->params.Range) {
110 	    float r0 = pfn->params.Range[2 * i],
111 		r1 = pfn->params.Range[2 * i + 1];
112 
113 	    if (value < r0)
114 		value = r0;
115 	    else if (value > r1)
116 		value = r1;
117 	}
118 	out[i] = value;
119 	if_debug3('~', "[~]ElIn %g => [%d]%g\n", arg, i, out[i]);
120     }
121     return 0;
122 }
123 
124 /* Test whether an Exponential function is monotonic.  (They always are.) */
125 private int
fn_ElIn_is_monotonic(const gs_function_t * pfn_common,const float * lower,const float * upper,uint * mask)126 fn_ElIn_is_monotonic(const gs_function_t * pfn_common,
127 		     const float *lower, const float *upper, uint *mask)
128 {
129     const gs_function_ElIn_t *const pfn =
130 	(const gs_function_ElIn_t *)pfn_common;
131 
132     if (lower[0] > pfn->params.Domain[1] ||
133 	upper[0] < pfn->params.Domain[0]
134 	)
135 	return_error(gs_error_rangecheck);
136     *mask = 0;
137     return 1;
138 }
139 
140 /* Write Exponential Interpolation function parameters on a parameter list. */
141 private int
fn_ElIn_get_params(const gs_function_t * pfn_common,gs_param_list * plist)142 fn_ElIn_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
143 {
144     const gs_function_ElIn_t *const pfn =
145 	(const gs_function_ElIn_t *)pfn_common;
146     int ecode = fn_common_get_params(pfn_common, plist);
147     int code;
148 
149     if (pfn->params.C0) {
150 	if ((code = param_write_float_values(plist, "C0", pfn->params.C0,
151 					     pfn->params.n, false)) < 0)
152 	    ecode = code;
153     }
154     if (pfn->params.C1) {
155 	if ((code = param_write_float_values(plist, "C1", pfn->params.C1,
156 					     pfn->params.n, false)) < 0)
157 	    ecode = code;
158     }
159     if ((code = param_write_float(plist, "N", &pfn->params.N)) < 0)
160 	ecode = code;
161     return ecode;
162 }
163 
164 /* Make a scaled copy of an Exponential Interpolation function. */
165 private int
fn_ElIn_make_scaled(const gs_function_ElIn_t * pfn,gs_function_ElIn_t ** ppsfn,const gs_range_t * pranges,gs_memory_t * mem)166 fn_ElIn_make_scaled(const gs_function_ElIn_t *pfn,
167 		     gs_function_ElIn_t **ppsfn,
168 		     const gs_range_t *pranges, gs_memory_t *mem)
169 {
170     gs_function_ElIn_t *psfn =
171 	gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
172 			"fn_ElIn_make_scaled");
173     float *c0;
174     float *c1;
175     int code, i;
176 
177     if (psfn == 0)
178 	return_error(gs_error_VMerror);
179     psfn->params = pfn->params;
180     psfn->params.C0 = c0 =
181 	fn_copy_values(pfn->params.C0, pfn->params.n, sizeof(float), mem);
182     psfn->params.C1 = c1 =
183 	fn_copy_values(pfn->params.C1, pfn->params.n, sizeof(float), mem);
184     if ((code = ((c0 == 0 && pfn->params.C0 != 0) ||
185 		 (c1 == 0 && pfn->params.C1 != 0) ?
186 		 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
187 	(code = fn_common_scale((gs_function_t *)psfn,
188 				(const gs_function_t *)pfn,
189 				pranges, mem)) < 0) {
190 	gs_function_free((gs_function_t *)psfn, true, mem);
191 	return code;
192     }
193     for (i = 0; i < pfn->params.n; ++i) {
194 	double base = pranges[i].rmin, factor = pranges[i].rmax - base;
195 
196 	c1[i] = c1[i] * factor + base;
197 	c0[i] = c0[i] * factor + base;
198     }
199     *ppsfn = psfn;
200     return 0;
201 }
202 
203 /* Free the parameters of an Exponential Interpolation function. */
204 void
gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,gs_memory_t * mem)205 gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,
206 			     gs_memory_t * mem)
207 {
208     gs_free_const_object(mem, params->C1, "C1");
209     gs_free_const_object(mem, params->C0, "C0");
210     fn_common_free_params((gs_function_params_t *) params, mem);
211 }
212 
213 /* Serialize. */
214 private int
gs_function_ElIn_serialize(const gs_function_t * pfn,stream * s)215 gs_function_ElIn_serialize(const gs_function_t * pfn, stream *s)
216 {
217     uint n;
218     const gs_function_ElIn_params_t * p = (const gs_function_ElIn_params_t *)&pfn->params;
219     int code = fn_common_serialize(pfn, s);
220 
221     if (code < 0)
222 	return code;
223     code = sputs(s, (const byte *)&p->C0[0], sizeof(p->C0[0]) * p->n, &n);
224     if (code < 0)
225 	return code;
226     code = sputs(s, (const byte *)&p->C1[0], sizeof(p->C1[0]) * p->n, &n);
227     if (code < 0)
228 	return code;
229     return sputs(s, (const byte *)&p->N, sizeof(p->N), &n);
230 }
231 
232 /* Allocate and initialize an Exponential Interpolation function. */
233 int
gs_function_ElIn_init(gs_function_t ** ppfn,const gs_function_ElIn_params_t * params,gs_memory_t * mem)234 gs_function_ElIn_init(gs_function_t ** ppfn,
235 		      const gs_function_ElIn_params_t * params,
236 		      gs_memory_t * mem)
237 {
238     static const gs_function_head_t function_ElIn_head = {
239 	function_type_ExponentialInterpolation,
240 	{
241 	    (fn_evaluate_proc_t) fn_ElIn_evaluate,
242 	    (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
243 	    gs_function_get_info_default,
244 	    (fn_get_params_proc_t) fn_ElIn_get_params,
245 	    (fn_make_scaled_proc_t) fn_ElIn_make_scaled,
246 	    (fn_free_params_proc_t) gs_function_ElIn_free_params,
247 	    fn_common_free,
248 	    (fn_serialize_proc_t) gs_function_ElIn_serialize,
249 	}
250     };
251     int code;
252 
253     *ppfn = 0;			/* in case of error */
254     code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
255     if (code < 0)
256 	return code;
257     if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
258 	return_error(gs_error_rangecheck);
259     if (params->N != floor(params->N)) {
260 	/* Non-integral exponent, all inputs must be non-negative. */
261 	if (params->Domain[0] < 0)
262 	    return_error(gs_error_rangecheck);
263     }
264     if (params->N < 0) {
265 	/* Negative exponent, input must not be zero. */
266 	if (params->Domain[0] <= 0 && params->Domain[1] >= 0)
267 	    return_error(gs_error_rangecheck);
268     } {
269 	gs_function_ElIn_t *pfn =
270 	    gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
271 			    "gs_function_ElIn_init");
272 
273 	if (pfn == 0)
274 	    return_error(gs_error_VMerror);
275 	pfn->params = *params;
276 	pfn->params.m = 1;
277 	pfn->head = function_ElIn_head;
278 	*ppfn = (gs_function_t *) pfn;
279     }
280     return 0;
281 }
282 
283 /* ---------------- 1-Input Stitching functions ---------------- */
284 
285 typedef struct gs_function_1ItSg_s {
286     gs_function_head_t head;
287     gs_function_1ItSg_params_t params;
288 } gs_function_1ItSg_t;
289 
290 private_st_function_1ItSg();
291 
292 /* Evaluate a 1-Input Stitching function. */
293 private int
fn_1ItSg_evaluate(const gs_function_t * pfn_common,const float * in,float * out)294 fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
295 {
296     const gs_function_1ItSg_t *const pfn =
297 	(const gs_function_1ItSg_t *)pfn_common;
298     float arg = in[0], b0, b1, e0, encoded;
299     int k = pfn->params.k;
300     int i;
301 
302     if (arg < pfn->params.Domain[0]) {
303 	arg = pfn->params.Domain[0];
304 	i = 0;
305     } else if (arg > pfn->params.Domain[1]) {
306 	arg = pfn->params.Domain[1];
307 	i = k - 1;
308     } else {
309 	for (i = 0; i < k - 1; ++i)
310 	    if (arg <= pfn->params.Bounds[i])
311 		break;
312     }
313     b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
314     b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
315     e0 = pfn->params.Encode[2 * i];
316     if (b1 == b0)
317 	encoded = e0;
318     else
319 	encoded =
320 	    (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
321     if_debug3('~', "[~]1ItSg %g in %d => %g\n", arg, i, encoded);
322     return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
323 }
324 
325 /* Test whether a 1-Input Stitching function is monotonic. */
326 private int
fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,const float * lower,const float * upper,uint * mask)327 fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
328 		      const float *lower, const float *upper, uint *mask)
329 {
330     const gs_function_1ItSg_t *const pfn =
331 	(const gs_function_1ItSg_t *)pfn_common;
332     float v0 = lower[0], v1 = upper[0];
333     float d0 = pfn->params.Domain[0], d1 = pfn->params.Domain[1];
334     int k = pfn->params.k;
335     int i;
336 
337     *mask = 0;
338     if (v0 > v1) {
339 	v0 = v1; v1 = lower[0];
340     }
341     if (v0 > d1 || v1 < d0)
342 	return_error(gs_error_rangecheck);
343     if (v0 < d0)
344 	v0 = d0;
345     if (v1 > d1)
346 	v1 = d1;
347     for (i = 0; i < pfn->params.k; ++i) {
348 	float b0 = (i == 0 ? d0 : pfn->params.Bounds[i - 1]);
349 	float b1 = (i == k - 1 ? d1 : pfn->params.Bounds[i]);
350 	const float small = 0.0000001 * (b1 - b0);
351 	float e0, e1;
352 	float w0, w1;
353 	float vv0, vv1;
354 	double vb0, vb1;
355 
356 	if (v0 >= b1)
357 	    continue;
358 	if (v0 >= b1 - small)
359 	    continue; /* Ignore a small noize */
360 	vv0 = max(b0, v0);
361 	vv1 = v1;
362 	if (vv1 > b1 && v1 < b1 + small)
363 	    vv1 = b1; /* Ignore a small noize */
364 	if (vv0 == vv1)
365 	    return 1;
366 	if (vv0 < b1 && vv1 > b1)
367 	    return 0; /* Consider stitches as monotonity beraks. */
368 	e0 = pfn->params.Encode[2 * i];
369 	e1 = pfn->params.Encode[2 * i + 1];
370 	vb0 = max(vv0, b0);
371 	vb1 = min(vv1, b1);
372 	w0 = (float)(vb0 - b0) * (e1 - e0) / (b1 - b0) + e0;
373 	w1 = (float)(vb1 - b0) * (e1 - e0) / (b1 - b0) + e0;
374 	/* Note that w0 > w1 is now possible if e0 > e1. */
375 	if (e0 > e1) {
376 	    if (w0 > e0 && w0 - small <= e0)
377 		w0 = e0; /* Suppress a small noize */
378 	    if (w1 < e1 && w1 + small >= e1)
379 		w1 = e1; /* Suppress a small noize */
380 	} else {
381 	    if (w0 < e0 && w0 + small >= e0)
382 		w0 = e0; /* Suppress a small noize */
383 	    if (w1 > e1 && w1 - small <= e1)
384 		w1 = e1; /* Suppress a small noize */
385 	}
386 	if (w0 > w1)
387 	    return gs_function_is_monotonic(pfn->params.Functions[i],
388 					    &w1, &w0, mask);
389 	else
390 	    return gs_function_is_monotonic(pfn->params.Functions[i],
391 					    &w0, &w1, mask);
392     }
393     /* v0 is equal to the range end. */
394     *mask = 0;
395     return 1;
396 }
397 
398 /* Return 1-Input Stitching function information. */
399 private void
fn_1ItSg_get_info(const gs_function_t * pfn_common,gs_function_info_t * pfi)400 fn_1ItSg_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
401 {
402     const gs_function_1ItSg_t *const pfn =
403 	(const gs_function_1ItSg_t *)pfn_common;
404 
405     gs_function_get_info_default(pfn_common, pfi);
406     pfi->Functions = pfn->params.Functions;
407     pfi->num_Functions = pfn->params.k;
408 }
409 
410 /* Write 1-Input Stitching function parameters on a parameter list. */
411 private int
fn_1ItSg_get_params(const gs_function_t * pfn_common,gs_param_list * plist)412 fn_1ItSg_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
413 {
414     const gs_function_1ItSg_t *const pfn =
415 	(const gs_function_1ItSg_t *)pfn_common;
416     int ecode = fn_common_get_params(pfn_common, plist);
417     int code;
418 
419     if ((code = param_write_float_values(plist, "Bounds", pfn->params.Bounds,
420 					 pfn->params.k - 1, false)) < 0)
421 	ecode = code;
422     if ((code = param_write_float_values(plist, "Encode", pfn->params.Encode,
423 					 2 * pfn->params.k, false)) < 0)
424 	ecode = code;
425     return ecode;
426 }
427 
428 /* Make a scaled copy of a 1-Input Stitching function. */
429 private int
fn_1ItSg_make_scaled(const gs_function_1ItSg_t * pfn,gs_function_1ItSg_t ** ppsfn,const gs_range_t * pranges,gs_memory_t * mem)430 fn_1ItSg_make_scaled(const gs_function_1ItSg_t *pfn,
431 		     gs_function_1ItSg_t **ppsfn,
432 		     const gs_range_t *pranges, gs_memory_t *mem)
433 {
434     gs_function_1ItSg_t *psfn =
435 	gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
436 			"fn_1ItSg_make_scaled");
437     int code;
438 
439     if (psfn == 0)
440 	return_error(gs_error_VMerror);
441     psfn->params = pfn->params;
442     psfn->params.Functions = 0;	/* in case of failure */
443     psfn->params.Bounds =
444 	fn_copy_values(pfn->params.Bounds, pfn->params.k - 1, sizeof(float),
445 		       mem);
446     psfn->params.Encode =
447 	fn_copy_values(pfn->params.Encode, 2 * pfn->params.k, sizeof(float),
448 		       mem);
449     if ((code = (psfn->params.Bounds == 0 || psfn->params.Encode == 0 ?
450 		 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
451 	(code = fn_common_scale((gs_function_t *)psfn,
452 				(const gs_function_t *)pfn,
453 				pranges, mem)) < 0 ||
454 	(code = fn_scale_functions((gs_function_t ***)&psfn->params.Functions,
455 				   pfn->params.Functions,
456 				   pfn->params.n, pranges, false, mem)) < 0) {
457 	gs_function_free((gs_function_t *)psfn, true, mem);
458 	return code;
459     }
460     *ppsfn = psfn;
461     return 0;
462 }
463 
464 /* Free the parameters of a 1-Input Stitching function. */
465 void
gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,gs_memory_t * mem)466 gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,
467 			      gs_memory_t * mem)
468 {
469     gs_free_const_object(mem, params->Encode, "Encode");
470     gs_free_const_object(mem, params->Bounds, "Bounds");
471     fn_free_functions(params->Functions, params->k, mem);
472     fn_common_free_params((gs_function_params_t *) params, mem);
473 }
474 
475 /* Serialize. */
476 private int
gs_function_1ItSg_serialize(const gs_function_t * pfn,stream * s)477 gs_function_1ItSg_serialize(const gs_function_t * pfn, stream *s)
478 {
479     uint n;
480     const gs_function_1ItSg_params_t * p = (const gs_function_1ItSg_params_t *)&pfn->params;
481     int code = fn_common_serialize(pfn, s);
482     int k;
483 
484     if (code < 0)
485 	return code;
486     code = sputs(s, (const byte *)&p->k, sizeof(p->k), &n);
487     if (code < 0)
488 	return code;
489 
490     for (k = 0; k < p->k && code >= 0; k++)
491 	code = gs_function_serialize(p->Functions[k], s);
492     if (code < 0)
493 	return code;
494     code = sputs(s, (const byte *)&p->Bounds[0], sizeof(p->Bounds[0]) * (p->k - 1), &n);
495     if (code < 0)
496 	return code;
497     return sputs(s, (const byte *)&p->Encode[0], sizeof(p->Encode[0]) * (p->k * 2), &n);
498 }
499 
500 /* Allocate and initialize a 1-Input Stitching function. */
501 int
gs_function_1ItSg_init(gs_function_t ** ppfn,const gs_function_1ItSg_params_t * params,gs_memory_t * mem)502 gs_function_1ItSg_init(gs_function_t ** ppfn,
503 	       const gs_function_1ItSg_params_t * params, gs_memory_t * mem)
504 {
505     static const gs_function_head_t function_1ItSg_head = {
506 	function_type_1InputStitching,
507 	{
508 	    (fn_evaluate_proc_t) fn_1ItSg_evaluate,
509 	    (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
510 	    (fn_get_info_proc_t) fn_1ItSg_get_info,
511 	    (fn_get_params_proc_t) fn_1ItSg_get_params,
512 	    (fn_make_scaled_proc_t) fn_1ItSg_make_scaled,
513 	    (fn_free_params_proc_t) gs_function_1ItSg_free_params,
514 	    fn_common_free,
515 	    (fn_serialize_proc_t) gs_function_1ItSg_serialize,
516 	}
517     };
518     int n = (params->Range == 0 ? 0 : params->n);
519     float prev = params->Domain[0];
520     int i;
521 
522     *ppfn = 0;			/* in case of error */
523     for (i = 0; i < params->k; ++i) {
524 	const gs_function_t *psubfn = params->Functions[i];
525 
526 	if (psubfn->params.m != 1)
527 	    return_error(gs_error_rangecheck);
528 	if (n == 0)
529 	    n = psubfn->params.n;
530 	else if (psubfn->params.n != n)
531 	    return_error(gs_error_rangecheck);
532 	/* There are only k - 1 Bounds, not k. */
533 	if (i < params->k - 1) {
534 	    if (params->Bounds[i] < prev)
535 		return_error(gs_error_rangecheck);
536 	    prev = params->Bounds[i];
537 	}
538     }
539     if (params->Domain[1] < prev)
540 	return_error(gs_error_rangecheck);
541     fn_check_mnDR((const gs_function_params_t *)params, 1, n);
542     {
543 	gs_function_1ItSg_t *pfn =
544 	    gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
545 			    "gs_function_1ItSg_init");
546 
547 	if (pfn == 0)
548 	    return_error(gs_error_VMerror);
549 	pfn->params = *params;
550 	pfn->params.m = 1;
551 	pfn->params.n = n;
552 	pfn->head = function_1ItSg_head;
553 	*ppfn = (gs_function_t *) pfn;
554     }
555     return 0;
556 }
557 
558 /* ---------------- Arrayed Output functions ---------------- */
559 
560 typedef struct gs_function_AdOt_s {
561     gs_function_head_t head;
562     gs_function_AdOt_params_t params;
563 } gs_function_AdOt_t;
564 
565 private_st_function_AdOt();
566 
567 /* Evaluate an Arrayed Output function. */
568 private int
fn_AdOt_evaluate(const gs_function_t * pfn_common,const float * in0,float * out)569 fn_AdOt_evaluate(const gs_function_t *pfn_common, const float *in0, float *out)
570 {
571     const gs_function_AdOt_t *const pfn =
572 	(const gs_function_AdOt_t *)pfn_common;
573     const float *in = in0;
574 #define MAX_ADOT_IN 16
575     float in_buf[MAX_ADOT_IN];
576     int i;
577 
578     /*
579      * We have to take special care to handle the case where in and out
580      * overlap.  For the moment, handle it only for a limited number of
581      * input values.
582      */
583     if (in <= out + (pfn->params.n - 1) && out <= in + (pfn->params.m - 1)) {
584 	if (pfn->params.m > MAX_ADOT_IN)
585 	    return_error(gs_error_rangecheck);
586 	memcpy(in_buf, in, pfn->params.m * sizeof(*in));
587 	in = in_buf;
588     }
589     for (i = 0; i < pfn->params.n; ++i) {
590 	int code =
591 	    gs_function_evaluate(pfn->params.Functions[i], in, out + i);
592 
593 	if (code < 0)
594 	    return code;
595     }
596     return 0;
597 #undef MAX_ADOT_IN
598 }
599 
600 /* Test whether an Arrayed Output function is monotonic. */
601 private int
fn_AdOt_is_monotonic(const gs_function_t * pfn_common,const float * lower,const float * upper,uint * mask)602 fn_AdOt_is_monotonic(const gs_function_t * pfn_common,
603 		     const float *lower, const float *upper, uint *mask)
604 {
605     const gs_function_AdOt_t *const pfn =
606 	(const gs_function_AdOt_t *)pfn_common;
607     int i;
608 
609     for (i = 0; i < pfn->params.n; ++i) {
610 	int code =
611 	    gs_function_is_monotonic(pfn->params.Functions[i], lower, upper, mask);
612 
613 	if (code <= 0)
614 	    return code;
615     }
616     return 1;
617 }
618 
619 /* Return Arrayed Output function information. */
620 private void
fn_AdOt_get_info(const gs_function_t * pfn_common,gs_function_info_t * pfi)621 fn_AdOt_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
622 {
623     const gs_function_AdOt_t *const pfn =
624 	(const gs_function_AdOt_t *)pfn_common;
625 
626     gs_function_get_info_default(pfn_common, pfi);
627     pfi->Functions = pfn->params.Functions;
628     pfi->num_Functions = pfn->params.n;
629 }
630 
631 /* Make a scaled copy of an Arrayed Output function. */
632 private int
fn_AdOt_make_scaled(const gs_function_AdOt_t * pfn,gs_function_AdOt_t ** ppsfn,const gs_range_t * pranges,gs_memory_t * mem)633 fn_AdOt_make_scaled(const gs_function_AdOt_t *pfn, gs_function_AdOt_t **ppsfn,
634 		    const gs_range_t *pranges, gs_memory_t *mem)
635 {
636     gs_function_AdOt_t *psfn =
637 	gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
638 			"fn_AdOt_make_scaled");
639     int code;
640 
641     if (psfn == 0)
642 	return_error(gs_error_VMerror);
643     psfn->params = pfn->params;
644     psfn->params.Functions = 0;	/* in case of failure */
645     if ((code = fn_common_scale((gs_function_t *)psfn,
646 				(const gs_function_t *)pfn,
647 				pranges, mem)) < 0 ||
648 	(code = fn_scale_functions((gs_function_t ***)&psfn->params.Functions,
649 				   pfn->params.Functions,
650 				   pfn->params.n, pranges, true, mem)) < 0) {
651 	gs_function_free((gs_function_t *)psfn, true, mem);
652 	return code;
653     }
654     *ppsfn = psfn;
655     return 0;
656 }
657 
658 /* Free the parameters of an Arrayed Output function. */
659 void
gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,gs_memory_t * mem)660 gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,
661 			     gs_memory_t * mem)
662 {
663     fn_free_functions(params->Functions, params->n, mem);
664     fn_common_free_params((gs_function_params_t *) params, mem);
665 }
666 
667 /* Serialize. */
668 private int
gs_function_AdOt_serialize(const gs_function_t * pfn,stream * s)669 gs_function_AdOt_serialize(const gs_function_t * pfn, stream *s)
670 {
671     const gs_function_AdOt_params_t * p = (const gs_function_AdOt_params_t *)&pfn->params;
672     int code = fn_common_serialize(pfn, s);
673     int k;
674 
675     if (code < 0)
676 	return code;
677     for (k = 0; k < p->n && code >= 0; k++)
678 	code = gs_function_serialize(p->Functions[k], s);
679     return code;
680 }
681 
682 /* Allocate and initialize an Arrayed Output function. */
683 int
gs_function_AdOt_init(gs_function_t ** ppfn,const gs_function_AdOt_params_t * params,gs_memory_t * mem)684 gs_function_AdOt_init(gs_function_t ** ppfn,
685 		const gs_function_AdOt_params_t * params, gs_memory_t * mem)
686 {
687     static const gs_function_head_t function_AdOt_head = {
688 	function_type_ArrayedOutput,
689 	{
690 	    (fn_evaluate_proc_t) fn_AdOt_evaluate,
691 	    (fn_is_monotonic_proc_t) fn_AdOt_is_monotonic,
692 	    (fn_get_info_proc_t) fn_AdOt_get_info,
693 	    fn_common_get_params,	/****** WHAT TO DO ABOUT THIS? ******/
694 	    (fn_make_scaled_proc_t) fn_AdOt_make_scaled,
695 	    (fn_free_params_proc_t) gs_function_AdOt_free_params,
696 	    fn_common_free,
697 	    (fn_serialize_proc_t) gs_function_AdOt_serialize,
698 	}
699     };
700     int m = params->m, n = params->n;
701 
702     *ppfn = 0;			/* in case of error */
703     if (m <= 0 || n <= 0)
704 	return_error(gs_error_rangecheck);
705     {
706 	gs_function_AdOt_t *pfn =
707 	    gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
708 			    "gs_function_AdOt_init");
709 	float *domain = (float *)
710 	    gs_alloc_byte_array(mem, 2 * m, sizeof(float),
711 				"gs_function_AdOt_init(Domain)");
712 	int i, j;
713 
714 	if (pfn == 0)
715 	    return_error(gs_error_VMerror);
716 	pfn->params = *params;
717 	pfn->params.Domain = domain;
718 	pfn->params.Range = 0;
719 	pfn->head = function_AdOt_head;
720 	if (domain == 0) {
721 	    gs_function_free((gs_function_t *)pfn, true, mem);
722 	    return_error(gs_error_VMerror);
723 	}
724 	/*
725 	 * We compute the Domain as the intersection of the Domains of
726 	 * the individual subfunctions.  This isn't quite right: some
727 	 * subfunction might actually make use of a larger domain of
728 	 * input values.  However, the only place that Arrayed Output
729 	 * functions are used is in Shading and similar dictionaries,
730 	 * where the input values are clamped to the intersection of
731 	 * the individual Domains anyway.
732 	 */
733 	memcpy(domain, params->Functions[0]->params.Domain,
734 	       2 * sizeof(float) * m);
735 	for (i = 1; i < n; ++i) {
736 	    const float *dom = params->Functions[i]->params.Domain;
737 
738 	    for (j = 0; j < 2 * m; j += 2, dom += 2) {
739 		domain[j] = max(domain[j], dom[0]);
740 		domain[j + 1] = min(domain[j + 1], dom[1]);
741 	    }
742 	}
743 	*ppfn = (gs_function_t *) pfn;
744     }
745     return 0;
746 }
747