Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}