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