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