Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/lcms2mt/src/cmsintrp.c
Line
Count
Source
1
//---------------------------------------------------------------------------------
2
//
3
//  Little Color Management System
4
//  Copyright (c) 1998-2026 Marti Maria Saguer
5
//
6
// Permission is hereby granted, free of charge, to any person obtaining
7
// a copy of this software and associated documentation files (the "Software"),
8
// to deal in the Software without restriction, including without limitation
9
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
// and/or sell copies of the Software, and to permit persons to whom the Software
11
// is furnished to do so, subject to the following conditions:
12
//
13
// The above copyright notice and this permission notice shall be included in
14
// all copies or substantial portions of the Software.
15
//
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
//
24
//---------------------------------------------------------------------------------
25
//
26
27
#include "lcms2_internal.h"
28
29
// This module incorporates several interpolation routines, for 1 to 8 channels on input and
30
// up to 65535 channels on output. The user may change those by using the interpolation plug-in
31
32
// Some people may want to compile as C++ with all warnings on, in this case make compiler silent
33
#ifdef _MSC_VER
34
#    if (_MSC_VER >= 1400)
35
#       pragma warning( disable : 4365 )
36
#    endif
37
#endif
38
39
// Interpolation routines by default
40
static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
41
42
// This is the default factory
43
_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL };
44
45
// The interpolation plug-in memory chunk allocator/dup
46
void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
47
162k
{
48
162k
    void* from;
49
50
162k
    _cmsAssert(ctx != NULL);
51
52
162k
    if (src != NULL) {
53
0
        from = src ->chunks[InterpPlugin];
54
0
    }
55
162k
    else {
56
162k
        static _cmsInterpPluginChunkType InterpPluginChunk = { NULL };
57
58
162k
        from = &InterpPluginChunk;
59
162k
    }
60
61
162k
    _cmsAssert(from != NULL);
62
162k
    ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType));
63
162k
}
64
65
66
// Main plug-in entry
67
cmsBool  _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data)
68
162k
{
69
162k
    cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
70
162k
    _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
71
72
162k
    if (Data == NULL) {
73
74
162k
        ptr ->Interpolators = NULL;
75
162k
        return TRUE;
76
162k
    }
77
78
    // Set replacement functions
79
0
    ptr ->Interpolators = Plugin ->InterpolatorsFactory;
80
0
    return TRUE;
81
162k
}
82
83
84
// Set the interpolation method
85
cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
86
19.6M
{
87
19.6M
    _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
88
89
19.6M
    p ->Interpolation.Lerp16 = NULL;
90
91
   // Invoke factory, possibly in the Plug-in
92
19.6M
    if (ptr ->Interpolators != NULL)
93
0
        p ->Interpolation = ptr->Interpolators(ContextID, p -> nInputs, p ->nOutputs, p ->dwFlags);
94
95
    // If unsupported by the plug-in, go for the LittleCMS default.
96
    // If happens only if an extern plug-in is being used
97
19.6M
    if (p ->Interpolation.Lerp16 == NULL)
98
19.6M
        p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);
99
100
    // Check for valid interpolator (we just check one member of the union)
101
19.6M
    if (p ->Interpolation.Lerp16 == NULL) {
102
0
            return FALSE;
103
0
    }
104
105
19.6M
    return TRUE;
106
19.6M
}
107
108
109
// This function precalculates as many parameters as possible to speed up the interpolation.
110
cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
111
                                           const cmsUInt32Number nSamples[],
112
                                           cmsUInt32Number InputChan, cmsUInt32Number OutputChan,
113
                                           const void *Table,
114
                                           cmsUInt32Number dwFlags)
115
18.6M
{
116
18.6M
    cmsInterpParams* p;
117
18.6M
    cmsUInt32Number i;
118
119
    // Check for maximum inputs
120
18.6M
    if (InputChan > MAX_INPUT_DIMENSIONS) {
121
0
             cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS);
122
0
            return NULL;
123
0
    }
124
125
    // Creates an empty object
126
18.6M
    p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));
127
18.6M
    if (p == NULL) return NULL;
128
129
    // Keep original parameters
130
18.6M
    p -> dwFlags  = dwFlags;
131
18.6M
    p -> nInputs  = InputChan;
132
18.6M
    p -> nOutputs = OutputChan;
133
18.6M
    p ->Table     = Table;
134
135
    // Fill samples per input direction and domain (which is number of nodes minus one)
136
45.8M
    for (i=0; i < InputChan; i++) {
137
138
27.1M
        p -> nSamples[i] = nSamples[i];
139
27.1M
        p -> Domain[i]   = nSamples[i] - 1;
140
27.1M
    }
141
142
    // Compute factors to apply to each component to index the grid array
143
18.6M
    p -> opta[0] = p -> nOutputs;
144
27.1M
    for (i=1; i < InputChan; i++)
145
8.49M
        p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
146
147
148
18.6M
    if (!_cmsSetInterpolationRoutine(ContextID, p)) {
149
0
         cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
150
0
        _cmsFree(ContextID, p);
151
0
        return NULL;
152
0
    }
153
154
    // All seems ok
155
18.6M
    return p;
156
18.6M
}
157
158
159
// This one is a wrapper on the anterior, but assuming all directions have same number of nodes
160
cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples,
161
                                                   cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags)
162
14.0M
{
163
14.0M
    int i;
164
14.0M
    cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
165
166
    // Fill the auxiliary array
167
224M
    for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
168
210M
        Samples[i] = nSamples;
169
170
    // Call the extended function
171
14.0M
    return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
172
14.0M
}
173
174
175
// Free all associated memory
176
void CMSEXPORT _cmsFreeInterpParams(cmsContext ContextID, cmsInterpParams* p)
177
18.6M
{
178
18.6M
    if (p != NULL) _cmsFree(ContextID, p);
179
18.6M
}
180
181
182
// Inline fixed point interpolation
183
cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
184
52.9G
{
185
52.9G
    cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
186
52.9G
    dif = (dif >> 16) + l;
187
52.9G
    return (cmsUInt16Number) (dif);
188
52.9G
}
189
190
191
//  Linear interpolation (Fixed-point optimized)
192
static
193
void LinLerp1D(cmsContext ContextID,
194
               CMSREGISTER const cmsUInt16Number Value[],
195
               CMSREGISTER cmsUInt16Number Output[],
196
               CMSREGISTER const cmsInterpParams* p)
197
45.0G
{
198
45.0G
    cmsUInt16Number y1, y0;
199
45.0G
    int cell0, rest;
200
45.0G
    int val3;
201
45.0G
    const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
202
45.0G
    cmsUNUSED_PARAMETER(ContextID);
203
204
    // if last value or just one point
205
45.0G
    if (Value[0] == 0xffff || p->Domain[0] == 0) {
206
207
801M
        Output[0] = LutTable[p -> Domain[0]];
208
801M
    }
209
44.2G
    else
210
44.2G
    {
211
44.2G
        val3 = p->Domain[0] * Value[0];
212
44.2G
        val3 = _cmsToFixedDomain(val3);    // To fixed 15.16
213
214
44.2G
        cell0 = FIXED_TO_INT(val3);             // Cell is 16 MSB bits
215
44.2G
        rest = FIXED_REST_TO_INT(val3);        // Rest is 16 LSB bits
216
217
44.2G
        y0 = LutTable[cell0];
218
44.2G
        y1 = LutTable[cell0 + 1];
219
220
44.2G
        Output[0] = LinearInterp(rest, y0, y1);
221
44.2G
    }
222
45.0G
}
223
224
// To prevent out of bounds indexing
225
cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v)
226
500M
{
227
500M
    return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);
228
500M
}
229
230
// Floating-point version of 1D interpolation
231
static
232
void LinLerp1Dfloat(cmsContext ContextID, const cmsFloat32Number Value[],
233
                    cmsFloat32Number Output[],
234
                    const cmsInterpParams* p)
235
500M
{
236
500M
       cmsFloat32Number y1, y0;
237
500M
       cmsFloat32Number val2, rest;
238
500M
       int cell0, cell1;
239
500M
       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
240
500M
       cmsUNUSED_PARAMETER(ContextID);
241
242
500M
       val2 = fclamp(Value[0]);
243
244
       // if last value...
245
500M
       if (val2 == 1.0 || p->Domain[0] == 0) {
246
61.1k
           Output[0] = LutTable[p -> Domain[0]];
247
61.1k
       }
248
500M
       else
249
500M
       {
250
500M
           val2 *= p->Domain[0];
251
252
500M
           cell0 = (int)floor(val2);
253
500M
           cell1 = (int)ceil(val2);
254
255
           // Rest is 16 LSB bits
256
500M
           rest = val2 - cell0;
257
258
500M
           y0 = LutTable[cell0];
259
500M
           y1 = LutTable[cell1];
260
261
500M
           Output[0] = y0 + (y1 - y0) * rest;
262
500M
       }
263
500M
}
264
265
266
267
// Eval gray LUT having only one input channel
268
static CMS_NO_SANITIZE
269
void Eval1Input(cmsContext ContextID,
270
                CMSREGISTER const cmsUInt16Number Input[],
271
                CMSREGISTER cmsUInt16Number Output[],
272
                CMSREGISTER const cmsInterpParams* p16)
273
17.3M
{
274
17.3M
       cmsS15Fixed16Number fk;
275
17.3M
       cmsS15Fixed16Number k0, k1, rk, K0, K1;
276
17.3M
       int v;
277
17.3M
       cmsUInt32Number OutChan;
278
17.3M
       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
279
17.3M
       cmsUNUSED_PARAMETER(ContextID);
280
281
282
       // if last value...
283
17.3M
       if (Input[0] == 0xffff || p16->Domain[0] == 0) {
284
285
4.45M
           cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0];
286
287
17.9M
           for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
288
13.4M
               Output[OutChan] = LutTable[y0 + OutChan];
289
13.4M
           }
290
4.45M
       }
291
12.9M
       else
292
12.9M
       {
293
294
12.9M
           v = Input[0] * p16->Domain[0];
295
12.9M
           fk = _cmsToFixedDomain(v);
296
297
12.9M
           k0 = FIXED_TO_INT(fk);
298
12.9M
           rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
299
300
12.9M
           k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
301
302
12.9M
           K0 = p16->opta[0] * k0;
303
12.9M
           K1 = p16->opta[0] * k1;
304
305
51.7M
           for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
306
307
38.8M
               Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
308
38.8M
           }
309
12.9M
       }
310
17.3M
}
311
312
313
314
// Eval gray LUT having only one input channel
315
static
316
void Eval1InputFloat(cmsContext ContextID, const cmsFloat32Number Value[],
317
                     cmsFloat32Number Output[],
318
                     const cmsInterpParams* p)
319
0
{
320
0
    cmsFloat32Number y1, y0;
321
0
    cmsFloat32Number val2, rest;
322
0
    int cell0, cell1;
323
0
    cmsUInt32Number OutChan;
324
0
    const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
325
0
    cmsUNUSED_PARAMETER(ContextID);
326
327
0
    val2 = fclamp(Value[0]);
328
329
    // if last value...
330
0
    if (val2 == 1.0 || p->Domain[0] == 0) {
331
332
0
        cmsUInt32Number start = p->Domain[0] * p->opta[0];
333
334
0
        for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
335
0
            Output[OutChan] = LutTable[start + OutChan];
336
0
        }
337
0
    }
338
0
    else
339
0
    {
340
0
        val2 *= p->Domain[0];
341
342
0
        cell0 = (int)floor(val2);
343
0
        cell1 = (int)ceil(val2);
344
345
        // Rest is 16 LSB bits
346
0
        rest = val2 - cell0;
347
348
0
        cell0 *= p->opta[0];
349
0
        cell1 *= p->opta[0];
350
351
0
        for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
352
353
0
            y0 = LutTable[cell0 + OutChan];
354
0
            y1 = LutTable[cell1 + OutChan];
355
356
0
            Output[OutChan] = y0 + (y1 - y0) * rest;
357
0
        }
358
0
    }
359
0
}
360
361
// Bilinear interpolation (16 bits) - cmsFloat32Number version
362
static
363
void BilinearInterpFloat(cmsContext ContextID, const cmsFloat32Number Input[],
364
                         cmsFloat32Number Output[],
365
                         const cmsInterpParams* p)
366
367
0
{
368
0
#   define LERP(a,l,h)    (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
369
0
#   define DENS(i,j)      (LutTable[(i)+(j)+OutChan])
370
371
0
    const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
372
0
    cmsFloat32Number      px, py;
373
0
    int        x0, y0,
374
0
               X0, Y0, X1, Y1;
375
0
    int        TotalOut, OutChan;
376
0
    cmsFloat32Number      fx, fy,
377
0
        d00, d01, d10, d11,
378
0
        dx0, dx1,
379
0
        dxy;
380
0
    cmsUNUSED_PARAMETER(ContextID);
381
382
0
    TotalOut   = p -> nOutputs;
383
0
    px = fclamp(Input[0]) * p->Domain[0];
384
0
    py = fclamp(Input[1]) * p->Domain[1];
385
386
0
    x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
387
0
    y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
388
389
0
    X0 = p -> opta[1] * x0;
390
0
    X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]);
391
392
0
    Y0 = p -> opta[0] * y0;
393
0
    Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]);
394
395
0
    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
396
397
0
        d00 = DENS(X0, Y0);
398
0
        d01 = DENS(X0, Y1);
399
0
        d10 = DENS(X1, Y0);
400
0
        d11 = DENS(X1, Y1);
401
402
0
        dx0 = LERP(fx, d00, d10);
403
0
        dx1 = LERP(fx, d01, d11);
404
405
0
        dxy = LERP(fy, dx0, dx1);
406
407
0
        Output[OutChan] = dxy;
408
0
    }
409
410
411
0
#   undef LERP
412
0
#   undef DENS
413
0
}
414
415
// Bilinear interpolation (16 bits) - optimized version
416
static CMS_NO_SANITIZE
417
void BilinearInterp16(cmsContext ContextID,
418
                      CMSREGISTER const cmsUInt16Number Input[],
419
                      CMSREGISTER cmsUInt16Number Output[],
420
                      CMSREGISTER const cmsInterpParams* p)
421
422
0
{
423
0
#define DENS(i,j) (LutTable[(i)+(j)+OutChan])
424
0
#define LERP(a,l,h)     (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
425
426
0
           const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
427
0
           int        OutChan, TotalOut;
428
0
           cmsS15Fixed16Number    fx, fy;
429
0
           CMSREGISTER int        rx, ry;
430
0
           int                    x0, y0;
431
0
           CMSREGISTER int        X0, X1, Y0, Y1;
432
433
0
           int                    d00, d01, d10, d11,
434
0
                                  dx0, dx1,
435
0
                                  dxy;
436
0
           cmsUNUSED_PARAMETER(ContextID);
437
438
0
    TotalOut   = p -> nOutputs;
439
440
0
    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
441
0
    x0  = FIXED_TO_INT(fx);
442
0
    rx  = FIXED_REST_TO_INT(fx);    // Rest in 0..1.0 domain
443
444
445
0
    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
446
0
    y0  = FIXED_TO_INT(fy);
447
0
    ry  = FIXED_REST_TO_INT(fy);
448
449
450
0
    X0 = p -> opta[1] * x0;
451
0
    X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
452
453
0
    Y0 = p -> opta[0] * y0;
454
0
    Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]);
455
456
0
    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
457
458
0
        d00 = DENS(X0, Y0);
459
0
        d01 = DENS(X0, Y1);
460
0
        d10 = DENS(X1, Y0);
461
0
        d11 = DENS(X1, Y1);
462
463
0
        dx0 = LERP(rx, d00, d10);
464
0
        dx1 = LERP(rx, d01, d11);
465
466
0
        dxy = LERP(ry, dx0, dx1);
467
468
0
        Output[OutChan] = (cmsUInt16Number) dxy;
469
0
    }
470
471
472
0
#   undef LERP
473
0
#   undef DENS
474
0
}
475
476
477
// Trilinear interpolation (16 bits) - cmsFloat32Number version
478
static
479
void TrilinearInterpFloat(cmsContext ContextID, const cmsFloat32Number Input[],
480
                          cmsFloat32Number Output[],
481
                          const cmsInterpParams* p)
482
483
0
{
484
0
#   define LERP(a,l,h)      (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
485
0
#   define DENS(i,j,k)      (LutTable[(i)+(j)+(k)+OutChan])
486
487
0
    const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
488
0
    cmsFloat32Number      px, py, pz;
489
0
    int        x0, y0, z0,
490
0
               X0, Y0, Z0, X1, Y1, Z1;
491
0
    int        TotalOut, OutChan;
492
493
0
    cmsFloat32Number      fx, fy, fz,
494
0
                          d000, d001, d010, d011,
495
0
                          d100, d101, d110, d111,
496
0
                          dx00, dx01, dx10, dx11,
497
0
                          dxy0, dxy1, dxyz;
498
0
    cmsUNUSED_PARAMETER(ContextID);
499
500
0
    TotalOut   = p -> nOutputs;
501
502
    // We need some clipping here
503
0
    px = fclamp(Input[0]) * p->Domain[0];
504
0
    py = fclamp(Input[1]) * p->Domain[1];
505
0
    pz = fclamp(Input[2]) * p->Domain[2];
506
507
0
    x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0;  // We need full floor functionality here
508
0
    y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0;
509
0
    z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0;
510
511
0
    X0 = p -> opta[2] * x0;
512
0
    X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
513
514
0
    Y0 = p -> opta[1] * y0;
515
0
    Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
516
517
0
    Z0 = p -> opta[0] * z0;
518
0
    Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
519
520
0
    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
521
522
0
        d000 = DENS(X0, Y0, Z0);
523
0
        d001 = DENS(X0, Y0, Z1);
524
0
        d010 = DENS(X0, Y1, Z0);
525
0
        d011 = DENS(X0, Y1, Z1);
526
527
0
        d100 = DENS(X1, Y0, Z0);
528
0
        d101 = DENS(X1, Y0, Z1);
529
0
        d110 = DENS(X1, Y1, Z0);
530
0
        d111 = DENS(X1, Y1, Z1);
531
532
533
0
        dx00 = LERP(fx, d000, d100);
534
0
        dx01 = LERP(fx, d001, d101);
535
0
        dx10 = LERP(fx, d010, d110);
536
0
        dx11 = LERP(fx, d011, d111);
537
538
0
        dxy0 = LERP(fy, dx00, dx10);
539
0
        dxy1 = LERP(fy, dx01, dx11);
540
541
0
        dxyz = LERP(fz, dxy0, dxy1);
542
543
0
        Output[OutChan] = dxyz;
544
0
    }
545
546
547
0
#   undef LERP
548
0
#   undef DENS
549
0
}
550
551
// Trilinear interpolation (16 bits) - optimized version
552
static CMS_NO_SANITIZE
553
void TrilinearInterp16(cmsContext ContextID,
554
                       CMSREGISTER const cmsUInt16Number Input[],
555
                       CMSREGISTER cmsUInt16Number Output[],
556
                       CMSREGISTER const cmsInterpParams* p)
557
558
731M
{
559
23.4G
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
560
20.4G
#define LERP(a,l,h)     (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
561
562
731M
           const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
563
731M
           int        OutChan, TotalOut;
564
731M
           cmsS15Fixed16Number    fx, fy, fz;
565
731M
           CMSREGISTER int        rx, ry, rz;
566
731M
           int                    x0, y0, z0;
567
731M
           CMSREGISTER int        X0, X1, Y0, Y1, Z0, Z1;
568
731M
           int                    d000, d001, d010, d011,
569
731M
                                  d100, d101, d110, d111,
570
731M
                                  dx00, dx01, dx10, dx11,
571
731M
                                  dxy0, dxy1, dxyz;
572
731M
           cmsUNUSED_PARAMETER(ContextID);
573
574
731M
    TotalOut   = p -> nOutputs;
575
576
731M
    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
577
731M
    x0  = FIXED_TO_INT(fx);
578
731M
    rx  = FIXED_REST_TO_INT(fx);    // Rest in 0..1.0 domain
579
580
581
731M
    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
582
731M
    y0  = FIXED_TO_INT(fy);
583
731M
    ry  = FIXED_REST_TO_INT(fy);
584
585
731M
    fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
586
731M
    z0 = FIXED_TO_INT(fz);
587
731M
    rz = FIXED_REST_TO_INT(fz);
588
589
590
731M
    X0 = p -> opta[2] * x0;
591
731M
    X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
592
593
731M
    Y0 = p -> opta[1] * y0;
594
731M
    Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
595
596
731M
    Z0 = p -> opta[0] * z0;
597
731M
    Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
598
599
3.65G
    for (OutChan = 0; OutChan < TotalOut; OutChan++) {
600
601
2.92G
        d000 = DENS(X0, Y0, Z0);
602
2.92G
        d001 = DENS(X0, Y0, Z1);
603
2.92G
        d010 = DENS(X0, Y1, Z0);
604
2.92G
        d011 = DENS(X0, Y1, Z1);
605
606
2.92G
        d100 = DENS(X1, Y0, Z0);
607
2.92G
        d101 = DENS(X1, Y0, Z1);
608
2.92G
        d110 = DENS(X1, Y1, Z0);
609
2.92G
        d111 = DENS(X1, Y1, Z1);
610
611
612
2.92G
        dx00 = LERP(rx, d000, d100);
613
2.92G
        dx01 = LERP(rx, d001, d101);
614
2.92G
        dx10 = LERP(rx, d010, d110);
615
2.92G
        dx11 = LERP(rx, d011, d111);
616
617
2.92G
        dxy0 = LERP(ry, dx00, dx10);
618
2.92G
        dxy1 = LERP(ry, dx01, dx11);
619
620
2.92G
        dxyz = LERP(rz, dxy0, dxy1);
621
622
2.92G
        Output[OutChan] = (cmsUInt16Number) dxyz;
623
2.92G
    }
624
625
626
731M
#   undef LERP
627
731M
#   undef DENS
628
731M
}
629
630
631
// Tetrahedral interpolation, using Sakamoto algorithm.
632
0
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
633
static
634
void TetrahedralInterpFloat(cmsContext ContextID, const cmsFloat32Number Input[],
635
                            cmsFloat32Number Output[],
636
                            const cmsInterpParams* p)
637
0
{
638
0
    const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
639
0
    cmsFloat32Number     px, py, pz;
640
0
    int                  x0, y0, z0,
641
0
                         X0, Y0, Z0, X1, Y1, Z1;
642
0
    cmsFloat32Number     rx, ry, rz;
643
0
    cmsFloat32Number     c0, c1=0, c2=0, c3=0;
644
0
    int                  OutChan, TotalOut;
645
0
    cmsUNUSED_PARAMETER(ContextID);
646
647
0
    TotalOut   = p -> nOutputs;
648
649
    // We need some clipping here
650
0
    px = fclamp(Input[0]) * p->Domain[0];
651
0
    py = fclamp(Input[1]) * p->Domain[1];
652
0
    pz = fclamp(Input[2]) * p->Domain[2];
653
654
0
    x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0);  // We need full floor functionality here
655
0
    y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0);
656
0
    z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0);
657
658
659
0
    X0 = p -> opta[2] * x0;
660
0
    X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
661
662
0
    Y0 = p -> opta[1] * y0;
663
0
    Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
664
665
0
    Z0 = p -> opta[0] * z0;
666
0
    Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
667
668
0
    for (OutChan=0; OutChan < TotalOut; OutChan++) {
669
670
       // These are the 6 Tetrahedral
671
672
0
        c0 = DENS(X0, Y0, Z0);
673
674
0
        if (rx >= ry && ry >= rz) {
675
676
0
            c1 = DENS(X1, Y0, Z0) - c0;
677
0
            c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
678
0
            c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
679
680
0
        }
681
0
        else
682
0
            if (rx >= rz && rz >= ry) {
683
684
0
                c1 = DENS(X1, Y0, Z0) - c0;
685
0
                c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
686
0
                c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
687
688
0
            }
689
0
            else
690
0
                if (rz >= rx && rx >= ry) {
691
692
0
                    c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
693
0
                    c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
694
0
                    c3 = DENS(X0, Y0, Z1) - c0;
695
696
0
                }
697
0
                else
698
0
                    if (ry >= rx && rx >= rz) {
699
700
0
                        c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
701
0
                        c2 = DENS(X0, Y1, Z0) - c0;
702
0
                        c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
703
704
0
                    }
705
0
                    else
706
0
                        if (ry >= rz && rz >= rx) {
707
708
0
                            c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
709
0
                            c2 = DENS(X0, Y1, Z0) - c0;
710
0
                            c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
711
712
0
                        }
713
0
                        else
714
0
                            if (rz >= ry && ry >= rx) {
715
716
0
                                c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
717
0
                                c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
718
0
                                c3 = DENS(X0, Y0, Z1) - c0;
719
720
0
                            }
721
0
                            else  {
722
0
                                c1 = c2 = c3 = 0;
723
0
                            }
724
725
0
       Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
726
0
       }
727
728
0
}
729
730
#undef DENS
731
732
static CMS_NO_SANITIZE
733
void TetrahedralInterp16(cmsContext ContextID,
734
                         CMSREGISTER const cmsUInt16Number Input[],
735
                         CMSREGISTER cmsUInt16Number Output[],
736
                         CMSREGISTER const cmsInterpParams* p)
737
285M
{
738
285M
    const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
739
285M
    cmsS15Fixed16Number fx, fy, fz;
740
285M
    cmsS15Fixed16Number rx, ry, rz;
741
285M
    int x0, y0, z0;
742
285M
    cmsS15Fixed16Number c0, c1, c2, c3, Rest;
743
285M
    cmsUInt32Number X0, X1, Y0, Y1, Z0, Z1;
744
285M
    cmsUInt32Number TotalOut = p -> nOutputs;
745
285M
    cmsUNUSED_PARAMETER(ContextID);
746
747
285M
    fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
748
285M
    fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
749
285M
    fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
750
751
285M
    x0 = FIXED_TO_INT(fx);
752
285M
    y0 = FIXED_TO_INT(fy);
753
285M
    z0 = FIXED_TO_INT(fz);
754
755
285M
    rx = FIXED_REST_TO_INT(fx);
756
285M
    ry = FIXED_REST_TO_INT(fy);
757
285M
    rz = FIXED_REST_TO_INT(fz);
758
759
285M
    X0 = p -> opta[2] * x0;
760
285M
    X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
761
762
285M
    Y0 = p -> opta[1] * y0;
763
285M
    Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
764
765
285M
    Z0 = p -> opta[0] * z0;
766
285M
    Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
767
768
285M
    LutTable += X0+Y0+Z0;
769
770
    // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))
771
    // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16
772
    // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16
773
    // at the cost of being off by one at 7fff and 17ffe.
774
775
285M
    if (rx >= ry) {
776
171M
        if (ry >= rz) {
777
104M
            Y1 += X1;
778
104M
            Z1 += Y1;
779
262M
            for (; TotalOut; TotalOut--) {
780
158M
                c1 = LutTable[X1];
781
158M
                c2 = LutTable[Y1];
782
158M
                c3 = LutTable[Z1];
783
158M
                c0 = *LutTable++;
784
158M
                c3 -= c2;
785
158M
                c2 -= c1;
786
158M
                c1 -= c0;
787
158M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
788
158M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
789
158M
            }
790
104M
        } else if (rz >= rx) {
791
39.3M
            X1 += Z1;
792
39.3M
            Y1 += X1;
793
99.6M
            for (; TotalOut; TotalOut--) {
794
60.3M
                c1 = LutTable[X1];
795
60.3M
                c2 = LutTable[Y1];
796
60.3M
                c3 = LutTable[Z1];
797
60.3M
                c0 = *LutTable++;
798
60.3M
                c2 -= c1;
799
60.3M
                c1 -= c3;
800
60.3M
                c3 -= c0;
801
60.3M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
802
60.3M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
803
60.3M
            }
804
39.3M
        } else {
805
27.5M
            Z1 += X1;
806
27.5M
            Y1 += Z1;
807
71.4M
            for (; TotalOut; TotalOut--) {
808
43.8M
                c1 = LutTable[X1];
809
43.8M
                c2 = LutTable[Y1];
810
43.8M
                c3 = LutTable[Z1];
811
43.8M
                c0 = *LutTable++;
812
43.8M
                c2 -= c3;
813
43.8M
                c3 -= c1;
814
43.8M
                c1 -= c0;
815
43.8M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
816
43.8M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
817
43.8M
            }
818
27.5M
        }
819
171M
    } else {
820
114M
        if (rx >= rz) {
821
45.8M
            X1 += Y1;
822
45.8M
            Z1 += X1;
823
120M
            for (; TotalOut; TotalOut--) {
824
74.9M
                c1 = LutTable[X1];
825
74.9M
                c2 = LutTable[Y1];
826
74.9M
                c3 = LutTable[Z1];
827
74.9M
                c0 = *LutTable++;
828
74.9M
                c3 -= c1;
829
74.9M
                c1 -= c2;
830
74.9M
                c2 -= c0;
831
74.9M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
832
74.9M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
833
74.9M
            }
834
68.7M
        } else if (ry >= rz) {
835
35.9M
            Z1 += Y1;
836
35.9M
            X1 += Z1;
837
87.9M
            for (; TotalOut; TotalOut--) {
838
51.9M
                c1 = LutTable[X1];
839
51.9M
                c2 = LutTable[Y1];
840
51.9M
                c3 = LutTable[Z1];
841
51.9M
                c0 = *LutTable++;
842
51.9M
                c1 -= c3;
843
51.9M
                c3 -= c2;
844
51.9M
                c2 -= c0;
845
51.9M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
846
51.9M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
847
51.9M
            }
848
35.9M
        } else {
849
32.8M
            Y1 += Z1;
850
32.8M
            X1 += Y1;
851
79.4M
            for (; TotalOut; TotalOut--) {
852
46.6M
                c1 = LutTable[X1];
853
46.6M
                c2 = LutTable[Y1];
854
46.6M
                c3 = LutTable[Z1];
855
46.6M
                c0 = *LutTable++;
856
46.6M
                c1 -= c2;
857
46.6M
                c2 -= c3;
858
46.6M
                c3 -= c0;
859
46.6M
                Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
860
46.6M
                *Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
861
46.6M
            }
862
32.8M
        }
863
114M
    }
864
285M
}
865
866
867
103G
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
868
static CMS_NO_SANITIZE
869
void Eval4Inputs(cmsContext ContextID,
870
                 CMSREGISTER const cmsUInt16Number Input[],
871
                 CMSREGISTER cmsUInt16Number Output[],
872
                 CMSREGISTER const cmsInterpParams* p16)
873
2.94G
{
874
2.94G
    const cmsUInt16Number* LutTable;
875
2.94G
    cmsS15Fixed16Number fk;
876
2.94G
    cmsS15Fixed16Number k0, rk;
877
2.94G
    int K0, K1;
878
2.94G
    cmsS15Fixed16Number    fx, fy, fz;
879
2.94G
    cmsS15Fixed16Number    rx, ry, rz;
880
2.94G
    int                    x0, y0, z0;
881
2.94G
    cmsS15Fixed16Number    X0, X1, Y0, Y1, Z0, Z1;
882
2.94G
    cmsUInt32Number i;
883
2.94G
    cmsS15Fixed16Number    c0, c1, c2, c3, Rest;
884
2.94G
    cmsUInt32Number        OutChan;
885
2.94G
    cmsUInt16Number        Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
886
2.94G
    cmsUNUSED_PARAMETER(ContextID);
887
888
889
2.94G
    fk  = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
890
2.94G
    fx  = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
891
2.94G
    fy  = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
892
2.94G
    fz  = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
893
894
2.94G
    k0  = FIXED_TO_INT(fk);
895
2.94G
    x0  = FIXED_TO_INT(fx);
896
2.94G
    y0  = FIXED_TO_INT(fy);
897
2.94G
    z0  = FIXED_TO_INT(fz);
898
899
2.94G
    rk  = FIXED_REST_TO_INT(fk);
900
2.94G
    rx  = FIXED_REST_TO_INT(fx);
901
2.94G
    ry  = FIXED_REST_TO_INT(fy);
902
2.94G
    rz  = FIXED_REST_TO_INT(fz);
903
904
2.94G
    K0 = p16 -> opta[3] * k0;
905
2.94G
    K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);
906
907
2.94G
    X0 = p16 -> opta[2] * x0;
908
2.94G
    X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);
909
910
2.94G
    Y0 = p16 -> opta[1] * y0;
911
2.94G
    Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);
912
913
2.94G
    Z0 = p16 -> opta[0] * z0;
914
2.94G
    Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);
915
916
2.94G
    LutTable = (cmsUInt16Number*) p16 -> Table;
917
2.94G
    LutTable += K0;
918
919
11.6G
    for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
920
921
8.66G
        c0 = DENS(X0, Y0, Z0);
922
923
8.66G
        if (rx >= ry && ry >= rz) {
924
925
1.64G
            c1 = DENS(X1, Y0, Z0) - c0;
926
1.64G
            c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
927
1.64G
            c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
928
929
1.64G
        }
930
7.01G
        else
931
7.01G
            if (rx >= rz && rz >= ry) {
932
933
1.52G
                c1 = DENS(X1, Y0, Z0) - c0;
934
1.52G
                c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
935
1.52G
                c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
936
937
1.52G
            }
938
5.49G
            else
939
5.49G
                if (rz >= rx && rx >= ry) {
940
941
1.35G
                    c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
942
1.35G
                    c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
943
1.35G
                    c3 = DENS(X0, Y0, Z1) - c0;
944
945
1.35G
                }
946
4.14G
                else
947
4.14G
                    if (ry >= rx && rx >= rz) {
948
949
1.54G
                        c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
950
1.54G
                        c2 = DENS(X0, Y1, Z0) - c0;
951
1.54G
                        c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
952
953
1.54G
                    }
954
2.59G
                    else
955
2.59G
                        if (ry >= rz && rz >= rx) {
956
957
1.39G
                            c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
958
1.39G
                            c2 = DENS(X0, Y1, Z0) - c0;
959
1.39G
                            c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
960
961
1.39G
                        }
962
1.20G
                        else
963
1.20G
                            if (rz >= ry && ry >= rx) {
964
965
1.20G
                                c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
966
1.20G
                                c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
967
1.20G
                                c3 = DENS(X0, Y0, Z1) - c0;
968
969
1.20G
                            }
970
0
                            else {
971
0
                                c1 = c2 = c3 = 0;
972
0
                            }
973
974
8.66G
        Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
975
976
8.66G
        Tmp1[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
977
8.66G
    }
978
979
980
2.94G
    LutTable = (cmsUInt16Number*) p16 -> Table;
981
2.94G
    LutTable += K1;
982
983
11.6G
    for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
984
985
8.66G
        c0 = DENS(X0, Y0, Z0);
986
987
8.66G
        if (rx >= ry && ry >= rz) {
988
989
1.64G
            c1 = DENS(X1, Y0, Z0) - c0;
990
1.64G
            c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
991
1.64G
            c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
992
993
1.64G
        }
994
7.01G
        else
995
7.01G
            if (rx >= rz && rz >= ry) {
996
997
1.52G
                c1 = DENS(X1, Y0, Z0) - c0;
998
1.52G
                c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
999
1.52G
                c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
1000
1001
1.52G
            }
1002
5.49G
            else
1003
5.49G
                if (rz >= rx && rx >= ry) {
1004
1005
1.35G
                    c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
1006
1.35G
                    c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
1007
1.35G
                    c3 = DENS(X0, Y0, Z1) - c0;
1008
1009
1.35G
                }
1010
4.14G
                else
1011
4.14G
                    if (ry >= rx && rx >= rz) {
1012
1013
1.54G
                        c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
1014
1.54G
                        c2 = DENS(X0, Y1, Z0) - c0;
1015
1.54G
                        c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
1016
1017
1.54G
                    }
1018
2.59G
                    else
1019
2.59G
                        if (ry >= rz && rz >= rx) {
1020
1021
1.39G
                            c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1022
1.39G
                            c2 = DENS(X0, Y1, Z0) - c0;
1023
1.39G
                            c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
1024
1025
1.39G
                        }
1026
1.20G
                        else
1027
1.20G
                            if (rz >= ry && ry >= rx) {
1028
1029
1.20G
                                c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1030
1.20G
                                c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
1031
1.20G
                                c3 = DENS(X0, Y0, Z1) - c0;
1032
1033
1.20G
                            }
1034
0
                            else  {
1035
0
                                c1 = c2 = c3 = 0;
1036
0
                            }
1037
1038
8.66G
        Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
1039
1040
8.66G
        Tmp2[OutChan] = (cmsUInt16Number) c0 + ((Rest + (Rest >> 16)) >> 16);
1041
8.66G
    }
1042
1043
1044
1045
11.6G
    for (i=0; i < p16 -> nOutputs; i++) {
1046
8.66G
        Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1047
8.66G
    }
1048
2.94G
}
1049
#undef DENS
1050
1051
1052
// For more that 3 inputs (i.e., CMYK)
1053
// evaluate two 3-dimensional interpolations and then linearly interpolate between them.
1054
static
1055
void Eval4InputsFloat(cmsContext ContextID, const cmsFloat32Number Input[],
1056
                      cmsFloat32Number Output[],
1057
                      const cmsInterpParams* p)
1058
0
{
1059
0
       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1060
0
       cmsFloat32Number rest;
1061
0
       cmsFloat32Number pk;
1062
0
       int k0, K0, K1;
1063
0
       const cmsFloat32Number* T;
1064
0
       cmsUInt32Number i;
1065
0
       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1066
0
       cmsInterpParams p1;
1067
1068
0
       pk = fclamp(Input[0]) * p->Domain[0];
1069
0
       k0 = _cmsQuickFloor(pk);
1070
0
       rest = pk - (cmsFloat32Number) k0;
1071
1072
0
       K0 = p -> opta[3] * k0;
1073
0
       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]);
1074
1075
0
       p1 = *p;
1076
0
       memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));
1077
1078
0
       T = LutTable + K0;
1079
0
       p1.Table = T;
1080
1081
0
       TetrahedralInterpFloat(ContextID, Input + 1,  Tmp1, &p1);
1082
1083
0
       T = LutTable + K1;
1084
0
       p1.Table = T;
1085
0
       TetrahedralInterpFloat(ContextID, Input + 1,  Tmp2, &p1);
1086
1087
0
       for (i=0; i < p -> nOutputs; i++)
1088
0
       {
1089
0
              cmsFloat32Number y0 = Tmp1[i];
1090
0
              cmsFloat32Number y1 = Tmp2[i];
1091
1092
0
              Output[i] = y0 + (y1 - y0) * rest;
1093
0
       }
1094
0
}
1095
1096
#define EVAL_FNS(N,NM) static CMS_NO_SANITIZE \
1097
0
void Eval##N##Inputs(cmsContext contextID, CMSREGISTER const cmsUInt16Number Input[], CMSREGISTER cmsUInt16Number Output[], CMSREGISTER const cmsInterpParams* p16) \
1098
0
{\
1099
0
       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;\
1100
0
       cmsS15Fixed16Number fk;\
1101
0
       cmsS15Fixed16Number k0, rk;\
1102
0
       int K0, K1;\
1103
0
       const cmsUInt16Number* T;\
1104
0
       cmsUInt32Number i;\
1105
0
       cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\
1106
0
       cmsInterpParams p1;\
1107
0
\
1108
0
       fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);\
1109
0
       k0 = FIXED_TO_INT(fk);\
1110
0
       rk = FIXED_REST_TO_INT(fk);\
1111
0
\
1112
0
       K0 = p16 -> opta[NM] * k0;\
1113
0
       K1 = p16 -> opta[NM] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));\
1114
0
\
1115
0
       p1 = *p16;\
1116
0
       memmove(&p1.Domain[0], &p16 ->Domain[1], NM*sizeof(cmsUInt32Number));\
1117
0
\
1118
0
       T = LutTable + K0;\
1119
0
       p1.Table = T;\
1120
0
\
1121
0
       Eval##NM##Inputs(contextID, Input + 1, Tmp1, &p1);\
1122
0
\
1123
0
       T = LutTable + K1;\
1124
0
       p1.Table = T;\
1125
0
\
1126
0
       Eval##NM##Inputs(contextID, Input + 1, Tmp2, &p1);\
1127
0
\
1128
0
       for (i=0; i < p16 -> nOutputs; i++) {\
1129
0
\
1130
0
              Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);\
1131
0
       }\
1132
0
}\
Unexecuted instantiation: cmsintrp.c:Eval5Inputs
Unexecuted instantiation: cmsintrp.c:Eval6Inputs
Unexecuted instantiation: cmsintrp.c:Eval7Inputs
Unexecuted instantiation: cmsintrp.c:Eval8Inputs
Unexecuted instantiation: cmsintrp.c:Eval9Inputs
Unexecuted instantiation: cmsintrp.c:Eval10Inputs
Unexecuted instantiation: cmsintrp.c:Eval11Inputs
Unexecuted instantiation: cmsintrp.c:Eval12Inputs
Unexecuted instantiation: cmsintrp.c:Eval13Inputs
Unexecuted instantiation: cmsintrp.c:Eval14Inputs
Unexecuted instantiation: cmsintrp.c:Eval15Inputs
1133
\
1134
static void Eval##N##InputsFloat(cmsContext contextID,\
1135
                                 const cmsFloat32Number Input[], \
1136
                                 cmsFloat32Number Output[],\
1137
0
                                 const cmsInterpParams * p)\
1138
0
{\
1139
0
       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;\
1140
0
       cmsFloat32Number rest;\
1141
0
       cmsFloat32Number pk;\
1142
0
       int k0, K0, K1;\
1143
0
       const cmsFloat32Number* T;\
1144
0
       cmsUInt32Number i;\
1145
0
       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\
1146
0
       cmsInterpParams p1;\
1147
0
\
1148
0
       pk = fclamp(Input[0]) * p->Domain[0];\
1149
0
       k0 = _cmsQuickFloor(pk);\
1150
0
       rest = pk - (cmsFloat32Number) k0;\
1151
0
\
1152
0
       K0 = p -> opta[NM] * k0;\
1153
0
       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[NM]);\
1154
0
\
1155
0
       p1 = *p;\
1156
0
       memmove(&p1.Domain[0], &p ->Domain[1], NM*sizeof(cmsUInt32Number));\
1157
0
\
1158
0
       T = LutTable + K0;\
1159
0
       p1.Table = T;\
1160
0
\
1161
0
       Eval##NM##InputsFloat(contextID, Input + 1, Tmp1, &p1);\
1162
0
\
1163
0
       T = LutTable + K1;\
1164
0
       p1.Table = T;\
1165
0
\
1166
0
       Eval##NM##InputsFloat(contextID, Input + 1, Tmp2, &p1);\
1167
0
\
1168
0
       for (i=0; i < p -> nOutputs; i++) {\
1169
0
\
1170
0
              cmsFloat32Number y0 = Tmp1[i];\
1171
0
              cmsFloat32Number y1 = Tmp2[i];\
1172
0
\
1173
0
              Output[i] = y0 + (y1 - y0) * rest;\
1174
0
       }\
1175
0
}
Unexecuted instantiation: cmsintrp.c:Eval5InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval6InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval7InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval8InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval9InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval10InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval11InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval12InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval13InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval14InputsFloat
Unexecuted instantiation: cmsintrp.c:Eval15InputsFloat
1176
1177
1178
/**
1179
* Thanks to Carles Llopis for the templating idea
1180
*/
1181
EVAL_FNS(5, 4)
1182
EVAL_FNS(6, 5)
1183
EVAL_FNS(7, 6)
1184
EVAL_FNS(8, 7)
1185
EVAL_FNS(9, 8)
1186
EVAL_FNS(10, 9)
1187
EVAL_FNS(11, 10)
1188
EVAL_FNS(12, 11)
1189
EVAL_FNS(13, 12)
1190
EVAL_FNS(14, 13)
1191
EVAL_FNS(15, 14)
1192
1193
1194
// The default factory
1195
static
1196
cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags)
1197
19.6M
{
1198
1199
19.6M
    cmsInterpFunction Interpolation;
1200
19.6M
    cmsBool  IsFloat     = (dwFlags & CMS_LERP_FLAGS_FLOAT);
1201
19.6M
    cmsBool  IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);
1202
1203
19.6M
    memset(&Interpolation, 0, sizeof(Interpolation));
1204
1205
    // Safety check
1206
19.6M
    if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)
1207
0
        return Interpolation;
1208
1209
19.6M
    switch (nInputChannels) {
1210
1211
14.4M
           case 1: // Gray LUT / linear
1212
1213
14.4M
               if (nOutputChannels == 1) {
1214
1215
14.3M
                   if (IsFloat)
1216
61.1k
                       Interpolation.LerpFloat = LinLerp1Dfloat;
1217
14.2M
                   else
1218
14.2M
                       Interpolation.Lerp16 = LinLerp1D;
1219
1220
14.3M
               }
1221
109k
               else {
1222
1223
109k
                   if (IsFloat)
1224
0
                       Interpolation.LerpFloat = Eval1InputFloat;
1225
109k
                   else
1226
109k
                       Interpolation.Lerp16 = Eval1Input;
1227
109k
               }
1228
14.4M
               break;
1229
1230
53
           case 2: // Duotone
1231
53
               if (IsFloat)
1232
0
                      Interpolation.LerpFloat =  BilinearInterpFloat;
1233
53
               else
1234
53
                      Interpolation.Lerp16    =  BilinearInterp16;
1235
53
               break;
1236
1237
5.14M
           case 3:  // RGB et al
1238
1239
5.14M
               if (IsTrilinear) {
1240
1241
2.04M
                   if (IsFloat)
1242
0
                       Interpolation.LerpFloat = TrilinearInterpFloat;
1243
2.04M
                   else
1244
2.04M
                       Interpolation.Lerp16 = TrilinearInterp16;
1245
2.04M
               }
1246
3.10M
               else {
1247
1248
3.10M
                   if (IsFloat)
1249
0
                       Interpolation.LerpFloat = TetrahedralInterpFloat;
1250
3.10M
                   else {
1251
1252
3.10M
                       Interpolation.Lerp16 = TetrahedralInterp16;
1253
3.10M
                   }
1254
3.10M
               }
1255
5.14M
               break;
1256
1257
82.6k
           case 4:  // CMYK lut
1258
1259
82.6k
               if (IsFloat)
1260
0
                   Interpolation.LerpFloat =  Eval4InputsFloat;
1261
82.6k
               else
1262
82.6k
                   Interpolation.Lerp16    =  Eval4Inputs;
1263
82.6k
               break;
1264
1265
0
           case 5: // 5 Inks
1266
0
               if (IsFloat)
1267
0
                   Interpolation.LerpFloat =  Eval5InputsFloat;
1268
0
               else
1269
0
                   Interpolation.Lerp16    =  Eval5Inputs;
1270
0
               break;
1271
1272
29
           case 6: // 6 Inks
1273
29
               if (IsFloat)
1274
0
                   Interpolation.LerpFloat =  Eval6InputsFloat;
1275
29
               else
1276
29
                   Interpolation.Lerp16    =  Eval6Inputs;
1277
29
               break;
1278
1279
21
           case 7: // 7 inks
1280
21
               if (IsFloat)
1281
0
                   Interpolation.LerpFloat =  Eval7InputsFloat;
1282
21
               else
1283
21
                   Interpolation.Lerp16    =  Eval7Inputs;
1284
21
               break;
1285
1286
0
           case 8: // 8 inks
1287
0
               if (IsFloat)
1288
0
                   Interpolation.LerpFloat =  Eval8InputsFloat;
1289
0
               else
1290
0
                   Interpolation.Lerp16    =  Eval8Inputs;
1291
0
               break;
1292
1293
0
           case 9:
1294
0
               if (IsFloat)
1295
0
                   Interpolation.LerpFloat = Eval9InputsFloat;
1296
0
               else
1297
0
                   Interpolation.Lerp16 = Eval9Inputs;
1298
0
               break;
1299
1300
0
           case 10:
1301
0
               if (IsFloat)
1302
0
                   Interpolation.LerpFloat = Eval10InputsFloat;
1303
0
               else
1304
0
                   Interpolation.Lerp16 = Eval10Inputs;
1305
0
               break;
1306
1307
0
           case 11:
1308
0
               if (IsFloat)
1309
0
                   Interpolation.LerpFloat = Eval11InputsFloat;
1310
0
               else
1311
0
                   Interpolation.Lerp16 = Eval11Inputs;
1312
0
               break;
1313
1314
0
           case 12:
1315
0
               if (IsFloat)
1316
0
                   Interpolation.LerpFloat = Eval12InputsFloat;
1317
0
               else
1318
0
                   Interpolation.Lerp16 = Eval12Inputs;
1319
0
               break;
1320
1321
0
           case 13:
1322
0
               if (IsFloat)
1323
0
                   Interpolation.LerpFloat = Eval13InputsFloat;
1324
0
               else
1325
0
                   Interpolation.Lerp16 = Eval13Inputs;
1326
0
               break;
1327
1328
0
           case 14:
1329
0
               if (IsFloat)
1330
0
                   Interpolation.LerpFloat = Eval14InputsFloat;
1331
0
               else
1332
0
                   Interpolation.Lerp16 = Eval14Inputs;
1333
0
               break;
1334
1335
0
           case 15:
1336
0
               if (IsFloat)
1337
0
                   Interpolation.LerpFloat = Eval15InputsFloat;
1338
0
               else
1339
0
                   Interpolation.Lerp16 = Eval15Inputs;
1340
0
               break;
1341
1342
0
           default:
1343
0
               Interpolation.Lerp16 = NULL;
1344
19.6M
    }
1345
1346
19.6M
    return Interpolation;
1347
19.6M
}