Coverage Report

Created: 2026-09-14 07:34

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