Coverage Report

Created: 2025-06-10 07:24

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