Coverage Report

Created: 2025-11-16 07:40

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
57.1k
{
42
57.1k
    int i;
43
44
57.1k
    if (Functions == NULL)
45
12.5k
        return;
46
47
211k
    for (i = count; --i >= 0;)
48
167k
        if (Functions[i])
49
163k
            gs_function_free((gs_function_t *)Functions[i], true, mem);
50
44.5k
    gs_free_const_object(mem, Functions, "Functions");
51
44.5k
}
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
119M
{
97
119M
    const gs_function_ElIn_t *const pfn =
98
119M
        (const gs_function_ElIn_t *)pfn_common;
99
119M
    double arg = in[0], raised;
100
119M
    int i;
101
102
119M
    if (arg < pfn->params.Domain[0])
103
0
        arg = pfn->params.Domain[0];
104
119M
    else if (arg > pfn->params.Domain[1])
105
1.98k
        arg = pfn->params.Domain[1];
106
119M
    raised = pow(arg, pfn->params.N);
107
465M
    for (i = 0; i < pfn->params.n; ++i) {
108
346M
        float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]);
109
346M
        float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]);
110
346M
        double value = v0 + raised * (v1 - v0);
111
112
346M
        if (pfn->params.Range) {
113
1.30M
            float r0 = pfn->params.Range[2 * i],
114
1.30M
                r1 = pfn->params.Range[2 * i + 1];
115
116
1.30M
            if (value < r0)
117
0
                value = r0;
118
1.30M
            else if (value > r1)
119
0
                value = r1;
120
1.30M
        }
121
346M
        out[i] = value;
122
346M
        if_debug3('~', "[~]ElIn %g => [%d]%g\n", arg, i, out[i]);
123
346M
    }
124
119M
    return 0;
125
119M
}
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
8.04M
{
132
8.04M
    const gs_function_ElIn_t *const pfn =
133
8.04M
        (const gs_function_ElIn_t *)pfn_common;
134
135
8.04M
    if (lower[0] > pfn->params.Domain[1] ||
136
8.04M
        upper[0] < pfn->params.Domain[0]
137
8.04M
        )
138
10
        return_error(gs_error_rangecheck);
139
8.04M
    *mask = 0;
140
8.04M
    return 1;
141
8.04M
}
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
8.51k
{
147
8.51k
    const gs_function_ElIn_t *const pfn =
148
8.51k
        (const gs_function_ElIn_t *)pfn_common;
149
8.51k
    int ecode = fn_common_get_params(pfn_common, plist);
150
8.51k
    int code;
151
152
8.51k
    if (pfn->params.C0) {
153
8.51k
        if ((code = param_write_float_values(plist, "C0", pfn->params.C0,
154
8.51k
                                             pfn->params.n, false)) < 0)
155
0
            ecode = code;
156
8.51k
    }
157
8.51k
    if (pfn->params.C1) {
158
8.51k
        if ((code = param_write_float_values(plist, "C1", pfn->params.C1,
159
8.51k
                                             pfn->params.n, false)) < 0)
160
0
            ecode = code;
161
8.51k
    }
162
8.51k
    if ((code = param_write_float(plist, "N", &pfn->params.N)) < 0)
163
0
        ecode = code;
164
8.51k
    return ecode;
165
8.51k
}
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
217k
{
230
217k
    gs_free_const_object(mem, params->C1, "C1");
231
217k
    params->C1 = NULL;
232
217k
    gs_free_const_object(mem, params->C0, "C0");
233
217k
    params->C0 = NULL;
234
217k
    fn_common_free_params((gs_function_params_t *) params, mem);
235
217k
}
236
237
/* Serialize. */
238
static int
239
gs_function_ElIn_serialize(const gs_function_t * pfn, stream *s)
240
5.71k
{
241
5.71k
    uint n;
242
5.71k
    const gs_function_ElIn_params_t * p = (const gs_function_ElIn_params_t *)&pfn->params;
243
5.71k
    int code = fn_common_serialize(pfn, s);
244
5.71k
    float C0_default[2] = {0, 0};
245
5.71k
    float C1_default[2] = {1, 0};
246
247
5.71k
    if (code < 0)
248
0
        return code;
249
5.71k
    if (p->C0)
250
5.71k
        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
5.71k
    if (code < 0)
254
0
        return code;
255
256
5.71k
    if (p->C1)
257
5.71k
        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
5.71k
    if (code < 0)
261
0
        return code;
262
5.71k
    return sputs(s, (const byte *)&p->N, sizeof(p->N), &n);
263
5.71k
}
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
217k
{
271
217k
    static const gs_function_head_t function_ElIn_head = {
272
217k
        function_type_ExponentialInterpolation,
273
217k
        {
274
217k
            (fn_evaluate_proc_t) fn_ElIn_evaluate,
275
217k
            (fn_is_monotonic_proc_t) fn_ElIn_is_monotonic,
276
217k
            gs_function_get_info_default,
277
217k
            (fn_get_params_proc_t) fn_ElIn_get_params,
278
217k
            (fn_make_scaled_proc_t) fn_ElIn_make_scaled,
279
217k
            (fn_free_params_proc_t) gs_function_ElIn_free_params,
280
217k
            fn_common_free,
281
217k
            (fn_serialize_proc_t) gs_function_ElIn_serialize,
282
217k
        }
283
217k
    };
284
217k
    int code;
285
286
217k
    *ppfn = 0;      /* in case of error */
287
217k
    code = fn_check_mnDR((const gs_function_params_t *)params, 1, params->n);
288
217k
    if (code < 0)
289
331
        return code;
290
216k
    if ((params->C0 == 0 || params->C1 == 0) && params->n != 1)
291
0
        return_error(gs_error_rangecheck);
292
216k
    if (params->N != floor(params->N)) {
293
        /* Non-integral exponent, all inputs must be non-negative. */
294
35.9k
        if (params->Domain[0] < 0)
295
0
            return_error(gs_error_rangecheck);
296
35.9k
    }
297
216k
    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
216k
    } {
302
216k
        gs_function_ElIn_t *pfn =
303
216k
            gs_alloc_struct(mem, gs_function_ElIn_t, &st_function_ElIn,
304
216k
                            "gs_function_ElIn_init");
305
306
216k
        if (pfn == 0)
307
0
            return_error(gs_error_VMerror);
308
216k
        pfn->params = *params;
309
216k
        pfn->params.m = 1;
310
216k
        pfn->head = function_ElIn_head;
311
216k
        *ppfn = (gs_function_t *) pfn;
312
216k
    }
313
0
    return 0;
314
216k
}
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
79.6M
{
329
79.6M
    const gs_function_1ItSg_t *const pfn =
330
79.6M
        (const gs_function_1ItSg_t *)pfn_common;
331
79.6M
    float arg = in[0], b0, b1, e0, encoded;
332
79.6M
    int k = pfn->params.k;
333
79.6M
    int i;
334
335
79.6M
    if (arg < pfn->params.Domain[0]) {
336
0
        arg = pfn->params.Domain[0];
337
0
        i = 0;
338
79.6M
    } else if (arg > pfn->params.Domain[1]) {
339
0
        arg = pfn->params.Domain[1];
340
0
        i = k - 1;
341
79.6M
    } else {
342
160M
        for (i = 0; i < k - 1; ++i)
343
146M
            if (arg <= pfn->params.Bounds[i])
344
66.4M
                break;
345
79.6M
    }
346
79.6M
    b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]);
347
79.6M
    b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]);
348
79.6M
    e0 = pfn->params.Encode[2 * i];
349
79.6M
    if (b1 == b0)
350
5.92k
        encoded = e0;
351
79.6M
    else
352
79.6M
        encoded =
353
79.6M
            (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0;
354
79.6M
    if_debug3('~', "[~]1ItSg %g in %d => %g\n", arg, i, encoded);
355
79.6M
    return gs_function_evaluate(pfn->params.Functions[i], &encoded, out);
356
79.6M
}
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
12.3M
{
363
12.3M
    const gs_function_1ItSg_t *const pfn =
364
12.3M
        (const gs_function_1ItSg_t *)pfn_common;
365
12.3M
    float v0 = lower[0], v1 = upper[0];
366
12.3M
    float d0 = pfn->params.Domain[0], d1 = pfn->params.Domain[1];
367
12.3M
    int k = pfn->params.k;
368
12.3M
    int i;
369
370
12.3M
    *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
12.3M
    if (v0 == v1)
376
4.47M
        return 1;
377
378
7.92M
    if (v0 > v1) {
379
3.46M
        v0 = v1; v1 = lower[0];
380
3.46M
    }
381
7.92M
    if (v0 > d1 || v1 < d0)
382
0
        return_error(gs_error_rangecheck);
383
7.92M
    if (v0 < d0)
384
0
        v0 = d0;
385
7.92M
    if (v1 > d1)
386
0
        v1 = d1;
387
13.6M
    for (i = 0; i < pfn->params.k; ++i) {
388
13.6M
        float b0 = (i == 0 ? d0 : pfn->params.Bounds[i - 1]);
389
13.6M
        float b1 = (i == k - 1 ? d1 : pfn->params.Bounds[i]);
390
13.6M
        const float bsmall = (float)1e-6 * (b1 - b0);
391
13.6M
        float esmall;
392
13.6M
        float e0, e1;
393
13.6M
        float w0, w1;
394
13.6M
        float vv0, vv1;
395
13.6M
        float vb0, vb1;
396
397
13.6M
        if (v0 >= b1 - bsmall)
398
5.71M
            continue; /* Ignore a small noise */
399
7.92M
        vv0 = max(b0, v0);
400
        /* make sure we promote *both* values, in case v0 was within the
401
         * noise threshold above.
402
         */
403
7.92M
        vv1 = max(b0, v1);
404
7.92M
        if (vv1 > b1 && v1 < b1 + bsmall)
405
2.36k
            vv1 = b1; /* Ignore a small noise */
406
7.92M
        if (vv0 == vv1)
407
0
            return 1;
408
7.92M
        if (vv0 < b1 && vv1 > b1) {
409
3.06M
            *mask = 1;
410
3.06M
            return 0; /* Consider stitches as monotony breaks. */
411
3.06M
        }
412
4.85M
        e0 = pfn->params.Encode[2 * i];
413
4.85M
        e1 = pfn->params.Encode[2 * i + 1];
414
4.85M
        esmall = (float)1e-6 * any_abs(e1 - e0);
415
4.85M
        vb0 = (float)max(vv0, b0);
416
4.85M
        vb1 = (float)min(vv1, b1);
417
4.85M
        if (b1 == b0)
418
0
            return 1; /* function is monotonous in a point */
419
4.85M
        w0 = (float)(vb0 - b0) * (e1 - e0) / (b1 - b0) + e0;
420
4.85M
        w1 = (float)(vb1 - b0) * (e1 - e0) / (b1 - b0) + e0;
421
        /* Note that w0 > w1 is now possible if e0 > e1. */
422
4.85M
        if (e0 > e1) {
423
139k
            if (w0 > e0 && w0 - esmall <= e0)
424
0
                w0 = e0; /* Suppress a small noise */
425
139k
            if (w1 < e1 && w1 + esmall >= e1)
426
0
                w1 = e1; /* Suppress a small noise */
427
4.71M
        } else {
428
4.71M
            if (w0 < e0 && w0 + esmall >= e0)
429
0
                w0 = e0; /* Suppress a small noise */
430
4.71M
            if (w1 > e1 && w1 - esmall <= e1)
431
0
                w1 = e1; /* Suppress a small noise */
432
4.71M
        }
433
4.85M
        if (w0 > w1)
434
139k
            return gs_function_is_monotonic(pfn->params.Functions[i],
435
4.85M
                                            &w1, &w0, mask);
436
4.71M
        else
437
4.71M
            return gs_function_is_monotonic(pfn->params.Functions[i],
438
4.85M
                                            &w0, &w1, mask);
439
4.85M
    }
440
    /* v0 is equal to the range end. */
441
0
    *mask = 0;
442
0
    return 1;
443
7.92M
}
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.93k
{
449
1.93k
    const gs_function_1ItSg_t *const pfn =
450
1.93k
        (const gs_function_1ItSg_t *)pfn_common;
451
452
1.93k
    gs_function_get_info_default(pfn_common, pfi);
453
1.93k
    pfi->Functions = pfn->params.Functions;
454
1.93k
    pfi->num_Functions = pfn->params.k;
455
1.93k
}
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.93k
{
461
1.93k
    const gs_function_1ItSg_t *const pfn =
462
1.93k
        (const gs_function_1ItSg_t *)pfn_common;
463
1.93k
    int ecode = fn_common_get_params(pfn_common, plist);
464
1.93k
    int code;
465
466
1.93k
    if ((code = param_write_float_values(plist, "Bounds", pfn->params.Bounds,
467
1.93k
                                         pfn->params.k - 1, false)) < 0)
468
0
        ecode = code;
469
1.93k
    if ((code = param_write_float_values(plist, "Encode", pfn->params.Encode,
470
1.93k
                                         2 * pfn->params.k, false)) < 0)
471
0
        ecode = code;
472
1.93k
    return ecode;
473
1.93k
}
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
44.5k
{
516
44.5k
    gs_free_const_object(mem, params->Encode, "Encode");
517
44.5k
    params->Encode = NULL;
518
44.5k
    gs_free_const_object(mem, params->Bounds, "Bounds");
519
44.5k
    params->Bounds = NULL;
520
44.5k
    fn_free_functions(params->Functions, params->k, mem);
521
44.5k
    params->Functions = NULL;
522
44.5k
    fn_common_free_params((gs_function_params_t *) params, mem);
523
44.5k
}
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
42.4k
{
555
42.4k
    static const gs_function_head_t function_1ItSg_head = {
556
42.4k
        function_type_1InputStitching,
557
42.4k
        {
558
42.4k
            (fn_evaluate_proc_t) fn_1ItSg_evaluate,
559
42.4k
            (fn_is_monotonic_proc_t) fn_1ItSg_is_monotonic,
560
42.4k
            (fn_get_info_proc_t) fn_1ItSg_get_info,
561
42.4k
            (fn_get_params_proc_t) fn_1ItSg_get_params,
562
42.4k
            (fn_make_scaled_proc_t) fn_1ItSg_make_scaled,
563
42.4k
            (fn_free_params_proc_t) gs_function_1ItSg_free_params,
564
42.4k
            fn_common_free,
565
42.4k
            (fn_serialize_proc_t) gs_function_1ItSg_serialize,
566
42.4k
        }
567
42.4k
    };
568
42.4k
    int n = (params->Range == 0 ? 0 : params->n);
569
42.4k
    float prev = params->Domain[0];
570
42.4k
    int code, i;
571
572
42.4k
    *ppfn = 0;      /* in case of error */
573
205k
    for (i = 0; i < params->k; ++i) {
574
162k
        const gs_function_t *psubfn = params->Functions[i];
575
576
162k
        if (psubfn->params.m != 1)
577
0
            return_error(gs_error_rangecheck);
578
162k
        if (n == 0)
579
42.3k
            n = psubfn->params.n;
580
120k
        else if (psubfn->params.n != n)
581
0
            return_error(gs_error_rangecheck);
582
        /* There are only k - 1 Bounds, not k. */
583
162k
        if (i < params->k - 1) {
584
120k
            if (params->Bounds[i] < prev)
585
1
                return_error(gs_error_rangecheck);
586
120k
            prev = params->Bounds[i];
587
120k
        }
588
162k
    }
589
42.4k
    if (params->Domain[1] < prev)
590
6
        return_error(gs_error_rangecheck);
591
592
42.4k
    code = fn_check_mnDR((const gs_function_params_t *)params, 1, n);
593
42.4k
    if(code < 0)
594
0
        return code;
595
42.4k
    else
596
42.4k
    {
597
42.4k
        gs_function_1ItSg_t *pfn =
598
42.4k
            gs_alloc_struct(mem, gs_function_1ItSg_t, &st_function_1ItSg,
599
42.4k
                            "gs_function_1ItSg_init");
600
601
42.4k
        if (pfn == 0)
602
0
            return_error(gs_error_VMerror);
603
42.4k
        pfn->params = *params;
604
42.4k
        pfn->params.m = 1;
605
42.4k
        pfn->params.n = n;
606
42.4k
        pfn->head = function_1ItSg_head;
607
42.4k
        *ppfn = (gs_function_t *) pfn;
608
42.4k
    }
609
42.4k
    return 0;
610
42.4k
}
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
12.5k
{
717
12.5k
    fn_free_functions(params->Functions, params->n, mem);
718
12.5k
    params->Functions = NULL;
719
12.5k
    fn_common_free_params((gs_function_params_t *) params, mem);
720
12.5k
}
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
}