Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gsfunc3.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 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
11.4k
{
42
11.4k
    int i;
43
44
11.4k
    if (Functions == NULL)
45
4.36k
        return;
46
47
28.5k
    for (i = count; --i >= 0;)
48
21.5k
        if (Functions[i])
49
19.1k
            gs_function_free((gs_function_t *)Functions[i], true, mem);
50
7.05k
    gs_free_const_object(mem, Functions, "Functions");
51
7.05k
}
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
47.8M
{
97
47.8M
    const gs_function_ElIn_t *const pfn =
98
47.8M
        (const gs_function_ElIn_t *)pfn_common;
99
47.8M
    double arg = in[0], raised;
100
47.8M
    int i;
101
102
47.8M
    if (arg < pfn->params.Domain[0])
103
0
        arg = pfn->params.Domain[0];
104
47.8M
    else if (arg > pfn->params.Domain[1])
105
1.51k
        arg = pfn->params.Domain[1];
106
47.8M
    raised = pow(arg, pfn->params.N);
107
190M
    for (i = 0; i < pfn->params.n; ++i) {
108
142M
        float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
109
142M
        float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
110
142M
        double value = v0 + raised * (v1 - v0);
111
112
142M
        if (pfn->params.Range) {
113
225k
            float r0 = pfn->params.Range[2 * i],
114
225k
                r1 = pfn->params.Range[2 * i + 1];
115
116
225k
            if (value < r0)
117
0
                value = r0;
118
225k
            else if (value > r1)
119
0
                value = r1;
120
225k
        }
121
142M
        out[i] = value;
122
142M
        if_debug3('~', "[~]ElIn %g => [%d]%g\n", arg, i, out[i]);
123
142M
    }
124
47.8M
    return 0;
125
47.8M
}
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
3.37M
{
132
3.37M
    const gs_function_ElIn_t *const pfn =
133
3.37M
        (const gs_function_ElIn_t *)pfn_common;
134
135
3.37M
    if (lower[0] > pfn->params.Domain[1] ||
136
3.37M
        upper[0] < pfn->params.Domain[0]
137
3.37M
        )
138
8
        return_error(gs_error_rangecheck);
139
3.37M
    *mask = 0;
140
3.37M
    return 1;
141
3.37M
}
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
6.14k
{
147
6.14k
    const gs_function_ElIn_t *const pfn =
148
6.14k
        (const gs_function_ElIn_t *)pfn_common;
149
6.14k
    int ecode = fn_common_get_params(pfn_common, plist);
150
6.14k
    int code;
151
152
6.14k
    if (pfn->params.C0) {
153
6.14k
        if ((code = param_write_float_values(plist, "C0", pfn->params.C0,
154
6.14k
                                             pfn->params.n, false)) < 0)
155
0
            ecode = code;
156
6.14k
    }
157
6.14k
    if (pfn->params.C1) {
158
6.14k
        if ((code = param_write_float_values(plist, "C1", pfn->params.C1,
159
6.14k
                                             pfn->params.n, false)) < 0)
160
0
            ecode = code;
161
6.14k
    }
162
6.14k
    if ((code = param_write_float(plist, "N", &pfn->params.N)) < 0)
163
0
        ecode = code;
164
6.14k
    return ecode;
165
6.14k
}
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
184
    /* If C0 or C1 is NULL here, we know from gs_function_ElIn_init() that n == 1. */
185
0
    if (pfn->params.C0) {
186
0
        c0 = fn_copy_values(pfn->params.C0, pfn->params.n, sizeof(float), mem);
187
0
    } else {
188
0
        c0 = (float *)gs_alloc_byte_array(mem, 1, sizeof(float), "fn_ElIn_make_scaled C0");
189
0
        if (c0 == 0)
190
0
            return_error(gs_error_VMerror);
191
0
        c0[0] = 0.0f; /* default c0 */
192
0
    }
193
194
0
    if (pfn->params.C1) {
195
0
        c1 = fn_copy_values(pfn->params.C1, pfn->params.n, sizeof(float), mem);
196
0
    } else {
197
0
        c1 = (float *)gs_alloc_byte_array(mem, 1, sizeof(float), "fn_ElIn_make_scaled C1");
198
0
        if (c1 == 0)
199
0
            return_error(gs_error_VMerror);
200
0
        c1[0] = 1.0f; /* default c1 */
201
0
    }
202
203
0
    psfn->params.C0 = c0;
204
0
    psfn->params.C1 = c1;
205
206
0
    if ((code = ((c0 == 0 && pfn->params.C0 != 0) ||
207
0
                 (c1 == 0 && pfn->params.C1 != 0) ?
208
0
                 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
209
0
        (code = fn_common_scale((gs_function_t *)psfn,
210
0
                                (const gs_function_t *)pfn,
211
0
                                pranges, mem)) < 0) {
212
0
        gs_function_free((gs_function_t *)psfn, true, mem);
213
0
        return code;
214
0
    }
215
0
    for (i = 0; i < pfn->params.n; ++i) {
216
0
        double base = pranges[i].rmin, factor = pranges[i].rmax - base;
217
218
0
        c1[i] = c1[i] * factor + base;
219
0
        c0[i] = c0[i] * factor + base;
220
0
    }
221
0
    *ppsfn = psfn;
222
0
    return 0;
223
0
}
224
225
/* Free the parameters of an Exponential Interpolation function. */
226
void
227
gs_function_ElIn_free_params(gs_function_ElIn_params_t * params,
228
                             gs_memory_t * mem)
229
34.8k
{
230
34.8k
    gs_free_const_object(mem, params->C1, "C1");
231
34.8k
    params->C1 = NULL;
232
34.8k
    gs_free_const_object(mem, params->C0, "C0");
233
34.8k
    params->C0 = NULL;
234
34.8k
    fn_common_free_params((gs_function_params_t *) params, mem);
235
34.8k
}
236
237
/* Serialize. */
238
static int
239
gs_function_ElIn_serialize(const gs_function_t * pfn, stream *s)
240
4.24k
{
241
4.24k
    uint n;
242
4.24k
    const gs_function_ElIn_params_t * p = (const gs_function_ElIn_params_t *)&pfn->params;
243
4.24k
    int code = fn_common_serialize(pfn, s);
244
4.24k
    float C0_default[2] = {0, 0};
245
4.24k
    float C1_default[2] = {1, 0};
246
247
4.24k
    if (code < 0)
248
0
        return code;
249
4.24k
    if (p->C0)
250
4.24k
        code = sputs(s, (const byte *)&p->C0[0], sizeof(p->C0[0]) * p->n, &n);
251
0
    else
252
0
        code = sputs(s, (const byte *)&C0_default, sizeof(float) * 2, &n);
253
4.24k
    if (code < 0)
254
0
        return code;
255
256
4.24k
    if (p->C1)
257
4.24k
        code = sputs(s, (const byte *)&p->C1[0], sizeof(p->C1[0]) * p->n, &n);
258
0
    else
259
0
        code = sputs(s, (const byte *)&C1_default, sizeof(float) * 2, &n);
260
4.24k
    if (code < 0)
261
0
        return code;
262
4.24k
    return sputs(s, (const byte *)&p->N, sizeof(p->N), &n);
263
4.24k
}
264
265
/* Allocate and initialize an Exponential Interpolation function. */
266
int
267
gs_function_ElIn_init(gs_function_t ** ppfn,
268
                      const gs_function_ElIn_params_t * params,
269
                      gs_memory_t * mem)
270
34.6k
{
271
34.6k
    static const gs_function_head_t function_ElIn_head = {
272
34.6k
        function_type_ExponentialInterpolation,
273
34.6k
        {
274
34.6k
            (fn_evaluate_proc_t) fn_ElIn_evaluate,
275
34.6k
            (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
276
34.6k
            gs_function_get_info_default,
277
34.6k
            (fn_get_params_proc_t) fn_ElIn_get_params,
278
34.6k
            (fn_make_scaled_proc_t) fn_ElIn_make_scaled,
279
34.6k
            (fn_free_params_proc_t) gs_function_ElIn_free_params,
280
34.6k
            fn_common_free,
281
34.6k
            (fn_serialize_proc_t) gs_function_ElIn_serialize,
282
34.6k
        }
283
34.6k
    };
284
34.6k
    int code;
285
286
34.6k
    *ppfn = 0;      /* in case of error */
287
34.6k
    code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
288
34.6k
    if (code < 0)
289
370
        return code;
290
34.3k
    if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
291
0
        return_error(gs_error_rangecheck);
292
34.3k
    if (params->N != floor(params->N)) {
293
        /* Non-integral exponent, all inputs must be non-negative. */
294
3.53k
        if (params->Domain[0] < 0)
295
0
            return_error(gs_error_rangecheck);
296
3.53k
    }
297
34.3k
    if (params->N < 0) {
298
        /* Negative exponent, input must not be zero. */
299
11
        if (params->Domain[0] <= 0 && params->Domain[1] >= 0)
300
11
            return_error(gs_error_rangecheck);
301
34.2k
    } {
302
34.2k
        gs_function_ElIn_t *pfn =
303
34.2k
            gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
304
34.2k
                            "gs_function_ElIn_init");
305
306
34.2k
        if (pfn == 0)
307
0
            return_error(gs_error_VMerror);
308
34.2k
        pfn->params = *params;
309
34.2k
        pfn->params.m = 1;
310
34.2k
        pfn->head = function_ElIn_head;
311
34.2k
        *ppfn = (gs_function_t *) pfn;
312
34.2k
    }
313
0
    return 0;
314
34.2k
}
315
316
/* ---------------- 1-Input Stitching functions ---------------- */
317
318
typedef struct gs_function_1ItSg_s {
319
    gs_function_head_t head;
320
    gs_function_1ItSg_params_t params;
321
} gs_function_1ItSg_t;
322
323
private_st_function_1ItSg();
324
325
/* Evaluate a 1-Input Stitching function. */
326
static int
327
fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
328
35.9M
{
329
35.9M
    const gs_function_1ItSg_t *const pfn =
330
35.9M
        (const gs_function_1ItSg_t *)pfn_common;
331
35.9M
    float arg = in[0], b0, b1, e0, encoded;
332
35.9M
    int k = pfn->params.k;
333
35.9M
    int i;
334
335
35.9M
    if (arg < pfn->params.Domain[0]) {
336
0
        arg = pfn->params.Domain[0];
337
0
        i = 0;
338
35.9M
    } else if (arg > pfn->params.Domain[1]) {
339
0
        arg = pfn->params.Domain[1];
340
0
        i = k - 1;
341
35.9M
    } else {
342
61.4M
        for (i = 0; i < k - 1; ++i)
343
56.0M
            if (arg <= pfn->params.Bounds[i])
344
30.4M
                break;
345
35.9M
    }
346
35.9M
    b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
347
35.9M
    b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
348
35.9M
    e0 = pfn->params.Encode[2 * i];
349
35.9M
    if (b1 == b0)
350
0
        encoded = e0;
351
35.9M
    else
352
35.9M
        encoded =
353
35.9M
            (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
354
35.9M
    if_debug3('~', "[~]1ItSg %g in %d => %g\n", arg, i, encoded);
355
35.9M
    return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
356
35.9M
}
357
358
/* Test whether a 1-Input Stitching function is monotonic. */
359
static int
360
fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
361
                      const float *lower, const float *upper, uint *mask)
362
6.53M
{
363
6.53M
    const gs_function_1ItSg_t *const pfn =
364
6.53M
        (const gs_function_1ItSg_t *)pfn_common;
365
6.53M
    float v0 = lower[0], v1 = upper[0];
366
6.53M
    float d0 = pfn->params.Domain[0], d1 = pfn->params.Domain[1];
367
6.53M
    int k = pfn->params.k;
368
6.53M
    int i;
369
370
6.53M
    *mask = 0;
371
372
    /* If the upper and lower parametric values are the same then this is a point
373
     * and so is monotonic.
374
     */
375
6.53M
    if (v0 == v1)
376
2.70M
        return 1;
377
378
3.82M
    if (v0 > v1) {
379
1.39M
        v0 = v1; v1 = lower[0];
380
1.39M
    }
381
3.82M
    if (v0 > d1 || v1 < d0)
382
0
        return_error(gs_error_rangecheck);
383
3.82M
    if (v0 < d0)
384
0
        v0 = d0;
385
3.82M
    if (v1 > d1)
386
0
        v1 = d1;
387
6.04M
    for (i = 0; i < pfn->params.k; ++i) {
388
6.04M
        float b0 = (i == 0 ? d0 : pfn->params.Bounds[i - 1]);
389
6.04M
        float b1 = (i == k - 1 ? d1 : pfn->params.Bounds[i]);
390
6.04M
        const float bsmall = (float)1e-6 * (b1 - b0);
391
6.04M
        float esmall;
392
6.04M
        float e0, e1;
393
6.04M
        float w0, w1;
394
6.04M
        float vv0, vv1;
395
6.04M
        float vb0, vb1;
396
397
6.04M
        if (v0 >= b1 - bsmall)
398
2.21M
            continue; /* Ignore a small noise */
399
3.82M
        vv0 = max(b0, v0);
400
        /* make sure we promote *both* values, in case v0 was within the
401
         * noise threshold above.
402
         */
403
3.82M
        vv1 = max(b0, v1);
404
3.82M
        if (vv1 > b1 && v1 < b1 + bsmall)
405
1.11k
            vv1 = b1; /* Ignore a small noise */
406
3.82M
        if (vv0 == vv1)
407
0
            return 1;
408
3.82M
        if (vv0 < b1 && vv1 > b1) {
409
1.49M
            *mask = 1;
410
1.49M
            return 0; /* Consider stitches as monotony breaks. */
411
1.49M
        }
412
2.33M
        e0 = pfn->params.Encode[2 * i];
413
2.33M
        e1 = pfn->params.Encode[2 * i + 1];
414
2.33M
        esmall = (float)1e-6 * any_abs(e1 - e0);
415
2.33M
        vb0 = (float)max(vv0, b0);
416
2.33M
        vb1 = (float)min(vv1, b1);
417
2.33M
        if (b1 == b0)
418
0
            return 1; /* function is monotonous in a point */
419
2.33M
        w0 = (float)(vb0 - b0) * (e1 - e0) / (b1 - b0) + e0;
420
2.33M
        w1 = (float)(vb1 - b0) * (e1 - e0) / (b1 - b0) + e0;
421
        /* Note that w0 > w1 is now possible if e0 > e1. */
422
2.33M
        if (e0 > e1) {
423
11.0k
            if (w0 > e0 && w0 - esmall <= e0)
424
0
                w0 = e0; /* Suppress a small noise */
425
11.0k
            if (w1 < e1 && w1 + esmall >= e1)
426
0
                w1 = e1; /* Suppress a small noise */
427
2.32M
        } else {
428
2.32M
            if (w0 < e0 && w0 + esmall >= e0)
429
0
                w0 = e0; /* Suppress a small noise */
430
2.32M
            if (w1 > e1 && w1 - esmall <= e1)
431
0
                w1 = e1; /* Suppress a small noise */
432
2.32M
        }
433
2.33M
        if (w0 > w1)
434
11.0k
            return gs_function_is_monotonic(pfn->params.Functions[i],
435
2.33M
                                            &w1, &w0, mask);
436
2.32M
        else
437
2.32M
            return gs_function_is_monotonic(pfn->params.Functions[i],
438
2.33M
                                            &w0, &w1, mask);
439
2.33M
    }
440
    /* v0 is equal to the range end. */
441
0
    *mask = 0;
442
0
    return 1;
443
3.82M
}
444
445
/* Return 1-Input Stitching function information. */
446
static void
447
fn_1ItSg_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
448
1.39k
{
449
1.39k
    const gs_function_1ItSg_t *const pfn =
450
1.39k
        (const gs_function_1ItSg_t *)pfn_common;
451
452
1.39k
    gs_function_get_info_default(pfn_common, pfi);
453
1.39k
    pfi->Functions = pfn->params.Functions;
454
1.39k
    pfi->num_Functions = pfn->params.k;
455
1.39k
}
456
457
/* Write 1-Input Stitching function parameters on a parameter list. */
458
static int
459
fn_1ItSg_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
460
1.39k
{
461
1.39k
    const gs_function_1ItSg_t *const pfn =
462
1.39k
        (const gs_function_1ItSg_t *)pfn_common;
463
1.39k
    int ecode = fn_common_get_params(pfn_common, plist);
464
1.39k
    int code;
465
466
1.39k
    if ((code = param_write_float_values(plist, "Bounds", pfn->params.Bounds,
467
1.39k
                                         pfn->params.k - 1, false)) < 0)
468
0
        ecode = code;
469
1.39k
    if ((code = param_write_float_values(plist, "Encode", pfn->params.Encode,
470
1.39k
                                         2 * pfn->params.k, false)) < 0)
471
0
        ecode = code;
472
1.39k
    return ecode;
473
1.39k
}
474
475
/* Make a scaled copy of a 1-Input Stitching function. */
476
static int
477
fn_1ItSg_make_scaled(const gs_function_1ItSg_t *pfn,
478
                     gs_function_1ItSg_t **ppsfn,
479
                     const gs_range_t *pranges, gs_memory_t *mem)
480
0
{
481
0
    gs_function_1ItSg_t *psfn =
482
0
        gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
483
0
                        "fn_1ItSg_make_scaled");
484
0
    int code;
485
486
0
    if (psfn == 0)
487
0
        return_error(gs_error_VMerror);
488
0
    psfn->params = pfn->params;
489
0
    psfn->params.Functions = 0; /* in case of failure */
490
0
    psfn->params.Bounds =
491
0
        fn_copy_values(pfn->params.Bounds, pfn->params.k - 1, sizeof(float),
492
0
                       mem);
493
0
    psfn->params.Encode =
494
0
        fn_copy_values(pfn->params.Encode, 2 * pfn->params.k, sizeof(float),
495
0
                       mem);
496
0
    if ((code = (psfn->params.Bounds == 0 || psfn->params.Encode == 0 ?
497
0
                 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
498
0
        (code = fn_common_scale((gs_function_t *)psfn,
499
0
                                (const gs_function_t *)pfn,
500
0
                                pranges, mem)) < 0 ||
501
0
        (code = fn_scale_functions((gs_function_t ***)&psfn->params.Functions,
502
0
                                   pfn->params.Functions,
503
0
                                   pfn->params.n, pranges, false, mem)) < 0) {
504
0
        gs_function_free((gs_function_t *)psfn, true, mem);
505
0
        return code;
506
0
    }
507
0
    *ppsfn = psfn;
508
0
    return 0;
509
0
}
510
511
/* Free the parameters of a 1-Input Stitching function. */
512
void
513
gs_function_1ItSg_free_params(gs_function_1ItSg_params_t * params,
514
                              gs_memory_t * mem)
515
7.06k
{
516
7.06k
    gs_free_const_object(mem, params->Encode, "Encode");
517
7.06k
    params->Encode = NULL;
518
7.06k
    gs_free_const_object(mem, params->Bounds, "Bounds");
519
7.06k
    params->Bounds = NULL;
520
7.06k
    fn_free_functions(params->Functions, params->k, mem);
521
7.06k
    params->Functions = NULL;
522
7.06k
    fn_common_free_params((gs_function_params_t *) params, mem);
523
7.06k
}
524
525
/* Serialize. */
526
static int
527
gs_function_1ItSg_serialize(const gs_function_t * pfn, stream *s)
528
0
{
529
0
    uint n;
530
0
    const gs_function_1ItSg_params_t * p = (const gs_function_1ItSg_params_t *)&pfn->params;
531
0
    int code = fn_common_serialize(pfn, s);
532
0
    int k;
533
534
0
    if (code < 0)
535
0
        return code;
536
0
    code = sputs(s, (const byte *)&p->k, sizeof(p->k), &n);
537
0
    if (code < 0)
538
0
        return code;
539
540
0
    for (k = 0; k < p->k && code >= 0; k++)
541
0
        code = gs_function_serialize(p->Functions[k], s);
542
0
    if (code < 0)
543
0
        return code;
544
0
    code = sputs(s, (const byte *)&p->Bounds[0], sizeof(p->Bounds[0]) * (p->k - 1), &n);
545
0
    if (code < 0)
546
0
        return code;
547
0
    return sputs(s, (const byte *)&p->Encode[0], sizeof(p->Encode[0]) * (p->k * 2), &n);
548
0
}
549
550
/* Allocate and initialize a 1-Input Stitching function. */
551
int
552
gs_function_1ItSg_init(gs_function_t ** ppfn,
553
               const gs_function_1ItSg_params_t * params, gs_memory_t * mem)
554
5.71k
{
555
5.71k
    static const gs_function_head_t function_1ItSg_head = {
556
5.71k
        function_type_1InputStitching,
557
5.71k
        {
558
5.71k
            (fn_evaluate_proc_t) fn_1ItSg_evaluate,
559
5.71k
            (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
560
5.71k
            (fn_get_info_proc_t) fn_1ItSg_get_info,
561
5.71k
            (fn_get_params_proc_t) fn_1ItSg_get_params,
562
5.71k
            (fn_make_scaled_proc_t) fn_1ItSg_make_scaled,
563
5.71k
            (fn_free_params_proc_t) gs_function_1ItSg_free_params,
564
5.71k
            fn_common_free,
565
5.71k
            (fn_serialize_proc_t) gs_function_1ItSg_serialize,
566
5.71k
        }
567
5.71k
    };
568
5.71k
    int n = (params->Range == 0 ? 0 : params->n);
569
5.71k
    float prev = params->Domain[0];
570
5.71k
    int code, i;
571
572
5.71k
    *ppfn = 0;      /* in case of error */
573
24.7k
    for (i = 0; i < params->k; ++i) {
574
18.9k
        const gs_function_t *psubfn = params->Functions[i];
575
576
18.9k
        if (psubfn->params.m != 1)
577
0
            return_error(gs_error_rangecheck);
578
18.9k
        if (n == 0)
579
5.68k
            n = psubfn->params.n;
580
13.2k
        else if (psubfn->params.n != n)
581
0
            return_error(gs_error_rangecheck);
582
        /* There are only k - 1 Bounds, not k. */
583
18.9k
        if (i < params->k - 1) {
584
13.2k
            if (params->Bounds[i] < prev)
585
0
                return_error(gs_error_rangecheck);
586
13.2k
            prev = params->Bounds[i];
587
13.2k
        }
588
18.9k
    }
589
5.71k
    if (params->Domain[1] < prev)
590
7
        return_error(gs_error_rangecheck);
591
592
5.70k
    code = fn_check_mnDR((const gs_function_params_t *)params, 1, n);
593
5.70k
    if(code < 0)
594
0
        return code;
595
5.70k
    else
596
5.70k
    {
597
5.70k
        gs_function_1ItSg_t *pfn =
598
5.70k
            gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
599
5.70k
                            "gs_function_1ItSg_init");
600
601
5.70k
        if (pfn == 0)
602
0
            return_error(gs_error_VMerror);
603
5.70k
        pfn->params = *params;
604
5.70k
        pfn->params.m = 1;
605
5.70k
        pfn->params.n = n;
606
5.70k
        pfn->head = function_1ItSg_head;
607
5.70k
        *ppfn = (gs_function_t *) pfn;
608
5.70k
    }
609
5.70k
    return 0;
610
5.70k
}
611
612
/* ---------------- Arrayed Output functions ---------------- */
613
614
typedef struct gs_function_AdOt_s {
615
    gs_function_head_t head;
616
    gs_function_AdOt_params_t params;
617
} gs_function_AdOt_t;
618
619
private_st_function_AdOt();
620
621
/* Evaluate an Arrayed Output function. */
622
static int
623
fn_AdOt_evaluate(const gs_function_t *pfn_common, const float *in0, float *out)
624
0
{
625
0
    const gs_function_AdOt_t *const pfn =
626
0
        (const gs_function_AdOt_t *)pfn_common;
627
0
    const float *in = in0;
628
0
#define MAX_ADOT_IN 16
629
0
    float in_buf[MAX_ADOT_IN];
630
0
    int i;
631
632
    /*
633
     * We have to take special care to handle the case where in and out
634
     * overlap.  For the moment, handle it only for a limited number of
635
     * input values.
636
     */
637
0
    if (in <= out + (pfn->params.n - 1) && out <= in + (pfn->params.m - 1)) {
638
0
        if (pfn->params.m > MAX_ADOT_IN)
639
0
            return_error(gs_error_rangecheck);
640
0
        memcpy(in_buf, in, pfn->params.m * sizeof(*in));
641
0
        in = in_buf;
642
0
    }
643
0
    for (i = 0; i < pfn->params.n; ++i) {
644
0
        int code =
645
0
            gs_function_evaluate(pfn->params.Functions[i], in, out + i);
646
647
0
        if (code < 0)
648
0
            return code;
649
0
    }
650
0
    return 0;
651
0
#undef MAX_ADOT_IN
652
0
}
653
654
/* Test whether an Arrayed Output function is monotonic. */
655
static int
656
fn_AdOt_is_monotonic(const gs_function_t * pfn_common,
657
                     const float *lower, const float *upper, uint *mask)
658
0
{
659
0
    const gs_function_AdOt_t *const pfn =
660
0
        (const gs_function_AdOt_t *)pfn_common;
661
0
    int i;
662
663
0
    for (i = 0; i < pfn->params.n; ++i) {
664
0
        int code =
665
0
            gs_function_is_monotonic(pfn->params.Functions[i], lower, upper, mask);
666
667
0
        if (code <= 0)
668
0
            return code;
669
0
    }
670
0
    return 1;
671
0
}
672
673
/* Return Arrayed Output function information. */
674
static void
675
fn_AdOt_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
676
0
{
677
0
    const gs_function_AdOt_t *const pfn =
678
0
        (const gs_function_AdOt_t *)pfn_common;
679
680
0
    gs_function_get_info_default(pfn_common, pfi);
681
0
    pfi->Functions = pfn->params.Functions;
682
0
    pfi->num_Functions = pfn->params.n;
683
0
}
684
685
/* Make a scaled copy of an Arrayed Output function. */
686
static int
687
fn_AdOt_make_scaled(const gs_function_AdOt_t *pfn, gs_function_AdOt_t **ppsfn,
688
                    const gs_range_t *pranges, gs_memory_t *mem)
689
0
{
690
0
    gs_function_AdOt_t *psfn =
691
0
        gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
692
0
                        "fn_AdOt_make_scaled");
693
0
    int code;
694
695
0
    if (psfn == 0)
696
0
        return_error(gs_error_VMerror);
697
0
    psfn->params = pfn->params;
698
0
    psfn->params.Functions = 0; /* in case of failure */
699
0
    if ((code = fn_common_scale((gs_function_t *)psfn,
700
0
                                (const gs_function_t *)pfn,
701
0
                                pranges, mem)) < 0 ||
702
0
        (code = fn_scale_functions((gs_function_t ***)&psfn->params.Functions,
703
0
                                   pfn->params.Functions,
704
0
                                   pfn->params.n, pranges, true, mem)) < 0) {
705
0
        gs_function_free((gs_function_t *)psfn, true, mem);
706
0
        return code;
707
0
    }
708
0
    *ppsfn = psfn;
709
0
    return 0;
710
0
}
711
712
/* Free the parameters of an Arrayed Output function. */
713
void
714
gs_function_AdOt_free_params(gs_function_AdOt_params_t * params,
715
                             gs_memory_t * mem)
716
4.35k
{
717
4.35k
    fn_free_functions(params->Functions, params->n, mem);
718
4.35k
    params->Functions = NULL;
719
4.35k
    fn_common_free_params((gs_function_params_t *) params, mem);
720
4.35k
}
721
722
/* Serialize. */
723
static int
724
gs_function_AdOt_serialize(const gs_function_t * pfn, stream *s)
725
0
{
726
0
    const gs_function_AdOt_params_t * p = (const gs_function_AdOt_params_t *)&pfn->params;
727
0
    int code = fn_common_serialize(pfn, s);
728
0
    int k;
729
730
0
    if (code < 0)
731
0
        return code;
732
0
    for (k = 0; k < p->n && code >= 0; k++)
733
0
        code = gs_function_serialize(p->Functions[k], s);
734
0
    return code;
735
0
}
736
737
/* Allocate and initialize an Arrayed Output function. */
738
int
739
gs_function_AdOt_init(gs_function_t ** ppfn,
740
                const gs_function_AdOt_params_t * params, gs_memory_t * mem)
741
0
{
742
0
    static const gs_function_head_t function_AdOt_head = {
743
0
        function_type_ArrayedOutput,
744
0
        {
745
0
            (fn_evaluate_proc_t) fn_AdOt_evaluate,
746
0
            (fn_is_monotonic_proc_t) fn_AdOt_is_monotonic,
747
0
            (fn_get_info_proc_t) fn_AdOt_get_info,
748
0
            fn_common_get_params, /****** WHAT TO DO ABOUT THIS? ******/
749
0
            (fn_make_scaled_proc_t) fn_AdOt_make_scaled,
750
0
            (fn_free_params_proc_t) gs_function_AdOt_free_params,
751
0
            fn_common_free,
752
0
            (fn_serialize_proc_t) gs_function_AdOt_serialize,
753
0
        }
754
0
    };
755
0
    int m = params->m, n = params->n;
756
757
0
    *ppfn = 0;      /* in case of error */
758
0
    if (m <= 0 || n <= 0)
759
0
        return_error(gs_error_rangecheck);
760
0
    {
761
0
        gs_function_AdOt_t *pfn =
762
0
            gs_alloc_struct(mem, gs_function_AdOt_t, &st_function_AdOt,
763
0
                            "gs_function_AdOt_init");
764
0
        float *domain = (float *)
765
0
            gs_alloc_byte_array(mem, 2 * m, sizeof(float),
766
0
                                "gs_function_AdOt_init(Domain)");
767
0
        int i, j;
768
769
0
        if (pfn == 0)
770
0
            return_error(gs_error_VMerror);
771
0
        pfn->params = *params;
772
0
        pfn->params.Domain = domain;
773
0
        pfn->params.Range = 0;
774
0
        pfn->head = function_AdOt_head;
775
0
        if (domain == 0) {
776
0
            gs_function_free((gs_function_t *)pfn, true, mem);
777
0
            return_error(gs_error_VMerror);
778
0
        }
779
        /*
780
         * We compute the Domain as the intersection of the Domains of
781
         * the individual subfunctions.  This isn't quite right: some
782
         * subfunction might actually make use of a larger domain of
783
         * input values.  However, the only place that Arrayed Output
784
         * functions are used is in Shading and similar dictionaries,
785
         * where the input values are clamped to the intersection of
786
         * the individual Domains anyway.
787
         */
788
0
        memcpy(domain, params->Functions[0]->params.Domain,
789
0
               2 * sizeof(float) * m);
790
0
        for (i = 1; i < n; ++i) {
791
0
            const float *dom = params->Functions[i]->params.Domain;
792
793
0
            for (j = 0; j < 2 * m; j += 2, dom += 2) {
794
0
                domain[j] = max(domain[j], dom[0]);
795
0
                domain[j + 1] = min(domain[j + 1], dom[1]);
796
0
            }
797
0
        }
798
0
        *ppfn = (gs_function_t *) pfn;
799
0
    }
800
0
    return 0;
801
0
}