Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gsfunc0.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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 FunctionType 0 (Sampled) Functions */
18
#include "math_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gsfunc0.h"
22
#include "gsparam.h"
23
#include "gxfarith.h"
24
#include "gxfunc.h"
25
#include "stream.h"
26
#include "gsccolor.h"           /* Only for GS_CLIENT_COLOR_MAX_COMPONENTS */
27
28
#define POLE_CACHE_DEBUG 0      /* A temporary development technology need.
29
                                   Remove after the beta testing. */
30
458
#define POLE_CACHE_GENERIC_1D 1 /* A temporary development technology need.
31
                                   Didn't decide yet - see fn_Sd_evaluate_cubic_cached_1d. */
32
836
#define POLE_CACHE_IGNORE 0     /* A temporary development technology need.
33
                                   Remove after the beta testing. */
34
35
82.8k
#define MAX_FAST_COMPS 8
36
37
typedef struct gs_function_Sd_s {
38
    gs_function_head_t head;
39
    gs_function_Sd_params_t params;
40
} gs_function_Sd_t;
41
42
/* GC descriptor */
43
private_st_function_Sd();
44
static
45
190
ENUM_PTRS_WITH(function_Sd_enum_ptrs, gs_function_Sd_t *pfn)
46
76
{
47
76
    index -= 6;
48
76
    if (index < st_data_source_max_ptrs)
49
19
        return ENUM_USING(st_data_source, &pfn->params.DataSource,
50
76
                          sizeof(pfn->params.DataSource), index);
51
57
    return ENUM_USING_PREFIX(st_function, st_data_source_max_ptrs);
52
76
}
53
76
ENUM_PTR3(0, gs_function_Sd_t, params.Encode, params.Decode, params.Size);
54
190
ENUM_PTR3(3, gs_function_Sd_t, params.pole, params.array_step, params.stream_step);
55
190
ENUM_PTRS_END
56
static
57
19
RELOC_PTRS_WITH(function_Sd_reloc_ptrs, gs_function_Sd_t *pfn)
58
19
{
59
19
    RELOC_PREFIX(st_function);
60
19
    RELOC_USING(st_data_source, &pfn->params.DataSource,
61
19
                sizeof(pfn->params.DataSource));
62
19
    RELOC_PTR3(gs_function_Sd_t, params.Encode, params.Decode, params.Size);
63
19
    RELOC_PTR3(gs_function_Sd_t, params.pole, params.array_step, params.stream_step);
64
19
}
65
19
RELOC_PTRS_END
66
67
/* Define the maximum plausible number of inputs and outputs */
68
/* for a Sampled function. */
69
#ifndef GS_CLIENT_SAMPLED_FN_MAX_COMPONENTS   /* Allow override with XCFLAGS */
70
35.7k
#  define max_Sd_m GS_CLIENT_COLOR_MAX_COMPONENTS
71
35.7k
#  define max_Sd_n GS_CLIENT_COLOR_MAX_COMPONENTS
72
#else
73
#  define max_Sd_m GS_CLIENT_SAMPLED_FN_MAX_COMPONENTS
74
#  define max_Sd_n GS_CLIENT_SAMPLED_FN_MAX_COMPONENTS
75
#endif
76
77
/* Get one set of sample values. */
78
#define SETUP_SAMPLES(bps, nbytes)\
79
6.37M
        int n = pfn->params.n;\
80
6.37M
        byte buf[max_Sd_n * ((bps + 7) >> 3)];\
81
6.37M
        const byte *p;\
82
6.37M
        int i;\
83
6.37M
\
84
6.37M
        data_source_access(&pfn->params.DataSource, offset >> 3,\
85
6.37M
                           nbytes, buf, &p)
86
87
static int
88
fn_gets_1(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
89
0
{
90
0
    SETUP_SAMPLES(1, ((offset & 7) + n + 7) >> 3);
91
0
    for (i = 0; i < n; ++i) {
92
0
        samples[i] = (*p >> (~offset & 7)) & 1;
93
0
        if (!(++offset & 7))
94
0
            p++;
95
0
    }
96
0
    return 0;
97
0
}
98
static int
99
fn_gets_2(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
100
0
{
101
0
    SETUP_SAMPLES(2, (((offset & 7) >> 1) + n + 3) >> 2);
102
0
    for (i = 0; i < n; ++i) {
103
0
        samples[i] = (*p >> (6 - (offset & 7))) & 3;
104
0
        if (!((offset += 2) & 7))
105
0
            p++;
106
0
    }
107
0
    return 0;
108
0
}
109
static int
110
fn_gets_4(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
111
0
{
112
0
    SETUP_SAMPLES(4, (((offset & 7) >> 2) + n + 1) >> 1);
113
0
    for (i = 0; i < n; ++i) {
114
0
        samples[i] = ((offset ^= 4) & 4 ? *p >> 4 : *p++ & 0xf);
115
0
    }
116
0
    return 0;
117
0
}
118
static int
119
fn_gets_8(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
120
6.31M
{
121
6.31M
    SETUP_SAMPLES(8, n);
122
21.2M
    for (i = 0; i < n; ++i) {
123
14.9M
        samples[i] = *p++;
124
14.9M
    }
125
6.31M
    return 0;
126
6.31M
}
127
static int
128
fn_gets_12(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
129
0
{
130
0
    SETUP_SAMPLES(12, (((offset & 7) >> 2) + 3 * n + 1) >> 1);
131
0
    for (i = 0; i < n; ++i) {
132
0
        if (offset & 4)
133
0
            samples[i] = ((*p & 0xf) << 8) + p[1], p += 2;
134
0
        else
135
0
            samples[i] = (*p << 4) + (p[1] >> 4), p++;
136
0
        offset ^= 4;
137
0
    }
138
0
    return 0;
139
0
}
140
static int
141
fn_gets_16(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
142
59.3k
{
143
59.3k
    SETUP_SAMPLES(16, n * 2);
144
119k
    for (i = 0; i < n; ++i) {
145
59.9k
        samples[i] = (*p << 8) + p[1];
146
59.9k
        p += 2;
147
59.9k
    }
148
59.3k
    return 0;
149
59.3k
}
150
static int
151
fn_gets_24(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
152
0
{
153
0
    SETUP_SAMPLES(24, n * 3);
154
0
    for (i = 0; i < n; ++i) {
155
0
        samples[i] = (*p << 16) + (p[1] << 8) + p[2];
156
0
        p += 3;
157
0
    }
158
0
    return 0;
159
0
}
160
static int
161
fn_gets_32(const gs_function_Sd_t * pfn, ulong offset, uint * samples)
162
0
{
163
0
    SETUP_SAMPLES(32, n * 4);
164
0
    for (i = 0; i < n; ++i) {
165
0
        samples[i] = (*p << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
166
0
        p += 4;
167
0
    }
168
0
    return 0;
169
0
}
170
171
static int (*const fn_get_samples[]) (const gs_function_Sd_t * pfn,
172
                                       ulong offset, uint * samples) =
173
{
174
    0, fn_gets_1, fn_gets_2, 0, fn_gets_4, 0, 0, 0,
175
        fn_gets_8, 0, 0, 0, fn_gets_12, 0, 0, 0,
176
        fn_gets_16, 0, 0, 0, 0, 0, 0, 0,
177
        fn_gets_24, 0, 0, 0, 0, 0, 0, 0,
178
        fn_gets_32
179
};
180
181
/*
182
 * Compute a value by cubic interpolation.
183
 * f[] = f(0), f(1), f(2), f(3); 1 < x < 2.
184
 * The formula is derived from those presented in
185
 * http://www.cs.uwa.edu.au/undergraduate/units/233.413/Handouts/Lecture04.html
186
 * (thanks to Raph Levien for the reference).
187
 */
188
static double
189
interpolate_cubic(double x, double f0, double f1, double f2, double f3)
190
0
{
191
    /*
192
     * The parameter 'a' affects the contribution of the high-frequency
193
     * components.  The abovementioned source suggests a = -0.5.
194
     */
195
0
#define a (-0.5)
196
0
#define SQR(v) ((v) * (v))
197
0
#define CUBE(v) ((v) * (v) * (v))
198
0
    const double xm1 = x - 1, m2x = 2 - x, m3x = 3 - x;
199
0
    const double c =
200
0
        (a * CUBE(x) - 5 * a * SQR(x) + 8 * a * x - 4 * a) * f0 +
201
0
        ((a+2) * CUBE(xm1) - (a+3) * SQR(xm1) + 1) * f1 +
202
0
        ((a+2) * CUBE(m2x) - (a+3) * SQR(m2x) + 1) * f2 +
203
0
        (a * CUBE(m3x) - 5 * a * SQR(m3x) + 8 * a * m3x - 4 * a) * f3;
204
205
0
    if_debug6('~', "[~](%g, %g, %g, %g)order3(%g) => %g\n",
206
0
              f0, f1, f2, f3, x, c);
207
0
    return c;
208
0
#undef a
209
0
#undef SQR
210
0
#undef CUBE
211
0
}
212
213
/*
214
 * Compute a value by quadratic interpolation.
215
 * f[] = f(0), f(1), f(2); 0 < x < 1.
216
 *
217
 * We used to use a quadratic formula for this, derived from
218
 * f(0) = f0, f(1) = f1, f'(1) = (f2 - f0) / 2, but now we
219
 * match what we believe is Acrobat Reader's behavior.
220
 */
221
static inline double
222
interpolate_quadratic(double x, double f0, double f1, double f2)
223
0
{
224
0
    return interpolate_cubic(x + 1, f0, f0, f1, f2);
225
0
}
226
227
/* Calculate a result by multicubic interpolation. */
228
static void
229
fn_interpolate_cubic(const gs_function_Sd_t *pfn, const float *fparts,
230
                     const int *iparts, const ulong *factors,
231
                     float *samples, ulong offset, int m)
232
0
{
233
0
    int j;
234
235
0
top:
236
0
    if (m == 0) {
237
0
        uint sdata[max_Sd_n];
238
239
0
        (*fn_get_samples[pfn->params.BitsPerSample])(pfn, offset, sdata);
240
0
        for (j = pfn->params.n - 1; j >= 0; --j)
241
0
            samples[j] = (float)sdata[j];
242
0
    } else {
243
0
        float fpart = *fparts++;
244
0
        int ipart = *iparts++;
245
0
        ulong delta = *factors++;
246
0
        int size = pfn->params.Size[pfn->params.m - m];
247
0
        float samples1[max_Sd_n], samplesm1[max_Sd_n], samples2[max_Sd_n];
248
249
0
        --m;
250
0
        if (is_fzero(fpart))
251
0
            goto top;
252
0
        fn_interpolate_cubic(pfn, fparts, iparts, factors, samples,
253
0
                             offset, m);
254
0
        fn_interpolate_cubic(pfn, fparts, iparts, factors, samples1,
255
0
                             offset + delta, m);
256
        /* Ensure we don't try to access out of bounds. */
257
        /*
258
         * If size == 1, the only possible value for ipart and fpart is
259
         * 0, so we've already handled this case.
260
         */
261
0
        if (size == 2) { /* ipart = 0 */
262
            /* Use linear interpolation. */
263
0
            for (j = pfn->params.n - 1; j >= 0; --j)
264
0
                samples[j] += (samples1[j] - samples[j]) * fpart;
265
0
            return;
266
0
        }
267
0
        if (ipart == 0) {
268
            /* Use quadratic interpolation. */
269
0
            fn_interpolate_cubic(pfn, fparts, iparts, factors,
270
0
                                 samples2, offset + delta * 2, m);
271
0
            for (j = pfn->params.n - 1; j >= 0; --j)
272
0
                samples[j] =
273
0
                    interpolate_quadratic(fpart, samples[j],
274
0
                                          samples1[j], samples2[j]);
275
0
            return;
276
0
        }
277
        /* At this point we know ipart > 0, size >= 3. */
278
0
        fn_interpolate_cubic(pfn, fparts, iparts, factors, samplesm1,
279
0
                             offset - delta, m);
280
0
        if (ipart == size - 2) {
281
            /* Use quadratic interpolation. */
282
0
            for (j = pfn->params.n - 1; j >= 0; --j)
283
0
                samples[j] =
284
0
                    interpolate_quadratic(1 - fpart, samples1[j],
285
0
                                          samples[j], samplesm1[j]);
286
0
            return;
287
0
        }
288
        /* Now we know 0 < ipart < size - 2, size > 3. */
289
0
        fn_interpolate_cubic(pfn, fparts, iparts, factors,
290
0
                             samples2, offset + delta * 2, m);
291
0
        for (j = pfn->params.n - 1; j >= 0; --j)
292
0
            samples[j] =
293
0
                interpolate_cubic(fpart + 1, samplesm1[j], samples[j],
294
0
                                  samples1[j], samples2[j]);
295
0
    }
296
0
}
297
298
/* Calculate a result by multilinear interpolation. */
299
static void
300
fn_interpolate_linear(const gs_function_Sd_t *pfn, const float *fparts,
301
                 const ulong *factors, float *samples, ulong offset, int m)
302
4.78M
{
303
4.78M
    int j;
304
305
4.93M
top:
306
4.93M
    if (m == 0) {
307
3.23M
        uint sdata[max_Sd_n];
308
309
3.23M
        (*fn_get_samples[pfn->params.BitsPerSample])(pfn, offset, sdata);
310
12.1M
        for (j = pfn->params.n - 1; j >= 0; --j)
311
8.90M
            samples[j] = (float)sdata[j];
312
3.23M
    } else {
313
1.69M
        float fpart = *fparts++;
314
1.69M
        float samples1[max_Sd_n];
315
316
1.69M
        if (is_fzero(fpart)) {
317
146k
            ++factors;
318
146k
            --m;
319
146k
            goto top;
320
146k
        }
321
1.54M
        fn_interpolate_linear(pfn, fparts, factors + 1, samples,
322
1.54M
                              offset, m - 1);
323
1.54M
        fn_interpolate_linear(pfn, fparts, factors + 1, samples1,
324
1.54M
                              offset + *factors, m - 1);
325
5.86M
        for (j = pfn->params.n - 1; j >= 0; --j)
326
4.32M
            samples[j] += (samples1[j] - samples[j]) * fpart;
327
1.54M
    }
328
4.93M
}
329
330
static inline double
331
fn_Sd_encode(const gs_function_Sd_t *pfn, int i, double sample)
332
10.6M
{
333
10.6M
    float d0, d1, r0, r1;
334
10.6M
    double value;
335
10.6M
    int bps = pfn->params.BitsPerSample;
336
    /* x86 machines have problems with shifts if bps >= 32 */
337
10.6M
    uint max_samp = (bps < (sizeof(uint) * 8)) ? ((1 << bps) - 1) : max_uint;
338
339
10.6M
    if (pfn->params.Range)
340
10.6M
        r0 = pfn->params.Range[2 * i], r1 = pfn->params.Range[2 * i + 1];
341
0
    else
342
0
        r0 = 0, r1 = (float)max_samp;
343
10.6M
    if (pfn->params.Decode)
344
8.72M
        d0 = pfn->params.Decode[2 * i], d1 = pfn->params.Decode[2 * i + 1];
345
1.92M
    else
346
1.92M
        d0 = r0, d1 = r1;
347
348
10.6M
    value = sample * (d1 - d0) / max_samp + d0;
349
10.6M
    if (value < r0)
350
0
        value = r0;
351
10.6M
    else if (value > r1)
352
0
        value = r1;
353
10.6M
    return value;
354
10.6M
}
355
356
/* Evaluate a Sampled function. */
357
/* A generic algorithm with a recursion by dimentions. */
358
static int
359
fn_Sd_evaluate_general(const gs_function_t * pfn_common, const float *in, float *out)
360
1.69M
{
361
1.69M
    const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
362
1.69M
    int bps = pfn->params.BitsPerSample;
363
1.69M
    ulong offset = 0;
364
1.69M
    int i;
365
1.69M
    float encoded[max_Sd_m];
366
1.69M
    int iparts[max_Sd_m]; /* only needed for cubic interpolation */
367
1.69M
    ulong factors[max_Sd_m];
368
1.69M
    float samples[max_Sd_n];
369
370
    /* Encode the input values. */
371
372
3.38M
    for (i = 0; i < pfn->params.m; ++i) {
373
1.69M
        float d0 = pfn->params.Domain[2 * i],
374
1.69M
            d1 = pfn->params.Domain[2 * i + 1];
375
1.69M
        float arg = in[i], enc;
376
377
1.69M
        if (arg < d0)
378
45
            arg = d0;
379
1.69M
        else if (arg > d1)
380
0
            arg = d1;
381
1.69M
        if (pfn->params.Encode) {
382
1.43M
            float e0 = pfn->params.Encode[2 * i];
383
1.43M
            float e1 = pfn->params.Encode[2 * i + 1];
384
385
1.43M
            enc = (arg - d0) * (e1 - e0) / (d1 - d0) + e0;
386
1.43M
            if (enc < 0)
387
0
                encoded[i] = 0;
388
1.43M
            else if (enc >= pfn->params.Size[i] - 1)
389
29.5k
                encoded[i] = (float)pfn->params.Size[i] - 1;
390
1.40M
            else
391
1.40M
                encoded[i] = enc;
392
1.43M
        } else {
393
            /* arg is guaranteed to be in bounds, ergo so is enc */
394
                /* TODO: possible issue here.  if (pfn->params.Size[i] == 1 */
395
255k
            encoded[i] = (arg - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
396
255k
        }
397
1.69M
    }
398
399
    /* Look up and interpolate the output values. */
400
401
1.69M
    {
402
1.69M
        ulong factor = (ulong)bps * pfn->params.n;
403
404
3.38M
        for (i = 0; i < pfn->params.m; factor *= pfn->params.Size[i++]) {
405
1.69M
            int ipart = (int)encoded[i];
406
407
1.69M
            offset += (factors[i] = factor) * ipart;
408
1.69M
            iparts[i] = ipart;  /* only needed for cubic interpolation */
409
1.69M
            encoded[i] -= ipart;
410
1.69M
        }
411
1.69M
    }
412
1.69M
    if (pfn->params.Order == 3)
413
0
        fn_interpolate_cubic(pfn, encoded, iparts, factors, samples,
414
0
                             offset, pfn->params.m);
415
1.69M
    else
416
1.69M
        fn_interpolate_linear(pfn, encoded, factors, samples, offset,
417
1.69M
                              pfn->params.m);
418
419
    /* Encode the output values. */
420
421
6.27M
    for (i = 0; i < pfn->params.n; ++i)
422
4.58M
        out[i] = (float)fn_Sd_encode(pfn, i, samples[i]);
423
424
1.69M
    return 0;
425
1.69M
}
426
427
static const double double_stub = 1e90;
428
429
static inline void
430
fn_make_cubic_poles(double *p, double f0, double f1, double f2, double f3,
431
            const int pole_step_minor)
432
16
{   /* The following is poles of the polinomial,
433
       which represents interpolate_cubic in [1,2]. */
434
16
    const double a = -0.5;
435
436
16
    p[pole_step_minor * 1] = (a*f0 + 3*f1 - a*f2)/3.0;
437
16
    p[pole_step_minor * 2] = (-a*f1 + 3*f2 + a*f3)/3.0;
438
16
}
439
440
static void
441
fn_make_poles(double *p, const int pole_step, int power, int bias)
442
16
{
443
16
    const int pole_step_minor = pole_step / 3;
444
16
    switch(power) {
445
0
        case 1: /* A linear 3d power curve. */
446
            /* bias must be 0. */
447
0
            p[pole_step_minor * 1] = (2 * p[pole_step * 0] + 1 * p[pole_step * 1]) / 3;
448
0
            p[pole_step_minor * 2] = (1 * p[pole_step * 0] + 2 * p[pole_step * 1]) / 3;
449
0
            break;
450
0
        case 2:
451
            /* bias may be be 0 or 1. */
452
            /* Duplicate the beginning or the ending pole (the old code compatible). */
453
0
            fn_make_cubic_poles(p + pole_step * bias,
454
0
                    p[pole_step * 0], p[pole_step * bias],
455
0
                    p[pole_step * (1 + bias)], p[pole_step * 2],
456
0
                    pole_step_minor);
457
0
            break;
458
16
        case 3:
459
            /* bias must be 1. */
460
16
            fn_make_cubic_poles(p + pole_step * bias,
461
16
                    p[pole_step * 0], p[pole_step * 1], p[pole_step * 2], p[pole_step * 3],
462
16
                    pole_step_minor);
463
16
            break;
464
0
        default: /* Must not happen. */
465
0
           DO_NOTHING;
466
16
    }
467
16
}
468
469
/* Evaluate a Sampled function.
470
   A cubic interpolation with a pole cache.
471
   Allows a fast check for extreme suspection. */
472
/* This implementation is a particular case of 1 dimension.
473
   maybe we'll use as an optimisation of the generic case,
474
   so keep it for a while. */
475
static int
476
fn_Sd_evaluate_cubic_cached_1d(const gs_function_Sd_t *pfn, const float *in, float *out)
477
0
{
478
0
    float d0 = pfn->params.Domain[2 * 0];
479
0
    float d1 = pfn->params.Domain[2 * 0 + 1];
480
0
    const int pole_step_minor = pfn->params.n;
481
0
    const int pole_step = 3 * pole_step_minor;
482
0
    int i0; /* A cell index. */
483
0
    int ib, ie, i, k;
484
0
    double *p, t0, t1, tt;
485
0
486
0
    tt = (in[0] - d0) * (pfn->params.Size[0] - 1) / (d1 - d0);
487
0
    i0 = (int)floor(tt);
488
0
    ib = max(i0 - 1, 0);
489
0
    ie = min(pfn->params.Size[0], i0 + 3);
490
0
    for (i = ib; i < ie; i++) {
491
0
        if (pfn->params.pole[i * pole_step] == double_stub) {
492
0
            uint sdata[max_Sd_n];
493
0
            int bps = pfn->params.BitsPerSample;
494
0
495
0
            p = &pfn->params.pole[i * pole_step];
496
0
            fn_get_samples[pfn->params.BitsPerSample](pfn, (ulong)i * bps * pfn->params.n, sdata);
497
0
            for (k = 0; k < pfn->params.n; k++, p++)
498
0
                *p = fn_Sd_encode(pfn, k, (double)sdata[k]);
499
0
        }
500
0
    }
501
0
    p = &pfn->params.pole[i0 * pole_step];
502
0
    t0 = tt - i0;
503
0
    if (t0 == 0) {
504
0
        for (k = 0; k < pfn->params.n; k++, p++)
505
0
            out[k] = *p;
506
0
    } else {
507
0
        if (p[1 * pole_step_minor] == double_stub) {
508
0
            for (k = 0; k < pfn->params.n; k++)
509
0
                fn_make_poles(&pfn->params.pole[ib * pole_step + k], pole_step,
510
0
                        ie - ib - 1, i0 - ib);
511
0
        }
512
0
        t1 = 1 - t0;
513
0
        for (k = 0; k < pfn->params.n; k++, p++) {
514
0
            double y = p[0 * pole_step_minor] * t1 * t1 * t1 +
515
0
                       p[1 * pole_step_minor] * t1 * t1 * t0 * 3 +
516
0
                       p[2 * pole_step_minor] * t1 * t0 * t0 * 3 +
517
0
                       p[3 * pole_step_minor] * t0 * t0 * t0;
518
0
            if (y < pfn->params.Range[0])
519
0
                y = pfn->params.Range[0];
520
0
            if (y > pfn->params.Range[1])
521
0
                y = pfn->params.Range[1];
522
0
            out[k] = y;
523
0
        }
524
0
    }
525
0
    return 0;
526
0
}
527
528
static inline void
529
decode_argument(const gs_function_Sd_t *pfn, const float *in, double T[max_Sd_m], int I[max_Sd_m])
530
229
{
531
229
    int i;
532
533
458
    for (i = 0; i < pfn->params.m; i++) {
534
229
        float xi = in[i];
535
229
        float d0 = pfn->params.Domain[2 * i + 0];
536
229
        float d1 = pfn->params.Domain[2 * i + 1];
537
229
        double t;
538
539
229
        if (xi < d0)
540
0
            xi = d0;
541
229
        if (xi > d1)
542
0
            xi = d1;
543
229
        t = (xi - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
544
229
        I[i] = (int)floor(t);
545
229
        T[i] = t - I[i];
546
229
    }
547
229
}
548
549
static inline void
550
index_span(const gs_function_Sd_t *pfn, int *I, double *T, int ii, int *Ii, int *ib, int *ie)
551
229
{
552
229
    *Ii = I[ii];
553
229
    if (T[ii] != 0) {
554
4
        *ib = max(*Ii - 1, 0);
555
4
        *ie = min(pfn->params.Size[ii], *Ii + 3);
556
225
    } else {
557
225
        *ib = *Ii;
558
225
        *ie = *Ii + 1;
559
225
    }
560
229
}
561
562
static inline int
563
load_vector_to(const gs_function_Sd_t *pfn, int s_offset, double *V)
564
3.13M
{
565
3.13M
    uint sdata[max_Sd_n];
566
3.13M
    int k, code;
567
568
3.13M
    code = fn_get_samples[pfn->params.BitsPerSample](pfn, s_offset, sdata);
569
3.13M
    if (code < 0)
570
0
        return code;
571
9.20M
    for (k = 0; k < pfn->params.n; k++)
572
6.07M
        V[k] = fn_Sd_encode(pfn, k, (double)sdata[k]);
573
3.13M
    return 0;
574
3.13M
}
575
576
static inline int
577
load_vector(const gs_function_Sd_t *pfn, int a_offset, int s_offset)
578
189
{
579
189
    if (*(pfn->params.pole + a_offset) == double_stub) {
580
189
        uint sdata[max_Sd_n];
581
189
        int k, code;
582
583
189
        code = fn_get_samples[pfn->params.BitsPerSample](pfn, s_offset, sdata);
584
189
        if (code < 0)
585
0
            return code;
586
945
        for (k = 0; k < pfn->params.n; k++)
587
756
            *(pfn->params.pole + a_offset + k) = fn_Sd_encode(pfn, k, (double)sdata[k]);
588
189
    }
589
189
    return 0;
590
189
}
591
592
static inline void
593
interpolate_vector(const gs_function_Sd_t *pfn, int offset, int pole_step, int power, int bias)
594
4
{
595
4
    int k;
596
597
20
    for (k = 0; k < pfn->params.n; k++)
598
16
        fn_make_poles(pfn->params.pole + offset + k, pole_step, power, bias);
599
4
}
600
601
static inline void
602
interpolate_tensors(const gs_function_Sd_t *pfn, int *I, double *T,
603
        int offset, int pole_step, int power, int bias, int ii)
604
4
{
605
4
    if (ii < 0)
606
4
        interpolate_vector(pfn, offset, pole_step, power, bias);
607
0
    else {
608
0
        int s = pfn->params.array_step[ii];
609
0
        int Ii = I[ii];
610
611
0
        if (T[ii] == 0) {
612
0
            interpolate_tensors(pfn, I, T, offset + Ii * s, pole_step, power, bias, ii - 1);
613
0
        } else {
614
0
            int l;
615
616
0
            for (l = 0; l < 4; l++)
617
0
                interpolate_tensors(pfn, I, T, offset + Ii * s + l * s / 3, pole_step, power, bias, ii - 1);
618
0
        }
619
0
    }
620
4
}
621
622
static inline bool
623
is_tensor_done(const gs_function_Sd_t *pfn, int *I, double *T, int a_offset, int ii)
624
229
{
625
    /* Check an inner pole of the cell. */
626
229
    int i, o = 0;
627
628
458
    for (i = ii; i >= 0; i--) {
629
229
        o += I[i] * pfn->params.array_step[i];
630
229
        if (T[i] != 0)
631
4
            o += pfn->params.array_step[i] / 3;
632
229
    }
633
229
    if (*(pfn->params.pole + a_offset + o) != double_stub)
634
52
        return true;
635
177
    return false;
636
229
}
637
638
/* Creates a tensor of Bezier coefficients by node interpolation. */
639
static inline int
640
make_interpolation_tensor(const gs_function_Sd_t *pfn, int *I, double *T,
641
                            int a_offset, int s_offset, int ii)
642
418
{
643
    /* Well, this function isn't obvious. Trying to explain what it does.
644
645
       Suppose we have a 4x4x4...x4 hypercube of nodes, and we want to build
646
       a multicubic interpolation function for the inner 2x2x2...x2 hypercube.
647
       We represent the multicubic function with a tensor of Besier poles,
648
       and the size of the tensor is 4x4x....x4. Note that the corners
649
       of the tensor are equal to the corners of the 2x2x...x2 hypercube.
650
651
       We organize the 'pole' array so that a tensor of a cell
652
       occupies the cell, and tensors for neighbour cells have a common hyperplane.
653
654
       For a 1-dimentional case let the nodes are n0, n1, n2, n3.
655
       It defines 3 cells n0...n1, n1...n2, n2...n3.
656
       For the 2nd cell n1...n2 let the tensor coefficients are q10, q11, q12, q13.
657
       We choose a cubic approximation, in which tangents at nodes n1, n2
658
       are parallel to (n2 - n0) and (n3 - n1) correspondingly.
659
       (Well, this doesn't give a the minimal curvity, but likely it is
660
       what Adobe implementations do, see the bug 687352,
661
       and we agree that it's some reasonable).
662
663
       Then we have :
664
665
       q11 = n0
666
       q12 = (n0/2 + 3*n1 - n2/2)/3;
667
       q11 = (n1/2 + 3*n2 - n3/2)/3;
668
       q13 = n2
669
670
       When the source node array have an insufficient nomber of nodes
671
       along a dimension to determine tangents a cell
672
       (this happens near the array boundaries),
673
       we simply duplicate ending nodes. This solution is done
674
       for the compatibility to the old code, and definitely
675
       there exists a better one. Likely Adobe does the same.
676
677
       For a 2-dimensional case we apply the 1-dimentional case through
678
       the first dimension, and then construct a surface by varying the
679
       second coordinate as a parameter. It gives a bicubic surface,
680
       and the result doesn't depend on the order of coordinates
681
       (I proved the latter with Matematica 3.0).
682
       Then we know that an interpolation by one coordinate and
683
       a differentiation by another coordinate are interchangeble operators.
684
       Due to that poles of the interpolated function are same as
685
       interpolated poles of the function (well, we didn't spend time
686
       for a strong proof, but this fact was confirmed with testing the
687
       implementation with POLE_CACHE_DEBUG).
688
689
       Then we apply the 2-dimentional considerations recursively
690
       to all dimensions. This is exactly what the function does.
691
692
     */
693
418
    int code;
694
695
418
    if (ii < 0) {
696
189
        if (POLE_CACHE_IGNORE || *(pfn->params.pole + a_offset) == double_stub) {
697
189
            code = load_vector(pfn, a_offset, s_offset);
698
189
            if (code < 0)
699
0
                return code;
700
189
        }
701
229
    } else {
702
229
        int Ii, ib, ie, i;
703
229
        int sa = pfn->params.array_step[ii];
704
229
        int ss = pfn->params.stream_step[ii];
705
706
229
        index_span(pfn, I, T, ii, &Ii, &ib, &ie);
707
229
        if (POLE_CACHE_IGNORE || !is_tensor_done(pfn, I, T, a_offset, ii)) {
708
366
            for (i = ib; i < ie; i++) {
709
189
                code = make_interpolation_tensor(pfn, I, T,
710
189
                                a_offset + i * sa, s_offset + i * ss, ii - 1);
711
189
                if (code < 0)
712
0
                    return code;
713
189
            }
714
177
            if (T[ii] != 0)
715
4
                interpolate_tensors(pfn, I, T, a_offset + ib * sa, sa, ie - ib - 1,
716
4
                                Ii - ib, ii - 1);
717
177
        }
718
229
    }
719
418
    return 0;
720
418
}
721
722
/* Creates a subarray of samples. */
723
static inline int
724
make_interpolation_nodes(const gs_function_Sd_t *pfn, double *T0, double *T1,
725
                            int *I, double *T,
726
                            int a_offset, int s_offset, int ii)
727
0
{
728
0
    int code;
729
730
0
    if (ii < 0) {
731
0
        if (POLE_CACHE_IGNORE || *(pfn->params.pole + a_offset) == double_stub) {
732
0
            code = load_vector(pfn, a_offset, s_offset);
733
0
            if (code < 0)
734
0
                return code;
735
0
        }
736
0
        if (pfn->params.Order == 3) {
737
0
            code = make_interpolation_tensor(pfn, I, T, 0, 0, pfn->params.m - 1);
738
0
            if (code < 0)
739
0
                return code;
740
0
        }
741
0
    } else {
742
0
        int i;
743
0
        int i0 = (int)floor(T0[ii]);
744
0
        int i1 = (int)ceil(T1[ii]);
745
0
        int sa = pfn->params.array_step[ii];
746
0
        int ss = pfn->params.stream_step[ii];
747
748
0
        if (i0 < 0 || i0 >= pfn->params.Size[ii])
749
0
            return_error(gs_error_unregistered); /* Must not happen. */
750
0
        if (i1 < 0 || i1 >= pfn->params.Size[ii])
751
0
            return_error(gs_error_unregistered); /* Must not happen. */
752
0
        I[ii] = i0;
753
0
        T[ii] = (i1 > i0 ? 1 : 0);
754
0
        for (i = i0; i <= i1; i++) {
755
0
            code = make_interpolation_nodes(pfn, T0, T1, I, T,
756
0
                            a_offset + i * sa, s_offset + i * ss, ii - 1);
757
0
            if (code < 0)
758
0
                return code;
759
0
        }
760
0
    }
761
0
    return 0;
762
0
}
763
764
static inline int
765
evaluate_from_tenzor(const gs_function_Sd_t *pfn, int *I, double *T, int offset, int ii, double *y)
766
470
{
767
470
    int s = pfn->params.array_step[ii], k, l, code;
768
769
470
    if (ii < 0) {
770
1.20k
        for (k = 0; k < pfn->params.n; k++)
771
964
            y[k] = *(pfn->params.pole + offset + k);
772
241
    } else if (T[ii] == 0) {
773
225
        return evaluate_from_tenzor(pfn, I, T, offset + s * I[ii], ii - 1, y);
774
225
    } else {
775
4
        double t0 = T[ii], t1 = 1 - t0;
776
4
        double p[4][max_Sd_n];
777
778
20
        for (l = 0; l < 4; l++) {
779
16
            code = evaluate_from_tenzor(pfn, I, T, offset + s * I[ii] + l * (s / 3), ii - 1, p[l]);
780
16
            if (code < 0)
781
0
                return code;
782
16
        }
783
20
        for (k = 0; k < pfn->params.n; k++)
784
16
            y[k] = p[0][k] * t1 * t1 * t1 +
785
16
                   p[1][k] * t1 * t1 * t0 * 3 +
786
16
                   p[2][k] * t1 * t0 * t0 * 3 +
787
16
           p[3][k] * t0 * t0 * t0;
788
4
    }
789
245
    return 0;
790
470
}
791
792
/* Evaluate a Sampled function. */
793
/* A cubic interpolation with pole cache. */
794
/* Allows a fast check for extreme suspection with is_tensor_monotonic. */
795
static int
796
fn_Sd_evaluate_multicubic_cached(const gs_function_Sd_t *pfn, const float *in, float *out)
797
229
{
798
229
    double T[max_Sd_m], y[max_Sd_n];
799
229
    int I[max_Sd_m], k, code;
800
801
229
    decode_argument(pfn, in, T, I);
802
229
    code = make_interpolation_tensor(pfn, I, T, 0, 0, pfn->params.m - 1);
803
229
    if (code < 0)
804
0
        return code;
805
229
    evaluate_from_tenzor(pfn, I, T, 0, pfn->params.m - 1, y);
806
1.14k
    for (k = 0; k < pfn->params.n; k++) {
807
916
        double yk = y[k];
808
809
916
        if (yk < pfn->params.Range[k * 2 + 0])
810
0
            yk = pfn->params.Range[k * 2 + 0];
811
916
        if (yk > pfn->params.Range[k * 2 + 1])
812
0
            yk = pfn->params.Range[k * 2 + 1];
813
916
        out[k] = yk;
814
916
    }
815
229
    return 0;
816
229
}
817
818
/* Evaluate a Sampled function. */
819
static int
820
fn_Sd_evaluate(const gs_function_t * pfn_common, const float *in, float *out)
821
1.69M
{
822
1.69M
    const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
823
1.69M
    int code;
824
825
1.69M
    if (pfn->params.Order == 3) {
826
229
        if (POLE_CACHE_GENERIC_1D || pfn->params.m > 1)
827
229
            code = fn_Sd_evaluate_multicubic_cached(pfn, in, out);
828
0
        else
829
0
            code = fn_Sd_evaluate_cubic_cached_1d(pfn, in, out);
830
# if POLE_CACHE_DEBUG
831
        {   float y[max_Sd_n];
832
            int k, code1;
833
834
            code1 = fn_Sd_evaluate_general(pfn_common, in, y);
835
            if (code != code1)
836
                return_error(gs_error_unregistered); /* Must not happen. */
837
            for (k = 0; k < pfn->params.n; k++) {
838
                if (any_abs(y[k] - out[k]) > 1e-6 * (pfn->params.Range[k * 2 + 1] - pfn->params.Range[k * 2 + 0]))
839
                    return_error(gs_error_unregistered); /* Must not happen. */
840
            }
841
        }
842
# endif
843
229
    } else
844
1.69M
        code = fn_Sd_evaluate_general(pfn_common, in, out);
845
1.69M
    return code;
846
1.69M
}
847
848
/* Map a function subdomain to the sample index subdomain. */
849
static inline int
850
get_scaled_range(const gs_function_Sd_t *const pfn,
851
                   const float *lower, const float *upper,
852
                   int i, float *pw0, float *pw1)
853
13.3k
{
854
13.3k
    float d0 = pfn->params.Domain[i * 2 + 0], d1 = pfn->params.Domain[i * 2 + 1];
855
13.3k
    float v0 = lower[i], v1 = upper[i];
856
13.3k
    float e0, e1, w0, w1, w;
857
13.3k
    const float small_noise = (float)1e-6;
858
859
13.3k
    if (v0 < d0 || v0 > d1)
860
15
        return_error(gs_error_rangecheck);
861
13.3k
    if (pfn->params.Encode)
862
11.3k
        e0 = pfn->params.Encode[i * 2 + 0], e1 = pfn->params.Encode[i * 2 + 1];
863
1.97k
    else
864
1.97k
        e0 = 0, e1 = (float)pfn->params.Size[i] - 1;
865
13.3k
    w0 = (v0 - d0) * (e1 - e0) / (d1 - d0) + e0;
866
13.3k
    if (w0 < 0)
867
0
        w0 = 0;
868
13.3k
    else if (w0 >= pfn->params.Size[i] - 1)
869
1.41k
        w0 = (float)pfn->params.Size[i] - 1;
870
13.3k
    w1 = (v1 - d0) * (e1 - e0) / (d1 - d0) + e0;
871
13.3k
    if (w1 < 0)
872
0
        w1 = 0;
873
13.3k
    else if (w1 >= pfn->params.Size[i] - 1)
874
2.56k
        w1 = (float)pfn->params.Size[i] - 1;
875
13.3k
    if (w0 > w1) {
876
1.19k
        w = w0; w0 = w1; w1 = w;
877
1.19k
    }
878
13.3k
    if (floor(w0 + 1) - w0 < small_noise * any_abs(e1 - e0))
879
56
        w0 = (floor(w0) + 1);
880
13.3k
    if (w1 - floor(w1) < small_noise * any_abs(e1 - e0))
881
4.16k
        w1 = floor(w1);
882
13.3k
    if (w0 > w1)
883
20
        w0 = w1;
884
13.3k
    *pw0 = w0;
885
13.3k
    *pw1 = w1;
886
13.3k
    return 0;
887
13.3k
}
888
889
/* Copy a tensor to a differently indexed pole array. */
890
static int
891
copy_poles(const gs_function_Sd_t *pfn, int *I, double *T0, double *T1, int a_offset,
892
                int ii, double *pole, int p_offset, int pole_step)
893
0
{
894
0
    int i, ei, sa, code;
895
0
    int order = pfn->params.Order;
896
897
0
    if (pole_step <= 0)
898
0
        return_error(gs_error_limitcheck); /* Too small buffer. */
899
0
    ei = (T0[ii] == T1[ii] ? 1 : order + 1);
900
0
    sa = pfn->params.array_step[ii];
901
0
    if (ii == 0) {
902
0
        for (i = 0; i < ei; i++)
903
0
            *(pole + p_offset + i * pole_step) =
904
0
                    *(pfn->params.pole + a_offset + I[ii] * sa + i * (sa / order));
905
0
    } else {
906
0
        for (i = 0; i < ei; i++) {
907
0
            code = copy_poles(pfn, I, T0, T1, a_offset + I[ii] * sa + i * (sa / order), ii - 1,
908
0
                            pole, p_offset + i * pole_step, pole_step / 4);
909
0
            if (code < 0)
910
0
                return code;
911
0
        }
912
0
    }
913
0
    return 0;
914
0
}
915
916
static inline void
917
subcurve(double *pole, int pole_step, double t0, double t1)
918
0
{
919
    /* Generated with subcurve.nb using Mathematica 3.0. */
920
0
    double q0 = pole[pole_step * 0];
921
0
    double q1 = pole[pole_step * 1];
922
0
    double q2 = pole[pole_step * 2];
923
0
    double q3 = pole[pole_step * 3];
924
0
    double t01 = t0 - 1, t11 = t1 - 1;
925
0
    double small = 1e-13;
926
927
0
#define Power2(a) (a) * (a)
928
0
#define Power3(a) (a) * (a) * (a)
929
0
    pole[pole_step * 0] = t0*(t0*(q3*t0 - 3*q2*t01) + 3*q1*Power2(t01)) - q0*Power3(t01);
930
0
    pole[pole_step * 1] = q1*t01*(-2*t0 - t1 + 3*t0*t1) + t0*(q2*t0 + 2*q2*t1 -
931
0
                            3*q2*t0*t1 + q3*t0*t1) - q0*t11*Power2(t01);
932
0
    pole[pole_step * 2] = t1*(2*q2*t0 + q2*t1 - 3*q2*t0*t1 + q3*t0*t1) +
933
0
                            q1*(-t0 - 2*t1 + 3*t0*t1)*t11 - q0*t01*Power2(t11);
934
0
    pole[pole_step * 3] = t1*(t1*(3*q2 - 3*q2*t1 + q3*t1) +
935
0
                            3*q1*Power2(t11)) - q0*Power3(t11);
936
0
#undef Power2
937
0
#undef Power3
938
0
    if (any_abs(pole[pole_step * 1] - pole[pole_step * 0]) < small)
939
0
        pole[pole_step * 1] = pole[pole_step * 0];
940
0
    if (any_abs(pole[pole_step * 2] - pole[pole_step * 3]) < small)
941
0
        pole[pole_step * 2] = pole[pole_step * 3];
942
0
}
943
944
static inline void
945
subline(double *pole, int pole_step, double t0, double t1)
946
0
{
947
0
    double q0 = pole[pole_step * 0];
948
0
    double q1 = pole[pole_step * 1];
949
950
0
    pole[pole_step * 0] = (1 - t0) * q0 + t0 * q1;
951
0
    pole[pole_step * 1] = (1 - t1) * q0 + t1 * q1;
952
0
}
953
954
static void
955
clamp_poles(double *T0, double *T1, int ii, int i, double * pole,
956
                int p_offset, int pole_step, int pole_step_i, int order)
957
0
{
958
0
    if (ii < 0) {
959
0
        if (order == 3)
960
0
            subcurve(pole + p_offset, pole_step_i, T0[i], T1[i]);
961
0
        else
962
0
            subline(pole + p_offset, pole_step_i, T0[i], T1[i]);
963
0
    } else if (i == ii) {
964
0
        clamp_poles(T0, T1, ii - 1, i, pole, p_offset, pole_step / 4, pole_step, order);
965
0
    } else {
966
0
        int j, ei = (T0[ii] == T1[ii] ? 1 : order + 1);
967
968
0
        for (j = 0; j < ei; j++)
969
0
            clamp_poles(T0, T1, ii - 1, i, pole, p_offset + j * pole_step,
970
0
                            pole_step / 4, pole_step_i, order);
971
0
    }
972
0
}
973
974
static inline int /* 3 - don't know, 2 - decreesing, 0 - constant, 1 - increasing. */
975
curve_monotonity(double *pole, int pole_step)
976
0
{
977
0
    double p0 = pole[pole_step * 0];
978
0
    double p1 = pole[pole_step * 1];
979
0
    double p2 = pole[pole_step * 2];
980
0
    double p3 = pole[pole_step * 3];
981
982
0
    if (p0 == p1 && any_abs(p1 - p2) < 1e-13 && p2 == p3)
983
0
        return 0;
984
0
    if (p0 <= p1 && p1 <= p2 && p2 <= p3)
985
0
        return 1;
986
0
    if (p0 >= p1 && p1 >= p2 && p2 >= p3)
987
0
        return 2;
988
    /* Maybe not monotonic.
989
       Don't want to solve quadratic equations, so return "don't know".
990
       This case should be rare.
991
     */
992
0
    return 3;
993
0
}
994
995
static inline int /* 2 - decreesing, 0 - constant, 1 - increasing. */
996
line_monotonity(double *pole, int pole_step)
997
0
{
998
0
    double p0 = pole[pole_step * 0];
999
0
    double p1 = pole[pole_step * 1];
1000
1001
0
    if (p1 - p0 > 1e-13)
1002
0
        return 1;
1003
0
    if (p0 - p1 > 1e-13)
1004
0
        return 2;
1005
0
    return 0;
1006
0
}
1007
1008
static int /* 3 bits per guide : 3 - non-monotonic or don't know,
1009
                    2 - decreesing, 0 - constant, 1 - increasing.
1010
                    The number of guides is order+1. */
1011
tensor_dimension_monotonity(const double *T0, const double *T1, int ii, int i0, double *pole,
1012
                int p_offset, int pole_step, int pole_step_i, int order)
1013
0
{
1014
0
    if (ii < 0) {
1015
0
        if (order == 3)
1016
0
            return curve_monotonity(pole + p_offset, pole_step_i);
1017
0
        else
1018
0
            return line_monotonity(pole + p_offset, pole_step_i);
1019
0
    } else if (i0 == ii) {
1020
        /* Delay the dimension till the end, and adjust pole_step. */
1021
0
        return tensor_dimension_monotonity(T0, T1, ii - 1, i0, pole, p_offset,
1022
0
                            pole_step / 4, pole_step, order);
1023
0
    } else {
1024
0
        int j, ei = (T0[ii] == T1[ii] ? 1 : order + 1), m = 0, mm;
1025
1026
0
        for (j = 0; j < ei; j++) {
1027
0
            mm = tensor_dimension_monotonity(T0, T1, ii - 1, i0, pole, p_offset + j * pole_step,
1028
0
                            pole_step/ 4, pole_step_i, order);
1029
0
            m |= mm << (j * 3);
1030
0
            if (mm == 3) {
1031
                /* If one guide is not monotonic, the dimension is not monotonic.
1032
                   Can return early. */
1033
0
                break;
1034
0
            }
1035
0
        }
1036
0
        return m;
1037
0
    }
1038
0
}
1039
1040
static inline int
1041
is_tensor_monotonic_by_dimension(const gs_function_Sd_t *pfn, int *I, double *T0, double *T1, int i0, int k,
1042
                    uint *mask /* 3 bits per guide : 3 - non-monotonic or don't know,
1043
                    2 - decreesing, 0 - constant, 1 - increasing.
1044
                    The number of guides is order+1. */)
1045
0
{
1046
0
    double pole[4*4*4]; /* For a while restricting with 3-in cubic functions.
1047
                 More arguments need a bigger buffer, but the rest of code is same. */
1048
0
    int i, code, ii = pfn->params.m - 1;
1049
0
    double TT0[3], TT1[3];
1050
1051
0
    *mask = 0;
1052
0
    if (ii >= 3) {
1053
         /* Unimplemented. We don't know practical cases,
1054
            because currently it is only called while decomposing a shading.  */
1055
0
        return_error(gs_error_limitcheck);
1056
0
    }
1057
0
    code = copy_poles(pfn, I, T0, T1, k, ii, pole, 0, count_of(pole) / 4);
1058
0
    if (code < 0)
1059
0
        return code;
1060
0
    for (i = ii; i >= 0; i--) {
1061
0
        TT0[i] = 0;
1062
0
        if (T0[i] != T1[i]) {
1063
0
            if (T0[i] != 0 || T1[i] != 1)
1064
0
                clamp_poles(T0, T1, ii, i, pole, 0, count_of(pole) / 4, -1, pfn->params.Order);
1065
0
            TT1[i] = 1;
1066
0
        } else
1067
0
            TT1[i] = 0;
1068
0
    }
1069
0
    *mask = tensor_dimension_monotonity(TT0, TT1, ii, i0, pole, 0,
1070
0
                        count_of(pole) / 4, 1, pfn->params.Order);
1071
0
    return 0;
1072
0
}
1073
1074
static int /* error code */
1075
is_lattice_monotonic_by_dimension(const gs_function_Sd_t *pfn, const double *T0, const double *T1,
1076
        int *I, double *S0, double *S1, int ii, int i0, int k,
1077
        uint *mask /* 3 bits per guide : 1 - non-monotonic or don't know, 0 - monotonic;
1078
                      The number of guides is order+1. */)
1079
0
{
1080
0
    if (ii == -1) {
1081
        /* fixme : could cache the cell monotonity against redundant evaluation. */
1082
0
        return is_tensor_monotonic_by_dimension(pfn, I, S0, S1, i0, k, mask);
1083
0
    } else {
1084
0
        int i1 = (ii > i0 ? ii : ii == 0 ? i0 : ii - 1); /* Delay the dimension i0 till the end of recursion. */
1085
0
        int j, code;
1086
0
        int bi = (int)floor(T0[i1]);
1087
0
        int ei = (int)floor(T1[i1]);
1088
0
        uint m, mm, m1 = 0x49249249 & ((1 << ((pfn->params.Order + 1) * 3)) - 1);
1089
1090
0
        if (floor(T1[i1]) == T1[i1])
1091
0
            ei --;
1092
0
        m = 0;
1093
0
        for (j = bi; j <= ei; j++) {
1094
            /* fixme : A better performance may be obtained with comparing central nodes with side ones. */
1095
0
            I[i1] = j;
1096
0
            S0[i1] = max(T0[i1] - j, 0);
1097
0
            S1[i1] = min(T1[i1] - j, 1);
1098
0
            code = is_lattice_monotonic_by_dimension(pfn, T0, T1, I, S0, S1, ii - 1, i0, k, &mm);
1099
0
            if (code < 0)
1100
0
                return code;
1101
0
            m |= mm;
1102
0
            if (m == m1) /* Don't return early - shadings need to know about all dimensions. */
1103
0
                break;
1104
0
        }
1105
0
        if (ii == 0) {
1106
            /* Detect non-monotonic guides. */
1107
0
            m = m & (m >> 1);
1108
0
        }
1109
0
        *mask = m;
1110
0
        return 0;
1111
0
    }
1112
0
}
1113
1114
static inline int /* error code */
1115
is_lattice_monotonic(const gs_function_Sd_t *pfn, const double *T0, const double *T1,
1116
         int *I, double *S0, double *S1,
1117
         int k, uint *mask /* 1 bit per dimension : 1 - non-monotonic or don't know,
1118
                      0 - monotonic. */)
1119
0
{
1120
0
    uint m, mm = 0;
1121
0
    int i, code;
1122
1123
0
    for (i = 0; i < pfn->params.m; i++) {
1124
0
        if (T0[i] != T1[i]) {
1125
0
            code = is_lattice_monotonic_by_dimension(pfn, T0, T1, I, S0, S1, pfn->params.m - 1, i, k, &m);
1126
0
            if (code < 0)
1127
0
                return code;
1128
0
            if (m)
1129
0
                mm |= 1 << i;
1130
0
        }
1131
0
    }
1132
0
    *mask = mm;
1133
0
    return 0;
1134
0
}
1135
1136
static int /* 3 bits per result : 3 - non-monotonic or don't know,
1137
               2 - decreesing, 0 - constant, 1 - increasing,
1138
               <0 - error. */
1139
fn_Sd_1arg_linear_monotonic_rec(const gs_function_Sd_t *const pfn, int i0, int i1,
1140
                                const double *V0, const double *V1)
1141
6.23M
{
1142
6.23M
    if (i1 - i0 <= 1) {
1143
3.12M
        int code = 0, i;
1144
1145
9.16M
        for (i = 0; i < pfn->params.n; i++) {
1146
6.04M
            if (V0[i] < V1[i])
1147
745k
                code |= 1 << (i * 3);
1148
5.30M
            else if (V0[i] > V1[i])
1149
720k
                code |= 2 << (i * 3);
1150
6.04M
        }
1151
3.12M
        return code;
1152
3.12M
    } else {
1153
3.11M
        double VV[MAX_FAST_COMPS];
1154
3.11M
        int ii = (i0 + i1) / 2, code, cod1;
1155
1156
3.11M
        code = load_vector_to(pfn, ii * pfn->params.n * pfn->params.BitsPerSample, VV);
1157
3.11M
        if (code < 0)
1158
0
            return code;
1159
3.11M
        if (code & (code >> 1))
1160
0
            return code; /* Not monotonic by some component of the result. */
1161
3.11M
        code = fn_Sd_1arg_linear_monotonic_rec(pfn, i0, ii, V0, VV);
1162
3.11M
        if (code < 0)
1163
0
            return code;
1164
3.11M
        cod1 = fn_Sd_1arg_linear_monotonic_rec(pfn, ii, i1, VV, V1);
1165
3.11M
        if (cod1 < 0)
1166
0
            return cod1;
1167
3.11M
        return code | cod1;
1168
3.11M
    }
1169
6.23M
}
1170
1171
static int
1172
fn_Sd_1arg_linear_monotonic(const gs_function_Sd_t *const pfn, double T0, double T1,
1173
                            uint *mask /* 1 - non-monotonic or don't know, 0 - monotonic. */)
1174
13.3k
{
1175
13.3k
    int i0 = (int)floor(T0);
1176
13.3k
    int i1 = (int)ceil(T1), code;
1177
13.3k
    double V0[MAX_FAST_COMPS], V1[MAX_FAST_COMPS];
1178
1179
13.3k
    if (i1 - i0 > 1) {
1180
9.55k
        code = load_vector_to(pfn, i0 * pfn->params.n * pfn->params.BitsPerSample, V0);
1181
9.55k
        if (code < 0)
1182
0
            return code;
1183
9.55k
        code = load_vector_to(pfn, i1 * pfn->params.n * pfn->params.BitsPerSample, V1);
1184
9.55k
        if (code < 0)
1185
0
            return code;
1186
9.55k
        code = fn_Sd_1arg_linear_monotonic_rec(pfn, i0, i1, V0, V1);
1187
9.55k
        if (code < 0)
1188
0
            return code;
1189
9.55k
        if (code & (code >> 1)) {
1190
3.99k
            *mask = 1;
1191
3.99k
            return 0;
1192
3.99k
        }
1193
9.55k
    }
1194
9.36k
    *mask = 0;
1195
9.36k
    return 1;
1196
13.3k
}
1197
1198
0
#define DEBUG_Sd_1arg 0
1199
1200
/* Test whether a Sampled function is monotonic. */
1201
static int /* 1 = monotonic, 0 = not or don't know, <0 = error. */
1202
fn_Sd_is_monotonic_aux(const gs_function_Sd_t *const pfn,
1203
                   const float *lower, const float *upper,
1204
                   uint *mask /* 1 bit per dimension : 1 - non-monotonic or don't know,
1205
                      0 - monotonic. */)
1206
13.3k
{
1207
13.3k
    int i, code, ii = pfn->params.m - 1;
1208
13.3k
    int I[4];
1209
13.3k
    double T0[count_of(I)], T1[count_of(I)];
1210
13.3k
    double S0[count_of(I)], S1[count_of(I)];
1211
13.3k
    uint m, mm, m1;
1212
#   if DEBUG_Sd_1arg
1213
    int code1, mask1;
1214
#   endif
1215
1216
13.3k
    if (ii >= count_of(T0)) {
1217
         /* Unimplemented. We don't know practical cases,
1218
            because currently it is only called while decomposing a shading.  */
1219
0
        return_error(gs_error_limitcheck);
1220
0
    }
1221
26.7k
    for (i = 0; i <= ii; i++) {
1222
13.3k
        float w0, w1;
1223
1224
13.3k
        code = get_scaled_range(pfn, lower, upper, i, &w0, &w1);
1225
13.3k
        if (code < 0)
1226
15
            return code;
1227
13.3k
        T0[i] = w0;
1228
13.3k
        T1[i] = w1;
1229
13.3k
    }
1230
13.3k
    if (pfn->params.m == 1 && pfn->params.Order == 1 && pfn->params.n <= MAX_FAST_COMPS) {
1231
13.3k
        code = fn_Sd_1arg_linear_monotonic(pfn, T0[0], T1[0], mask);
1232
13.3k
# if !DEBUG_Sd_1arg
1233
13.3k
            return code;
1234
# else
1235
            mask1 = *mask;
1236
            code1 = code;
1237
# endif
1238
13.3k
    }
1239
0
    m1 = (1 << pfn->params.m )- 1;
1240
0
    code = make_interpolation_nodes(pfn, T0, T1, I, S0, 0, 0, ii);
1241
0
    if (code < 0)
1242
0
        return code;
1243
0
    mm = 0;
1244
0
    for (i = 0; i < pfn->params.n; i++) {
1245
0
        code = is_lattice_monotonic(pfn, T0, T1, I, S0, S1, i, &m);
1246
0
        if (code < 0)
1247
0
            return code;
1248
0
        mm |= m;
1249
0
        if (mm == m1) /* Don't return early - shadings need to know about all dimensions. */
1250
0
            break;
1251
0
    }
1252
#   if DEBUG_Sd_1arg
1253
        if (mask1 != mm)
1254
            return_error(gs_error_unregistered);
1255
        if (code1 != !mm)
1256
            return_error(gs_error_unregistered);
1257
#   endif
1258
0
    *mask = mm;
1259
0
    return !mm;
1260
0
}
1261
1262
/* Test whether a Sampled function is monotonic. */
1263
/* 1 = monotonic, 0 = don't know, <0 = error. */
1264
static int
1265
fn_Sd_is_monotonic(const gs_function_t * pfn_common,
1266
                   const float *lower, const float *upper, uint *mask)
1267
13.3k
{
1268
13.3k
    const gs_function_Sd_t *const pfn =
1269
13.3k
        (const gs_function_Sd_t *)pfn_common;
1270
1271
13.3k
    return fn_Sd_is_monotonic_aux(pfn, lower, upper, mask);
1272
13.3k
}
1273
1274
/* Return Sampled function information. */
1275
static void
1276
fn_Sd_get_info(const gs_function_t *pfn_common, gs_function_info_t *pfi)
1277
33.2k
{
1278
33.2k
    const gs_function_Sd_t *const pfn =
1279
33.2k
        (const gs_function_Sd_t *)pfn_common;
1280
33.2k
    long size;
1281
33.2k
    int i;
1282
1283
33.2k
    gs_function_get_info_default(pfn_common, pfi);
1284
33.2k
    pfi->DataSource = &pfn->params.DataSource;
1285
67.7k
    for (i = 0, size = 1; i < pfn->params.m; ++i)
1286
34.4k
        size *= pfn->params.Size[i];
1287
33.2k
    pfi->data_size =
1288
33.2k
        (size * pfn->params.n * pfn->params.BitsPerSample + 7) >> 3;
1289
33.2k
}
1290
1291
/* Write Sampled function parameters on a parameter list. */
1292
static int
1293
fn_Sd_get_params(const gs_function_t *pfn_common, gs_param_list *plist)
1294
16.3k
{
1295
16.3k
    const gs_function_Sd_t *const pfn =
1296
16.3k
        (const gs_function_Sd_t *)pfn_common;
1297
16.3k
    int ecode = fn_common_get_params(pfn_common, plist);
1298
16.3k
    int code;
1299
1300
16.3k
    if (pfn->params.Order != 1) {
1301
38
        if ((code = param_write_int(plist, "Order", &pfn->params.Order)) < 0)
1302
0
            ecode = code;
1303
38
    }
1304
16.3k
    if ((code = param_write_int(plist, "BitsPerSample",
1305
16.3k
                                &pfn->params.BitsPerSample)) < 0)
1306
0
        ecode = code;
1307
16.3k
    if (pfn->params.Encode) {
1308
1.19k
        if ((code = param_write_float_values(plist, "Encode",
1309
1.19k
                                             pfn->params.Encode,
1310
1.19k
                                             2 * pfn->params.m, false)) < 0)
1311
0
            ecode = code;
1312
1.19k
    }
1313
16.3k
    if (pfn->params.Decode) {
1314
6.65k
        if ((code = param_write_float_values(plist, "Decode",
1315
6.65k
                                             pfn->params.Decode,
1316
6.65k
                                             2 * pfn->params.n, false)) < 0)
1317
0
            ecode = code;
1318
6.65k
    }
1319
16.3k
    if (pfn->params.Size) {
1320
16.3k
        if ((code = param_write_int_values(plist, "Size", pfn->params.Size,
1321
16.3k
                                           pfn->params.m, false)) < 0)
1322
0
            ecode = code;
1323
16.3k
    }
1324
16.3k
    return ecode;
1325
16.3k
}
1326
1327
/* Make a scaled copy of a Sampled function. */
1328
static int
1329
fn_Sd_make_scaled(const gs_function_Sd_t *pfn, gs_function_Sd_t **ppsfn,
1330
                  const gs_range_t *pranges, gs_memory_t *mem)
1331
0
{
1332
0
    gs_function_Sd_t *psfn =
1333
0
        gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd,
1334
0
                        "fn_Sd_make_scaled");
1335
0
    int code;
1336
1337
0
    if (psfn == 0)
1338
0
        return_error(gs_error_VMerror);
1339
0
    psfn->params = pfn->params;
1340
0
    psfn->params.Encode = 0;    /* in case of failure */
1341
0
    psfn->params.Decode = 0;
1342
0
    psfn->params.Size =
1343
0
        fn_copy_values(pfn->params.Size, pfn->params.m, sizeof(int), mem);
1344
0
    if ((code = (psfn->params.Size == 0 ?
1345
0
                 gs_note_error(gs_error_VMerror) : 0)) < 0 ||
1346
0
        (code = fn_common_scale((gs_function_t *)psfn,
1347
0
                                (const gs_function_t *)pfn,
1348
0
                                pranges, mem)) < 0 ||
1349
0
        (code = fn_scale_pairs(&psfn->params.Encode, pfn->params.Encode,
1350
0
                               pfn->params.m, NULL, mem)) < 0 ||
1351
0
        (code = fn_scale_pairs(&psfn->params.Decode, pfn->params.Decode,
1352
0
                               pfn->params.n, pranges, mem)) < 0) {
1353
0
        gs_function_free((gs_function_t *)psfn, true, mem);
1354
0
    } else
1355
0
        *ppsfn = psfn;
1356
0
    return code;
1357
0
}
1358
1359
/* Free the parameters of a Sampled function. */
1360
void
1361
gs_function_Sd_free_params(gs_function_Sd_params_t * params, gs_memory_t * mem)
1362
24.0k
{
1363
24.0k
    gs_free_const_object(mem, params->Size, "Size");
1364
24.0k
    params->Size = NULL;
1365
24.0k
    gs_free_const_object(mem, params->Decode, "Decode");
1366
24.0k
    params->Decode = NULL;
1367
24.0k
    gs_free_const_object(mem, params->Encode, "Encode");
1368
24.0k
    params->Encode = NULL;
1369
24.0k
    fn_common_free_params((gs_function_params_t *) params, mem);
1370
24.0k
    if (params->DataSource.type == data_source_type_stream && params->DataSource.data.strm != NULL) {
1371
23.1k
        s_close_filters(&params->DataSource.data.strm, params->DataSource.data.strm->strm);
1372
23.1k
        params->DataSource.data.strm = NULL;
1373
23.1k
    }
1374
24.0k
    gs_free_object(mem, params->pole, "gs_function_Sd_free_params");
1375
24.0k
    params->pole = NULL;
1376
24.0k
    gs_free_object(mem, params->array_step, "gs_function_Sd_free_params");
1377
24.0k
    params->array_step = NULL;
1378
24.0k
    gs_free_object(mem, params->stream_step, "gs_function_Sd_free_params");
1379
24.0k
    params->stream_step = NULL;
1380
24.0k
}
1381
1382
/* aA helper for gs_function_Sd_serialize. */
1383
static int serialize_array(const float *a, int half_size, stream *s)
1384
33.9k
{
1385
33.9k
    uint n;
1386
33.9k
    const float dummy[2] = {0, 0};
1387
33.9k
    int i, code;
1388
1389
33.9k
    if (a != NULL)
1390
22.6k
        return sputs(s, (const byte *)a, sizeof(a[0]) * half_size * 2, &n);
1391
39.5k
    for (i = 0; i < half_size; i++) {
1392
28.2k
        code = sputs(s, (const byte *)dummy, sizeof(dummy), &n);
1393
28.2k
        if (code < 0)
1394
0
            return code;
1395
28.2k
    }
1396
11.2k
    return 0;
1397
11.2k
}
1398
1399
/* Serialize. */
1400
static int
1401
gs_function_Sd_serialize(const gs_function_t * pfn, stream *s)
1402
16.9k
{
1403
16.9k
    uint n;
1404
16.9k
    const gs_function_Sd_params_t * p = (const gs_function_Sd_params_t *)&pfn->params;
1405
16.9k
    gs_function_info_t info;
1406
16.9k
    int code = fn_common_serialize(pfn, s);
1407
16.9k
    ulong pos;
1408
16.9k
    uint count;
1409
16.9k
    byte buf[100];
1410
16.9k
    const byte *ptr;
1411
1412
16.9k
    if (code < 0)
1413
0
        return code;
1414
16.9k
    code = sputs(s, (const byte *)&p->Order, sizeof(p->Order), &n);
1415
16.9k
    if (code < 0)
1416
0
        return code;
1417
16.9k
    code = sputs(s, (const byte *)&p->BitsPerSample, sizeof(p->BitsPerSample), &n);
1418
16.9k
    if (code < 0)
1419
0
        return code;
1420
16.9k
    code = serialize_array(p->Encode, p->m, s);
1421
16.9k
    if (code < 0)
1422
0
        return code;
1423
16.9k
    code = serialize_array(p->Decode, p->n, s);
1424
16.9k
    if (code < 0)
1425
0
        return code;
1426
16.9k
    gs_function_get_info(pfn, &info);
1427
16.9k
    code = sputs(s, (const byte *)&info.data_size, sizeof(info.data_size), &n);
1428
16.9k
    if (code < 0)
1429
0
        return code;
1430
185k
    for (pos = 0; pos < info.data_size; pos += count) {
1431
169k
        count = min(sizeof(buf), info.data_size - pos);
1432
169k
        data_source_access_only(info.DataSource, pos, count, buf, &ptr);
1433
169k
        code = sputs(s, ptr, count, &n);
1434
169k
        if (code < 0)
1435
0
            return code;
1436
169k
    }
1437
16.9k
    return 0;
1438
16.9k
}
1439
1440
/* Allocate and initialize a Sampled function. */
1441
int
1442
gs_function_Sd_init(gs_function_t ** ppfn,
1443
                  const gs_function_Sd_params_t * params, gs_memory_t * mem)
1444
35.7k
{
1445
35.7k
    static const gs_function_head_t function_Sd_head = {
1446
35.7k
        function_type_Sampled,
1447
35.7k
        {
1448
35.7k
            (fn_evaluate_proc_t) fn_Sd_evaluate,
1449
35.7k
            (fn_is_monotonic_proc_t) fn_Sd_is_monotonic,
1450
35.7k
            (fn_get_info_proc_t) fn_Sd_get_info,
1451
35.7k
            (fn_get_params_proc_t) fn_Sd_get_params,
1452
35.7k
            (fn_make_scaled_proc_t) fn_Sd_make_scaled,
1453
35.7k
            (fn_free_params_proc_t) gs_function_Sd_free_params,
1454
35.7k
            fn_common_free,
1455
35.7k
            (fn_serialize_proc_t) gs_function_Sd_serialize,
1456
35.7k
        }
1457
35.7k
    };
1458
35.7k
    int code;
1459
35.7k
    int i;
1460
1461
35.7k
    *ppfn = 0;      /* in case of error */
1462
35.7k
    code = fn_check_mnDR((const gs_function_params_t *)params,
1463
35.7k
                         params->m, params->n);
1464
35.7k
    if (code < 0)
1465
27
        return code;
1466
35.7k
    if (params->m > max_Sd_m || params->n > max_Sd_n)
1467
0
        return_error(gs_error_limitcheck);
1468
35.7k
    switch (params->Order) {
1469
858
        case 0:   /* use default */
1470
35.2k
        case 1:
1471
35.7k
        case 3:
1472
35.7k
            break;
1473
0
        default:
1474
0
            return_error(gs_error_rangecheck);
1475
35.7k
    }
1476
35.7k
    switch (params->BitsPerSample) {
1477
0
        case 1:
1478
0
        case 2:
1479
0
        case 4:
1480
34.0k
        case 8:
1481
34.0k
        case 12:
1482
35.5k
        case 16:
1483
35.5k
        case 24:
1484
35.5k
        case 32:
1485
35.5k
            break;
1486
216
        default:
1487
216
            return_error(gs_error_rangecheck);
1488
35.7k
    }
1489
72.4k
    for (i = 0; i < params->m; ++i)
1490
36.8k
        if (params->Size[i] <= 0)
1491
0
            return_error(gs_error_rangecheck);
1492
35.5k
    {
1493
35.5k
        gs_function_Sd_t *pfn =
1494
35.5k
            gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd,
1495
35.5k
                            "gs_function_Sd_init");
1496
35.5k
        int bps, sa, ss, i, order, was;
1497
1498
35.5k
        if (pfn == 0)
1499
0
            return_error(gs_error_VMerror);
1500
35.5k
        pfn->params = *params;
1501
35.5k
        if (params->Order == 0)
1502
858
            pfn->params.Order = 1; /* default */
1503
35.5k
        pfn->params.pole = NULL;
1504
35.5k
        pfn->params.array_step = NULL;
1505
35.5k
        pfn->params.stream_step = NULL;
1506
35.5k
        pfn->head = function_Sd_head;
1507
35.5k
        pfn->params.array_size = 0;
1508
35.5k
        if (pfn->params.m == 1 && pfn->params.Order == 1 && pfn->params.n <= MAX_FAST_COMPS && !DEBUG_Sd_1arg) {
1509
            /* Won't use pole cache. Call fn_Sd_1arg_linear_monotonic instead. */
1510
33.9k
        } else {
1511
1.58k
            pfn->params.array_step = (int *)gs_alloc_byte_array(mem,
1512
1.58k
                                    max_Sd_m, sizeof(int), "gs_function_Sd_init");
1513
1.58k
            pfn->params.stream_step = (int *)gs_alloc_byte_array(mem,
1514
1.58k
                                    max_Sd_m, sizeof(int), "gs_function_Sd_init");
1515
1.58k
            if (pfn->params.array_step == NULL || pfn->params.stream_step == NULL)
1516
0
                return_error(gs_error_VMerror);
1517
1.58k
            bps = pfn->params.BitsPerSample;
1518
1.58k
            sa = pfn->params.n;
1519
1.58k
            ss = pfn->params.n * bps;
1520
1.58k
            order = pfn->params.Order;
1521
4.53k
            for (i = 0; i < pfn->params.m; i++) {
1522
2.95k
                pfn->params.array_step[i] = sa * order;
1523
2.95k
                was = sa;
1524
2.95k
                sa = (pfn->params.Size[i] * order - (order - 1)) * sa;
1525
                /* If the calculation of sa went backwards then we overflowed! */
1526
2.95k
                if (was > sa)
1527
0
                    return_error(gs_error_VMerror);
1528
2.95k
                pfn->params.stream_step[i] = ss;
1529
2.95k
                ss = pfn->params.Size[i] * ss;
1530
2.95k
            }
1531
1.58k
            pfn->params.pole = (double *)gs_alloc_byte_array(mem,
1532
1.58k
                                    sa, sizeof(double), "gs_function_Sd_init");
1533
1.58k
            if (pfn->params.pole == NULL)
1534
0
                return_error(gs_error_VMerror);
1535
4.58M
            for (i = 0; i < sa; i++)
1536
4.57M
                pfn->params.pole[i] = double_stub;
1537
1.58k
            pfn->params.array_size = sa;
1538
1.58k
        }
1539
35.5k
        *ppfn = (gs_function_t *) pfn;
1540
35.5k
    }
1541
0
    return 0;
1542
35.5k
}