Coverage Report

Created: 2026-10-28 08:05

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
528
#define POLE_CACHE_GENERIC_1D 1 /* A temporary development technology need.
32
                                   Didn't decide yet - see fn_Sd_evaluate_cubic_cached_1d. */
33
958
#define POLE_CACHE_IGNORE 0     /* A temporary development technology need.
34
                                   Remove after the beta testing. */
35
36
71.8k
#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
220
ENUM_PTRS_WITH(function_Sd_enum_ptrs, gs_function_Sd_t *pfn)
47
88
{
48
88
    index -= 6;
49
88
    if (index < st_data_source_max_ptrs)
50
22
        return ENUM_USING(st_data_source, &pfn->params.DataSource,
51
88
                          sizeof(pfn->params.DataSource), index);
52
66
    return ENUM_USING_PREFIX(st_function, st_data_source_max_ptrs);
53
88
}
54
88
ENUM_PTR3(0, gs_function_Sd_t, params.Encode, params.Decode, params.Size);
55
220
ENUM_PTR3(3, gs_function_Sd_t, params.pole, params.array_step, params.stream_step);
56
220
ENUM_PTRS_END
57
static
58
22
RELOC_PTRS_WITH(function_Sd_reloc_ptrs, gs_function_Sd_t *pfn)
59
22
{
60
22
    RELOC_PREFIX(st_function);
61
22
    RELOC_USING(st_data_source, &pfn->params.DataSource,
62
22
                sizeof(pfn->params.DataSource));
63
22
    RELOC_PTR3(gs_function_Sd_t, params.Encode, params.Decode, params.Size);
64
22
    RELOC_PTR3(gs_function_Sd_t, params.pole, params.array_step, params.stream_step);
65
22
}
66
22
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
29.3k
#  define max_Sd_m GS_CLIENT_COLOR_MAX_COMPONENTS
72
29.3k
#  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
5.11M
        int n = pfn->params.n;\
81
5.11M
        byte buf[max_Sd_n * ((bps + 7) >> 3)];\
82
5.11M
        const byte *p;\
83
5.11M
        int i;\
84
5.11M
\
85
5.11M
        data_source_access(&pfn->params.DataSource, offset >> 3,\
86
5.11M
                           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
5.05M
{
122
5.05M
    SETUP_SAMPLES(8, n);
123
19.7M
    for (i = 0; i < n; ++i) {
124
14.6M
        samples[i] = *p++;
125
14.6M
    }
126
5.05M
    return 0;
127
5.05M
}
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
63.6k
{
144
63.6k
    SETUP_SAMPLES(16, n * 2);
145
127k
    for (i = 0; i < n; ++i) {
146
64.2k
        samples[i] = (*p << 8) + p[1];
147
64.2k
        p += 2;
148
64.2k
    }
149
63.6k
    return 0;
150
63.6k
}
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
4.82M
{
304
4.82M
    int j;
305
306
4.98M
top:
307
4.98M
    if (m == 0) {
308
3.26M
        uint sdata[max_Sd_n];
309
310
3.26M
        (*fn_get_samples[pfn->params.BitsPerSample])(pfn, offset, sdata);
311
12.4M
        for (j = pfn->params.n - 1; j >= 0; --j)
312
9.21M
            samples[j] = (float)sdata[j];
313
3.26M
    } else {
314
1.71M
        float fpart = *fparts++;
315
1.71M
        float samples1[max_Sd_n];
316
317
1.71M
        if (is_fzero(fpart)) {
318
157k
            ++factors;
319
157k
            --m;
320
157k
            goto top;
321
157k
        }
322
1.55M
        fn_interpolate_linear(pfn, fparts, factors + 1, samples,
323
1.55M
                              offset, m - 1);
324
1.55M
        fn_interpolate_linear(pfn, fparts, factors + 1, samples1,
325
1.55M
                              offset + *factors, m - 1);
326
6.02M
        for (j = pfn->params.n - 1; j >= 0; --j)
327
4.46M
            samples[j] += (samples1[j] - samples[j]) * fpart;
328
1.55M
    }
329
4.98M
}
330
331
static inline double
332
fn_Sd_encode(const gs_function_Sd_t *pfn, int i, double sample)
333
10.2M
{
334
10.2M
    float d0, d1, r0, r1;
335
10.2M
    double value;
336
10.2M
    int bps = pfn->params.BitsPerSample;
337
    /* x86 machines have problems with shifts if bps >= 32 */
338
10.2M
    uint max_samp = (bps < (sizeof(uint) * 8)) ? ((1 << bps) - 1) : max_uint;
339
340
10.2M
    if (pfn->params.Range)
341
10.2M
        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
10.2M
    if (pfn->params.Decode)
345
10.0M
        d0 = pfn->params.Decode[2 * i], d1 = pfn->params.Decode[2 * i + 1];
346
214k
    else
347
214k
        d0 = r0, d1 = r1;
348
349
10.2M
    value = sample * (d1 - d0) / max_samp + d0;
350
10.2M
    if (value < r0)
351
0
        value = r0;
352
10.2M
    else if (value > r1)
353
0
        value = r1;
354
10.2M
    return value;
355
10.2M
}
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
1.71M
{
362
1.71M
    const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
363
1.71M
    int bps = pfn->params.BitsPerSample;
364
1.71M
    ulong offset = 0;
365
1.71M
    int i;
366
1.71M
    float encoded[max_Sd_m];
367
1.71M
    int iparts[max_Sd_m]; /* only needed for cubic interpolation */
368
1.71M
    ulong factors[max_Sd_m];
369
1.71M
    float samples[max_Sd_n];
370
371
    /* Encode the input values. */
372
373
3.42M
    for (i = 0; i < pfn->params.m; ++i) {
374
1.71M
        float d0 = pfn->params.Domain[2 * i],
375
1.71M
            d1 = pfn->params.Domain[2 * i + 1];
376
1.71M
        float arg = in[i], enc;
377
378
1.71M
        if (arg < d0)
379
48
            arg = d0;
380
1.71M
        else if (arg > d1)
381
0
            arg = d1;
382
1.71M
        if (pfn->params.Encode) {
383
1.51M
            float e0 = pfn->params.Encode[2 * i];
384
1.51M
            float e1 = pfn->params.Encode[2 * i + 1];
385
386
1.51M
            enc = (arg - d0) * (e1 - e0) / (d1 - d0) + e0;
387
1.51M
            if (enc < 0)
388
0
                encoded[i] = 0;
389
1.51M
            else if (enc >= pfn->params.Size[i] - 1)
390
34.0k
                encoded[i] = (float)pfn->params.Size[i] - 1;
391
1.47M
            else
392
1.47M
                encoded[i] = enc;
393
1.51M
        } 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
200k
            encoded[i] = (arg - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
397
200k
        }
398
1.71M
    }
399
400
    /* Look up and interpolate the output values. */
401
402
1.71M
    {
403
1.71M
        ulong factor = (ulong)bps * pfn->params.n;
404
405
3.42M
        for (i = 0; i < pfn->params.m; factor *= pfn->params.Size[i++]) {
406
1.71M
            int ipart = (int)encoded[i];
407
408
1.71M
            offset += (factors[i] = factor) * ipart;
409
1.71M
            iparts[i] = ipart;  /* only needed for cubic interpolation */
410
1.71M
            encoded[i] -= ipart;
411
1.71M
        }
412
1.71M
    }
413
1.71M
    if (pfn->params.Order == 3)
414
0
        fn_interpolate_cubic(pfn, encoded, iparts, factors, samples,
415
0
                             offset, pfn->params.m);
416
1.71M
    else
417
1.71M
        fn_interpolate_linear(pfn, encoded, factors, samples, offset,
418
1.71M
                              pfn->params.m);
419
420
    /* Encode the output values. */
421
422
6.46M
    for (i = 0; i < pfn->params.n; ++i)
423
4.75M
        out[i] = (float)fn_Sd_encode(pfn, i, samples[i]);
424
425
1.71M
    return 0;
426
1.71M
}
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
20
{   /* The following is poles of the polinomial,
434
       which represents interpolate_cubic in [1,2]. */
435
20
    const double a = -0.5;
436
437
20
    p[pole_step_minor * 1] = (a*f0 + 3*f1 - a*f2)/3.0;
438
20
    p[pole_step_minor * 2] = (-a*f1 + 3*f2 + a*f3)/3.0;
439
20
}
440
441
static void
442
fn_make_poles(double *p, const int pole_step, int power, int bias)
443
20
{
444
20
    const int pole_step_minor = pole_step / 3;
445
20
    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
20
        case 3:
460
            /* bias must be 1. */
461
20
            fn_make_cubic_poles(p + pole_step * bias,
462
20
                    p[pole_step * 0], p[pole_step * 1], p[pole_step * 2], p[pole_step * 3],
463
20
                    pole_step_minor);
464
20
            break;
465
0
        default: /* Must not happen. */
466
0
           DO_NOTHING;
467
20
    }
468
20
}
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
264
{
532
264
    int i;
533
534
528
    for (i = 0; i < pfn->params.m; i++) {
535
264
        float xi = in[i];
536
264
        float d0 = pfn->params.Domain[2 * i + 0];
537
264
        float d1 = pfn->params.Domain[2 * i + 1];
538
264
        double t;
539
540
264
        if (xi < d0)
541
0
            xi = d0;
542
264
        if (xi > d1)
543
0
            xi = d1;
544
264
        t = (xi - d0) * (pfn->params.Size[i] - 1) / (d1 - d0);
545
264
        I[i] = (int)floor(t);
546
264
        T[i] = t - I[i];
547
264
    }
548
264
}
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
264
{
553
264
    *Ii = I[ii];
554
264
    if (T[ii] != 0) {
555
5
        *ib = max(*Ii - 1, 0);
556
5
        *ie = min(pfn->params.Size[ii], *Ii + 3);
557
259
    } else {
558
259
        *ib = *Ii;
559
259
        *ie = *Ii + 1;
560
259
    }
561
264
}
562
563
static inline int
564
load_vector_to(const gs_function_Sd_t *pfn, int s_offset, double *V)
565
1.84M
{
566
1.84M
    uint sdata[max_Sd_n];
567
1.84M
    int k, code;
568
569
1.84M
    code = fn_get_samples[pfn->params.BitsPerSample](pfn, s_offset, sdata);
570
1.84M
    if (code < 0)
571
0
        return code;
572
7.39M
    for (k = 0; k < pfn->params.n; k++)
573
5.54M
        V[k] = fn_Sd_encode(pfn, k, (double)sdata[k]);
574
1.84M
    return 0;
575
1.84M
}
576
577
static inline int
578
load_vector(const gs_function_Sd_t *pfn, int a_offset, int s_offset)
579
215
{
580
215
    if (*(pfn->params.pole + a_offset) == double_stub) {
581
215
        uint sdata[max_Sd_n];
582
215
        int k, code;
583
584
215
        code = fn_get_samples[pfn->params.BitsPerSample](pfn, s_offset, sdata);
585
215
        if (code < 0)
586
0
            return code;
587
1.07k
        for (k = 0; k < pfn->params.n; k++)
588
860
            *(pfn->params.pole + a_offset + k) = fn_Sd_encode(pfn, k, (double)sdata[k]);
589
215
    }
590
215
    return 0;
591
215
}
592
593
static inline void
594
interpolate_vector(const gs_function_Sd_t *pfn, int offset, int pole_step, int power, int bias)
595
5
{
596
5
    int k;
597
598
25
    for (k = 0; k < pfn->params.n; k++)
599
20
        fn_make_poles(pfn->params.pole + offset + k, pole_step, power, bias);
600
5
}
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
5
{
606
5
    if (ii < 0)
607
5
        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
5
}
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
264
{
626
    /* Check an inner pole of the cell. */
627
264
    int i, o = 0;
628
629
528
    for (i = ii; i >= 0; i--) {
630
264
        o += I[i] * pfn->params.array_step[i];
631
264
        if (T[i] != 0)
632
5
            o += pfn->params.array_step[i] / 3;
633
264
    }
634
264
    if (*(pfn->params.pole + a_offset + o) != double_stub)
635
64
        return true;
636
200
    return false;
637
264
}
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
479
{
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
479
    int code;
695
696
479
    if (ii < 0) {
697
215
        if (POLE_CACHE_IGNORE || *(pfn->params.pole + a_offset) == double_stub) {
698
215
            code = load_vector(pfn, a_offset, s_offset);
699
215
            if (code < 0)
700
0
                return code;
701
215
        }
702
264
    } else {
703
264
        int Ii, ib, ie, i;
704
264
        int sa = pfn->params.array_step[ii];
705
264
        int ss = pfn->params.stream_step[ii];
706
707
264
        index_span(pfn, I, T, ii, &Ii, &ib, &ie);
708
264
        if (POLE_CACHE_IGNORE || !is_tensor_done(pfn, I, T, a_offset, ii)) {
709
415
            for (i = ib; i < ie; i++) {
710
215
                code = make_interpolation_tensor(pfn, I, T,
711
215
                                a_offset + i * sa, s_offset + i * ss, ii - 1);
712
215
                if (code < 0)
713
0
                    return code;
714
215
            }
715
200
            if (T[ii] != 0)
716
5
                interpolate_tensors(pfn, I, T, a_offset + ib * sa, sa, ie - ib - 1,
717
5
                                Ii - ib, ii - 1);
718
200
        }
719
264
    }
720
479
    return 0;
721
479
}
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
543
{
768
543
    int s = pfn->params.array_step[ii], k, l, code;
769
770
543
    if (ii < 0) {
771
1.39k
        for (k = 0; k < pfn->params.n; k++)
772
1.11k
            y[k] = *(pfn->params.pole + offset + k);
773
279
    } else if (T[ii] == 0) {
774
259
        return evaluate_from_tenzor(pfn, I, T, offset + s * I[ii], ii - 1, y);
775
259
    } else {
776
5
        double t0 = T[ii], t1 = 1 - t0;
777
5
        double p[4][max_Sd_n];
778
779
25
        for (l = 0; l < 4; l++) {
780
20
            code = evaluate_from_tenzor(pfn, I, T, offset + s * I[ii] + l * (s / 3), ii - 1, p[l]);
781
20
            if (code < 0)
782
0
                return code;
783
20
        }
784
25
        for (k = 0; k < pfn->params.n; k++)
785
20
            y[k] = p[0][k] * t1 * t1 * t1 +
786
20
                   p[1][k] * t1 * t1 * t0 * 3 +
787
20
                   p[2][k] * t1 * t0 * t0 * 3 +
788
20
           p[3][k] * t0 * t0 * t0;
789
5
    }
790
284
    return 0;
791
543
}
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
264
{
799
264
    double T[max_Sd_m], y[max_Sd_n];
800
264
    int I[max_Sd_m], k, code;
801
802
264
    decode_argument(pfn, in, T, I);
803
264
    code = make_interpolation_tensor(pfn, I, T, 0, 0, pfn->params.m - 1);
804
264
    if (code < 0)
805
0
        return code;
806
264
    evaluate_from_tenzor(pfn, I, T, 0, pfn->params.m - 1, y);
807
1.32k
    for (k = 0; k < pfn->params.n; k++) {
808
1.05k
        double yk = y[k];
809
810
1.05k
        if (yk < pfn->params.Range[k * 2 + 0])
811
0
            yk = pfn->params.Range[k * 2 + 0];
812
1.05k
        if (yk > pfn->params.Range[k * 2 + 1])
813
0
            yk = pfn->params.Range[k * 2 + 1];
814
1.05k
        out[k] = yk;
815
1.05k
    }
816
264
    return 0;
817
264
}
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
1.71M
{
823
1.71M
    const gs_function_Sd_t *pfn = (const gs_function_Sd_t *)pfn_common;
824
1.71M
    int code;
825
826
1.71M
    if (pfn->params.Order == 3) {
827
264
        if (POLE_CACHE_GENERIC_1D || pfn->params.m > 1)
828
264
            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
264
    } else
845
1.71M
        code = fn_Sd_evaluate_general(pfn_common, in, out);
846
1.71M
    return code;
847
1.71M
}
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
15.1k
{
855
15.1k
    float d0 = pfn->params.Domain[i * 2 + 0], d1 = pfn->params.Domain[i * 2 + 1];
856
15.1k
    float v0 = lower[i], v1 = upper[i];
857
15.1k
    float e0, e1, w0, w1, w;
858
15.1k
    const float small_noise = (float)1e-6;
859
860
15.1k
    if (v0 < d0 || v0 > d1)
861
16
        return_error(gs_error_rangecheck);
862
15.1k
    if (pfn->params.Encode)
863
14.6k
        e0 = pfn->params.Encode[i * 2 + 0], e1 = pfn->params.Encode[i * 2 + 1];
864
478
    else
865
478
        e0 = 0, e1 = (float)pfn->params.Size[i] - 1;
866
15.1k
    w0 = (v0 - d0) * (e1 - e0) / (d1 - d0) + e0;
867
15.1k
    if (w0 < 0)
868
0
        w0 = 0;
869
15.1k
    else if (w0 >= pfn->params.Size[i] - 1)
870
1.31k
        w0 = (float)pfn->params.Size[i] - 1;
871
15.1k
    w1 = (v1 - d0) * (e1 - e0) / (d1 - d0) + e0;
872
15.1k
    if (w1 < 0)
873
0
        w1 = 0;
874
15.1k
    else if (w1 >= pfn->params.Size[i] - 1)
875
2.19k
        w1 = (float)pfn->params.Size[i] - 1;
876
15.1k
    if (w0 > w1) {
877
1.14k
        w = w0; w0 = w1; w1 = w;
878
1.14k
    }
879
15.1k
    if (floor(w0 + 1) - w0 < small_noise * any_abs(e1 - e0))
880
46
        w0 = (floor(w0) + 1);
881
15.1k
    if (w1 - floor(w1) < small_noise * any_abs(e1 - e0))
882
3.73k
        w1 = floor(w1);
883
15.1k
    if (w0 > w1)
884
10
        w0 = w1;
885
15.1k
    *pw0 = w0;
886
15.1k
    *pw1 = w1;
887
15.1k
    return 0;
888
15.1k
}
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
3.66M
{
1143
3.66M
    if (i1 - i0 <= 1) {
1144
1.83M
        int code = 0, i;
1145
1146
7.34M
        for (i = 0; i < pfn->params.n; i++) {
1147
5.51M
            if (V0[i] < V1[i])
1148
766k
                code |= 1 << (i * 3);
1149
4.74M
            else if (V0[i] > V1[i])
1150
846k
                code |= 2 << (i * 3);
1151
5.51M
        }
1152
1.83M
        return code;
1153
1.83M
    } else {
1154
1.82M
        double VV[MAX_FAST_COMPS];
1155
1.82M
        int ii = (i0 + i1) / 2, code, cod1;
1156
1157
1.82M
        code = load_vector_to(pfn, ii * pfn->params.n * pfn->params.BitsPerSample, VV);
1158
1.82M
        if (code < 0)
1159
0
            return code;
1160
1.82M
        if (code & (code >> 1))
1161
0
            return code; /* Not monotonic by some component of the result. */
1162
1.82M
        code = fn_Sd_1arg_linear_monotonic_rec(pfn, i0, ii, V0, VV);
1163
1.82M
        if (code < 0)
1164
0
            return code;
1165
1.82M
        cod1 = fn_Sd_1arg_linear_monotonic_rec(pfn, ii, i1, VV, V1);
1166
1.82M
        if (cod1 < 0)
1167
0
            return cod1;
1168
1.82M
        return code | cod1;
1169
1.82M
    }
1170
3.66M
}
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
15.1k
{
1176
15.1k
    int i0 = (int)floor(T0);
1177
15.1k
    int i1 = (int)ceil(T1), code;
1178
15.1k
    double V0[MAX_FAST_COMPS], V1[MAX_FAST_COMPS];
1179
1180
15.1k
    if (i1 - i0 > 1) {
1181
11.4k
        code = load_vector_to(pfn, i0 * pfn->params.n * pfn->params.BitsPerSample, V0);
1182
11.4k
        if (code < 0)
1183
0
            return code;
1184
11.4k
        code = load_vector_to(pfn, i1 * pfn->params.n * pfn->params.BitsPerSample, V1);
1185
11.4k
        if (code < 0)
1186
0
            return code;
1187
11.4k
        code = fn_Sd_1arg_linear_monotonic_rec(pfn, i0, i1, V0, V1);
1188
11.4k
        if (code < 0)
1189
0
            return code;
1190
11.4k
        if (code & (code >> 1)) {
1191
4.58k
            *mask = 1;
1192
4.58k
            return 0;
1193
4.58k
        }
1194
11.4k
    }
1195
10.5k
    *mask = 0;
1196
10.5k
    return 1;
1197
15.1k
}
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
15.1k
{
1208
15.1k
    int i, code, ii = pfn->params.m - 1;
1209
15.1k
    int I[4];
1210
15.1k
    double T0[count_of(I)], T1[count_of(I)];
1211
15.1k
    double S0[count_of(I)], S1[count_of(I)];
1212
15.1k
    uint m, mm, m1;
1213
#   if DEBUG_Sd_1arg
1214
    int code1, mask1;
1215
#   endif
1216
1217
15.1k
    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
30.3k
    for (i = 0; i <= ii; i++) {
1223
15.1k
        float w0, w1;
1224
1225
15.1k
        code = get_scaled_range(pfn, lower, upper, i, &w0, &w1);
1226
15.1k
        if (code < 0)
1227
16
            return code;
1228
15.1k
        T0[i] = w0;
1229
15.1k
        T1[i] = w1;
1230
15.1k
    }
1231
15.1k
    if (pfn->params.m == 1 && pfn->params.Order == 1 && pfn->params.n <= MAX_FAST_COMPS) {
1232
15.1k
        code = fn_Sd_1arg_linear_monotonic(pfn, T0[0], T1[0], mask);
1233
15.1k
# if !DEBUG_Sd_1arg
1234
15.1k
            return code;
1235
# else
1236
            mask1 = *mask;
1237
            code1 = code;
1238
# endif
1239
15.1k
    }
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
15.1k
{
1269
15.1k
    const gs_function_Sd_t *const pfn =
1270
15.1k
        (const gs_function_Sd_t *)pfn_common;
1271
1272
15.1k
    return fn_Sd_is_monotonic_aux(pfn, lower, upper, mask);
1273
15.1k
}
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
27.8k
{
1279
27.8k
    const gs_function_Sd_t *const pfn =
1280
27.8k
        (const gs_function_Sd_t *)pfn_common;
1281
27.8k
    long size;
1282
27.8k
    int i;
1283
1284
27.8k
    gs_function_get_info_default(pfn_common, pfi);
1285
27.8k
    pfi->DataSource = &pfn->params.DataSource;
1286
56.7k
    for (i = 0, size = 1; i < pfn->params.m; ++i)
1287
28.8k
        size *= pfn->params.Size[i];
1288
27.8k
    pfi->data_size =
1289
27.8k
        (size * pfn->params.n * pfn->params.BitsPerSample + 7) >> 3;
1290
27.8k
}
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
10.7k
{
1296
10.7k
    const gs_function_Sd_t *const pfn =
1297
10.7k
        (const gs_function_Sd_t *)pfn_common;
1298
10.7k
    int ecode = fn_common_get_params(pfn_common, plist);
1299
10.7k
    int code;
1300
1301
10.7k
    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
10.7k
    if ((code = param_write_int(plist, "BitsPerSample",
1306
10.7k
                                &pfn->params.BitsPerSample)) < 0)
1307
0
        ecode = code;
1308
10.7k
    if (pfn->params.Encode) {
1309
836
        if ((code = param_write_float_values(plist, "Encode",
1310
836
                                             pfn->params.Encode,
1311
836
                                             2 * pfn->params.m, false)) < 0)
1312
0
            ecode = code;
1313
836
    }
1314
10.7k
    if (pfn->params.Decode) {
1315
4.07k
        if ((code = param_write_float_values(plist, "Decode",
1316
4.07k
                                             pfn->params.Decode,
1317
4.07k
                                             2 * pfn->params.n, false)) < 0)
1318
0
            ecode = code;
1319
4.07k
    }
1320
10.7k
    if (pfn->params.Size) {
1321
10.7k
        if ((code = param_write_int_values(plist, "Size", pfn->params.Size,
1322
10.7k
                                           pfn->params.m, false)) < 0)
1323
0
            ecode = code;
1324
10.7k
    }
1325
10.7k
    return ecode;
1326
10.7k
}
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
22.1k
{
1364
22.1k
    gs_free_const_object(mem, params->Size, "Size");
1365
22.1k
    params->Size = NULL;
1366
22.1k
    gs_free_const_object(mem, params->Decode, "Decode");
1367
22.1k
    params->Decode = NULL;
1368
22.1k
    gs_free_const_object(mem, params->Encode, "Encode");
1369
22.1k
    params->Encode = NULL;
1370
22.1k
    fn_common_free_params((gs_function_params_t *) params, mem);
1371
22.1k
    if (params->DataSource.type == data_source_type_stream && params->DataSource.data.strm != NULL) {
1372
21.2k
        s_close_filters(&params->DataSource.data.strm, params->DataSource.data.strm->strm);
1373
21.2k
        params->DataSource.data.strm = NULL;
1374
21.2k
    }
1375
22.1k
    gs_free_object(mem, params->pole, "gs_function_Sd_free_params");
1376
22.1k
    params->pole = NULL;
1377
22.1k
    gs_free_object(mem, params->array_step, "gs_function_Sd_free_params");
1378
22.1k
    params->array_step = NULL;
1379
22.1k
    gs_free_object(mem, params->stream_step, "gs_function_Sd_free_params");
1380
22.1k
    params->stream_step = NULL;
1381
22.1k
}
1382
1383
/* aA helper for gs_function_Sd_serialize. */
1384
static int serialize_array(const float *a, int half_size, stream *s)
1385
34.3k
{
1386
34.3k
    uint n;
1387
34.3k
    const float dummy[2] = {0, 0};
1388
34.3k
    int i, code;
1389
1390
34.3k
    if (a != NULL)
1391
24.4k
        return sputs(s, (const byte *)a, sizeof(a[0]) * half_size * 2, &n);
1392
34.8k
    for (i = 0; i < half_size; i++) {
1393
24.8k
        code = sputs(s, (const byte *)dummy, sizeof(dummy), &n);
1394
24.8k
        if (code < 0)
1395
0
            return code;
1396
24.8k
    }
1397
9.91k
    return 0;
1398
9.91k
}
1399
1400
/* Serialize. */
1401
static int
1402
gs_function_Sd_serialize(const gs_function_t * pfn, stream *s)
1403
17.1k
{
1404
17.1k
    uint n;
1405
17.1k
    const gs_function_Sd_params_t * p = (const gs_function_Sd_params_t *)&pfn->params;
1406
17.1k
    gs_function_info_t info;
1407
17.1k
    int code = fn_common_serialize(pfn, s);
1408
17.1k
    ulong pos;
1409
17.1k
    uint count;
1410
17.1k
    byte buf[100];
1411
17.1k
    const byte *ptr;
1412
1413
17.1k
    if (code < 0)
1414
0
        return code;
1415
17.1k
    code = sputs(s, (const byte *)&p->Order, sizeof(p->Order), &n);
1416
17.1k
    if (code < 0)
1417
0
        return code;
1418
17.1k
    code = sputs(s, (const byte *)&p->BitsPerSample, sizeof(p->BitsPerSample), &n);
1419
17.1k
    if (code < 0)
1420
0
        return code;
1421
17.1k
    code = serialize_array(p->Encode, p->m, s);
1422
17.1k
    if (code < 0)
1423
0
        return code;
1424
17.1k
    code = serialize_array(p->Decode, p->n, s);
1425
17.1k
    if (code < 0)
1426
0
        return code;
1427
17.1k
    gs_function_get_info(pfn, &info);
1428
17.1k
    code = sputs(s, (const byte *)&info.data_size, sizeof(info.data_size), &n);
1429
17.1k
    if (code < 0)
1430
0
        return code;
1431
183k
    for (pos = 0; pos < info.data_size; pos += count) {
1432
166k
        count = min(sizeof(buf), info.data_size - pos);
1433
166k
        data_source_access_only(info.DataSource, pos, count, buf, &ptr);
1434
166k
        code = sputs(s, ptr, count, &n);
1435
166k
        if (code < 0)
1436
0
            return code;
1437
166k
    }
1438
17.1k
    return 0;
1439
17.1k
}
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
29.3k
{
1446
29.3k
    static const gs_function_head_t function_Sd_head = {
1447
29.3k
        function_type_Sampled,
1448
29.3k
        {
1449
29.3k
            (fn_evaluate_proc_t) fn_Sd_evaluate,
1450
29.3k
            (fn_is_monotonic_proc_t) fn_Sd_is_monotonic,
1451
29.3k
            (fn_get_info_proc_t) fn_Sd_get_info,
1452
29.3k
            (fn_get_params_proc_t) fn_Sd_get_params,
1453
29.3k
            (fn_make_scaled_proc_t) fn_Sd_make_scaled,
1454
29.3k
            (fn_free_params_proc_t) gs_function_Sd_free_params,
1455
29.3k
            fn_common_free,
1456
29.3k
            (fn_serialize_proc_t) gs_function_Sd_serialize,
1457
29.3k
        }
1458
29.3k
    };
1459
29.3k
    int code;
1460
29.3k
    int i;
1461
1462
29.3k
    *ppfn = 0;      /* in case of error */
1463
29.3k
    code = fn_check_mnDR((const gs_function_params_t *)params,
1464
29.3k
                         params->m, params->n);
1465
29.3k
    if (code < 0)
1466
24
        return code;
1467
29.3k
    if (params->m > max_Sd_m || params->n > max_Sd_n)
1468
0
        return_error(gs_error_limitcheck);
1469
29.3k
    switch (params->Order) {
1470
809
        case 0:   /* use default */
1471
28.8k
        case 1:
1472
29.3k
        case 3:
1473
29.3k
            break;
1474
0
        default:
1475
0
            return_error(gs_error_rangecheck);
1476
29.3k
    }
1477
29.3k
    switch (params->BitsPerSample) {
1478
0
        case 1:
1479
0
        case 2:
1480
0
        case 4:
1481
27.6k
        case 8:
1482
27.6k
        case 12:
1483
29.1k
        case 16:
1484
29.1k
        case 24:
1485
29.1k
        case 32:
1486
29.1k
            break;
1487
215
        default:
1488
215
            return_error(gs_error_rangecheck);
1489
29.3k
    }
1490
59.5k
    for (i = 0; i < params->m; ++i)
1491
30.4k
        if (params->Size[i] <= 0)
1492
0
            return_error(gs_error_rangecheck);
1493
29.1k
    {
1494
29.1k
        gs_function_Sd_t *pfn =
1495
29.1k
            gs_alloc_struct(mem, gs_function_Sd_t, &st_function_Sd,
1496
29.1k
                            "gs_function_Sd_init");
1497
29.1k
        int bps, sa, ss, i, order, was;
1498
1499
29.1k
        if (pfn == 0)
1500
0
            return_error(gs_error_VMerror);
1501
29.1k
        pfn->params = *params;
1502
29.1k
        if (params->Order == 0)
1503
809
            pfn->params.Order = 1; /* default */
1504
29.1k
        pfn->params.pole = NULL;
1505
29.1k
        pfn->params.array_step = NULL;
1506
29.1k
        pfn->params.stream_step = NULL;
1507
29.1k
        pfn->head = function_Sd_head;
1508
29.1k
        pfn->params.array_size = 0;
1509
29.1k
        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
27.5k
        } else {
1512
1.55k
            pfn->params.array_step = (int *)gs_alloc_byte_array(mem,
1513
1.55k
                                    max_Sd_m, sizeof(int), "gs_function_Sd_init");
1514
1.55k
            pfn->params.stream_step = (int *)gs_alloc_byte_array(mem,
1515
1.55k
                                    max_Sd_m, sizeof(int), "gs_function_Sd_init");
1516
1.55k
            if (pfn->params.array_step == NULL || pfn->params.stream_step == NULL)
1517
0
                return_error(gs_error_VMerror);
1518
1.55k
            bps = pfn->params.BitsPerSample;
1519
1.55k
            sa = pfn->params.n;
1520
1.55k
            ss = pfn->params.n * bps;
1521
1.55k
            order = pfn->params.Order;
1522
4.40k
            for (i = 0; i < pfn->params.m; i++) {
1523
2.84k
                pfn->params.array_step[i] = sa * order;
1524
2.84k
                was = sa;
1525
2.84k
                if (check_int_multiply(pfn->params.Size[i], order, &sa) < 0)
1526
0
                    return_error(gs_error_limitcheck);
1527
2.84k
                sa -= (order - 1);
1528
2.84k
                if (check_int_multiply(sa, was, &sa) < 0)
1529
0
                    return_error(gs_error_limitcheck);
1530
1531
2.84k
                pfn->params.stream_step[i] = ss;
1532
2.84k
                if (check_int_multiply(pfn->params.Size[i], ss, &ss) < 0)
1533
0
                    return_error(gs_error_limitcheck);
1534
2.84k
            }
1535
1.55k
            pfn->params.pole = (double *)gs_alloc_byte_array(mem,
1536
1.55k
                                    sa, sizeof(double), "gs_function_Sd_init");
1537
1.55k
            if (pfn->params.pole == NULL)
1538
0
                return_error(gs_error_VMerror);
1539
4.72M
            for (i = 0; i < sa; i++)
1540
4.72M
                pfn->params.pole[i] = double_stub;
1541
1.55k
            pfn->params.array_size = sa;
1542
1.55k
        }
1543
29.1k
        *ppfn = (gs_function_t *) pfn;
1544
29.1k
    }
1545
0
    return 0;
1546
29.1k
}