changeset 2693:fd7eb86ac690

6523398: OSS CMM: Need to implement writing ICC profile tags in new lcms library Reviewed-by: igor, prr
author bae
date Thu, 09 Sep 2010 16:20:55 +0400
parents d4012b86a6e9
children abe6a61835cb
files make/sun/cmm/lcms/FILES_c_unix.gmk make/sun/cmm/lcms/FILES_c_windows.gmk make/sun/cmm/lcms/Makefile src/share/classes/sun/java2d/cmm/CMSManager.java src/share/classes/sun/java2d/cmm/lcms/LCMS.java src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java src/share/native/sun/java2d/cmm/lcms/LCMS.c src/share/native/sun/java2d/cmm/lcms/cmscam02.c src/share/native/sun/java2d/cmm/lcms/cmscam97.c src/share/native/sun/java2d/cmm/lcms/cmscgats.c src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c src/share/native/sun/java2d/cmm/lcms/cmserr.c src/share/native/sun/java2d/cmm/lcms/cmsgamma.c src/share/native/sun/java2d/cmm/lcms/cmsgmt.c src/share/native/sun/java2d/cmm/lcms/cmsintrp.c src/share/native/sun/java2d/cmm/lcms/cmsio0.c src/share/native/sun/java2d/cmm/lcms/cmsio1.c src/share/native/sun/java2d/cmm/lcms/cmslut.c src/share/native/sun/java2d/cmm/lcms/cmsmatsh.c src/share/native/sun/java2d/cmm/lcms/cmsmd5.c src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c src/share/native/sun/java2d/cmm/lcms/cmsnamed.c src/share/native/sun/java2d/cmm/lcms/cmsopt.c src/share/native/sun/java2d/cmm/lcms/cmspack.c src/share/native/sun/java2d/cmm/lcms/cmspcs.c src/share/native/sun/java2d/cmm/lcms/cmsplugin.c src/share/native/sun/java2d/cmm/lcms/cmsps2.c src/share/native/sun/java2d/cmm/lcms/cmssamp.c src/share/native/sun/java2d/cmm/lcms/cmssm.c src/share/native/sun/java2d/cmm/lcms/cmstypes.c src/share/native/sun/java2d/cmm/lcms/cmsvirt.c src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c src/share/native/sun/java2d/cmm/lcms/cmsxform.c src/share/native/sun/java2d/cmm/lcms/icc34.h src/share/native/sun/java2d/cmm/lcms/lcms.h src/share/native/sun/java2d/cmm/lcms/lcms2.h src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
diffstat 38 files changed, 25462 insertions(+), 20652 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/cmm/lcms/FILES_c_unix.gmk	Tue Sep 07 16:54:39 2010 +0400
+++ b/make/sun/cmm/lcms/FILES_c_unix.gmk	Thu Sep 09 16:20:55 2010 +0400
@@ -25,7 +25,6 @@
 
 FILES_c = \
     cmscam02.c \
-    cmscam97.c \
     cmscgats.c \
     cmscnvrt.c \
     cmserr.c \
@@ -35,13 +34,17 @@
     cmsio0.c \
     cmsio1.c \
     cmslut.c \
-    cmsmatsh.c \
+    cmsmd5.c \
     cmsmtrx.c \
     cmsnamed.c \
+    cmsopt.c \
     cmspack.c \
     cmspcs.c \
+    cmsplugin.c \
     cmsps2.c \
     cmssamp.c \
+    cmssm.c \
+    cmstypes.c \
     cmsvirt.c \
     cmswtpnt.c \
     cmsxform.c \
--- a/make/sun/cmm/lcms/FILES_c_windows.gmk	Tue Sep 07 16:54:39 2010 +0400
+++ b/make/sun/cmm/lcms/FILES_c_windows.gmk	Thu Sep 09 16:20:55 2010 +0400
@@ -25,7 +25,6 @@
 
 FILES_c = \
     cmscam02.c \
-    cmscam97.c \
     cmscgats.c \
     cmscnvrt.c \
     cmserr.c \
@@ -35,13 +34,17 @@
     cmsio0.c \
     cmsio1.c \
     cmslut.c \
-    cmsmatsh.c \
+    cmsmd5.c \
     cmsmtrx.c \
     cmsnamed.c \
+    cmsopt.c \
     cmspack.c \
     cmspcs.c \
+    cmsplugin.c \
     cmsps2.c \
     cmssamp.c \
+    cmssm.c \
+    cmstypes.c \
     cmsvirt.c \
     cmswtpnt.c \
     cmsxform.c \
--- a/make/sun/cmm/lcms/Makefile	Tue Sep 07 16:54:39 2010 +0400
+++ b/make/sun/cmm/lcms/Makefile	Thu Sep 09 16:20:55 2010 +0400
@@ -80,8 +80,8 @@
 vpath %.c   $(SHARE_SRC)/native/sun/java2d
 
 ifeq ($(PLATFORM), windows)
-
-OTHER_LDLIBS = user32.lib version.lib $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib
+OTHER_CFLAGS += -DCMS_IS_WINDOWS_ -Dsqrtf=sqrt
+OTHER_LDLIBS = $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib
 OTHER_INCLUDES += -I$(SHARE_SRC)/native/sun/java2d \
                   -I$(SHARE_SRC)/native/sun/awt/debug
 
--- a/src/share/classes/sun/java2d/cmm/CMSManager.java	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/classes/sun/java2d/cmm/CMSManager.java	Thu Sep 09 16:20:55 2010 +0400
@@ -100,12 +100,12 @@
         public long loadProfile(byte[] data) {
             System.err.print(cName + ".loadProfile");
             long profileID = tcmm.loadProfile(data);
-            System.err.println("(ID=" + profileID + ")");
+            System.err.printf("(ID=%x)\n", profileID);
             return profileID;
         }
 
         public void freeProfile(long profileID) {
-            System.err.println(cName + ".freeProfile(ID=" + profileID + ")");
+            System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID);
             tcmm.freeProfile(profileID);
         }
 
@@ -123,8 +123,8 @@
         }
 
         public int getTagSize(long profileID, int tagSignature) {
-            System.err.print(cName + ".getTagSize(ID=" + profileID +
-                               ", TagSig=" + tagSignature + ")");
+            System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)",
+                              profileID, signatureToString(tagSignature));
             int size = tcmm.getTagSize(profileID, tagSignature);
             System.err.println("=" + size);
             return size;
@@ -132,8 +132,8 @@
 
         public void getTagData(long profileID, int tagSignature,
                                byte[] data) {
-            System.err.print(cName + ".getTagData(ID=" + profileID +
-                             ", TagSig=" + tagSignature + ")");
+            System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)",
+                              profileID, signatureToString(tagSignature));
             System.err.println(" requested " + data.length + " byte(s)");
             tcmm.getTagData(profileID, tagSignature, data);
         }
@@ -158,5 +158,13 @@
             System.err.println(cName + ".createTransform(ColorTransform[])");
             return tcmm.createTransform(transforms);
         }
+
+        private static String signatureToString(int sig) {
+            return String.format("%c%c%c%c",
+                                 (char)(0xff & (sig >> 24)),
+                                 (char)(0xff & (sig >> 16)),
+                                 (char)(0xff & (sig >>  8)),
+                                 (char)(0xff & (sig      )));
+        }
     }
 }
--- a/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Thu Sep 09 16:20:55 2010 +0400
@@ -53,7 +53,8 @@
     public static native long getProfileID(ICC_Profile profile);
 
     public static native long createNativeTransform(
-        long[] profileIDs, int renderType, Object disposerRef);
+        long[] profileIDs, int renderType, int inFormatter, int outFormatter,
+        Object disposerRef);
 
    /**
      * Constructs ColorTransform object corresponding to an ICC_profile
--- a/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Thu Sep 09 16:20:55 2010 +0400
@@ -55,11 +55,17 @@
 
 public class LCMSTransform implements ColorTransform {
     long ID;
+    private int inFormatter;
+    private int outFormatter;
+
     ICC_Profile[] profiles;
     long [] profileIDs;
     int renderType;
     int transformType;
 
+    private int numInComponents = -1;
+    private int numOutComponents = -1;
+
     private Object disposerReferent = new Object();
 
     /* the class initializer */
@@ -80,6 +86,14 @@
         this.renderType = (renderType == ColorTransform.Any)?
                               ICC_Profile.icPerceptual : renderType;
         this.transformType = transformType;
+
+        /* Note that ICC_Profile.getNumComponents() is quite expensive
+         * (it may results in a reading of the profile header).
+         * So, here we cache the number of components of input and
+         * output profiles for further usage.
+         */
+        numInComponents = profiles[0].getNumComponents();
+        numOutComponents = profiles[profiles.length - 1].getNumComponents();
     }
 
     public LCMSTransform (ColorTransform[] transforms) {
@@ -99,26 +113,51 @@
             j += curTrans.profiles.length;
         }
         renderType = ((LCMSTransform)transforms[0]).renderType;
-        ID = LCMS.createNativeTransform(profileIDs, renderType,
-                                        disposerReferent);
+
+        /* Note that ICC_Profile.getNumComponents() is quite expensive
+         * (it may results in a reading of the profile header).
+         * So, here we cache the number of components of input and
+         * output profiles for further usage.
+         */
+        numInComponents = profiles[0].getNumComponents();
+        numOutComponents = profiles[profiles.length - 1].getNumComponents();
     }
 
     public int getNumInComponents() {
-        return profiles[0].getNumComponents();
+        return numInComponents;
     }
 
     public int getNumOutComponents() {
-        return profiles[profiles.length - 1].getNumComponents();
+        return numOutComponents;
+    }
+
+    private synchronized void doTransform(LCMSImageLayout in,
+                                          LCMSImageLayout out) {
+        // update native transfrom if needed
+        if (ID == 0L ||
+            inFormatter != in.pixelType ||
+            outFormatter != out.pixelType) {
+
+            if (ID != 0L) {
+                // Disposer will destroy forgotten transform
+                disposerReferent = new Object();
+            }
+            inFormatter = in.pixelType;
+            outFormatter = out.pixelType;
+
+            ID = LCMS.createNativeTransform(profileIDs, renderType,
+                                            inFormatter, outFormatter,
+                                            disposerReferent);
+        }
+
+        LCMS.colorConvert(this, in, out);
     }
 
     public void colorConvert(BufferedImage src, BufferedImage dst) {
         if (LCMSImageLayout.isSupported(src) &&
             LCMSImageLayout.isSupported(dst))
         {
-            synchronized(this) {
-                LCMS.colorConvert(this, new LCMSImageLayout(src),
-                                  new LCMSImageLayout(dst));
-            }
+            doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst));
             return;
         }
         LCMSImageLayout srcIL, dstIL;
@@ -204,9 +243,8 @@
                     }
                 }
                 // color convert srcLine to dstLine
-                synchronized (this) {
-                    LCMS.colorConvert(this, srcIL, dstIL);
-                }
+                doTransform(srcIL, dstIL);
+
                 // convert dst scanline
                 pixel = null;
                 idx = 0;
@@ -263,9 +301,8 @@
                     }
                 }
                 // color convert srcLine to dstLine
-                synchronized(this) {
-                    LCMS.colorConvert(this, srcIL, dstIL);
-                }
+                doTransform(srcIL, dstIL);
+
                 // convert dst scanline
                 pixel = null;
                 idx = 0;
@@ -377,9 +414,7 @@
             }
 
             // color convert srcLine to dstLine
-            synchronized(this) {
-                LCMS.colorConvert(this, srcIL, dstIL);
-            }
+            doTransform(srcIL, dstIL);
 
             // store dst scanline
             xd = dst.getMinX();
@@ -470,9 +505,7 @@
                 }
 
                 // color convert srcLine to dstLine
-                synchronized(this) {
-                    LCMS.colorConvert(this, srcIL, dstIL);
-                }
+                doTransform(srcIL, dstIL);
 
                 // store dst scanline
                 xd = dst.getMinX();
@@ -513,9 +546,8 @@
                 }
 
                 // color convert srcLine to dstLine
-                synchronized(this) {
-                    LCMS.colorConvert(this, srcIL, dstIL);
-                }
+                doTransform(srcIL, dstIL);
+
                 // store dst scanline
                 xd = dst.getMinX();
                 idx = 0;
@@ -550,9 +582,7 @@
             LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
             LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
 
-        synchronized(this) {
-            LCMS.colorConvert(this, srcIL, dstIL);
-        }
+        doTransform(srcIL, dstIL);
 
         return dst;
     }
@@ -572,9 +602,7 @@
             LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
             LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
 
-        synchronized(this) {
-            LCMS.colorConvert(this, srcIL, dstIL);
-        }
+        doTransform(srcIL, dstIL);
 
         return dst;
     }
--- a/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Thu Sep 09 16:20:55 2010 +0400
@@ -24,11 +24,13 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
 #include "sun_java2d_cmm_lcms_LCMS.h"
 #include "jni_util.h"
 #include "Trace.h"
 #include "Disposer.h"
-#include "lcms.h"
+#include "lcms2.h"
 
 
 #define ALIGNLONG(x) (((x)+3) & ~(3))         // Aligns to DWORD boundary
@@ -38,10 +40,10 @@
 #else
 
 static
-void AdjustEndianess32(LPBYTE pByte)
+void AdjustEndianess32(cmsUInt8Number *pByte)
 {
-    BYTE temp1;
-    BYTE temp2;
+    cmsUInt8Number temp1;
+    cmsUInt8Number temp2;
 
     temp1 = *pByte++;
     temp2 = *pByte++;
@@ -57,11 +59,11 @@
 // big endian notation.
 
 static
-icInt32Number TransportValue32(icInt32Number Value)
+cmsInt32Number TransportValue32(cmsInt32Number Value)
 {
-    icInt32Number Temp = Value;
+    cmsInt32Number Temp = Value;
 
-    AdjustEndianess32((LPBYTE) &Temp);
+    AdjustEndianess32((cmsUInt8Number*) &Temp);
     return Temp;
 }
 
@@ -84,7 +86,13 @@
 /* Default temp profile list size */
 #define DF_ICC_BUF_SIZE 32
 
-#define ERR_MSG_SIZE 20
+#define ERR_MSG_SIZE 256
+
+#ifdef _MSC_VER
+# ifndef snprintf
+#       define snprintf  _snprintf
+# endif
+#endif
 
 typedef union storeID_s {    /* store SProfile stuff in a Java Long */
     cmsHPROFILE pf;
@@ -93,6 +101,11 @@
     jlong j;
 } storeID_t, *storeID_p;
 
+typedef union {
+    cmsTagSignature cms;
+    jint j;
+} TagSignature_t, *TagSignature_p;
+
 static jfieldID Trans_profileIDs_fID;
 static jfieldID Trans_renderType_fID;
 static jfieldID Trans_ID_fID;
@@ -108,21 +121,26 @@
 
 JavaVM *javaVM;
 
-int errorHandler(int errorCode, const char *errorText) {
+void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode,
+                  const char *errorText) {
     JNIEnv *env;
     char errMsg[ERR_MSG_SIZE];
-    /* We can safely use sprintf here because error message has limited size */
-    sprintf(errMsg, "LCMS error %d", errorCode);
+
+    int count = snprintf(errMsg, ERR_MSG_SIZE,
+                          "LCMS error %d: %s", errorCode, errorText);
+    if (count < 0 || count >= ERR_MSG_SIZE) {
+        count = ERR_MSG_SIZE - 1;
+    }
+    errMsg[count] = 0;
 
     (*javaVM)->AttachCurrentThread(javaVM, (void**)&env, NULL);
     JNU_ThrowByName(env, "java/awt/color/CMMException", errMsg);
-    return 1;
 }
 
 JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
     javaVM = jvm;
 
-    cmsSetErrorHandler(errorHandler);
+    cmsSetLogErrorHandler(errorHandler);
     return JNI_VERSION_1_6;
 }
 
@@ -141,11 +159,10 @@
  */
 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
   (JNIEnv *env, jclass cls, jlongArray profileIDs, jint renderType,
-   jobject disposerRef)
+   jint inFormatter, jint outFormatter, jobject disposerRef)
 {
-    LPLCMSICCPROFILE _iccArray[DF_ICC_BUF_SIZE];
-    LPLCMSICCPROFILE *iccArray = &_iccArray[0];
-    cmsHTRANSFORM transform;
+    cmsHPROFILE _iccArray[DF_ICC_BUF_SIZE];
+    cmsHPROFILE *iccArray = &_iccArray[0];
     storeID_t sTrans;
     int i, j, size;
     jlong* ids;
@@ -154,17 +171,19 @@
     ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0);
 
     if (DF_ICC_BUF_SIZE < size*2) {
-        iccArray = (LPLCMSICCPROFILE*) malloc(
-            size*2*sizeof(LPLCMSICCPROFILE));
+        iccArray = (cmsHPROFILE*) malloc(
+            size*2*sizeof(cmsHPROFILE));
         if (iccArray == NULL) {
             J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
-            return NULL;
+            return 0L;
         }
     }
 
     j = 0;
     for (i = 0; i < size; i++) {
-        LPLCMSICCPROFILE icc;
+        cmsHPROFILE icc;
+        cmsColorSpaceSignature cs;
+
         sTrans.j = ids[i];
         icc = sTrans.pf;
         iccArray[j++] = icc;
@@ -172,16 +191,17 @@
         /* Middle non-abstract profiles should be doubled before passing to
          * the cmsCreateMultiprofileTransform function
          */
+
+        cs = cmsGetColorSpace(icc);
         if (size > 2 && i != 0 && i != size - 1 &&
-            icc->ColorSpace != icSigXYZData &&
-            icc->ColorSpace != icSigLabData)
+            cs != cmsSigXYZData && cs != cmsSigLabData)
         {
             iccArray[j++] = icc;
         }
     }
 
     sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j,
-        0, 0, renderType, 0);
+        inFormatter, outFormatter, renderType, 0);
 
     (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0);
 
@@ -190,12 +210,13 @@
                                        "sTrans.xf == NULL");
         JNU_ThrowByName(env, "java/awt/color/CMMException",
                         "Cannot get color transform");
+    } else {
+        Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
     }
 
     if (iccArray != &_iccArray[0]) {
         free(iccArray);
     }
-    Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
     return sTrans.j;
 }
 
@@ -215,7 +236,8 @@
     dataArray = (*env)->GetByteArrayElements (env, data, 0);
     dataSize = (*env)->GetArrayLength (env, data);
 
-    sProf.pf = cmsOpenProfileFromMem((LPVOID)dataArray, (DWORD) dataSize);
+    sProf.pf = cmsOpenProfileFromMem((const void *)dataArray,
+                                     (cmsUInt32Number) dataSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -254,20 +276,17 @@
 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize
   (JNIEnv *env, jobject obj, jlong id)
 {
-    LPLCMSICCPROFILE Icc;
     storeID_t sProf;
-    unsigned char pfSize[4];
+    cmsUInt32Number pfSize = 0;
+    sProf.j = id;
 
-    sProf.j = id;
-    Icc = (LPLCMSICCPROFILE) sProf.pf;
-    Icc -> Seek(Icc, 0);
-    Icc -> Read(pfSize, 4, 1, Icc);
-
-    /* TODO: It's a correct but non-optimal for BE machines code, so should
-     * be special cased for them
-     */
-    return (pfSize[0]<<24) | (pfSize[1]<<16) | (pfSize[2]<<8) |
-        pfSize[3];
+    if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
+        return (jint)pfSize;
+    } else {
+      JNU_ThrowByName(env, "java/awt/color/CMMException",
+                      "Can not access specified profile.");
+        return -1;
+    }
 }
 
 /*
@@ -278,29 +297,46 @@
 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData
   (JNIEnv *env, jobject obj, jlong id, jbyteArray data)
 {
-    LPLCMSICCPROFILE Icc;
     storeID_t sProf;
-    unsigned char pfSize[4];
     jint size;
     jbyte* dataArray;
+    cmsUInt32Number pfSize = 0;
+    cmsBool status;
 
     sProf.j = id;
-    Icc = (LPLCMSICCPROFILE) sProf.pf;
-    Icc -> Seek(Icc, 0);
-    Icc -> Read(pfSize, 4, 1, Icc);
+
+    // determine actual profile size
+    if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Can not access specified profile.");
+        return;
+    }
+
+    // verify java buffer capacity
+    size = (*env)->GetArrayLength(env, data);
+    if (0 >= size || pfSize > (cmsUInt32Number)size) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Insufficient buffer capacity.");
+        return;
+    }
 
     dataArray = (*env)->GetByteArrayElements (env, data, 0);
-    Icc->Seek(Icc, 0);
 
-    /* TODO: It's a correct but non-optimal for BE machines code, so should
-     * be special cased for them
-     */
-    Icc->Read(dataArray, 1,
-              (pfSize[0]<<24) | (pfSize[1]<<16) | (pfSize[2]<<8) | pfSize[3],
-              Icc);
+    status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize);
+
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
+    if (!status) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Can not access specified profile.");
+        return;
+    }
 }
 
+/* Get profile header info */
+cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
+cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
+
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    getTagSize
@@ -309,24 +345,21 @@
 JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize
   (JNIEnv *env, jobject obj, jlong id, jint tagSig)
 {
-    LPLCMSICCPROFILE Icc;
     storeID_t sProf;
-    int i;
-    jint result;
+    TagSignature_t sig;
+    jint result = -1;
 
     sProf.j = id;
-    Icc = (LPLCMSICCPROFILE) sProf.pf;
+    sig.j = tagSig;
 
     if (tagSig == SigHead) {
-        result = sizeof(icHeader);
+        result = sizeof(cmsICCHeader);
     } else {
-        i =  _cmsSearchTag(Icc, tagSig, FALSE);
-        if (i >= 0) {
-            result = Icc->TagSizes[i];
+      if (cmsIsTag(sProf.pf, sig.cms)) {
+            result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
         } else {
             JNU_ThrowByName(env, "java/awt/color/CMMException",
                             "ICC profile tag not found");
-            result = -1;
         }
     }
 
@@ -341,43 +374,83 @@
 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData
   (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
 {
-    LPLCMSICCPROFILE Icc;
     storeID_t sProf;
+    TagSignature_t sig;
+    cmsInt32Number tagSize;
+
     jbyte* dataArray;
-    int i, tagSize;
+    jint bufSize;
 
     sProf.j = id;
-    Icc = (LPLCMSICCPROFILE) sProf.pf;
+    sig.j = tagSig;
 
     if (tagSig == SigHead) {
+        cmsBool status;
+
+        bufSize =(*env)->GetArrayLength(env, data);
+
+        if (bufSize < sizeof(cmsICCHeader)) {
+           JNU_ThrowByName(env, "java/awt/color/CMMException",
+                            "Insufficient buffer capacity");
+           return;
+        }
+
         dataArray = (*env)->GetByteArrayElements (env, data, 0);
-        tagSize =(*env)->GetArrayLength(env, data);
-        Icc -> Seek(Icc, 0);
-        Icc -> Read(dataArray, sizeof(icHeader), 1, Icc);
+
+        if (dataArray == NULL) {
+           JNU_ThrowByName(env, "java/awt/color/CMMException",
+                            "Unable to get buffer");
+           return;
+        }
+
+        status = _getHeaderInfo(sProf.pf, dataArray, bufSize);
+
         (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
+        if (!status) {
+            JNU_ThrowByName(env, "java/awt/color/CMMException",
+                            "ICC Profile header not found");
+        }
+
         return;
     }
 
-
-    i =  _cmsSearchTag(Icc, tagSig, FALSE);
-    if (i >=0) {
-        tagSize = Icc->TagSizes[i];
-        dataArray = (*env)->GetByteArrayElements (env, data, 0);
-        Icc->Seek(Icc, Icc->TagOffsets[i]);
-        Icc->Read(dataArray, 1, tagSize, Icc);
-        (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+    if (cmsIsTag(sProf.pf, sig.cms)) {
+        tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
+    } else {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "ICC profile tag not found");
         return;
     }
 
-    JNU_ThrowByName(env, "java/awt/color/CMMException",
-                    "ICC profile tag not found");
+    // verify data buffer capacity
+    bufSize = (*env)->GetArrayLength(env, data);
+
+    if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Insufficient buffer capacity.");
+        return;
+    }
+
+    dataArray = (*env)->GetByteArrayElements (env, data, 0);
+
+    if (dataArray == NULL) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Unable to get buffer");
+        return;
+    }
+
+    bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);
+
+    (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
+    if (bufSize != tagSize) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Can not get tag data.");
+    }
     return;
 }
 
-// Modify data for a tag in a profile
-LCMSBOOL LCMSEXPORT _cmsModifyTagData(cmsHPROFILE hProfile,
-                                 icTagSignature sig, void *data, size_t size);
-
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    setTagData
@@ -386,23 +459,32 @@
 JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData
   (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
 {
-    cmsHPROFILE profile;
     storeID_t sProf;
+    TagSignature_t sig;
+    cmsBool status;
     jbyte* dataArray;
     int tagSize;
 
+    sProf.j = id;
+    sig.j = tagSig;
+
+
+    tagSize =(*env)->GetArrayLength(env, data);
+
+    dataArray = (*env)->GetByteArrayElements(env, data, 0);
+
     if (tagSig == SigHead) {
-        J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_setTagData on icSigHead not "
-                      "permitted");
-        return;
+        status = _setHeaderInfo(sProf.pf, dataArray, tagSize);
+    } else {
+        status = cmsWriteRawTag(sProf.pf, sig.cms, dataArray, tagSize);
     }
 
-    sProf.j = id;
-    profile = (cmsHPROFILE) sProf.pf;
-    dataArray = (*env)->GetByteArrayElements(env, data, 0);
-    tagSize =(*env)->GetArrayLength(env, data);
-    _cmsModifyTagData(profile, (icTagSignature) tagSig, dataArray, tagSize);
     (*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
+
+    if (!status) {
+        JNU_ThrowByName(env, "java/awt/color/CMMException",
+                        "Can not write tag data.");
+    }
 }
 
 void* getILData (JNIEnv *env, jobject img, jint* pDataType,
@@ -456,7 +538,7 @@
   (JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst)
 {
     storeID_t sTrans;
-    int size, inFmt, outFmt, srcDType, dstDType, outSize, renderType;
+    int inFmt, outFmt, srcDType, dstDType;
     int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;
     int width, height, i;
     void* inputBuffer;
@@ -483,8 +565,6 @@
     }
 #endif
     sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID);
-    cmsChangeBuffersFormat(sTrans.xf, inFmt, outFmt);
-
 
     if (sTrans.xf == NULL) {
         J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
@@ -565,190 +645,54 @@
     PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
 }
 
-LCMSBOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig,
-                       void *data, size_t size)
+cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
 {
-    LCMSBOOL isNew;
-    int i, idx, delta, count;
-    LPBYTE padChars[3] = {0, 0, 0};
-    LPBYTE beforeBuf, afterBuf, ptr;
-    size_t beforeSize, afterSize;
-    icUInt32Number profileSize, temp;
-    LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
+  cmsUInt32Number pfSize = 0;
+  cmsUInt8Number* pfBuffer = NULL;
+  cmsBool status = FALSE;
 
-    isNew = FALSE;
-    idx = _cmsSearchTag(Icc, sig, FALSE);
-    if (idx < 0) {
-        isNew = TRUE;
-        idx = Icc->TagCount++;
-        if (Icc->TagCount >= MAX_TABLE_TAG) {
-            J2dRlsTraceLn1(J2D_TRACE_ERROR, "_cmsModifyTagData: Too many tags "
-                           "(%d)\n", Icc->TagCount);
-            Icc->TagCount = MAX_TABLE_TAG-1;
-            return FALSE;
-        }
-    }
+  if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
+      pfSize < sizeof(cmsICCHeader) ||
+      bufferSize < sizeof(cmsICCHeader))
+  {
+    return FALSE;
+  }
 
-    /* Read in size from header */
-    Icc->Seek(Icc, 0);
-    Icc->Read(&profileSize, sizeof(icUInt32Number), 1, Icc);
-    AdjustEndianess32((LPBYTE) &profileSize);
+  pfBuffer = malloc(pfSize);
+  if (pfBuffer == NULL) {
+    return FALSE;
+  }
 
-    /* Compute the change in profile size */
-    if (isNew) {
-        delta = sizeof(icTag) + ALIGNLONG(size);
-    } else {
-        delta = ALIGNLONG(size) - ALIGNLONG(Icc->TagSizes[idx]);
-    }
-    /* Add tag to internal structures */
-    ptr = malloc(size);
-    if (ptr == NULL) {
-        if(isNew) {
-            Icc->TagCount--;
-        }
-        J2dRlsTraceLn(J2D_TRACE_ERROR, "_cmsModifyTagData: ptr == NULL");
-        return FALSE;
-    }
+  // load raw profile data into the buffer
+  if (cmsSaveProfileToMem(pf, pfBuffer, &pfSize)) {
+    memcpy(pBuffer, pfBuffer, sizeof(cmsICCHeader));
+    status = TRUE;
+  }
+  free(pfBuffer);
+  return status;
+}
 
-    /* We change the size of Icc here only if we know it'll actually
-     * grow: if Icc is about to shrink we must wait until we've read
-     * the previous data.  */
-    if (delta > 0) {
-        if (!Icc->Grow(Icc, delta)) {
-            free(ptr);
-            if(isNew) {
-                Icc->TagCount--;
-            }
-            J2dRlsTraceLn(J2D_TRACE_ERROR,
-                          "_cmsModifyTagData: Icc->Grow() == FALSE");
-            return FALSE;
-        }
-    }
+cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
+{
+  cmsICCHeader pfHeader = { 0 };
 
-    /* Compute size of tag data before/after the modified tag */
-    beforeSize = ((isNew)?profileSize:Icc->TagOffsets[idx]) -
-                 Icc->TagOffsets[0];
-    if (Icc->TagCount == (idx + 1)) {
-        afterSize = 0;
-    } else {
-        afterSize = profileSize - Icc->TagOffsets[idx+1];
-    }
-    /* Make copies of the data before/after the modified tag */
-    if (beforeSize > 0) {
-        beforeBuf = malloc(beforeSize);
-        if (!beforeBuf) {
-            if(isNew) {
-                Icc->TagCount--;
-            }
-            free(ptr);
-            J2dRlsTraceLn(J2D_TRACE_ERROR,
-                          "_cmsModifyTagData: beforeBuf == NULL");
-            return FALSE;
-        }
-        Icc->Seek(Icc, Icc->TagOffsets[0]);
-        Icc->Read(beforeBuf, beforeSize, 1, Icc);
-    }
+  if (pBuffer == NULL || bufferSize < sizeof(cmsICCHeader)) {
+    return FALSE;
+  }
 
-    if (afterSize > 0) {
-        afterBuf = malloc(afterSize);
-        if (!afterBuf) {
-            free(ptr);
-            if(isNew) {
-                Icc->TagCount--;
-            }
-            if (beforeSize > 0) {
-                free(beforeBuf);
-            }
-            J2dRlsTraceLn(J2D_TRACE_ERROR,
-                          "_cmsModifyTagData: afterBuf == NULL");
-            return FALSE;
-        }
-        Icc->Seek(Icc, Icc->TagOffsets[idx+1]);
-        Icc->Read(afterBuf, afterSize, 1, Icc);
-    }
+  memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader));
 
-    CopyMemory(ptr, data, size);
-    Icc->TagSizes[idx] = size;
-    Icc->TagNames[idx] = sig;
-    if (Icc->TagPtrs[idx]) {
-        free(Icc->TagPtrs[idx]);
-    }
-    Icc->TagPtrs[idx] = ptr;
-    if (isNew) {
-        Icc->TagOffsets[idx] = profileSize;
-    }
+  // now set header fields, which we can access using the lcms2 public API
+  cmsSetHeaderFlags(pf, pfHeader.flags);
+  cmsSetHeaderManufacturer(pf, pfHeader.manufacturer);
+  cmsSetHeaderModel(pf, pfHeader.model);
+  cmsSetHeaderAttributes(pf, pfHeader.attributes);
+  cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID));
+  cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent);
+  cmsSetPCS(pf, pfHeader.pcs);
+  cmsSetColorSpace(pf, pfHeader.colorSpace);
+  cmsSetDeviceClass(pf, pfHeader.deviceClass);
+  cmsSetEncodedICCversion(pf, pfHeader.version);
 
-
-    /* Update the profile size in the header */
-    profileSize += delta;
-    Icc->Seek(Icc, 0);
-    temp = TransportValue32(profileSize);
-    Icc->Write(Icc, sizeof(icUInt32Number), &temp);
-
-    /* Shrink Icc, if needed.  */
-    if (delta < 0) {
-        if (!Icc->Grow(Icc, delta)) {
-            free(ptr);
-            if(isNew) {
-                Icc->TagCount--;
-            }
-            J2dRlsTraceLn(J2D_TRACE_ERROR,
-                          "_cmsModifyTagData: Icc->Grow() == FALSE");
-            return FALSE;
-        }
-    }
-
-    /* Adjust tag offsets: if the tag is new, we must account
-       for the new tag table entry; otherwise, only those tags after
-       the modified tag are changed (by delta) */
-    if (isNew) {
-        for (i = 0; i < Icc->TagCount; ++i) {
-            Icc->TagOffsets[i] += sizeof(icTag);
-        }
-    } else {
-        for (i = idx+1; i < Icc->TagCount; ++i) {
-            Icc->TagOffsets[i] += delta;
-        }
-    }
-
-    /* Write out a new tag table */
-    count = 0;
-    for (i = 0; i < Icc->TagCount; ++i) {
-        if (Icc->TagNames[i] != 0) {
-            ++count;
-        }
-    }
-    Icc->Seek(Icc, sizeof(icHeader));
-    temp = TransportValue32(count);
-    Icc->Write(Icc, sizeof(icUInt32Number), &temp);
-
-    for (i = 0; i < Icc->TagCount; ++i) {
-        if (Icc->TagNames[i] != 0) {
-            icTag tag;
-            tag.sig = TransportValue32(Icc->TagNames[i]);
-            tag.offset = TransportValue32((icInt32Number) Icc->TagOffsets[i]);
-            tag.size = TransportValue32((icInt32Number) Icc->TagSizes[i]);
-            Icc->Write(Icc, sizeof(icTag), &tag);
-        }
-    }
-
-    /* Write unchanged data before the modified tag */
-    if (beforeSize > 0) {
-        Icc->Write(Icc, beforeSize, beforeBuf);
-        free(beforeBuf);
-    }
-
-    /* Write modified tag data */
-    Icc->Write(Icc, size, data);
-    if (size % 4) {
-        Icc->Write(Icc, 4 - (size % 4), padChars);
-    }
-
-    /* Write unchanged data after the modified tag */
-    if (afterSize > 0) {
-        Icc->Write(Icc, afterSize, afterBuf);
-        free(afterBuf);
-    }
-
-    return TRUE;
+  return TRUE;
 }
--- a/src/share/native/sun/java2d/cmm/lcms/cmscam02.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmscam02.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -48,69 +49,65 @@
 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
 
-
+#include "lcms2_internal.h"
 
 // CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging.
 
-#include "lcms.h"
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC);
-LCMSAPI void       LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel);
-LCMSAPI void       LCMSEXPORT cmsCIECAM02Forward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void       LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn,    LPcmsCIEXYZ pOut);
-
-
 // ---------- Implementation --------------------------------------------
 
 typedef struct  {
 
-    double XYZ[3];
-    double RGB[3];
-    double RGBc[3];
-    double RGBp[3];
-    double RGBpa[3];
-    double a, b, h, e, H, A, J, Q, s, t, C, M;
-    double abC[2];
-    double abs[2];
-    double abM[2];
+    cmsFloat64Number XYZ[3];
+    cmsFloat64Number RGB[3];
+    cmsFloat64Number RGBc[3];
+    cmsFloat64Number RGBp[3];
+    cmsFloat64Number RGBpa[3];
+    cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M;
+    cmsFloat64Number abC[2];
+    cmsFloat64Number abs[2];
+    cmsFloat64Number abM[2];
 
-} CAM02COLOR, *LPCAM02COLOR;
+} CAM02COLOR;
 
 typedef struct  {
 
     CAM02COLOR adoptedWhite;
-    double LA, Yb;
-    double F, c, Nc;
-    int surround;
-    double n, Nbb, Ncb, z, FL, D;
+    cmsFloat64Number LA, Yb;
+    cmsFloat64Number F, c, Nc;
+    cmsUInt32Number surround;
+    cmsFloat64Number n, Nbb, Ncb, z, FL, D;
 
-} cmsCIECAM02, *LPcmsCIECAM02;
+       cmsContext ContextID;
+
+} cmsCIECAM02;
 
 
 static
-double compute_n(LPcmsCIECAM02 pMod)
+cmsFloat64Number compute_n(cmsCIECAM02* pMod)
 {
-    return(pMod -> Yb / pMod -> adoptedWhite.XYZ[1]);
+    return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]);
 }
 
 static
-double compute_z(LPcmsCIECAM02 pMod)
+cmsFloat64Number compute_z(cmsCIECAM02* pMod)
 {
-    return(1.48 + pow(pMod -> n, 0.5));
+    return (1.48 + pow(pMod -> n, 0.5));
 }
 
 static
-double computeNbb(LPcmsCIECAM02 pMod)
+cmsFloat64Number computeNbb(cmsCIECAM02* pMod)
 {
-    return(0.725 * pow((1.0 / pMod -> n), 0.2));
+    return (0.725 * pow((1.0 / pMod -> n), 0.2));
 }
 
 static
-double computeFL(LPcmsCIECAM02 pMod)
+cmsFloat64Number computeFL(cmsCIECAM02* pMod)
 {
-    double k, FL;
+    cmsFloat64Number k, FL;
 
     k = 1.0 / ((5.0 * pMod->LA) + 1.0);
     FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 *
@@ -121,9 +118,9 @@
 }
 
 static
-double computeD(LPcmsCIECAM02 pMod)
+cmsFloat64Number computeD(cmsCIECAM02* pMod)
 {
-    double D;
+    cmsFloat64Number D;
 
     D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0)));
 
@@ -142,9 +139,10 @@
 }
 
 static
-CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
 {
-    int i;
+    cmsUInt32Number i;
+
     for (i = 0; i < 3; i++) {
         clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] *
             (pMod->D / pMod -> adoptedWhite.RGB[i])) +
@@ -156,11 +154,9 @@
 
 
 static
-CAM02COLOR CAT02toHPE (CAM02COLOR clr)
+CAM02COLOR CAT02toHPE(CAM02COLOR clr)
 {
-
-    double M[9];
-
+    cmsFloat64Number M[9];
 
     M[0] =(( 0.38971 *  1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628));
     M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698));
@@ -180,10 +176,10 @@
 }
 
 static
-CAM02COLOR NonlinearCompression(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod)
 {
-    int i;
-    double temp;
+    cmsUInt32Number i;
+    cmsFloat64Number temp;
 
     for (i = 0; i < 3; i++) {
         if (clr.RGBp[i] < 0) {
@@ -204,9 +200,9 @@
 }
 
 static
-CAM02COLOR ComputeCorrelates(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
 {
-    double a, b, temp, e, t, r2d, d2r;
+    cmsFloat64Number a, b, temp, e, t, r2d, d2r;
 
     a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0);
     b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0;
@@ -274,10 +270,10 @@
 
 
 static
-CAM02COLOR InverseCorrelates(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
 {
 
-    double t, e, p1, p2, p3, p4, p5, hr, d2r;
+    cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r;
     d2r = 3.141592654 / 180.0;
 
     t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) *
@@ -327,10 +323,10 @@
 }
 
 static
-CAM02COLOR InverseNonlinearity(CAM02COLOR clr, LPcmsCIECAM02 pMod)
+CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod)
 {
-    int i;
-    double c1;
+    cmsUInt32Number i;
+    cmsFloat64Number c1;
 
     for (i = 0; i < 3; i++) {
         if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1;
@@ -347,7 +343,7 @@
 static
 CAM02COLOR HPEtoCAT02(CAM02COLOR clr)
 {
-    double M[9];
+    cmsFloat64Number M[9];
 
     M[0] = (( 0.7328 *  1.910197) + (0.4296 * 0.370950));
     M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054));
@@ -362,19 +358,19 @@
     clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]);
     clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]);
     clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]);
-    return (clr);
+    return clr;
 }
 
 
 static
-CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr,  LPcmsCIECAM02 pMod)
+CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr,  cmsCIECAM02* pMod)
 {
-    int i;
+    cmsUInt32Number i;
     for (i = 0; i < 3; i++) {
         clr.RGB[i] = clr.RGBc[i] /
             ((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D);
     }
-    return(clr);
+    return clr;
 }
 
 
@@ -385,23 +381,21 @@
     clr.XYZ[1] = (clr.RGB[0] *  0.454369) + (clr.RGB[1] *  0.473533) + (clr.RGB[2] *  0.072098);
     clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] *  1.015326);
 
-    return(clr);
+    return clr;
 }
 
 
+cmsHANDLE  CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC)
+{
+    cmsCIECAM02* lpMod;
 
+    _cmsAssert(pVC != NULL);
 
-LCMSHANDLE LCMSEXPORT cmsCIECAM02Init(LPcmsViewingConditions pVC)
-{
-    LPcmsCIECAM02 lpMod;
-
-
-   if((lpMod = (LPcmsCIECAM02) _cmsMalloc(sizeof(cmsCIECAM02))) == NULL) {
-        return (LCMSHANDLE) NULL;
+    if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) {
+        return NULL;
     }
 
-
-    ZeroMemory(lpMod, sizeof(cmsCIECAM02));
+    lpMod ->ContextID = ContextID;
 
     lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X;
     lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y;
@@ -414,36 +408,30 @@
 
     switch (lpMod -> surround) {
 
-    case AVG_SURROUND_4:
-        lpMod->F = 1.0;     // Not included in CAM02
-        lpMod->c = 0.69;
-        lpMod->Nc = 1.0;
-        break;
 
-    case CUTSHEET_SURROUND:
-        lpMod->F = 0.8;
-        lpMod->c = 0.41;
-        lpMod->Nc = 0.8;
-        break;
+      case CUTSHEET_SURROUND:
+          lpMod->F = 0.8;
+          lpMod->c = 0.41;
+          lpMod->Nc = 0.8;
+          break;
 
-    case DARK_SURROUND:
-        lpMod -> F  = 0.8;
-        lpMod -> c  = 0.525;
-        lpMod -> Nc = 0.8;
-        break;
+      case DARK_SURROUND:
+          lpMod -> F  = 0.8;
+          lpMod -> c  = 0.525;
+          lpMod -> Nc = 0.8;
+          break;
 
+      case DIM_SURROUND:
+          lpMod -> F  = 0.9;
+          lpMod -> c  = 0.59;
+          lpMod -> Nc = 0.95;
+          break;
 
-    case DIM_SURROUND:
-        lpMod -> F  = 0.9;
-        lpMod -> c  = 0.59;
-        lpMod -> Nc = 0.95;
-        break;
-
-    default:
-        // Average surround
-        lpMod -> F  = 1.0;
-        lpMod -> c  = 0.69;
-        lpMod -> Nc = 1.0;
+      default:
+          // Average surround
+          lpMod -> F  = 1.0;
+          lpMod -> c  = 0.69;
+          lpMod -> Nc = 1.0;
     }
 
     lpMod -> n   = compute_n(lpMod);
@@ -451,10 +439,8 @@
     lpMod -> Nbb = computeNbb(lpMod);
     lpMod -> FL  = computeFL(lpMod);
 
-    if (lpMod -> D == D_CALCULATE ||
-        lpMod -> D == D_CALCULATE_DISCOUNT) {
-
-    lpMod -> D   = computeD(lpMod);
+    if (lpMod -> D == D_CALCULATE) {
+        lpMod -> D   = computeD(lpMod);
     }
 
     lpMod -> Ncb = lpMod -> Nbb;
@@ -464,21 +450,26 @@
     lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite);
     lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod);
 
-    return (LCMSHANDLE) lpMod;
+    return (cmsHANDLE) lpMod;
 
 }
 
-void LCMSEXPORT cmsCIECAM02Done(LCMSHANDLE hModel)
+void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel)
 {
-    LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel;
-    if (lpMod) _cmsFree(lpMod);
+    cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
+
+    if (lpMod) _cmsFree(lpMod ->ContextID, lpMod);
 }
 
 
-void LCMSEXPORT cmsCIECAM02Forward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut)
+void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut)
 {
     CAM02COLOR clr;
-    LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel;
+    cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
+
+    _cmsAssert(lpMod != NULL);
+    _cmsAssert(pIn != NULL);
+    _cmsAssert(pOut != NULL);
 
     clr.XYZ[0] = pIn ->X;
     clr.XYZ[1] = pIn ->Y;
@@ -495,11 +486,14 @@
     pOut ->h = clr.h;
 }
 
-void LCMSEXPORT cmsCIECAM02Reverse(LCMSHANDLE hModel, LPcmsJCh pIn, LPcmsCIEXYZ pOut)
+void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut)
 {
     CAM02COLOR clr;
-    LPcmsCIECAM02 lpMod = (LPcmsCIECAM02) (LPSTR) hModel;
+    cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
 
+    _cmsAssert(lpMod != NULL);
+    _cmsAssert(pIn != NULL);
+    _cmsAssert(pOut != NULL);
 
     clr.J = pIn -> J;
     clr.C = pIn -> C;
@@ -514,6 +508,5 @@
     pOut ->X = clr.XYZ[0];
     pOut ->Y = clr.XYZ[1];
     pOut ->Z = clr.XYZ[2];
-
 }
 
--- a/src/share/native/sun/java2d/cmm/lcms/cmscam97.c	Tue Sep 07 16:54:39 2010 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,750 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// This file is available under and governed by the GNU General Public
-// License version 2 only, as published by the Free Software Foundation.
-// However, the following notice accompanied the original version of this
-// file:
-//
-//
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software
-// is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-#include "lcms.h"
-
-
-/*
-typedef struct {
-               double J;
-               double C;
-               double h;
-
-               } cmsJCh, FAR* LPcmsJCh;
-
-
-#define AVG_SURROUND_4     0
-#define AVG_SURROUND       1
-#define DIM_SURROUND       2
-#define DARK_SURROUND      3
-#define CUTSHEET_SURROUND  4
-
-
-typedef struct {
-
-              cmsCIEXYZ whitePoint;
-              double    Yb;
-              double    La;
-              int       surround;
-              double    D_value;
-
-              } cmsViewingConditions, FAR* LPcmsViewingConditions;
-
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC);
-LCMSAPI void   LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel);
-LCMSAPI void   LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ pIn, LPcmsJCh pOut);
-LCMSAPI void   LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh pIn,    LPcmsCIEXYZ pOut);
-
-*/
-
-// ---------- Implementation --------------------------------------------
-
-// #define USE_CIECAM97s2  1
-
-#ifdef USE_CIECAM97s2
-
-#       define NOISE_CONSTANT   3.05
-#else
-#       define NOISE_CONSTANT   2.05
-#endif
-
-
-/*
-  The model input data are the adapting field luminance in cd/m2
-  (normally taken to be 20% of the luminance of white in the adapting field),
-  LA , the relative tristimulus values of the stimulus, XYZ, the relative
-  tristimulus values of white in the same viewing conditions, Xw Yw Zw ,
-  and the relative luminance of the background, Yb . Relative tristimulus
-  values should be expressed on a scale from Y = 0 for a perfect black
-  to Y = 100 for a perfect reflecting diffuser. Additionally, the
-  parameters c, for the impact of surround, Nc , a chromatic induction factor,
-  and F, a factor for degree of adaptation, must be selected according to the
-  guidelines in table
-
-  All CIE tristimulus values are obtained using the CIE 1931
-  Standard Colorimetric Observer (2).
-
-*/
-
-typedef struct {
-
-    cmsCIEXYZ WP;
-    int surround;
-    int calculate_D;
-
-    double  Yb;         // rel. luminance of background
-
-    cmsCIEXYZ RefWhite;
-
-    double La;    // The adapting field luminance in cd/m2
-
-    double c;     // Impact of surround
-    double Nc;    // Chromatic induction factor
-    double Fll;   // Lightness contrast factor (Removed on rev 2)
-    double F;     // Degree of adaptation
-
-
-    double k;
-    double Fl;
-
-    double Nbb;  // The background and chromatic brightness induction factors.
-    double Ncb;
-    double z;    // base exponential nonlinearity
-    double n;    // background induction factor
-    double D;
-
-    MAT3 MlamRigg;
-    MAT3 MlamRigg_1;
-
-    MAT3 Mhunt;
-    MAT3 Mhunt_1;
-
-    MAT3 Mhunt_x_MlamRigg_1;
-    MAT3 MlamRigg_x_Mhunt_1;
-
-
-    VEC3 RGB_subw;
-    VEC3 RGB_subw_prime;
-
-    double p;
-
-    VEC3 RGB_subwc;
-
-    VEC3 RGB_subaw_prime;
-    double A_subw;
-    double Q_subw;
-
-    } cmsCIECAM97s,FAR *LPcmsCIECAM97s;
-
-
-
-// Free model structure
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sDone(LCMSHANDLE hModel)
-{
-    LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
-    if (lpMod) _cmsFree(lpMod);
-}
-
-// Partial discounting for adaptation degree computation
-
-static
-double discount(double d, double chan)
-{
-    return (d * chan + 1 - d);
-}
-
-
-// This routine does model exponential nonlinearity on the short wavelenght
-// sensitive channel. On CIECAM97s rev 2 this has been reverted to linear.
-
-static
-void FwAdaptationDegree(LPcmsCIECAM97s lpMod, LPVEC3 RGBc, LPVEC3 RGB)
-{
-
-
-#ifdef USE_CIECAM97s2
-    RGBc->n[0] = RGB->n[0]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[1]);
-    RGBc->n[2] = RGB->n[2]* discount(lpMod->D, 100.0/lpMod->RGB_subw.n[2]);
-#else
-
-    RGBc->n[0] = RGB->n[0]* discount(lpMod->D, 1.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]* discount(lpMod->D, 1.0/lpMod->RGB_subw.n[1]);
-
-    RGBc->n[2] = pow(fabs(RGB->n[2]), lpMod ->p) * discount(lpMod->D, (1.0/pow(lpMod->RGB_subw.n[2], lpMod->p)));
-
-    // If B happens to be negative, Then Bc is also set to be negative
-
-    if (RGB->n[2] < 0)
-           RGBc->n[2] = -RGBc->n[2];
-#endif
-}
-
-
-static
-void RvAdaptationDegree(LPcmsCIECAM97s lpMod, LPVEC3 RGBc, LPVEC3 RGB)
-{
-
-
-#ifdef USE_CIECAM97s2
-    RGBc->n[0] = RGB->n[0]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[1]);
-    RGBc->n[2] = RGB->n[2]/discount(lpMod->D, 100.0/lpMod->RGB_subw.n[2]);
-#else
-
-    RGBc->n[0] = RGB->n[0]/discount(lpMod->D, 1.0/lpMod->RGB_subw.n[0]);
-    RGBc->n[1] = RGB->n[1]/discount(lpMod->D, 1.0/lpMod->RGB_subw.n[1]);
-    RGBc->n[2] = pow(fabs(RGB->n[2]), 1.0/lpMod->p)/pow(discount(lpMod->D, 1.0/pow(lpMod->RGB_subw.n[2], lpMod->p)), 1.0/lpMod->p);
-    if (RGB->n[2] < 0)
-           RGBc->n[2] = -RGBc->n[2];
-#endif
-}
-
-
-
-static
-void PostAdaptationConeResponses(LPcmsCIECAM97s lpMod, LPVEC3 RGBa_prime, LPVEC3 RGBprime)
-{
-     if (RGBprime->n[0]>=0.0) {
-
-            RGBa_prime->n[0]=((40.0*pow(lpMod -> Fl * RGBprime->n[0]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[0]/100.0, 0.73)+2))+1;
-     }
-     else
-     {
-            RGBa_prime->n[0]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[0])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[0])/100.0, 0.73)+2))+1;
-     }
-
-     if (RGBprime->n[1]>=0.0)
-     {
-            RGBa_prime->n[1]=((40.0*pow(lpMod -> Fl * RGBprime->n[1]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[1]/100.0, 0.73)+2))+1;
-     }
-     else
-     {
-            RGBa_prime->n[1]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[1])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[1])/100.0, 0.73)+2))+1;
-     }
-
-     if (RGBprime->n[2]>=0.0)
-     {
-            RGBa_prime->n[2]=((40.0*pow(lpMod -> Fl * RGBprime->n[2]/100.0, 0.73))/(pow(lpMod -> Fl * RGBprime->n[2]/100.0, 0.73)+2))+1;
-     }
-     else
-     {
-            RGBa_prime->n[2]=((-40.0*pow((-lpMod -> Fl * RGBprime->n[2])/100.0, 0.73))/(pow((-lpMod -> Fl * RGBprime->n[2])/100.0, 0.73)+2))+1;
-     }
-}
-
-
-// Compute hue quadrature, eccentricity factor, e
-
-static
-void ComputeHueQuadrature(double h, double* H, double* e)
-{
-
-
-#define IRED    0
-#define IYELLOW 1
-#define IGREEN  2
-#define IBLUE   3
-
-      double e_tab[] = {0.8, 0.7, 1.0, 1.2};
-      double H_tab[] = {  0, 100, 200, 300};
-      int p1, p2;
-      double e1, e2, h1, h2;
-
-
-       if (h >= 20.14 && h < 90.0) { // Red
-
-                        p1 = IRED;
-                        p2 = IYELLOW;
-       }
-       else
-       if (h >= 90.0 && h < 164.25) { // Yellow
-
-                        p1 = IYELLOW;
-                        p2 = IGREEN;
-       }
-       else
-       if (h >= 164.25 && h < 237.53) { // Green
-
-                        p1 = IGREEN;
-                        p2 = IBLUE;       }
-       else {                         // Blue
-
-                        p1 = IBLUE;
-                        p2 = IRED;
-       }
-
-       e1 = e_tab[p1]; e2 = e_tab[p2];
-       h1 = H_tab[p1]; h2 = H_tab[p2];
-
-
-
-       *e = e1 + ((e2-e1)*(h-h1)/(h2 - h1));
-       *H = h1 + (100. * (h - h1) / e1) / ((h - h1)/e1 + (h2 - h) / e2);
-
-#undef IRED
-#undef IYELLOW
-#undef IGREEN
-#undef IBLUE
-
-}
-
-
-
-
-
-
-LCMSAPI LCMSHANDLE LCMSEXPORT cmsCIECAM97sInit(LPcmsViewingConditions pVC)
-{
-    LPcmsCIECAM97s lpMod;
-    VEC3 tmp;
-
-    if((lpMod = (LPcmsCIECAM97s) _cmsMalloc(sizeof(cmsCIECAM97s))) == NULL) {
-        return (LCMSHANDLE) NULL;
-    }
-
-
-    lpMod->WP.X = pVC->whitePoint.X;
-    lpMod->WP.Y = pVC->whitePoint.Y;
-    lpMod->WP.Z = pVC->whitePoint.Z;
-
-    lpMod->Yb   = pVC->Yb;
-    lpMod->La   = pVC->La;
-
-    lpMod->surround = pVC->surround;
-
-    lpMod->RefWhite.X = 100.0;
-    lpMod->RefWhite.Y = 100.0;
-    lpMod->RefWhite.Z = 100.0;
-
-#ifdef USE_CIECAM97s2
-
-    VEC3init(&lpMod->MlamRigg.v[0],  0.8562, 0.3372, -0.1934);
-    VEC3init(&lpMod->MlamRigg.v[1], -0.8360, 1.8327,  0.0033);
-    VEC3init(&lpMod->MlamRigg.v[2],  0.0357,-0.0469,  1.0112);
-
-    VEC3init(&lpMod->MlamRigg_1.v[0], 0.9874, -0.1768, 0.1894);
-    VEC3init(&lpMod->MlamRigg_1.v[1], 0.4504,  0.4649, 0.0846);
-    VEC3init(&lpMod->MlamRigg_1.v[2],-0.0139,  0.0278, 0.9861);
-
-#else
-    // Bradford transform: Lam-Rigg cone responses
-    VEC3init(&lpMod->MlamRigg.v[0],  0.8951,  0.2664, -0.1614);
-    VEC3init(&lpMod->MlamRigg.v[1], -0.7502,  1.7135,  0.0367);
-    VEC3init(&lpMod->MlamRigg.v[2],  0.0389, -0.0685,  1.0296);
-
-
-    // Inverse of Lam-Rigg
-    VEC3init(&lpMod->MlamRigg_1.v[0],  0.98699, -0.14705,  0.15996);
-    VEC3init(&lpMod->MlamRigg_1.v[1],  0.43231,  0.51836,  0.04929);
-    VEC3init(&lpMod->MlamRigg_1.v[2], -0.00853,  0.04004,  0.96849);
-
-#endif
-
-    // Hunt-Pointer-Estevez cone responses
-    VEC3init(&lpMod->Mhunt.v[0],   0.38971,  0.68898, -0.07868);
-    VEC3init(&lpMod->Mhunt.v[1],  -0.22981,  1.18340,  0.04641);
-    VEC3init(&lpMod->Mhunt.v[2],   0.0,      0.0,      1.0);
-
-    // Inverse of Hunt-Pointer-Estevez
-    VEC3init(&lpMod->Mhunt_1.v[0],     1.91019, -1.11214, 0.20195);
-    VEC3init(&lpMod->Mhunt_1.v[1],     0.37095,  0.62905, 0.0);
-    VEC3init(&lpMod->Mhunt_1.v[2],     0.0,      0.0,     1.0);
-
-
-    if (pVC->D_value == -1.0)
-          lpMod->calculate_D = 1;
-    else
-    if (pVC->D_value == -2.0)
-           lpMod->calculate_D = 2;
-    else {
-        lpMod->calculate_D = 0;
-        lpMod->D = pVC->D_value;
-    }
-
-   // Table I (revised)
-
-   switch (lpMod->surround) {
-
-    case AVG_SURROUND_4:
-       lpMod->F = 1.0;
-       lpMod->c = 0.69;
-       lpMod->Fll = 0.0;    // Not included on Rev 2
-       lpMod->Nc = 1.0;
-       break;
-    case AVG_SURROUND:
-       lpMod->F = 1.0;
-       lpMod->c = 0.69;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 1.0;
-       break;
-    case DIM_SURROUND:
-       lpMod->F = 0.99;
-       lpMod->c = 0.59;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 0.95;
-       break;
-    case DARK_SURROUND:
-       lpMod->F = 0.9;
-       lpMod->c = 0.525;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 0.8;
-       break;
-    case CUTSHEET_SURROUND:
-       lpMod->F = 0.9;
-       lpMod->c = 0.41;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 0.8;
-       break;
-    default:
-       lpMod->F = 1.0;
-       lpMod->c = 0.69;
-       lpMod->Fll = 1.0;
-       lpMod->Nc = 1.0;
-       break;
-    }
-
-    lpMod->k = 1 / (5 * lpMod->La  + 1);
-    lpMod->Fl = lpMod->La * pow(lpMod->k, 4) + 0.1*pow(1 - pow(lpMod->k, 4), 2.0) * pow(5*lpMod->La, 1.0/3.0);
-
-    if (lpMod->calculate_D > 0) {
-
-       lpMod->D = lpMod->F * (1 - 1 / (1 + 2*pow(lpMod->La, 0.25) + pow(lpMod->La, 2)/300.0));
-       if (lpMod->calculate_D > 1)
-           lpMod->D = (lpMod->D + 1.0) / 2;
-    }
-
-
-    // RGB_subw = [MlamRigg][WP/YWp]
-#ifdef USE_CIECAM97s2
-    MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &lpMod -> WP);
-#else
-    VEC3divK(&tmp, (LPVEC3) &lpMod -> WP, lpMod->WP.Y);
-    MAT3eval(&lpMod -> RGB_subw, &lpMod -> MlamRigg, &tmp);
-#endif
-
-
-
-    MAT3per(&lpMod -> Mhunt_x_MlamRigg_1,   &lpMod -> Mhunt,   &lpMod->MlamRigg_1  );
-    MAT3per(&lpMod -> MlamRigg_x_Mhunt_1,   &lpMod -> MlamRigg, &lpMod -> Mhunt_1  );
-
-    // p is used on forward model
-    lpMod->p = pow(lpMod->RGB_subw.n[2], 0.0834);
-
-    FwAdaptationDegree(lpMod, &lpMod->RGB_subwc, &lpMod->RGB_subw);
-
-#if USE_CIECAM97s2
-    MAT3eval(&lpMod->RGB_subw_prime, &lpMod->Mhunt_x_MlamRigg_1, &lpMod -> RGB_subwc);
-#else
-    VEC3perK(&tmp, &lpMod -> RGB_subwc, lpMod->WP.Y);
-    MAT3eval(&lpMod->RGB_subw_prime, &lpMod->Mhunt_x_MlamRigg_1, &tmp);
-#endif
-
-    lpMod->n = lpMod-> Yb / lpMod-> WP.Y;
-
-    lpMod->z = 1 + lpMod->Fll * sqrt(lpMod->n);
-    lpMod->Nbb = lpMod->Ncb = 0.725 / pow(lpMod->n, 0.2);
-
-    PostAdaptationConeResponses(lpMod, &lpMod->RGB_subaw_prime, &lpMod->RGB_subw_prime);
-
-    lpMod->A_subw=lpMod->Nbb*(2.0*lpMod->RGB_subaw_prime.n[0]+lpMod->RGB_subaw_prime.n[1]+lpMod->RGB_subaw_prime.n[2]/20.0-NOISE_CONSTANT);
-
-    return (LCMSHANDLE) lpMod;
-}
-
-
-
-
-//
-// The forward model: XYZ -> JCh
-//
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sForward(LCMSHANDLE hModel, LPcmsCIEXYZ inPtr, LPcmsJCh outPtr)
-{
-
-        LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
-        double a, b, h, s, H1val, es, A;
-        VEC3 In, RGB, RGBc, RGBprime, RGBa_prime;
-
-        if (inPtr -> Y <= 0.0) {
-
-      outPtr -> J = outPtr -> C = outPtr -> h = 0.0;
-          return;
-        }
-
-       // An initial chromatic adaptation transform is used to go from the source
-       // viewing conditions to corresponding colours under the equal-energy-illuminant
-       // reference viewing conditions. This is handled differently on rev 2
-
-       VEC3init(&In, inPtr -> X, inPtr -> Y, inPtr -> Z);    // 2.1
-
-#ifdef USE_CIECAM97s2
-       // Since the chromatic adaptation transform has been linearized, it
-       // is no longer required to divide the stimulus tristimulus values
-       // by their own Y tristimulus value prior to the chromatic adaptation.
-#else
-       VEC3divK(&In, &In, inPtr -> Y);
-#endif
-
-       MAT3eval(&RGB, &lpMod -> MlamRigg, &In);              // 2.2
-
-       FwAdaptationDegree(lpMod, &RGBc, &RGB);
-
-       // The post-adaptation signals for both the sample and the white are then
-       // transformed from the sharpened cone responses to the Hunt-Pointer-Estevez
-       // cone responses.
-#ifdef USE_CIECAM97s2
-#else
-       VEC3perK(&RGBc, &RGBc, inPtr->Y);
-#endif
-
-       MAT3eval(&RGBprime, &lpMod->Mhunt_x_MlamRigg_1, &RGBc);
-
-       // The post-adaptation cone responses (for both the stimulus and the white)
-       // are then calculated.
-
-       PostAdaptationConeResponses(lpMod, &RGBa_prime, &RGBprime);
-
-       // Preliminary red-green and yellow-blue opponent dimensions are calculated
-
-       a = RGBa_prime.n[0] - (12.0 * RGBa_prime.n[1] / 11.0) + RGBa_prime.n[2]/11.0;
-       b = (RGBa_prime.n[0] + RGBa_prime.n[1] - 2.0 * RGBa_prime.n[2]) / 9.0;
-
-
-       // The CIECAM97s hue angle, h, is then calculated
-       h = (180.0/M_PI)*(atan2(b, a));
-
-
-       while (h < 0)
-              h += 360.0;
-
-       outPtr->h = h;
-
-       // hue quadrature and eccentricity factors, e, are calculated
-
-       ComputeHueQuadrature(h, &H1val, &es);
-
-       // ComputeHueQuadrature(h, &H1val, &h1, &e1, &h2, &e2, &es);
-
-
-      // The achromatic response A
-      A = lpMod->Nbb * (2.0 * RGBa_prime.n[0] + RGBa_prime.n[1] + RGBa_prime.n[2]/20.0 - NOISE_CONSTANT);
-
-      // CIECAM97s Lightness J
-      outPtr -> J = 100.0 * pow(A / lpMod->A_subw, lpMod->c * lpMod->z);
-
-      // CIECAM97s saturation s
-      s =  (50 * hypot (a, b) * 100 * es * (10.0/13.0) * lpMod-> Nc * lpMod->Ncb) / (RGBa_prime.n[0] + RGBa_prime.n[1] + 1.05 * RGBa_prime.n[2]);
-
-      // CIECAM97s Chroma C
-
-#ifdef USE_CIECAM97s2
-      // Eq. 26 has been modified to allow accurate prediction of the Munsell chroma scales.
-      outPtr->C = 0.7487 * pow(s, 0.973) * pow(outPtr->J/100.0, 0.945 * lpMod->n) * (1.64 - pow(0.29, lpMod->n));
-
-#else
-      outPtr->C = 2.44 * pow(s, 0.69) * pow(outPtr->J/100.0, 0.67 * lpMod->n) * (1.64 - pow(0.29, lpMod->n));
-#endif
-}
-
-
-//
-// The reverse model JCh -> XYZ
-//
-
-
-LCMSAPI void LCMSEXPORT cmsCIECAM97sReverse(LCMSHANDLE hModel, LPcmsJCh inPtr, LPcmsCIEXYZ outPtr)
-{
-    LPcmsCIECAM97s lpMod = (LPcmsCIECAM97s) (LPSTR) hModel;
-    double J, C, h, A, H1val, es, s, a, b;
-    double tan_h, sec_h;
-    double R_suba_prime, G_suba_prime, B_suba_prime;
-    double R_prime, G_prime, B_prime;
-    double Y_subc, Y_prime, B_term;
-    VEC3 tmp;
-    VEC3 RGB_prime, RGB_subc_Y;
-    VEC3 Y_over_Y_subc_RGB;
-    VEC3 XYZ_primeprime_over_Y_subc;
-#ifdef USE_CIECAM92s2
-    VEC3 RGBY;
-    VEC3 Out;
-#endif
-
-    J = inPtr->J;
-    h = inPtr->h;
-    C = inPtr->C;
-
-    if (J <= 0) {
-
-        outPtr->X =  0.0;
-        outPtr->Y =  0.0;
-        outPtr->Z =  0.0;
-        return;
-    }
-
-
-
-    // (2) From J Obtain A
-
-    A =  pow(J/100.0, 1/(lpMod->c * lpMod->z)) * lpMod->A_subw;
-
-
-    // (3), (4), (5) Using H Determine h1, h2, e1, e2
-    // e1 and h1 are the values  of e and h for the unique hue having the
-    // nearest lower valur of h and e2 and h2 are the values of e and h for
-    // the unique hue having the nearest higher value of h.
-
-
-    ComputeHueQuadrature(h, &H1val, &es);
-
-    // (7) Calculate s
-
-    s = pow(C / (2.44 * pow(J/100.0, 0.67*lpMod->n) * (1.64 - pow(0.29, lpMod->n))) , (1./0.69));
-
-
-    // (8) Calculate a and b.
-    // NOTE: sqrt(1 + tan^2) == sec(h)
-
-    tan_h = tan ((M_PI/180.)*(h));
-    sec_h = sqrt(1 + tan_h * tan_h);
-
-    if ((h > 90) && (h < 270))
-            sec_h = -sec_h;
-
-    a = s * ( A/lpMod->Nbb + NOISE_CONSTANT) / ( sec_h * 50000.0 * es * lpMod->Nc * lpMod->Ncb/ 13.0 +
-           s * (11.0 / 23.0 + (108.0/23.0) * tan_h));
-
-    b = a * tan_h;
-
-    //(9) Calculate R'a G'a and B'a
-
-    R_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) + (41.0/61.0) * (11.0/23.0) * a + (288.0/61.0) / 23.0 * b;
-    G_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) - (81.0/61.0) * (11.0/23.0) * a - (261.0/61.0) / 23.0 * b;
-    B_suba_prime = (20.0/61.0) * (A/lpMod->Nbb + NOISE_CONSTANT) - (20.0/61.0) * (11.0/23.0) * a - (20.0/61.0) * (315.0/23.0) * b;
-
-    // (10) Calculate R', G' and B'
-
-    if ((R_suba_prime - 1) < 0) {
-
-         R_prime = -100.0 * pow((2.0 - 2.0 * R_suba_prime) /
-                            (39.0 + R_suba_prime), 1.0/0.73);
-    }
-    else
-    {
-         R_prime = 100.0 * pow((2.0 * R_suba_prime - 2.0) /
-                            (41.0 - R_suba_prime), 1.0/0.73);
-    }
-
-    if ((G_suba_prime - 1) < 0)
-    {
-         G_prime = -100.0 * pow((2.0 - 2.0 * G_suba_prime) /
-                            (39.0 + G_suba_prime), 1.0/0.73);
-    }
-    else
-    {
-         G_prime = 100.0 * pow((2.0 * G_suba_prime - 2.0) /
-                            (41.0 - G_suba_prime), 1.0/0.73);
-    }
-
-    if ((B_suba_prime - 1) < 0)
-    {
-         B_prime = -100.0 * pow((2.0 - 2.0 * B_suba_prime) /
-                            (39.0 + B_suba_prime), 1.0/0.73);
-    }
-    else
-    {
-         B_prime = 100.0 * pow((2.0 * B_suba_prime - 2.0) /
-                            (41.0 - B_suba_prime), 1.0/0.73);
-    }
-
-
-    // (11) Calculate RcY, GcY and BcY
-
-    VEC3init(&RGB_prime, R_prime, G_prime, B_prime);
-    VEC3divK(&tmp, &RGB_prime, lpMod -> Fl);
-
-    MAT3eval(&RGB_subc_Y, &lpMod->MlamRigg_x_Mhunt_1, &tmp);
-
-
-
-
-#ifdef USE_CIECAM97s2
-
-       // (12)
-
-
-           RvAdaptationDegree(lpMod, &RGBY, &RGB_subc_Y);
-           MAT3eval(&Out, &lpMod->MlamRigg_1, &RGBY);
-
-           outPtr -> X = Out.n[0];
-           outPtr -> Y = Out.n[1];
-           outPtr -> Z = Out.n[2];
-
-#else
-
-           // (12) Calculate Yc
-
-       Y_subc = 0.43231*RGB_subc_Y.n[0]+0.51836*RGB_subc_Y.n[1]+0.04929*RGB_subc_Y.n[2];
-
-           // (13) Calculate (Y/Yc)R, (Y/Yc)G and (Y/Yc)B
-
-           VEC3divK(&RGB_subc_Y, &RGB_subc_Y, Y_subc);
-           RvAdaptationDegree(lpMod, &Y_over_Y_subc_RGB, &RGB_subc_Y);
-
-           // (14) Calculate Y'
-       Y_prime = 0.43231*(Y_over_Y_subc_RGB.n[0]*Y_subc) + 0.51836*(Y_over_Y_subc_RGB.n[1]*Y_subc) + 0.04929 * (Y_over_Y_subc_RGB.n[2]*Y_subc);
-
-           if (Y_prime < 0 || Y_subc < 0)
-           {
-                // Discard to near black point
-
-                outPtr -> X = 0;
-                outPtr -> Y = 0;
-                outPtr -> Z = 0;
-                return;
-           }
-
-       B_term = pow(Y_prime / Y_subc, (1.0 / lpMod->p) - 1);
-
-          // (15) Calculate X'', Y'' and Z''
-           Y_over_Y_subc_RGB.n[2] /= B_term;
-           MAT3eval(&XYZ_primeprime_over_Y_subc, &lpMod->MlamRigg_1, &Y_over_Y_subc_RGB);
-
-           outPtr->X =  XYZ_primeprime_over_Y_subc.n[0] * Y_subc;
-           outPtr->Y =  XYZ_primeprime_over_Y_subc.n[1] * Y_subc;
-           outPtr->Z =  XYZ_primeprime_over_Y_subc.n[2] * Y_subc;
-#endif
-
-}
--- a/src/share/native/sun/java2d/cmm/lcms/cmscgats.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmscgats.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -49,104 +50,30 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// IT8.7 / CGATS.17-200x handling
-
-#include "lcms.h"
-
-
-LCMSAPI LCMSHANDLE      LCMSEXPORT cmsIT8Alloc(void);
-LCMSAPI void            LCMSEXPORT cmsIT8Free(LCMSHANDLE IT8);
-
-// Tables
-
-LCMSAPI int             LCMSEXPORT cmsIT8TableCount(LCMSHANDLE IT8);
-LCMSAPI int             LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable);
-
-// Persistence
-LCMSAPI LCMSHANDLE      LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName);
-LCMSAPI LCMSHANDLE      LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len);
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName);
-
-// Properties
-LCMSAPI const char*     LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8);
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* cComment);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* cProp, const char *Str);
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val);
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val);
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char* cSubProp, const char *Val);
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer);
-
-LCMSAPI const char*     LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* cProp);
-LCMSAPI double          LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp);
-LCMSAPI const char*     LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char *cSubProp);
-LCMSAPI int             LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE IT8, const char ***PropertyNames);
-LCMSAPI int             LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char*** SubpropertyNames);
-
-// Datasets
-
-LCMSAPI const char*     LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer);
-
-LCMSAPI const char*     LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE IT8, int row, int col);
-LCMSAPI double          LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE IT8, int col, int row);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col,
-                                                const char* Val);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col,
-                                                double Val);
-
-LCMSAPI const char*     LCMSEXPORT cmsIT8GetData(LCMSHANDLE IT8, const char* cPatch, const char* cSample);
-
-
-LCMSAPI double          LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetData(LCMSHANDLE IT8, const char* cPatch,
-                                                const char* cSample,
-                                                const char *Val);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch,
-                                                const char* cSample,
-                                                double Val);
-
-LCMSAPI LCMSBOOL        LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample);
-LCMSAPI int             LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames);
-
-LCMSAPI void            LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE IT8, const char* Formatter);
-
-LCMSAPI int             LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet,
-                                                                          const char* cField,
-                                                                          const char* ExpectedType);
-
-// ------------------------------------------------------------- Implementation
-
-
-#define SIZEOFLONGMINUS1    (sizeof(long)-1)
-#define ALIGNLONG(x) (((x)+SIZEOFLONGMINUS1) & ~(SIZEOFLONGMINUS1))
-
-// #define STRICT_CGATS  1
-
-#define MAXID       128     // Max lenght of identifier
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+
+// IT8.7 / CGATS.17-200x handling -----------------------------------------------------------------------------
+
+
+#define MAXID        128     // Max lenght of identifier
 #define MAXSTR      1024     // Max lenght of string
-#define MAXTABLES   255     // Max Number of tables in a single stream
-#define MAXINCLUDE   20     // Max number of nested includes
+#define MAXTABLES    255     // Max Number of tables in a single stream
+#define MAXINCLUDE    20     // Max number of nested includes
 
 #define DEFAULT_DBL_FORMAT  "%.10g" // Double formatting
 
-#include <ctype.h>
-#include <limits.h>
-
-#ifndef NON_WINDOWS
-#include <io.h>
-#define DIR_CHAR    '\\'
+#ifdef CMS_IS_WINDOWS_
+#    include <io.h>
+#    define DIR_CHAR    '\\'
 #else
-#define DIR_CHAR    '/'
+#    define DIR_CHAR    '/'
 #endif
 
 // Symbols
-
 typedef enum {
 
         SNONE,
@@ -173,8 +100,8 @@
 
 
 // How to write the value
-
 typedef enum {
+
         WRITE_UNCOOKED,
         WRITE_STRINGIFY,
         WRITE_HEXADECIMAL,
@@ -184,7 +111,6 @@
     } WRITEMODE;
 
 // Linked list of variable names
-
 typedef struct _KeyVal {
 
         struct _KeyVal*  Next;
@@ -194,108 +120,101 @@
         char*            Value;         // Points to value
         WRITEMODE        WriteAs;       // How to write the value
 
-   } KEYVALUE, *LPKEYVALUE;
+   } KEYVALUE;
 
 
 // Linked list of memory chunks (Memory sink)
-
 typedef struct _OwnedMem {
 
         struct _OwnedMem* Next;
         void *            Ptr;          // Point to value
 
-   } OWNEDMEM, *LPOWNEDMEM;
+   } OWNEDMEM;
 
 // Suballocator
-
 typedef struct _SubAllocator {
 
-         LPBYTE Block;
-         size_t BlockSize;
-         size_t Used;
-
-    } SUBALLOCATOR, *LPSUBALLOCATOR;
+         cmsUInt8Number* Block;
+         cmsUInt32Number BlockSize;
+         cmsUInt32Number Used;
+
+    } SUBALLOCATOR;
 
 // Table. Each individual table can hold properties and rows & cols
-
 typedef struct _Table {
 
         int            nSamples, nPatches;    // Cols, Rows
         int            SampleID;              // Pos of ID
 
-        LPKEYVALUE     HeaderList;            // The properties
+        KEYVALUE*      HeaderList;            // The properties
 
         char**         DataFormat;            // The binary stream descriptor
         char**         Data;                  // The binary stream
 
-    } TABLE, *LPTABLE;
+    } TABLE;
 
 // File stream being parsed
-
 typedef struct _FileContext {
-        char           FileName[MAX_PATH];    // File name if being readed from file
-        FILE*          Stream;                // File stream or NULL if holded in memory
-    } FILECTX, *LPFILECTX;
-
-// This struct hold all information about an openened
-// IT8 handler. Only one dataset is allowed.
-
+        char           FileName[cmsMAX_PATH];    // File name if being readed from file
+        FILE*          Stream;                   // File stream or NULL if holded in memory
+    } FILECTX;
+
+// This struct hold all information about an open IT8 handler.
 typedef struct {
 
-        char SheetType[MAXSTR];
-
-        int  TablesCount;                     // How many tables in this stream
-        int  nTable;                          // The actual table
+        char SheetType[MAXSTR];               // The first row of the IT8 (the type)
+
+        cmsUInt32Number  TablesCount;                     // How many tables in this stream
+        cmsUInt32Number  nTable;                          // The actual table
 
         TABLE Tab[MAXTABLES];
 
         // Memory management
-
-        LPOWNEDMEM     MemorySink;            // The storage backend
+        OWNEDMEM*      MemorySink;            // The storage backend
         SUBALLOCATOR   Allocator;             // String suballocator -- just to keep it fast
 
         // Parser state machine
-
         SYMBOL         sy;                    // Current symbol
         int            ch;                    // Current character
 
         int            inum;                  // integer value
-        double         dnum;                  // real value
+        cmsFloat64Number         dnum;                  // real value
         char           id[MAXID];             // identifier
         char           str[MAXSTR];           // string
 
         // Allowed keywords & datasets. They have visibility on whole stream
-
-        LPKEYVALUE     ValidKeywords;
-        LPKEYVALUE     ValidSampleID;
+        KEYVALUE*     ValidKeywords;
+        KEYVALUE*     ValidSampleID;
 
         char*          Source;                // Points to loc. being parsed
         int            lineno;                // line counter for error reporting
 
-        LPFILECTX      FileStack[MAXINCLUDE]; // Stack of files being parsed
+        FILECTX*       FileStack[MAXINCLUDE]; // Stack of files being parsed
         int            IncludeSP;             // Include Stack Pointer
 
         char*          MemoryBlock;           // The stream if holded in memory
 
-        char           DoubleFormatter[MAXID];   // Printf-like 'double' formatter
-
-   } IT8, *LPIT8;
-
-
-
+        char           DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter
+
+        cmsContext    ContextID;              // The threading context
+
+   } cmsIT8;
+
+
+// The stream for save operations
 typedef struct {
 
         FILE* stream;   // For save-to-file behaviour
 
-        LPBYTE Base;
-        LPBYTE Ptr;     // For save-to-mem behaviour
-        size_t Used;
-        size_t Max;
-
-    } SAVESTREAM, FAR* LPSAVESTREAM;
-
-
-// ------------------------------------------------------ IT8 parsing routines
+        cmsUInt8Number* Base;
+        cmsUInt8Number* Ptr;        // For save-to-mem behaviour
+        cmsUInt32Number Used;
+        cmsUInt32Number Max;
+
+    } SAVESTREAM;
+
+
+// ------------------------------------------------------ cmsIT8 parsing routines
 
 
 // A keyword
@@ -309,14 +228,15 @@
 // The keyword->symbol translation table. Sorting is required.
 static const KEYWORD TabKeys[] = {
 
-        {"$INCLUDE",            SINCLUDE},
-        {".INCLUDE",            SINCLUDE},
-        {"BEGIN_DATA",          SBEGIN_DATA },
-        {"BEGIN_DATA_FORMAT",   SBEGIN_DATA_FORMAT },
+        {"$INCLUDE",               SINCLUDE},   // This is an extension!
+        {".INCLUDE",               SINCLUDE},   // This is an extension!
+
+        {"BEGIN_DATA",             SBEGIN_DATA },
+        {"BEGIN_DATA_FORMAT",      SBEGIN_DATA_FORMAT },
         {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID},
-        {"END_DATA",            SEND_DATA},
-        {"END_DATA_FORMAT",     SEND_DATA_FORMAT},
-        {"KEYWORD",             SKEYWORD}
+        {"END_DATA",               SEND_DATA},
+        {"END_DATA_FORMAT",        SEND_DATA_FORMAT},
+        {"KEYWORD",                SKEYWORD}
         };
 
 #define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
@@ -325,8 +245,8 @@
 
 // A property
 typedef struct {
-        const char *id;
-        WRITEMODE as;
+        const char *id;    // The identifier
+        WRITEMODE as;      // How is supposed to be written
     } PROPERTY;
 
 static PROPERTY PredefinedProperties[] = {
@@ -366,7 +286,8 @@
 
         {"CHISQ_DOF",        WRITE_STRINGIFY},   // Degrees of freedom associated with the Chi squared statistic
 
-//    new in recent specs:
+       // below properties are new in recent specs:
+
         {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated
                                // along with details of the geometry and the aperture size and shape. For example,
                                // for transmission measurements it is important to identify 0/diffuse, diffuse/0,
@@ -438,9 +359,9 @@
         "LAB_B",          // b* component of Lab data
         "LAB_C",          // C*ab component of Lab data
         "LAB_H",          // hab component of Lab data
-        "LAB_DE",         //  CIE dE
-        "LAB_DE_94",      //  CIE dE using CIE 94
-        "LAB_DE_CMC",     //  dE using CMC
+        "LAB_DE",         // CIE dE
+        "LAB_DE_94",      // CIE dE using CIE 94
+        "LAB_DE_CMC",     // dE using CMC
         "LAB_DE_2000",    // CIE dE using CIE DE 2000
         "MEAN_DE",        // Mean Delta E (LAB_DE) of samples compared to batch average
                           // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets)
@@ -458,84 +379,94 @@
 #define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *))
 
 //Forward declaration of some internal functions
-static
-void* AllocChunk(LPIT8 it8, size_t size);
+static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size);
 
 // Checks if c is a separator
 static
-LCMSBOOL isseparator(int c)
+cmsBool isseparator(int c)
 {
         return (c == ' ') || (c == '\t') || (c == '\r');
 }
 
 // Checks whatever if c is a valid identifier char
 static
-LCMSBOOL ismiddle(int c)
+cmsBool ismiddle(int c)
 {
    return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127));
 }
 
 // Checks whatsever if c is a valid identifier middle char.
 static
-LCMSBOOL isidchar(int c)
+cmsBool isidchar(int c)
 {
    return isalnum(c) || ismiddle(c);
 }
 
 // Checks whatsever if c is a valid identifier first char.
 static
-LCMSBOOL isfirstidchar(int c)
+cmsBool isfirstidchar(int c)
 {
      return !isdigit(c) && ismiddle(c);
 }
 
-// checks whether the supplied path looks like an absolute path
-// NOTE: this function doesn't checks if the path exists or even if it's legal
+// Guess whether the supplied path looks like an absolute path
 static
-LCMSBOOL isabsolutepath(const char *path)
+cmsBool isabsolutepath(const char *path)
 {
+    char ThreeChars[4];
+
     if(path == NULL)
         return FALSE;
-
-    if(path[0] == DIR_CHAR)
+    if (path[0] == 0)
+        return FALSE;
+
+    strncpy(ThreeChars, path, 3);
+    ThreeChars[3] = 0;
+
+    if(ThreeChars[0] == DIR_CHAR)
         return TRUE;
 
-#ifndef NON_WINDOWS
-    if(isalpha(path[0]) && path[1] == ':')
+#ifdef  CMS_IS_WINDOWS_
+    if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':')
         return TRUE;
 #endif
     return FALSE;
 }
 
 // Makes a file path based on a given reference path
-// NOTE: buffer is assumed to point to at least MAX_PATH bytes
-// NOTE: both relPath and basePath are assumed to be no more than MAX_PATH characters long (including the null terminator!)
 // NOTE: this function doesn't check if the path exists or even if it's legal
 static
-LCMSBOOL _cmsMakePath(const char *relPath, const char *basePath, char *buffer)
+cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen)
 {
-    if (!isabsolutepath(relPath)) {
-
-        char *tail;
-
-        strncpy(buffer, basePath, MAX_PATH-1);
-        tail = strrchr(buffer, DIR_CHAR);
-        if (tail != NULL) {
-
-            size_t len = tail - buffer;
-            strncpy(tail + 1, relPath, MAX_PATH - len -1);
-            //  TODO: if combined path is longer than MAX_PATH, this should return FALSE!
-            return TRUE;
-        }
+    char *tail;
+    cmsUInt32Number len;
+
+    // Already absolute?
+    if (isabsolutepath(relPath)) {
+
+        strncpy(buffer, relPath, MaxLen);
+        buffer[MaxLen-1] = 0;
+        return TRUE;
     }
-    strncpy(buffer, relPath, MAX_PATH - 1);
-        buffer[MAX_PATH-1] = 0;
+
+    // No, search for last
+    strncpy(buffer, basePath, MaxLen);
+    buffer[MaxLen-1] = 0;
+
+    tail = strrchr(buffer, DIR_CHAR);
+    if (tail == NULL) return FALSE;    // Is not absolute and has no separators??
+
+    len = (cmsUInt32Number) (tail - buffer);
+    if (len >= MaxLen) return FALSE;
+
+    // No need to assure zero terminator over here
+    strncpy(tail + 1, relPath, MaxLen - len);
+
     return TRUE;
 }
 
 
 // Make sure no exploit is being even tried
-
 static
 const char* NoMeta(const char* str)
 {
@@ -545,40 +476,37 @@
     return str;
 }
 
-
 // Syntax error
 static
-LCMSBOOL SynError(LPIT8 it8, const char *Txt, ...)
+cmsBool SynError(cmsIT8* it8, const char *Txt, ...)
 {
-        char Buffer[256], ErrMsg[1024];
-        va_list args;
-
-        va_start(args, Txt);
-        vsnprintf(Buffer, 255, Txt, args);
-        Buffer[255] = 0;
-        va_end(args);
-
-        snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer);
-        ErrMsg[1023] = 0;
-        it8->sy = SSYNERROR;
-        cmsSignalError(LCMS_ERRC_ABORTED, "%s", ErrMsg);
-        return FALSE;
+    char Buffer[256], ErrMsg[1024];
+    va_list args;
+
+    va_start(args, Txt);
+    vsnprintf(Buffer, 255, Txt, args);
+    Buffer[255] = 0;
+    va_end(args);
+
+    snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer);
+    ErrMsg[1023] = 0;
+    it8->sy = SSYNERROR;
+    cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg);
+    return FALSE;
 }
 
 // Check if current symbol is same as specified. issue an error else.
 static
-LCMSBOOL Check(LPIT8 it8, SYMBOL sy, const char* Err)
+cmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err)
 {
         if (it8 -> sy != sy)
                 return SynError(it8, NoMeta(Err));
         return TRUE;
 }
 
-
-
 // Read Next character from stream
 static
-void NextCh(LPIT8 it8)
+void NextCh(cmsIT8* it8)
 {
     if (it8 -> FileStack[it8 ->IncludeSP]->Stream) {
 
@@ -594,9 +522,6 @@
             } else
                 it8 ->ch = 0;   // EOF
         }
-
-
-
     }
     else {
         it8->ch = *it8->Source;
@@ -609,100 +534,98 @@
 static
 SYMBOL BinSrchKey(const char *id)
 {
-        int l = 1;
-        int r = NUMKEYS;
-        int x, res;
-
-        while (r >= l)
-        {
-                x = (l+r)/2;
-                res = stricmp(id, TabKeys[x-1].id);
-                if (res == 0) return TabKeys[x-1].sy;
-                if (res < 0) r = x - 1;
-                else l = x + 1;
-        }
-
-        return SNONE;
+    int l = 1;
+    int r = NUMKEYS;
+    int x, res;
+
+    while (r >= l)
+    {
+        x = (l+r)/2;
+        res = cmsstrcasecmp(id, TabKeys[x-1].id);
+        if (res == 0) return TabKeys[x-1].sy;
+        if (res < 0) r = x - 1;
+        else l = x + 1;
+    }
+
+    return SNONE;
 }
 
 
 // 10 ^n
 static
-double xpow10(int n)
+cmsFloat64Number xpow10(int n)
 {
-    return pow(10, (double) n);
+    return pow(10, (cmsFloat64Number) n);
 }
 
 
 //  Reads a Real number, tries to follow from integer number
 static
-void ReadReal(LPIT8 it8, int inum)
+void ReadReal(cmsIT8* it8, int inum)
 {
-        it8->dnum = (double) inum;
-
-        while (isdigit(it8->ch)) {
+    it8->dnum = (cmsFloat64Number) inum;
+
+    while (isdigit(it8->ch)) {
 
         it8->dnum = it8->dnum * 10.0 + (it8->ch - '0');
         NextCh(it8);
+    }
+
+    if (it8->ch == '.') {        // Decimal point
+
+        cmsFloat64Number frac = 0.0;      // fraction
+        int prec = 0;           // precision
+
+        NextCh(it8);               // Eats dec. point
+
+        while (isdigit(it8->ch)) {
+
+            frac = frac * 10.0 + (it8->ch - '0');
+            prec++;
+            NextCh(it8);
         }
 
-        if (it8->ch == '.') {        // Decimal point
-
-                double frac = 0.0;      // fraction
-                int prec = 0;           // precission
-
-                NextCh(it8);               // Eats dec. point
-
-                while (isdigit(it8->ch)) {
-
-                        frac = frac * 10.0 + (it8->ch - '0');
-                        prec++;
-                        NextCh(it8);
-                }
-
-                it8->dnum = it8->dnum + (frac / xpow10(prec));
+        it8->dnum = it8->dnum + (frac / xpow10(prec));
+    }
+
+    // Exponent, example 34.00E+20
+    if (toupper(it8->ch) == 'E') {
+
+        int e;
+        int sgn;
+
+        NextCh(it8); sgn = 1;
+
+        if (it8->ch == '-') {
+
+            sgn = -1; NextCh(it8);
         }
-
-        // Exponent, example 34.00E+20
-        if (toupper(it8->ch) == 'E') {
-
-                int e;
-                int sgn;
-
-                NextCh(it8); sgn = 1;
-
-                if (it8->ch == '-') {
-
-                        sgn = -1; NextCh(it8);
-                }
-                else
-                if (it8->ch == '+') {
-
-                        sgn = +1;
-                        NextCh(it8);
-                }
-
-
-                e = 0;
-                while (isdigit(it8->ch)) {
-
-                        if ((double) e * 10L < INT_MAX)
-                            e = e * 10 + (it8->ch - '0');
-
-                        NextCh(it8);
-                }
-
-                e = sgn*e;
-
-                it8 -> dnum = it8 -> dnum * xpow10(e);
-        }
+        else
+            if (it8->ch == '+') {
+
+                sgn = +1;
+                NextCh(it8);
+            }
+
+            e = 0;
+            while (isdigit(it8->ch)) {
+
+                if ((cmsFloat64Number) e * 10L < INT_MAX)
+                    e = e * 10 + (it8->ch - '0');
+
+                NextCh(it8);
+            }
+
+            e = sgn*e;
+            it8 -> dnum = it8 -> dnum * xpow10(e);
+    }
 }
 
 
 
 // Reads next symbol
 static
-void InSymbol(LPIT8 it8)
+void InSymbol(cmsIT8* it8)
 {
     register char *idptr;
     register int k;
@@ -716,7 +639,6 @@
 
         if (isfirstidchar(it8->ch)) {          // Identifier
 
-
             k = 0;
             idptr = it8->id;
 
@@ -845,7 +767,6 @@
                     } while (isidchar(it8->ch));
 
                     *idptr = '\0';
-
                     it8->sy = SIDENT;
                 }
                 return;
@@ -860,7 +781,6 @@
             break;
 
         // Eof stream markers
-
         case 0:
         case -1:
             it8->sy = SEOF;
@@ -868,7 +788,6 @@
 
 
         // Next line
-
         case '\n':
             NextCh(it8);
             it8->sy = SEOLN;
@@ -876,7 +795,6 @@
             break;
 
         // Comment
-
         case '#':
             NextCh(it8);
             while (it8->ch && it8->ch != '\n')
@@ -885,8 +803,7 @@
             it8->sy = SCOMMENT;
             break;
 
-            // String.
-
+        // String.
         case '\'':
         case '\"':
             idptr = it8->str;
@@ -921,10 +838,10 @@
 
     if (it8 -> sy == SINCLUDE) {
 
-                LPFILECTX FileNest;
-
-                if(it8 -> IncludeSP >= (MAXINCLUDE-1))
-                {
+                FILECTX* FileNest;
+
+                if(it8 -> IncludeSP >= (MAXINCLUDE-1)) {
+
                     SynError(it8, "Too many recursion levels");
                     return;
                 }
@@ -933,15 +850,16 @@
                 if (!Check(it8, SSTRING, "Filename expected")) return;
 
                 FileNest = it8 -> FileStack[it8 -> IncludeSP + 1];
-                if(FileNest == NULL)
-                {
-                    FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX));
+                if(FileNest == NULL) {
+
+                    FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
                     //if(FileNest == NULL)
-                        //  TODO: how to manage out-of-memory conditions?
+                    //  TODO: how to manage out-of-memory conditions?
                 }
 
-                if(_cmsMakePath(it8->str, it8->FileStack[it8->IncludeSP]->FileName, FileNest->FileName) == FALSE)
-                {
+                if (BuildAbsolutePath(it8->str,
+                                      it8->FileStack[it8->IncludeSP]->FileName,
+                                      FileNest->FileName, cmsMAX_PATH-1) == FALSE) {
                     SynError(it8, "File path too long");
                     return;
                 }
@@ -962,7 +880,7 @@
 
 // Checks end of line separator
 static
-LCMSBOOL CheckEOLN(LPIT8 it8)
+cmsBool CheckEOLN(cmsIT8* it8)
 {
         if (!Check(it8, SEOLN, "Expected separator")) return FALSE;
         while (it8 -> sy == SEOLN)
@@ -974,7 +892,7 @@
 // Skip a symbol
 
 static
-void Skip(LPIT8 it8, SYMBOL sy)
+void Skip(cmsIT8* it8, SYMBOL sy)
 {
         if (it8->sy == sy && it8->sy != SEOF)
                         InSymbol(it8);
@@ -983,7 +901,7 @@
 
 // Skip multiple EOLN
 static
-void SkipEOLN(LPIT8 it8)
+void SkipEOLN(cmsIT8* it8)
 {
     while (it8->sy == SEOLN) {
              InSymbol(it8);
@@ -993,7 +911,7 @@
 
 // Returns a string holding current value
 static
-LCMSBOOL GetVal(LPIT8 it8, char* Buffer, size_t max, const char* ErrorTitle)
+cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle)
 {
     switch (it8->sy) {
 
@@ -1018,9 +936,9 @@
 // ---------------------------------------------------------- Table
 
 static
-LPTABLE GetTable(LPIT8 it8)
+TABLE* GetTable(cmsIT8* it8)
 {
-   if ((it8 -> nTable >= it8 ->TablesCount) || (it8 -> nTable < 0)) {
+   if ((it8 -> nTable >= it8 ->TablesCount)) {
 
            SynError(it8, "Table %d out of sequence", it8 -> nTable);
            return it8 -> Tab;
@@ -1032,75 +950,70 @@
 // ---------------------------------------------------------- Memory management
 
 
-
 // Frees an allocator and owned memory
-void LCMSEXPORT cmsIT8Free(LCMSHANDLE hIT8)
+void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8)
 {
-   LPIT8 it8 = (LPIT8) hIT8;
+   cmsIT8* it8 = (cmsIT8*) hIT8;
 
     if (it8 == NULL)
         return;
 
-
     if (it8->MemorySink) {
 
-        LPOWNEDMEM p;
-        LPOWNEDMEM n;
+        OWNEDMEM* p;
+        OWNEDMEM* n;
 
         for (p = it8->MemorySink; p != NULL; p = n) {
 
             n = p->Next;
-            if (p->Ptr) _cmsFree(p->Ptr);
-            _cmsFree(p);
+            if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr);
+            _cmsFree(it8 ->ContextID, p);
         }
     }
 
     if (it8->MemoryBlock)
-        _cmsFree(it8->MemoryBlock);
-
-     _cmsFree(it8);
+        _cmsFree(it8 ->ContextID, it8->MemoryBlock);
+
+    _cmsFree(it8 ->ContextID, it8);
 }
 
 
 // Allocates a chunk of data, keep linked list
 static
-void* AllocBigBlock(LPIT8 it8, size_t size)
+void* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size)
 {
-   LPOWNEDMEM ptr1;
-   void* ptr = _cmsMalloc(size);
-
-        if (ptr) {
-
-                ZeroMemory(ptr, size);
-                ptr1 = (LPOWNEDMEM) _cmsMalloc(sizeof(OWNEDMEM));
-
-                if (ptr1 == NULL) {
-
-                     _cmsFree(ptr);
-                    return NULL;
-                }
-
-                ZeroMemory(ptr1, sizeof(OWNEDMEM));
-
-                ptr1-> Ptr        = ptr;
-                ptr1-> Next       = it8 -> MemorySink;
-                it8 -> MemorySink = ptr1;
+    OWNEDMEM* ptr1;
+    void* ptr = _cmsMallocZero(it8->ContextID, size);
+
+    if (ptr != NULL) {
+
+        ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM));
+
+        if (ptr1 == NULL) {
+
+            _cmsFree(it8 ->ContextID, ptr);
+            return NULL;
         }
 
-        return ptr;
+        ptr1-> Ptr        = ptr;
+        ptr1-> Next       = it8 -> MemorySink;
+        it8 -> MemorySink = ptr1;
+    }
+
+    return ptr;
 }
 
 
 // Suballocator.
 static
-void* AllocChunk(LPIT8 it8, size_t size)
+void* AllocChunk(cmsIT8* it8, cmsUInt32Number size)
 {
-    size_t free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used;
-    LPBYTE ptr;
-
-    size = ALIGNLONG(size);
-
-    if (size > free) {
+    cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used;
+    cmsUInt8Number* ptr;
+
+    size = _cmsALIGNLONG(size);
+
+    if (size > Free) {
 
         if (it8 -> Allocator.BlockSize == 0)
 
@@ -1112,7 +1025,7 @@
                 it8 ->Allocator.BlockSize = size;
 
         it8 ->Allocator.Used = 0;
-        it8 ->Allocator.Block = (LPBYTE) AllocBigBlock(it8, it8 ->Allocator.BlockSize);
+        it8 ->Allocator.Block = (cmsUInt8Number*)  AllocBigBlock(it8, it8 ->Allocator.BlockSize);
     }
 
     ptr = it8 ->Allocator.Block + it8 ->Allocator.Used;
@@ -1125,9 +1038,9 @@
 
 // Allocates a string
 static
-char *AllocString(LPIT8 it8, const char* str)
+char *AllocString(cmsIT8* it8, const char* str)
 {
-    size_t Size = strlen(str)+1;
+    cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1;
     char *ptr;
 
 
@@ -1140,7 +1053,7 @@
 // Searches through linked list
 
 static
-LCMSBOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, const char* Subkey, LPKEYVALUE* LastPtr)
+cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr)
 {
     if (LastPtr) *LastPtr = p;
 
@@ -1150,7 +1063,7 @@
 
         if (*Key != '#') { // Comments are ignored
 
-            if (stricmp(Key, p->Keyword) == 0)
+            if (cmsstrcasecmp(Key, p->Keyword) == 0)
                     break;
         }
         }
@@ -1165,9 +1078,9 @@
 
         if (LastPtr) *LastPtr = p;
 
-        if (stricmp(Subkey, p->Subkey) == 0)
-            return TRUE;
-    }
+        if (cmsstrcasecmp(Subkey, p->Subkey) == 0)
+                    return TRUE;
+        }
 
     return FALSE;
 }
@@ -1176,55 +1089,62 @@
 
 // Add a property into a linked list
 static
-LPKEYVALUE AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
+KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
 {
-    LPKEYVALUE p;
-
-    // Check if property is already in list (this is an error)
+    KEYVALUE* p;
+    KEYVALUE* last;
+
+
+    // Check if property is already in list
 
     if (IsAvailableOnList(*Head, Key, Subkey, &p)) {
 
-            // This may work for editing properties
+        // This may work for editing properties
 
         //     return SynError(it8, "duplicate key <%s>", Key);
     }
     else {
-        LPKEYVALUE last = p;
-
-    // Allocate the container
-    p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE));
-    if (p == NULL)
-    {
+
+        last = p;
+
+        // Allocate the container
+        p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE));
+        if (p == NULL)
+        {
             SynError(it8, "AddToList: out of memory");
             return NULL;
-    }
-
-    // Store name and value
-    p->Keyword = AllocString(it8, Key);
+        }
+
+        // Store name and value
+        p->Keyword = AllocString(it8, Key);
         p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
 
         // Keep the container in our list
-        if (*Head == NULL)
+        if (*Head == NULL) {
             *Head = p;
+        }
         else
         {
-            if(Subkey != 0 && last != 0) {
+            if (Subkey != NULL && last != NULL) {
+
                 last->NextSubkey = p;
 
                 // If Subkey is not null, then last is the last property with the same key,
                 // but not necessarily is the last property in the list, so we need to move
                 // to the actual list end
-                while(last->Next != 0)
-                    last = last->Next;
-    }
-            last->Next = p;
-    }
-
-    p->Next    = NULL;
+                while (last->Next != NULL)
+                         last = last->Next;
+            }
+
+            if (last != NULL) last->Next = p;
+        }
+
+        p->Next    = NULL;
         p->NextSubkey = NULL;
     }
 
     p->WriteAs = WriteAs;
+
     if (xValue != NULL) {
 
         p->Value   = AllocString(it8, xValue);
@@ -1237,23 +1157,23 @@
 }
 
 static
-LPKEYVALUE AddAvailableProperty(LPIT8 it8, const char* Key, WRITEMODE as)
+KEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as)
 {
-        return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as);
+    return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as);
 }
 
 
 static
-LPKEYVALUE AddAvailableSampleID(LPIT8 it8, const char* Key)
+KEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key)
 {
-        return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED);
+    return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED);
 }
 
 
 static
-void AllocTable(LPIT8 it8)
+void AllocTable(cmsIT8* it8)
 {
-    LPTABLE t;
+    TABLE* t;
 
     t = it8 ->Tab + it8 ->TablesCount;
 
@@ -1265,9 +1185,9 @@
 }
 
 
-int LCMSEXPORT cmsIT8SetTable(LCMSHANDLE IT8, int nTable)
+cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE  IT8, cmsUInt32Number nTable)
 {
-     LPIT8 it8 = (LPIT8) IT8;
+     cmsIT8* it8 = (cmsIT8*) IT8;
 
      if (nTable >= it8 ->TablesCount) {
 
@@ -1289,16 +1209,14 @@
 
 
 // Init an empty container
-LCMSHANDLE LCMSEXPORT cmsIT8Alloc(void)
+cmsHANDLE  CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
 {
-    LPIT8 it8;
+    cmsIT8* it8;
     int i;
 
-    it8 = (LPIT8) malloc(sizeof(IT8));
+    it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8));
     if (it8 == NULL) return NULL;
 
-    ZeroMemory(it8, sizeof(IT8));
-
     AllocTable(it8);
 
     it8->MemoryBlock = NULL;
@@ -1306,6 +1224,7 @@
 
     it8 ->nTable = 0;
 
+    it8->ContextID = ContextID;
     it8->Allocator.Used = 0;
     it8->Allocator.Block = NULL;
     it8->Allocator.BlockSize = 0;
@@ -1319,7 +1238,7 @@
     it8 -> inum = 0;
     it8 -> dnum = 0.0;
 
-    it8->FileStack[0] = (LPFILECTX)AllocChunk(it8, sizeof(FILECTX));
+    it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
     it8->IncludeSP   = 0;
     it8 -> lineno = 1;
 
@@ -1335,30 +1254,30 @@
             AddAvailableSampleID(it8, PredefinedSampleID[i]);
 
 
-   return (LCMSHANDLE) it8;
+   return (cmsHANDLE) it8;
 }
 
 
-const char* LCMSEXPORT cmsIT8GetSheetType(LCMSHANDLE hIT8)
+const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8)
 {
-        LPIT8 it8 = (LPIT8) hIT8;
+        cmsIT8* it8 = (cmsIT8*) hIT8;
 
         return it8 ->SheetType;
 
 }
 
-LCMSBOOL  LCMSEXPORT cmsIT8SetSheetType(LCMSHANDLE hIT8, const char* Type)
+cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type)
 {
-        LPIT8 it8 = (LPIT8) hIT8;
+        cmsIT8* it8 = (cmsIT8*) hIT8;
 
         strncpy(it8 ->SheetType, Type, MAXSTR-1);
         it8 ->SheetType[MAXSTR-1] = 0;
         return TRUE;
 }
 
-LCMSBOOL LCMSEXPORT cmsIT8SetComment(LCMSHANDLE hIT8, const char* Val)
+cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
 
     if (!Val) return FALSE;
     if (!*Val) return FALSE;
@@ -1369,9 +1288,9 @@
 
 
 // Sets a property
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyStr(LCMSHANDLE hIT8, const char* Key, const char *Val)
+cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
 
     if (!Val) return FALSE;
     if (!*Val) return FALSE;
@@ -1380,9 +1299,9 @@
 }
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val)
+cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
     char Buffer[1024];
 
     sprintf(Buffer, it8->DoubleFormatter, Val);
@@ -1390,9 +1309,9 @@
     return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL;
 }
 
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyHex(LCMSHANDLE hIT8, const char* cProp, int Val)
+cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
     char Buffer[1024];
 
     sprintf(Buffer, "%d", Val);
@@ -1400,25 +1319,25 @@
     return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL;
 }
 
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyUncooked(LCMSHANDLE hIT8, const char* Key, const char* Buffer)
+cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
 
     return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL;
 }
 
-LCMSBOOL LCMSEXPORT cmsIT8SetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer)
+cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
 
     return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL;
 }
 
 // Gets a property
-const char* LCMSEXPORT cmsIT8GetProperty(LCMSHANDLE hIT8, const char* Key)
+const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
-    LPKEYVALUE p;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    KEYVALUE* p;
 
     if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p))
     {
@@ -1428,7 +1347,7 @@
 }
 
 
-double LCMSEXPORT cmsIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp)
+cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp)
 {
     const char *v = cmsIT8GetProperty(hIT8, cProp);
 
@@ -1436,13 +1355,12 @@
     else return 0.0;
 }
 
-const char* LCMSEXPORT cmsIT8GetPropertyMulti(LCMSHANDLE hIT8, const char* Key, const char *SubKey)
+const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
-    LPKEYVALUE p;
-
-    if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p))
-    {
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    KEYVALUE* p;
+
+    if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) {
         return p -> Value;
     }
     return NULL;
@@ -1452,9 +1370,9 @@
 
 
 static
-void AllocateDataFormat(LPIT8 it8)
+void AllocateDataFormat(cmsIT8* it8)
 {
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     if (t -> DataFormat) return;    // Already allocated
 
@@ -1467,17 +1385,17 @@
         }
 
     t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *));
-    if (t->DataFormat == NULL)
-    {
+    if (t->DataFormat == NULL) {
+
         SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array");
     }
 
 }
 
 static
-const char *GetDataFormat(LPIT8 it8, int n)
+const char *GetDataFormat(cmsIT8* it8, int n)
 {
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     if (t->DataFormat)
         return t->DataFormat[n];
@@ -1486,16 +1404,9 @@
 }
 
 static
-LCMSBOOL SetDataFormat(LPIT8 it8, int n, const char *label)
+cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label)
 {
-    LPTABLE t = GetTable(it8);
-
-#ifdef  STRICT_CGATS
-    if (!IsAvailableOnList(it8-> ValidSampleID, label, NULL, NULL)) {
-        SynError(it8, "Invalid data format '%s'.", label);
-        return FALSE;
-    }
-#endif
+    TABLE* t = GetTable(it8);
 
     if (!t->DataFormat)
         AllocateDataFormat(it8);
@@ -1505,7 +1416,6 @@
         return FALSE;
     }
 
-
     if (t->DataFormat) {
         t->DataFormat[n] = AllocString(it8, label);
     }
@@ -1514,16 +1424,16 @@
 }
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample)
+cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE  h, int n, const char *Sample)
 {
-        LPIT8 it8 = (LPIT8) h;
+        cmsIT8* it8 = (cmsIT8*) h;
         return SetDataFormat(it8, n, Sample);
 }
 
 static
-void AllocateDataSet(LPIT8 it8)
+void AllocateDataSet(cmsIT8* it8)
 {
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     if (t -> Data) return;    // Already allocated
 
@@ -1531,21 +1441,20 @@
     t-> nPatches   = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
 
     t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*));
-    if (t->Data == NULL)
-    {
+    if (t->Data == NULL) {
+
         SynError(it8, "AllocateDataSet: Unable to allocate data array");
     }
 
 }
 
 static
-char* GetData(LPIT8 it8, int nSet, int nField)
+char* GetData(cmsIT8* it8, int nSet, int nField)
 {
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
     int  nSamples   = t -> nSamples;
     int  nPatches   = t -> nPatches;
 
-
     if (nSet >= nPatches || nField >= nSamples)
         return NULL;
 
@@ -1554,17 +1463,15 @@
 }
 
 static
-LCMSBOOL SetData(LPIT8 it8, int nSet, int nField, const char *Val)
+cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val)
 {
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     if (!t->Data)
         AllocateDataSet(it8);
 
     if (!t->Data) return FALSE;
 
-
-
     if (nSet > t -> nPatches || nSet < 0) {
 
             return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches);
@@ -1575,7 +1482,6 @@
 
     }
 
-
     t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val);
     return TRUE;
 }
@@ -1586,38 +1492,38 @@
 
 // Writes a string to file
 static
-void WriteStr(LPSAVESTREAM f, const char *str)
+void WriteStr(SAVESTREAM* f, const char *str)
 {
-
-    size_t len;
+    cmsUInt32Number len;
 
     if (str == NULL)
         str = " ";
 
     // Lenghth to write
-    len = strlen(str);
+    len = (cmsUInt32Number) strlen(str);
     f ->Used += len;
 
 
     if (f ->stream) {   // Should I write it to a file?
 
-        fwrite(str, 1, len, f->stream);
+        if (fwrite(str, 1, len, f->stream) != len) {
+            cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser");
+            return;
+        }
 
     }
     else {  // Or to a memory block?
 
-
         if (f ->Base) {   // Am I just counting the bytes?
 
             if (f ->Used > f ->Max) {
 
-                cmsSignalError(LCMS_ERRC_ABORTED, "Write to memory overflows in CGATS parser");
-                return;
+                 cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser");
+                 return;
             }
 
-            CopyMemory(f ->Ptr, str, len);
+            memmove(f ->Ptr, str, len);
             f->Ptr += len;
-
         }
 
     }
@@ -1627,7 +1533,7 @@
 // Write formatted
 
 static
-void Writef(LPSAVESTREAM f, const char* frm, ...)
+void Writef(SAVESTREAM* f, const char* frm, ...)
 {
     char Buffer[4096];
     va_list args;
@@ -1642,10 +1548,10 @@
 
 // Writes full header
 static
-void WriteHeader(LPIT8 it8, LPSAVESTREAM fp)
+void WriteHeader(cmsIT8* it8, SAVESTREAM* fp)
 {
-    LPKEYVALUE p;
-    LPTABLE t = GetTable(it8);
+    KEYVALUE* p;
+    TABLE* t = GetTable(it8);
 
 
     for (p = t->HeaderList; (p != NULL); p = p->Next)
@@ -1672,14 +1578,13 @@
 
         if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) {
 
-#ifdef STRICT_CGATS
+#ifdef CMS_STRICT_CGATS
             WriteStr(fp, "KEYWORD\t\"");
             WriteStr(fp, p->Keyword);
             WriteStr(fp, "\"\n");
 #endif
 
             AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED);
-
         }
 
         WriteStr(fp, p->Keyword);
@@ -1720,10 +1625,10 @@
 
 // Writes the data format
 static
-void WriteDataFormat(LPSAVESTREAM fp, LPIT8 it8)
+void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
 {
     int i, nSamples;
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     if (!t -> DataFormat) return;
 
@@ -1743,10 +1648,10 @@
 
 // Writes data array
 static
-void WriteData(LPSAVESTREAM fp, LPIT8 it8)
+void WriteData(SAVESTREAM* fp, cmsIT8* it8)
 {
        int  i, j;
-       LPTABLE t = GetTable(it8);
+       TABLE* t = GetTable(it8);
 
        if (!t->Data) return;
 
@@ -1785,13 +1690,13 @@
 
 
 // Saves whole file
-LCMSBOOL LCMSEXPORT cmsIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName)
+cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
 {
     SAVESTREAM sd;
-    int i;
-    LPIT8 it8 = (LPIT8) hIT8;
-
-    ZeroMemory(&sd, sizeof(SAVESTREAM));
+    cmsUInt32Number i;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    memset(&sd, 0, sizeof(sd));
 
     sd.stream = fopen(cFileName, "wt");
     if (!sd.stream) return FALSE;
@@ -1806,23 +1711,23 @@
             WriteData(&sd, it8);
     }
 
-    fclose(sd.stream);
+    if (fclose(sd.stream) != 0) return FALSE;
 
     return TRUE;
 }
 
 
 // Saves to memory
-LCMSBOOL LCMSEXPORT cmsIT8SaveToMem(LCMSHANDLE hIT8, void *MemPtr, size_t* BytesNeeded)
+cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded)
 {
     SAVESTREAM sd;
-    int i;
-    LPIT8 it8 = (LPIT8) hIT8;
-
-    ZeroMemory(&sd, sizeof(SAVESTREAM));
+    cmsUInt32Number i;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    memset(&sd, 0, sizeof(sd));
 
     sd.stream = NULL;
-    sd.Base   = (LPBYTE) MemPtr;
+    sd.Base   = (cmsUInt8Number*)  MemPtr;
     sd.Ptr    = sd.Base;
 
     sd.Used = 0;
@@ -1856,10 +1761,10 @@
 // -------------------------------------------------------------- Higer level parsing
 
 static
-LCMSBOOL DataFormatSection(LPIT8 it8)
+cmsBool DataFormatSection(cmsIT8* it8)
 {
     int iField = 0;
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     InSymbol(it8);   // Eats "BEGIN_DATA_FORMAT"
     CheckEOLN(it8);
@@ -1897,12 +1802,12 @@
 
 
 static
-LCMSBOOL DataSection (LPIT8 it8)
+cmsBool DataSection (cmsIT8* it8)
 {
     int  iField = 0;
     int  iSet   = 0;
-    char Buffer[MAXSTR];
-    LPTABLE t = GetTable(it8);
+    char Buffer[256];
+    TABLE* t = GetTable(it8);
 
     InSymbol(it8);   // Eats "BEGIN_DATA"
     CheckEOLN(it8);
@@ -1949,11 +1854,11 @@
 
 
 static
-LCMSBOOL HeaderSection(LPIT8 it8)
+cmsBool HeaderSection(cmsIT8* it8)
 {
     char VarName[MAXID];
     char Buffer[MAXSTR];
-    LPKEYVALUE Key;
+    KEYVALUE* Key;
 
         while (it8->sy != SEOF &&
                it8->sy != SSYNERROR &&
@@ -1985,7 +1890,7 @@
 
                 if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) {
 
-#ifdef STRICT_CGATS
+#ifdef CMS_STRICT_CGATS
                  return SynError(it8, "Undefined keyword '%s'", VarName);
 #else
                     Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED);
@@ -2007,7 +1912,7 @@
                         return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
 
                     // chop the string as a list of "subkey, value" pairs, using ';' as a separator
-                    for(Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
+                    for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
                     {
                         char *Value, *temp;
 
@@ -2058,7 +1963,7 @@
 
 
 static
-LCMSBOOL ParseIT8(LPIT8 it8, LCMSBOOL nosheet)
+cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
 {
     char* SheetTypePtr = it8 ->SheetType;
 
@@ -2119,33 +2024,32 @@
 // Init usefull pointers
 
 static
-void CookPointers(LPIT8 it8)
+void CookPointers(cmsIT8* it8)
 {
     int idField, i;
     char* Fld;
-    int j;
-    int nOldTable = it8 ->nTable;
+    cmsUInt32Number j;
+    cmsUInt32Number nOldTable = it8 ->nTable;
 
     for (j=0; j < it8 ->TablesCount; j++) {
 
-    LPTABLE t = it8 ->Tab + j;
+    TABLE* t = it8 ->Tab + j;
 
     t -> SampleID = 0;
     it8 ->nTable = j;
 
     for (idField = 0; idField < t -> nSamples; idField++)
     {
-        if (t ->DataFormat == NULL) {
-             SynError(it8, "Undefined DATA_FORMAT");
-             return;
-
+        if (t ->DataFormat == NULL){
+            SynError(it8, "Undefined DATA_FORMAT");
+            return;
         }
 
         Fld = t->DataFormat[idField];
         if (!Fld) continue;
 
 
-        if (stricmp(Fld, "SAMPLE_ID") == 0) {
+        if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
 
                     t -> SampleID = idField;
 
@@ -2170,7 +2074,7 @@
 
         // "LABEL" is an extension. It keeps references to forward tables
 
-        if ((stricmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) {
+        if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) {
 
                     // Search for table references...
                     for (i=0; i < t -> nPatches; i++) {
@@ -2179,15 +2083,15 @@
 
                             if (Label) {
 
-                                int k;
+                                cmsUInt32Number k;
 
                                 // This is the label, search for a table containing
                                 // this property
 
                                 for (k=0; k < it8 ->TablesCount; k++) {
 
-                                    LPTABLE Table = it8 ->Tab + k;
-                                    LPKEYVALUE p;
+                                    TABLE* Table = it8 ->Tab + k;
+                                    KEYVALUE* p;
 
                                     if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
 
@@ -2221,10 +2125,10 @@
 // that should be something like some printable characters plus a \n
 
 static
-int IsMyBlock(LPBYTE Buffer, size_t n)
+int IsMyBlock(cmsUInt8Number* Buffer, int n)
 {
     int cols = 1, space = 0, quot = 0;
-    size_t i;
+    int i;
 
     if (n < 10) return FALSE;   // Too small
 
@@ -2261,20 +2165,22 @@
 
 
 static
-int IsMyFile(const char* FileName)
+cmsBool IsMyFile(const char* FileName)
 {
    FILE *fp;
-   size_t Size;
-   BYTE Ptr[133];
+   cmsUInt32Number Size;
+   cmsUInt8Number Ptr[133];
 
    fp = fopen(FileName, "rt");
    if (!fp) {
-       cmsSignalError(LCMS_ERRC_ABORTED, "File '%s' not found", FileName);
+       cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName);
        return FALSE;
    }
 
-   Size = fread(Ptr, 1, 132, fp);
-   fclose(fp);
+   Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp);
+
+   if (fclose(fp) != 0)
+       return FALSE;
 
    Ptr[Size] = '\0';
 
@@ -2284,24 +2190,28 @@
 // ---------------------------------------------------------- Exported routines
 
 
-LCMSHANDLE LCMSEXPORT cmsIT8LoadFromMem(void *Ptr, size_t len)
+cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len)
 {
-    LCMSHANDLE hIT8;
-    LPIT8  it8;
-
-    int type = IsMyBlock((LPBYTE) Ptr, len);
+    cmsHANDLE hIT8;
+    cmsIT8*  it8;
+    int type;
+
+    _cmsAssert(Ptr != NULL);
+    _cmsAssert(len != 0);
+
+    type = IsMyBlock((cmsUInt8Number*)Ptr, len);
     if (type == 0) return NULL;
 
-    hIT8 = cmsIT8Alloc();
+    hIT8 = cmsIT8Alloc(ContextID);
     if (!hIT8) return NULL;
 
-    it8 = (LPIT8) hIT8;
-    it8 ->MemoryBlock = (char*) _cmsMalloc(len + 1);
+    it8 = (cmsIT8*) hIT8;
+    it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1);
 
     strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
     it8 ->MemoryBlock[len] = 0;
 
-    strncpy(it8->FileStack[0]->FileName, "", MAX_PATH-1);
+    strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1);
     it8-> Source = it8 -> MemoryBlock;
 
     if (!ParseIT8(it8, type-1)) {
@@ -2313,7 +2223,7 @@
     CookPointers(it8);
     it8 ->nTable = 0;
 
-     _cmsFree(it8->MemoryBlock);
+    _cmsFree(ContextID, it8->MemoryBlock);
     it8 -> MemoryBlock = NULL;
 
     return hIT8;
@@ -2322,17 +2232,20 @@
 }
 
 
-LCMSHANDLE LCMSEXPORT cmsIT8LoadFromFile(const char* cFileName)
+cmsHANDLE  CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName)
 {
 
-     LCMSHANDLE hIT8;
-     LPIT8  it8;
-
-     int type = IsMyFile(cFileName);
+     cmsHANDLE hIT8;
+     cmsIT8*  it8;
+     int type;
+
+     _cmsAssert(cFileName != NULL);
+
+     type = IsMyFile(cFileName);
      if (type == 0) return NULL;
 
-     hIT8 = cmsIT8Alloc();
-     it8 = (LPIT8) hIT8;
+     hIT8 = cmsIT8Alloc(ContextID);
+     it8 = (cmsIT8*) hIT8;
      if (!hIT8) return NULL;
 
 
@@ -2344,8 +2257,8 @@
      }
 
 
-    strncpy(it8->FileStack[0]->FileName, cFileName, MAX_PATH-1);
-    it8->FileStack[0]->FileName[MAX_PATH-1] = 0;
+    strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1);
+    it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0;
 
     if (!ParseIT8(it8, type-1)) {
 
@@ -2357,28 +2270,41 @@
     CookPointers(it8);
     it8 ->nTable = 0;
 
-    fclose(it8 ->FileStack[0]->Stream);
+    if (fclose(it8 ->FileStack[0]->Stream)!= 0) {
+        cmsIT8Free(hIT8);
+            return NULL;
+    }
+
     return hIT8;
 
 }
 
-int LCMSEXPORT cmsIT8EnumDataFormat(LCMSHANDLE hIT8, char ***SampleNames)
+int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames)
 {
-        LPIT8 it8 = (LPIT8) hIT8;
-        LPTABLE t = GetTable(it8);
-
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    TABLE* t;
+
+    _cmsAssert(hIT8 != NULL);
+
+    t = GetTable(it8);
+
+    if (SampleNames)
         *SampleNames = t -> DataFormat;
-        return t -> nSamples;
+    return t -> nSamples;
 }
 
 
-int LCMSEXPORT cmsIT8EnumProperties(LCMSHANDLE hIT8, const char ***PropertyNames)
+cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
-    LPKEYVALUE p;
-    int n;
-    const char **Props;
-    LPTABLE t = GetTable(it8);
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    KEYVALUE* p;
+    cmsUInt32Number n;
+    char **Props;
+    TABLE* t;
+
+    _cmsAssert(hIT8 != NULL);
+
+    t = GetTable(it8);
 
     // Pass#1 - count properties
 
@@ -2388,7 +2314,7 @@
     }
 
 
-    Props = (const char **) AllocChunk(it8, sizeof(char *) * n);
+    Props = (char **) AllocChunk(it8, sizeof(char *) * n);
 
     // Pass#2 - Fill pointers
     n = 0;
@@ -2400,13 +2326,18 @@
     return n;
 }
 
-int LCMSEXPORT cmsIT8EnumPropertyMulti(LCMSHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
+cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
-    LPKEYVALUE p, tmp;
-    int n;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    KEYVALUE *p, *tmp;
+    cmsUInt32Number n;
     const char **Props;
-    LPTABLE t = GetTable(it8);
+    TABLE* t;
+
+    _cmsAssert(hIT8 != NULL);
+
+
+    t = GetTable(it8);
 
     if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) {
         *SubpropertyNames = 0;
@@ -2436,11 +2367,11 @@
 }
 
 static
-int LocatePatch(LPIT8 it8, const char* cPatch)
+int LocatePatch(cmsIT8* it8, const char* cPatch)
 {
     int i;
     const char *data;
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     for (i=0; i < t-> nPatches; i++) {
 
@@ -2448,7 +2379,7 @@
 
         if (data != NULL) {
 
-                if (stricmp(data, cPatch) == 0)
+                if (cmsstrcasecmp(data, cPatch) == 0)
                         return i;
                 }
         }
@@ -2459,62 +2390,65 @@
 
 
 static
-int LocateEmptyPatch(LPIT8 it8)
+int LocateEmptyPatch(cmsIT8* it8)
 {
     int i;
     const char *data;
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     for (i=0; i < t-> nPatches; i++) {
 
         data = GetData(it8, i, t->SampleID);
 
         if (data == NULL)
-                    return i;
-
-        }
-
-        return -1;
+            return i;
+
+    }
+
+    return -1;
 }
 
 static
-int LocateSample(LPIT8 it8, const char* cSample)
+int LocateSample(cmsIT8* it8, const char* cSample)
 {
     int i;
     const char *fld;
-    LPTABLE t = GetTable(it8);
+    TABLE* t = GetTable(it8);
 
     for (i=0; i < t->nSamples; i++) {
 
         fld = GetDataFormat(it8, i);
-        if (stricmp(fld, cSample) == 0)
+        if (cmsstrcasecmp(fld, cSample) == 0)
             return i;
     }
 
-
-    // SynError(it8, "Couldn't find data field %s\n", cSample);
     return -1;
 
 }
 
 
-int LCMSEXPORT cmsIT8GetDataFormat(LCMSHANDLE hIT8, const char* cSample)
+int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    _cmsAssert(hIT8 != NULL);
+
     return LocateSample(it8, cSample);
 }
 
 
 
-const char* LCMSEXPORT cmsIT8GetDataRowCol(LCMSHANDLE hIT8, int row, int col)
+const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    _cmsAssert(hIT8 != NULL);
 
     return GetData(it8, row, col);
 }
 
 
-double LCMSEXPORT cmsIT8GetDataRowColDbl(LCMSHANDLE hIT8, int row, int col)
+cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col)
 {
     const char* Buffer;
 
@@ -2530,19 +2464,23 @@
 }
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetDataRowCol(LCMSHANDLE hIT8, int row, int col, const char* Val)
+cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    _cmsAssert(hIT8 != NULL);
 
     return SetData(it8, row, col, Val);
 }
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetDataRowColDbl(LCMSHANDLE hIT8, int row, int col, double Val)
+cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
     char Buff[256];
 
+    _cmsAssert(hIT8 != NULL);
+
     sprintf(Buff, it8->DoubleFormatter, Val);
 
     return SetData(it8, row, col, Buff);
@@ -2550,18 +2488,18 @@
 
 
 
-const char* LCMSEXPORT cmsIT8GetData(LCMSHANDLE hIT8, const char* cPatch, const char* cSample)
+const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
     int iField, iSet;
 
+    _cmsAssert(hIT8 != NULL);
 
     iField = LocateSample(it8, cSample);
     if (iField < 0) {
         return NULL;
     }
 
-
     iSet = LocatePatch(it8, cPatch);
     if (iSet < 0) {
             return NULL;
@@ -2571,7 +2509,7 @@
 }
 
 
-double LCMSEXPORT cmsIT8GetDataDbl(LCMSHANDLE it8, const char* cPatch, const char* cSample)
+cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE  it8, const char* cPatch, const char* cSample)
 {
     const char* Buffer;
 
@@ -2589,100 +2527,109 @@
 
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetData(LCMSHANDLE hIT8, const char* cPatch,
-                        const char* cSample,
-                        const char *Val)
+cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
     int iField, iSet;
-    LPTABLE t = GetTable(it8);
-
+    TABLE* t;
+
+    _cmsAssert(hIT8 != NULL);
+
+    t = GetTable(it8);
 
     iField = LocateSample(it8, cSample);
 
     if (iField < 0)
         return FALSE;
 
-
-
-        if (t-> nPatches == 0) {
-
-                AllocateDataFormat(it8);
-                AllocateDataSet(it8);
-                CookPointers(it8);
+    if (t-> nPatches == 0) {
+
+        AllocateDataFormat(it8);
+        AllocateDataSet(it8);
+        CookPointers(it8);
+    }
+
+    if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) {
+
+        iSet   = LocateEmptyPatch(it8);
+        if (iSet < 0) {
+            return SynError(it8, "Couldn't add more patches '%s'\n", cPatch);
         }
 
-
-        if (stricmp(cSample, "SAMPLE_ID") == 0)
-        {
-
-                iSet   = LocateEmptyPatch(it8);
-                if (iSet < 0) {
-                        return SynError(it8, "Couldn't add more patches '%s'\n", cPatch);
-                }
-
-                iField = t -> SampleID;
+        iField = t -> SampleID;
+    }
+    else {
+        iSet = LocatePatch(it8, cPatch);
+        if (iSet < 0) {
+            return FALSE;
         }
-        else {
-                iSet = LocatePatch(it8, cPatch);
-                if (iSet < 0) {
-                    return FALSE;
-            }
-        }
-
-        return SetData(it8, iSet, iField, Val);
+    }
+
+    return SetData(it8, iSet, iField, Val);
 }
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetDataDbl(LCMSHANDLE hIT8, const char* cPatch,
-                        const char* cSample,
-                        double Val)
+cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch,
+                                   const char* cSample,
+                                   cmsFloat64Number Val)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
     char Buff[256];
 
-        snprintf(Buff, 255, it8->DoubleFormatter, Val);
-        return cmsIT8SetData(hIT8, cPatch, cSample, Buff);
-
+    _cmsAssert(hIT8 != NULL);
+
+    snprintf(Buff, 255, it8->DoubleFormatter, Val);
+    return cmsIT8SetData(hIT8, cPatch, cSample, Buff);
 }
 
 // Buffer should get MAXSTR at least
 
-const char* LCMSEXPORT cmsIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer)
+const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer)
 {
-        LPIT8 it8 = (LPIT8) hIT8;
-        LPTABLE t = GetTable(it8);
-        char* Data = GetData(it8, nPatch, t->SampleID);
-
-        if (!Data) return NULL;
-        if (!buffer) return Data;
-
-        strncpy(buffer, Data, MAXSTR-1);
-        buffer[MAXSTR-1] = 0;
-        return buffer;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    TABLE* t;
+    char* Data;
+
+    _cmsAssert(hIT8 != NULL);
+
+    t = GetTable(it8);
+    Data = GetData(it8, nPatch, t->SampleID);
+
+    if (!Data) return NULL;
+    if (!buffer) return Data;
+
+    strncpy(buffer, Data, MAXSTR-1);
+    buffer[MAXSTR-1] = 0;
+    return buffer;
 }
 
-int LCMSEXPORT cmsIT8GetPatchByName(LCMSHANDLE hIT8, const char *cPatch)
+int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch)
 {
-    return LocatePatch((LPIT8)hIT8, cPatch);
+    _cmsAssert(hIT8 != NULL);
+
+    return LocatePatch((cmsIT8*)hIT8, cPatch);
 }
 
-int LCMSEXPORT cmsIT8TableCount(LCMSHANDLE hIT8)
+cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8)
 {
-        LPIT8 it8 = (LPIT8) hIT8;
-
-        return it8 ->TablesCount;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    _cmsAssert(hIT8 != NULL);
+
+    return it8 ->TablesCount;
 }
 
 // This handles the "LABEL" extension.
 // Label, nTable, Type
 
-int LCMSEXPORT cmsIT8SetTableByLabel(LCMSHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType)
+int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType)
 {
     const char* cLabelFld;
     char Type[256], Label[256];
     int nTable;
 
+    _cmsAssert(hIT8 != NULL);
+
     if (cField != NULL && *cField == 0)
             cField = "LABEL";
 
@@ -2700,18 +2647,21 @@
 
     if (ExpectedType) {
 
-        if (stricmp(Type, ExpectedType) != 0) return -1;
+        if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1;
     }
 
     return cmsIT8SetTable(hIT8, nTable);
 }
 
 
-LCMSBOOL LCMSEXPORT cmsIT8SetIndexColumn(LCMSHANDLE hIT8, const char* cSample)
+cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
-
-    int pos = LocateSample(it8, cSample);
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+    int pos;
+
+    _cmsAssert(hIT8 != NULL);
+
+    pos = LocateSample(it8, cSample);
     if(pos == -1)
         return FALSE;
 
@@ -2720,9 +2670,11 @@
 }
 
 
-void LCMSEXPORT cmsIT8DefineDblFormat(LCMSHANDLE hIT8, const char* Formatter)
+void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
 {
-    LPIT8 it8 = (LPIT8) hIT8;
+    cmsIT8* it8 = (cmsIT8*) hIT8;
+
+    _cmsAssert(hIT8 != NULL);
 
     if (Formatter == NULL)
         strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
--- a/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -48,178 +49,117 @@
 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
 
-#include "lcms.h"
+#include "lcms2_internal.h"
 
 
+// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point
+// compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS
+// after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1)
+cmsPipeline* _cmsLinkProfiles(cmsContext     ContextID,
+                              cmsUInt32Number nProfiles,
+                              cmsUInt32Number Intents[],
+                              cmsHPROFILE     hProfiles[],
+                              cmsBool         BPC[],
+                              cmsFloat64Number AdaptationStates[],
+                              cmsUInt32Number dwFlags);
 
+//---------------------------------------------------------------------------------
 
-/*
-       This module provides conversion stages for handling intents.
+// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin.
+// Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric
+static
+cmsPipeline* DefaultICCintents(cmsContext     ContextID,
+                               cmsUInt32Number nProfiles,
+                               cmsUInt32Number Intents[],
+                               cmsHPROFILE     hProfiles[],
+                               cmsBool         BPC[],
+                               cmsFloat64Number AdaptationStates[],
+                               cmsUInt32Number dwFlags);
 
-The chain of evaluation in a transform is:
+//---------------------------------------------------------------------------------
 
-                PCS1            PCS2                    PCS3          PCS4
+// This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile
+// to do the trick (no devicelinks allowed at that position)
+static
+cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
+                                          cmsUInt32Number nProfiles,
+                                          cmsUInt32Number Intents[],
+                                          cmsHPROFILE     hProfiles[],
+                                          cmsBool         BPC[],
+                                          cmsFloat64Number AdaptationStates[],
+                                          cmsUInt32Number dwFlags);
 
-|From |  |From  |  |Conversion |  |Preview |  |Gamut   |  |Conversion |  |To    |  |To     |
-|Input|->|Device|->|Stage 1    |->|handling|->|Checking|->|Stage 2    |->|Device|->|output |
+//---------------------------------------------------------------------------------
 
---------  -------  -------------   ---------  ----------  -------------   -------  ---------
+// This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile
+// to do the trick (no devicelinks allowed at that position)
+static
+cmsPipeline*  BlackPreservingKPlaneIntents(cmsContext     ContextID,
+                                           cmsUInt32Number nProfiles,
+                                           cmsUInt32Number Intents[],
+                                           cmsHPROFILE     hProfiles[],
+                                           cmsBool         BPC[],
+                                           cmsFloat64Number AdaptationStates[],
+                                           cmsUInt32Number dwFlags);
 
-          AToB0                     prew0       gamut                     BToA0
-Formatting LUT      Adjusting        LUT         LUT       Adjusting       LUT      Formatting
-          Intent     Intent 1       intent      intent      Intent 2      Intent
+//---------------------------------------------------------------------------------
 
 
-Some of these LUT may be missing
+// This is a structure holding implementations for all supported intents.
+typedef struct _cms_intents_list {
 
-There are two intents involved here, the intent of the transform itself, and the
-intent the proof is being done, if is the case. Since the first intent is to be
-applied to preview, is the proofing intent. The second intent  identifies the
-transform intent. Input data of any stage is taked as relative colorimetric
-always.
+    cmsUInt32Number Intent;
+    char            Description[256];
+    cmsIntentFn     Link;
+    struct _cms_intents_list*  Next;
 
+} cmsIntentsList;
 
-NOTES: V4 states than perceptual & saturation intents between mixed v2 & v4 profiles should
-scale PCS from a black point equal to ZERO in v2 profiles to the reference media black of
-perceptual v4 PCS. Since I found many v2 profiles to be using a perceptual intent with black
-point not zero at all, I'm implementing that as a black point compensation from whatever
-black from perceptal intent to the reference media black for v4 profiles.
 
-*/
+// Built-in intents
+static cmsIntentsList DefaultIntents[] = {
 
+    { INTENT_PERCEPTUAL,                            "Perceptual",                                   DefaultICCintents,            &DefaultIntents[1] },
+    { INTENT_RELATIVE_COLORIMETRIC,                 "Relative colorimetric",                        DefaultICCintents,            &DefaultIntents[2] },
+    { INTENT_SATURATION,                            "Saturation",                                   DefaultICCintents,            &DefaultIntents[3] },
+    { INTENT_ABSOLUTE_COLORIMETRIC,                 "Absolute colorimetric",                        DefaultICCintents,            &DefaultIntents[4] },
+    { INTENT_PRESERVE_K_ONLY_PERCEPTUAL,            "Perceptual preserving black ink",              BlackPreservingKOnlyIntents,  &DefaultIntents[5] },
+    { INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC, "Relative colorimetric preserving black ink",   BlackPreservingKOnlyIntents,  &DefaultIntents[6] },
+    { INTENT_PRESERVE_K_ONLY_SATURATION,            "Saturation preserving black ink",              BlackPreservingKOnlyIntents,  &DefaultIntents[7] },
+    { INTENT_PRESERVE_K_PLANE_PERCEPTUAL,           "Perceptual preserving black plane",            BlackPreservingKPlaneIntents, &DefaultIntents[8] },
+    { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] },
+    { INTENT_PRESERVE_K_PLANE_SATURATION,           "Saturation preserving black plane",            BlackPreservingKPlaneIntents, NULL }
+};
 
 
+// A pointer to the begining of the list
+static cmsIntentsList *Intents = DefaultIntents;
 
-int cdecl cmsChooseCnvrt(int Absolute,
-                 int Phase1, LPcmsCIEXYZ BlackPointIn,
-                             LPcmsCIEXYZ WhitePointIn,
-                             LPcmsCIEXYZ IlluminantIn,
-                             LPMAT3 ChromaticAdaptationMatrixIn,
+// Search the list for a suitable intent. Returns NULL if not found
+static
+cmsIntentsList* SearchIntent(cmsUInt32Number Intent)
+{
+    cmsIntentsList* pt;
 
-                 int Phase2, LPcmsCIEXYZ BlackPointOut,
-                             LPcmsCIEXYZ WhitePointOut,
-                             LPcmsCIEXYZ IlluminantOut,
-                             LPMAT3 ChromaticAdaptationMatrixOut,
+    for (pt = Intents; pt != NULL; pt = pt -> Next)
+        if (pt ->Intent == Intent) return pt;
 
-                int DoBlackPointCompensation,
-                double AdaptationState,
-                 _cmsADJFN *fn1,
-                 LPWMAT3 wm, LPWVEC3 wof);
-
-
-// -------------------------------------------------------------------------
-
-// D50 - Widely used
-
-LCMSAPI LPcmsCIEXYZ LCMSEXPORT cmsD50_XYZ(void)
-{
-    static cmsCIEXYZ D50XYZ = {D50X, D50Y, D50Z};
-
-    return &D50XYZ;
+    return NULL;
 }
 
-LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void)
+// Black point compensation. Implemented as a linear scaling in XYZ. Black points
+// should come relative to the white point. Fills an matrix/offset element m
+// which is organized as a 4x4 matrix.
+static
+void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn,
+                                   const cmsCIEXYZ* BlackPointOut,
+                                   cmsMAT3* m, cmsVEC3* off)
 {
-    static cmsCIExyY D50xyY;
-    cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
-
-    return &D50xyY;
-}
-
-
-// ---------------- From LUT to LUT --------------------------
-
-
-// Calculate m, offset Relativ -> Absolute undoing any chromatic
-// adaptation done by the profile.
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4100 4505)
-#endif
-
-
-
-// join scalings to obtain:
-//     relative input to absolute and then to relative output
-
-static
-void Rel2RelStepAbsCoefs(double AdaptationState,
-
-                         LPcmsCIEXYZ BlackPointIn,
-                         LPcmsCIEXYZ WhitePointIn,
-                         LPcmsCIEXYZ IlluminantIn,
-                         LPMAT3 ChromaticAdaptationMatrixIn,
-
-                         LPcmsCIEXYZ BlackPointOut,
-                         LPcmsCIEXYZ WhitePointOut,
-                         LPcmsCIEXYZ IlluminantOut,
-                         LPMAT3 ChromaticAdaptationMatrixOut,
-
-                         LPMAT3 m, LPVEC3 of)
-{
-
-       VEC3 WtPtIn, WtPtInAdapted;
-       VEC3 WtPtOut, WtPtOutAdapted;
-       MAT3 Scale, m1, m2, m3;
-
-       VEC3init(&WtPtIn, WhitePointIn->X, WhitePointIn->Y, WhitePointIn->Z);
-       MAT3eval(&WtPtInAdapted, ChromaticAdaptationMatrixIn, &WtPtIn);
-
-       VEC3init(&WtPtOut, WhitePointOut->X, WhitePointOut->Y, WhitePointOut->Z);
-       MAT3eval(&WtPtOutAdapted, ChromaticAdaptationMatrixOut, &WtPtOut);
-
-       VEC3init(&Scale.v[0], WtPtInAdapted.n[0] / WtPtOutAdapted.n[0], 0, 0);
-       VEC3init(&Scale.v[1], 0, WtPtInAdapted.n[1] / WtPtOutAdapted.n[1], 0);
-       VEC3init(&Scale.v[2], 0, 0, WtPtInAdapted.n[2] / WtPtOutAdapted.n[2]);
-
-
-       // Adaptation state
-
-       if (AdaptationState == 1.0) {
-
-           // Observer is fully adapted. Keep chromatic adaptation
-
-           CopyMemory(m, &Scale, sizeof(MAT3));
-
-       }
-       else {
-
-            // Observer is not adapted, undo the chromatic adaptation
-            m1 = *ChromaticAdaptationMatrixIn;
-            MAT3inverse(&m1, &m2);
-
-            MAT3per(&m3, &m2, &Scale);
-            MAT3per(m, &m3, ChromaticAdaptationMatrixOut);
-       }
-
-
-       VEC3init(of, 0.0, 0.0, 0.0);
-
-}
-
-
-// The (in)famous black point compensation. Right now implemented as
-// a linear scaling in XYZ
-
-static
-void ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn,
-                      LPcmsCIEXYZ WhitePointIn,
-                      LPcmsCIEXYZ IlluminantIn,
-                      LPcmsCIEXYZ BlackPointOut,
-                      LPcmsCIEXYZ WhitePointOut,
-                      LPcmsCIEXYZ IlluminantOut,
-                      LPMAT3 m, LPVEC3 of)
-{
-
-
-   cmsCIEXYZ RelativeBlackPointIn, RelativeBlackPointOut;
-   double ax, ay, az, bx, by, bz, tx, ty, tz;
-
-   // At first, convert both black points to relative.
-
-   cmsAdaptToIlluminant(&RelativeBlackPointIn,  WhitePointIn, IlluminantIn, BlackPointIn);
-   cmsAdaptToIlluminant(&RelativeBlackPointOut, WhitePointOut, IlluminantOut, BlackPointOut);
+  cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz;
 
    // Now we need to compute a matrix plus an offset m and of such of
    // [m]*bpin + off = bpout
@@ -229,438 +169,900 @@
    // a = (bpout - D50) / (bpin - D50)
    // b = - D50* (bpout - bpin) / (bpin - D50)
 
+   tx = BlackPointIn->X - cmsD50_XYZ()->X;
+   ty = BlackPointIn->Y - cmsD50_XYZ()->Y;
+   tz = BlackPointIn->Z - cmsD50_XYZ()->Z;
 
-   tx = RelativeBlackPointIn.X - IlluminantIn ->X;
-   ty = RelativeBlackPointIn.Y - IlluminantIn ->Y;
-   tz = RelativeBlackPointIn.Z - IlluminantIn ->Z;
+   ax = (BlackPointOut->X - cmsD50_XYZ()->X) / tx;
+   ay = (BlackPointOut->Y - cmsD50_XYZ()->Y) / ty;
+   az = (BlackPointOut->Z - cmsD50_XYZ()->Z) / tz;
 
-   ax = (RelativeBlackPointOut.X - IlluminantOut ->X) / tx;
-   ay = (RelativeBlackPointOut.Y - IlluminantOut ->Y) / ty;
-   az = (RelativeBlackPointOut.Z - IlluminantOut ->Z) / tz;
+   bx = - cmsD50_XYZ()-> X * (BlackPointOut->X - BlackPointIn->X) / tx;
+   by = - cmsD50_XYZ()-> Y * (BlackPointOut->Y - BlackPointIn->Y) / ty;
+   bz = - cmsD50_XYZ()-> Z * (BlackPointOut->Z - BlackPointIn->Z) / tz;
 
-   bx = - IlluminantOut -> X * (RelativeBlackPointOut.X - RelativeBlackPointIn.X) / tx;
-   by = - IlluminantOut -> Y * (RelativeBlackPointOut.Y - RelativeBlackPointIn.Y) / ty;
-   bz = - IlluminantOut -> Z * (RelativeBlackPointOut.Z - RelativeBlackPointIn.Z) / tz;
-
-
-   MAT3identity(m);
-
-   m->v[VX].n[0] = ax;
-   m->v[VY].n[1] = ay;
-   m->v[VZ].n[2] = az;
-
-   VEC3init(of, bx, by, bz);
+   _cmsVEC3init(&m ->v[0], ax, 0,  0);
+   _cmsVEC3init(&m ->v[1], 0, ay,  0);
+   _cmsVEC3init(&m ->v[2], 0,  0,  az);
+   _cmsVEC3init(off, bx, by, bz);
 
 }
 
-// Return TRUE if both m and of are empy -- "m" being identity and "of" being 0
 
+// Approximate a blackbody illuminant based on CHAD information
 static
-LCMSBOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of)
+cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad)
 {
-    WVEC3 wv0;
+    // Convert D50 across CHAD to get the absolute white point
+     cmsVEC3 d, s;
+     cmsCIEXYZ Dest;
+     cmsCIExyY DestChromaticity;
+     cmsFloat64Number TempK;
 
-    VEC3initF(&wv0, 0, 0, 0);
+    s.n[VX] = cmsD50_XYZ() -> X;
+    s.n[VY] = cmsD50_XYZ() -> Y;
+    s.n[VZ] = cmsD50_XYZ() -> Z;
 
-    if (!MAT3isIdentity(m, 0.00001)) return FALSE;
-    if (!VEC3equal(of, &wv0, 0.00001)) return FALSE;
+    _cmsMAT3eval(&d, Chad, &s);
+
+    Dest.X = d.n[VX];
+    Dest.Y = d.n[VY];
+    Dest.Z = d.n[VZ];
+
+    cmsXYZ2xyY(&DestChromaticity, &Dest);
+
+    if (!cmsTempFromWhitePoint(&TempK, &DestChromaticity))
+        return -1.0;
+
+    return TempK;
+}
+
+// Compute a CHAD based on a given temperature
+static
+void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
+{
+    cmsCIEXYZ White;
+    cmsCIExyY ChromaticityOfWhite;
+
+    cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp);
+    cmsxyY2XYZ(&White, &ChromaticityOfWhite);
+    _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White);
+
+}
+
+// Join scalings to obtain relative input to absolute and then to relative output.
+// Result is stored in a 3x3 matrix
+static
+cmsBool  ComputeAbsoluteIntent(cmsFloat64Number AdaptationState,
+                               const cmsCIEXYZ* WhitePointIn,
+                               const cmsMAT3* ChromaticAdaptationMatrixIn,
+                               const cmsCIEXYZ* WhitePointOut,
+                               const cmsMAT3* ChromaticAdaptationMatrixOut,
+                               cmsMAT3* m)
+{
+    cmsMAT3 Scale, m1, m2, m3;
+
+    // Adaptation state
+    if (AdaptationState == 1.0) {
+
+        // Observer is fully adapted. Keep chromatic adaptation.
+        // That is the standard V4 behaviour
+        _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0);
+        _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0);
+        _cmsVEC3init(&m->v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z);
+
+    }
+    else  {
+
+        // Incomplete adaptation. This is an advanced feature.
+        _cmsVEC3init(&Scale.v[0], WhitePointIn->X / WhitePointOut->X, 0, 0);
+        _cmsVEC3init(&Scale.v[1], 0,  WhitePointIn->Y / WhitePointOut->Y, 0);
+        _cmsVEC3init(&Scale.v[2], 0, 0,  WhitePointIn->Z / WhitePointOut->Z);
+
+        m1 = *ChromaticAdaptationMatrixIn;
+        if (!_cmsMAT3inverse(&m1, &m2)) return FALSE;
+        _cmsMAT3per(&m3, &m2, &Scale);
+
+        // m3 holds CHAD from input white to D50 times abs. col. scaling
+        if (AdaptationState == 0.0) {
+
+            // Observer is not adapted, undo the chromatic adaptation
+            _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut);
+
+        } else {
+
+            cmsMAT3 MixedCHAD;
+            cmsFloat64Number TempSrc, TempDest, Temp;
+
+            TempSrc  = CHAD2Temp(ChromaticAdaptationMatrixIn);  // K for source white
+            TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white
+
+            if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong
+
+            if (_cmsMAT3isIdentity(&Scale) && fabs(TempSrc - TempDest) < 0.01) {
+
+                _cmsMAT3identity(m);
+                return TRUE;
+            }
+
+            Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest;
+
+            // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD
+            Temp2CHAD(&MixedCHAD, Temp);
+
+            _cmsMAT3per(m, &m3, &MixedCHAD);
+        }
+
+    }
+    return TRUE;
+
+}
+
+// Just to see if m matrix should be applied
+static
+cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off)
+{
+    cmsFloat64Number diff = 0;
+    cmsMAT3 Ident;
+    int i;
+
+    if (m == NULL && off == NULL) return TRUE;  // NULL is allowed as an empty layer
+    if (m == NULL && off != NULL) return FALSE; // This is an internal error
+
+    _cmsMAT3identity(&Ident);
+
+    for (i=0; i < 3*3; i++)
+        diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]);
+
+    for (i=0; i < 3; i++)
+        diff += fabs(((cmsFloat64Number*)off)[i]);
+
+
+    return (diff < 0.002);
+}
+
+
+// Compute the conversion layer
+static
+cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[],
+                                 cmsUInt32Number Intent,
+                                 cmsBool BPC,
+                                 cmsFloat64Number AdaptationState,
+                                 cmsMAT3* m, cmsVEC3* off)
+{
+
+    int k;
+
+    // m  and off are set to identity and this is detected latter on
+    _cmsMAT3identity(m);
+    _cmsVEC3init(off, 0, 0, 0);
+
+    // If intent is abs. colorimetric,
+    if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) {
+
+        cmsCIEXYZ WhitePointIn, WhitePointOut;
+        cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut;
+
+        _cmsReadMediaWhitePoint(&WhitePointIn,  hProfiles[i-1]);
+        _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]);
+
+        _cmsReadMediaWhitePoint(&WhitePointOut,  hProfiles[i]);
+        _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]);
+
+        if (!ComputeAbsoluteIntent(AdaptationState,
+                                  &WhitePointIn,  &ChromaticAdaptationMatrixIn,
+                                  &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE;
+
+    }
+    else {
+        // Rest of intents may apply BPC.
+
+        if (BPC) {
+
+            cmsCIEXYZ BlackPointIn, BlackPointOut;
+
+            cmsDetectBlackPoint(&BlackPointIn,  hProfiles[i-1], Intent, 0);
+            cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0);
+
+            // If black points are equal, then do nothing
+            if (BlackPointIn.X != BlackPointOut.X ||
+                BlackPointIn.Y != BlackPointOut.Y ||
+                BlackPointIn.Z != BlackPointOut.Z)
+                    ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off);
+        }
+    }
+
+    // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0,
+    // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so
+    // we have first to convert from encoded to XYZ and then convert back to encoded.
+    // y = Mx + Off
+    // x = x'c
+    // y = M x'c + Off
+    // y = y'c; y' = y / c
+    // y' = (Mx'c + Off) /c = Mx' + (Off / c)
+
+    for (k=0; k < 3; k++) {
+        off ->n[k] /= MAX_ENCODEABLE_XYZ;
+    }
 
     return TRUE;
 }
 
 
+// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space
+static
+cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off)
+{
+    cmsFloat64Number* m_as_dbl = (cmsFloat64Number*) m;
+    cmsFloat64Number* off_as_dbl = (cmsFloat64Number*) off;
 
+    // Handle PCS mismatches. A specialized stage is added to the LUT in such case
+    switch (InPCS) {
 
-// ----------------------------------------- Inter PCS conversions
+        case cmsSigXYZData: // Input profile operates in XYZ
 
-// XYZ to XYZ linear scaling. Aso used on Black point compensation
+            switch (OutPCS) {
 
-static
-void XYZ2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
-{
+            case cmsSigXYZData:  // XYZ -> XYZ
+                if (!IsEmptyLayer(m, off))
+                    cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+                break;
 
-    WVEC3 a, r;
+            case cmsSigLabData:  // XYZ -> Lab
+                if (!IsEmptyLayer(m, off))
+                    cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+                cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
+                break;
 
-    a.n[0] = In[0] << 1;
-    a.n[1] = In[1] << 1;
-    a.n[2] = In[2] << 1;
+            default:
+                return FALSE;   // Colorspace mismatch
+                }
+                break;
 
-    MAT3evalW(&r, m, &a);
 
-    Out[0] = _cmsClampWord((r.n[VX] + of->n[VX]) >> 1);
-    Out[1] = _cmsClampWord((r.n[VY] + of->n[VY]) >> 1);
-    Out[2] = _cmsClampWord((r.n[VZ] + of->n[VZ]) >> 1);
+        case cmsSigLabData: // Input profile operates in Lab
+
+            switch (OutPCS) {
+
+            case cmsSigXYZData:  // Lab -> XYZ
+
+                cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID));
+                if (!IsEmptyLayer(m, off))
+                    cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+                break;
+
+            case cmsSigLabData:  // Lab -> Lab
+
+                if (!IsEmptyLayer(m, off)) {
+                    cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID));
+                    cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
+                    cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
+                }
+                break;
+
+            default:
+                return FALSE;  // Mismatch
+            }
+            break;
+
+
+            // On colorspaces other than PCS, check for same space
+        default:
+            if (InPCS != OutPCS) return FALSE;
+            break;
+    }
+
+    return TRUE;
 }
 
 
-// XYZ to Lab, scaling first
+// Is a given space compatible with another?
+static
+cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature b)
+{
+    // If they are same, they are compatible.
+    if (a == b) return TRUE;
 
-static
-void XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
-{
-  WORD XYZ[3];
+    // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other.
+    if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE;
+    if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE;
 
-  XYZ2XYZ(In, XYZ, m, of);
-  cmsXYZ2LabEncoded(XYZ, Out);
+    return FALSE;
 }
 
-// Lab to XYZ, then scalling
 
+// Default handler for ICC-style intents
 static
-void Lab2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+cmsPipeline* DefaultICCintents(cmsContext       ContextID,
+                               cmsUInt32Number  nProfiles,
+                               cmsUInt32Number  TheIntents[],
+                               cmsHPROFILE      hProfiles[],
+                               cmsBool          BPC[],
+                               cmsFloat64Number AdaptationStates[],
+                               cmsUInt32Number  dwFlags)
 {
-       WORD XYZ[3];
+    cmsPipeline* Lut, *Result;
+    cmsHPROFILE hProfile;
+    cmsMAT3 m;
+    cmsVEC3 off;
+    cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace;
+    cmsProfileClassSignature ClassSig;
+    cmsUInt32Number  i, Intent;
 
-       cmsLab2XYZEncoded(In, XYZ);
-       XYZ2XYZ(XYZ, Out, m, of);
+    // For safety
+    if (nProfiles == 0) return NULL;
+
+    // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined'
+    Result = cmsPipelineAlloc(ContextID, 0, 0);
+    if (Result == NULL) return NULL;
+
+    CurrentColorSpace = cmsGetColorSpace(hProfiles[0]);
+
+    for (i=0; i < nProfiles; i++) {
+
+        cmsBool  lIsDeviceLink, lIsInput;
+
+        hProfile      = hProfiles[i];
+        ClassSig      = cmsGetDeviceClass(hProfile);
+        lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass );
+
+        // First profile is used as input unless devicelink or abstract
+        if ((i == 0) && !lIsDeviceLink) {
+            lIsInput = TRUE;
+        }
+        else {
+            // Else use profile in the input direction if current space is not PCS
+        lIsInput      = (CurrentColorSpace != cmsSigXYZData) &&
+                        (CurrentColorSpace != cmsSigLabData);
+        }
+
+        Intent        = TheIntents[i];
+
+        if (lIsInput || lIsDeviceLink) {
+
+            ColorSpaceIn    = cmsGetColorSpace(hProfile);
+            ColorSpaceOut   = cmsGetPCS(hProfile);
+        }
+        else {
+
+            ColorSpaceIn    = cmsGetPCS(hProfile);
+            ColorSpaceOut   = cmsGetColorSpace(hProfile);
+        }
+
+        if (!ColorSpaceIsCompatible(ColorSpaceIn, CurrentColorSpace)) {
+
+            cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "ColorSpace mismatch");
+            goto Error;
+        }
+
+        // If devicelink is found, then no custom intent is allowed and we can
+        // read the LUT to be applied. Settings don't apply here.
+        if (lIsDeviceLink) {
+
+            // Get the involved LUT from the profile
+            Lut = _cmsReadDevicelinkLUT(hProfile, Intent);
+            if (Lut == NULL) goto Error;
+
+            // What about abstract profiles?
+             if (ClassSig == cmsSigAbstractClass && i > 0) {
+                if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error;
+             }
+             else {
+                _cmsMAT3identity(&m);
+                _cmsVEC3init(&off, 0, 0, 0);
+             }
+
+
+            if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error;
+
+        }
+        else {
+
+            if (lIsInput) {
+                // Input direction means non-pcs connection, so proceed like devicelinks
+                Lut = _cmsReadInputLUT(hProfile, Intent);
+                if (Lut == NULL) goto Error;
+            }
+            else {
+
+                // Output direction means PCS connection. Intent may apply here
+                Lut = _cmsReadOutputLUT(hProfile, Intent);
+                if (Lut == NULL) goto Error;
+
+
+                if (!ComputeConversion(i, hProfiles, Intent, BPC[i], AdaptationStates[i], &m, &off)) goto Error;
+                if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error;
+
+            }
+        }
+
+        // Concatenate to the output LUT
+        cmsPipelineCat(Result, Lut);
+        cmsPipelineFree(Lut);
+
+        // Update current space
+        CurrentColorSpace = ColorSpaceOut;
+    }
+
+    return Result;
+
+Error:
+
+    if (Result != NULL) cmsPipelineFree(Result);
+    return NULL;
+
+    cmsUNUSED_PARAMETER(dwFlags);
 }
 
-// Lab to XYZ, scalling and then, back to Lab
 
-static
-void Lab2XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
+// Wrapper for DLL calling convention
+cmsPipeline*  CMSEXPORT _cmsDefaultICCintents(cmsContext     ContextID,
+                                              cmsUInt32Number nProfiles,
+                                              cmsUInt32Number TheIntents[],
+                                              cmsHPROFILE     hProfiles[],
+                                              cmsBool         BPC[],
+                                              cmsFloat64Number AdaptationStates[],
+                                              cmsUInt32Number dwFlags)
 {
-       WORD XYZ[3], XYZ2[3];
-
-       cmsLab2XYZEncoded(In, XYZ);
-       XYZ2XYZ(XYZ, XYZ2, m, of);
-       cmsXYZ2LabEncoded(XYZ2, Out);
+    return DefaultICCintents(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags);
 }
 
-// ------------------------------------------------------------------
+// Black preserving intents ---------------------------------------------------------------------------------------------
 
-// Dispatcher for XYZ Relative LUT
+// Translate black-preserving intents to ICC ones
+static
+int TranslateNonICCIntents(int Intent)
+{
+    switch (Intent) {
+        case INTENT_PRESERVE_K_ONLY_PERCEPTUAL:
+        case INTENT_PRESERVE_K_PLANE_PERCEPTUAL:
+            return INTENT_PERCEPTUAL;
 
-static
-int FromXYZRelLUT(int Absolute,
-                             LPcmsCIEXYZ BlackPointIn,
-                             LPcmsCIEXYZ WhitePointIn,
-                             LPcmsCIEXYZ IlluminantIn,
-                             LPMAT3 ChromaticAdaptationMatrixIn,
+        case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC:
+        case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC:
+            return INTENT_RELATIVE_COLORIMETRIC;
 
-                 int Phase2, LPcmsCIEXYZ BlackPointOut,
-                             LPcmsCIEXYZ WhitePointOut,
-                             LPcmsCIEXYZ IlluminantOut,
-                             LPMAT3 ChromaticAdaptationMatrixOut,
+        case INTENT_PRESERVE_K_ONLY_SATURATION:
+        case INTENT_PRESERVE_K_PLANE_SATURATION:
+            return INTENT_SATURATION;
 
-                 int DoBlackPointCompensation,
-                 double AdaptationState,
-                 _cmsADJFN *fn1,
-                 LPMAT3 m, LPVEC3 of)
-
-{
-              switch (Phase2) {
-
-                     // From relative XYZ to Relative XYZ.
-
-                     case XYZRel:
-
-                            if (Absolute)
-                            {
-                                   // From input relative to absolute, and then
-                                   // back to output relative
-
-                                   Rel2RelStepAbsCoefs(AdaptationState,
-                                                       BlackPointIn,
-                                                       WhitePointIn,
-                                                       IlluminantIn,
-                                                       ChromaticAdaptationMatrixIn,
-                                                       BlackPointOut,
-                                                       WhitePointOut,
-                                                       IlluminantOut,
-                                                       ChromaticAdaptationMatrixOut,
-                                                       m, of);
-                                   *fn1 = XYZ2XYZ;
-
-                            }
-                            else
-                            {
-                                   // XYZ Relative to XYZ relative, no op required
-                                   *fn1 = NULL;
-                                   if (DoBlackPointCompensation) {
-
-                                      *fn1 = XYZ2XYZ;
-                                      ComputeBlackPointCompensationFactors(BlackPointIn,
-                                                                      WhitePointIn,
-                                                                      IlluminantIn,
-                                                                      BlackPointOut,
-                                                                      WhitePointOut,
-                                                                      IlluminantOut,
-                                                                      m, of);
-
-                                   }
-                            }
-                            break;
-
-
-                     // From relative XYZ to Relative Lab
-
-                     case LabRel:
-
-                            // First pass XYZ to absolute, then to relative and
-                            // finally to Lab. I use here D50 for output in order
-                            // to prepare the "to Lab" conversion.
-
-                            if (Absolute)
-                            {
-
-                                Rel2RelStepAbsCoefs(AdaptationState,
-                                                    BlackPointIn,
-                                                    WhitePointIn,
-                                                    IlluminantIn,
-                                                    ChromaticAdaptationMatrixIn,
-                                                    BlackPointOut,
-                                                    WhitePointOut,
-                                                    IlluminantOut,
-                                                    ChromaticAdaptationMatrixOut,
-                                                    m, of);
-
-                                *fn1 = XYZ2Lab;
-
-                            }
-                            else
-                            {
-                                   // Just Convert to Lab
-
-                                   MAT3identity(m);
-                                   VEC3init(of, 0, 0, 0);
-                                   *fn1 = XYZ2Lab;
-
-                                   if (DoBlackPointCompensation) {
-
-                                    ComputeBlackPointCompensationFactors(BlackPointIn,
-                                                                          WhitePointIn,
-                                                                          IlluminantIn,
-                                                                          BlackPointOut,
-                                                                          WhitePointOut,
-                                                                          IlluminantOut,
-                                                                          m, of);
-                                   }
-                            }
-                            break;
-
-
-                     default: return FALSE;
-                     }
-
-              return TRUE;
+        default: return Intent;
+    }
 }
 
+// Sampler for Black-only preserving CMYK->CMYK transforms
 
+typedef struct {
+    cmsPipeline*    cmyk2cmyk;      // The original transform
+    cmsToneCurve*   KTone;          // Black-to-black tone curve
 
+} GrayOnlyParams;
 
-// From Lab Relative type LUT
 
+// Preserve black only if that is the only ink used
 static
-int FromLabRelLUT(int Absolute,
-                             LPcmsCIEXYZ BlackPointIn,
-                             LPcmsCIEXYZ WhitePointIn,
-                             LPcmsCIEXYZ IlluminantIn,
-                             LPMAT3 ChromaticAdaptationMatrixIn,
+int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+{
+    GrayOnlyParams* bp = (GrayOnlyParams*) Cargo;
 
-                 int Phase2, LPcmsCIEXYZ BlackPointOut,
-                             LPcmsCIEXYZ WhitePointOut,
-                             LPcmsCIEXYZ IlluminantOut,
-                             LPMAT3 ChromaticAdaptationMatrixOut,
+    // If going across black only, keep black only
+    if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
 
-                int DoBlackPointCompensation,
-                double AdaptationState,
+        // TAC does not apply because it is black ink!
+        Out[0] = Out[1] = Out[2] = 0;
+        Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]);
+        return TRUE;
+    }
 
-                 _cmsADJFN *fn1,
-                 LPMAT3 m, LPVEC3 of)
-{
-
-          switch (Phase2) {
-
-              // From Lab Relative to XYZ Relative, very usual case
-
-              case XYZRel:
-
-                  if (Absolute) {  // Absolute intent
-
-                            // From lab relative, to XYZ absolute, and then,
-                            // back to XYZ relative
-
-                            Rel2RelStepAbsCoefs(AdaptationState,
-                                                BlackPointIn,
-                                                WhitePointIn,
-                                                cmsD50_XYZ(),
-                                                ChromaticAdaptationMatrixIn,
-                                                BlackPointOut,
-                                                WhitePointOut,
-                                                IlluminantOut,
-                                                ChromaticAdaptationMatrixOut,
-                                                m, of);
-
-                            *fn1 = Lab2XYZ;
-
-                     }
-                     else
-                     {
-                            // From Lab relative, to XYZ relative.
-
-                            *fn1 = Lab2XYZ;
-                            if (DoBlackPointCompensation) {
-
-                                 ComputeBlackPointCompensationFactors(BlackPointIn,
-                                                                      WhitePointIn,
-                                                                      IlluminantIn,
-                                                                      BlackPointOut,
-                                                                      WhitePointOut,
-                                                                      IlluminantOut,
-                                                                      m, of);
-
-                            }
-                     }
-                     break;
-
-
-
-              case LabRel:
-
-                     if (Absolute) {
-
-                             // First pass to XYZ using the input illuminant
-                             // * InIlluminant / D50, then to absolute. Then
-                             // to relative, but for input
-
-                             Rel2RelStepAbsCoefs(AdaptationState,
-                                                 BlackPointIn,
-                                                 WhitePointIn, IlluminantIn,
-                                                 ChromaticAdaptationMatrixIn,
-                                                 BlackPointOut,
-                                                 WhitePointOut, cmsD50_XYZ(),
-                                                 ChromaticAdaptationMatrixOut,
-                                                 m, of);
-                             *fn1 = Lab2XYZ2Lab;
-                     }
-                     else
-                     {      // Lab -> Lab relative don't need any adjust unless
-                            // black point compensation
-
-                            *fn1 = NULL;
-                             if (DoBlackPointCompensation) {
-
-                                 *fn1 = Lab2XYZ2Lab;
-                                 ComputeBlackPointCompensationFactors(BlackPointIn,
-                                                                      WhitePointIn,
-                                                                      IlluminantIn,
-                                                                      BlackPointOut,
-                                                                      WhitePointOut,
-                                                                      IlluminantOut,
-                                                                      m, of);
-
-
-                            }
-                     }
-                     break;
-
-
-              default: return FALSE;
-              }
-
-   return TRUE;
+    // Keep normal transform for other colors
+    bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data);
+    return TRUE;
 }
 
+// This is the entry for black-preserving K-only intents, which are non-ICC
+static
+cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
+                                          cmsUInt32Number nProfiles,
+                                          cmsUInt32Number TheIntents[],
+                                          cmsHPROFILE     hProfiles[],
+                                          cmsBool         BPC[],
+                                          cmsFloat64Number AdaptationStates[],
+                                          cmsUInt32Number dwFlags)
+{
+    GrayOnlyParams  bp;
+    cmsPipeline*    Result;
+    cmsUInt32Number ICCIntents[256];
+    cmsStage*         CLUT;
+    cmsUInt32Number i, nGridPoints;
 
-// This function does calculate the necessary conversion operations
-// needed from transpassing data from a LUT to a LUT. The conversion
-// is modeled as a pointer of function and two coefficients, a and b
-// The function is actually called only if not null pointer is provided,
-// and the two paramaters are passed in. There are several types of
-// conversions, but basically they do a linear scalling and a interchange
 
+    // Sanity check
+    if (nProfiles < 1 || nProfiles > 255) return NULL;
 
+    // Translate black-preserving intents to ICC ones
+    for (i=0; i < nProfiles; i++)
+        ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]);
 
-// Main dispatcher
+    // Check for non-cmyk profiles
+    if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+        cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData)
+           return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
 
-int cmsChooseCnvrt(int Absolute,
-                  int Phase1, LPcmsCIEXYZ BlackPointIn,
-                              LPcmsCIEXYZ WhitePointIn,
-                              LPcmsCIEXYZ IlluminantIn,
-                              LPMAT3 ChromaticAdaptationMatrixIn,
+    memset(&bp, 0, sizeof(bp));
 
-                  int Phase2, LPcmsCIEXYZ BlackPointOut,
-                              LPcmsCIEXYZ WhitePointOut,
-                              LPcmsCIEXYZ IlluminantOut,
-                              LPMAT3 ChromaticAdaptationMatrixOut,
+    // Allocate an empty LUT for holding the result
+    Result = cmsPipelineAlloc(ContextID, 4, 4);
+    if (Result == NULL) return NULL;
 
-                  int DoBlackPointCompensation,
-                  double AdaptationState,
-                  _cmsADJFN *fn1,
-                  LPWMAT3 wm, LPWVEC3 wof)
-{
+    // Create a LUT holding normal ICC transform
+    bp.cmyk2cmyk = DefaultICCintents(ContextID,
+        nProfiles,
+        ICCIntents,
+        hProfiles,
+        BPC,
+        AdaptationStates,
+        dwFlags);
 
-       int rc;
-       MAT3 m;
-       VEC3 of;
+    if (bp.cmyk2cmyk == NULL) goto Error;
 
+    // Now, compute the tone curve
+    bp.KTone = _cmsBuildKToneCurve(ContextID,
+        4096,
+        nProfiles,
+        ICCIntents,
+        hProfiles,
+        BPC,
+        AdaptationStates,
+        dwFlags);
 
-       MAT3identity(&m);
-       VEC3init(&of, 0, 0, 0);
+    if (bp.KTone == NULL) goto Error;
 
-       switch (Phase1) {
 
-       // Input LUT is giving XYZ relative values.
+    // How many gridpoints are we going to use?
+    nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags);
 
-       case XYZRel:  rc = FromXYZRelLUT(Absolute,
-                                          BlackPointIn,
-                                          WhitePointIn,
-                                          IlluminantIn,
-                                          ChromaticAdaptationMatrixIn,
-                                          Phase2,
-                                          BlackPointOut,
-                                          WhitePointOut,
-                                          IlluminantOut,
-                                          ChromaticAdaptationMatrixOut,
-                                          DoBlackPointCompensation,
-                                          AdaptationState,
-                                          fn1, &m, &of);
-                     break;
+    // Create the CLUT. 16 bits
+    CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL);
+    if (CLUT == NULL) goto Error;
 
+    // This is the one and only MPE in this LUT
+    cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT);
 
+    // Sample it. We cannot afford pre/post linearization this time.
+    if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0))
+        goto Error;
 
-       // Input LUT is giving Lab relative values
+    // Get rid of xform and tone curve
+    cmsPipelineFree(bp.cmyk2cmyk);
+    cmsFreeToneCurve(bp.KTone);
 
-       case LabRel:  rc =  FromLabRelLUT(Absolute,
-                                          BlackPointIn,
-                                          WhitePointIn,
-                                          IlluminantIn,
-                                          ChromaticAdaptationMatrixIn,
-                                          Phase2,
-                                          BlackPointOut,
-                                          WhitePointOut,
-                                          IlluminantOut,
-                                          ChromaticAdaptationMatrixOut,
-                                          DoBlackPointCompensation,
-                                          AdaptationState,
-                                          fn1, &m, &of);
-                     break;
+    return Result;
 
+Error:
 
+    if (bp.cmyk2cmyk != NULL) cmsPipelineFree(bp.cmyk2cmyk);
+    if (bp.KTone != NULL)  cmsFreeToneCurve(bp.KTone);
+    if (Result != NULL) cmsPipelineFree(Result);
+    return NULL;
 
-
-       // Unrecognized combination
-
-       default:    cmsSignalError(LCMS_ERRC_ABORTED, "(internal) Phase error");
-                   return FALSE;
-
-       }
-
-       MAT3toFix(wm, &m);
-       VEC3toFix(wof, &of);
-
-       // Do some optimization -- discard conversion if identity parameters.
-
-       if (*fn1 == XYZ2XYZ || *fn1 == Lab2XYZ2Lab) {
-
-           if (IdentityParameters(wm, wof))
-               *fn1 = NULL;
-       }
-
-
-       return rc;
 }
 
+// K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------
 
+typedef struct {
 
+    cmsPipeline*     cmyk2cmyk;     // The original transform
+    cmsHTRANSFORM    hProofOutput;  // Output CMYK to Lab (last profile)
+    cmsHTRANSFORM    cmyk2Lab;      // The input chain
+    cmsToneCurve*    KTone;         // Black-to-black tone curve
+    cmsPipeline*     LabK2cmyk;     // The output profile
+    cmsFloat64Number MaxError;
+
+    cmsHTRANSFORM    hRoundTrip;
+    cmsFloat64Number MaxTAC;
+
+
+} PreserveKPlaneParams;
+
+
+// The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision
+static
+int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+{
+    int i;
+    cmsFloat32Number Inf[4], Outf[4];
+    cmsFloat32Number LabK[4];
+    cmsFloat64Number SumCMY, SumCMYK, Error, Ratio;
+    cmsCIELab ColorimetricLab, BlackPreservingLab;
+    PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo;
+
+    // Convert from 16 bits to floating point
+    for (i=0; i < 4; i++)
+        Inf[i] = (cmsFloat32Number) (In[i] / 65535.0);
+
+    // Get the K across Tone curve
+    LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]);
+
+    // If going across black only, keep black only
+    if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
+
+        Out[0] = Out[1] = Out[2] = 0;
+        Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0);
+        return TRUE;
+    }
+
+    // Try the original transform,
+    cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk);
+
+    // Store a copy of the floating point result into 16-bit
+    for (i=0; i < 4; i++)
+            Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0);
+
+    // Maybe K is already ok (mostly on K=0)
+    if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) {
+        return TRUE;
+    }
+
+    // K differ, mesure and keep Lab measurement for further usage
+    // this is done in relative colorimetric intent
+    cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1);
+
+    // Is not black only and the transform doesn't keep black.
+    // Obtain the Lab of output CMYK. After that we have Lab + K
+    cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1);
+
+    // Obtain the corresponding CMY using reverse interpolation
+    // (K is fixed in LabK[3])
+    if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) {
+
+        // Cannot find a suitable value, so use colorimetric xform
+        // which is already stored in Out[]
+        return TRUE;
+    }
+
+    // Make sure to pass thru K (which now is fixed)
+    Outf[3] = LabK[3];
+
+    // Apply TAC if needed
+    SumCMY   = Outf[0]  + Outf[1] + Outf[2];
+    SumCMYK  = SumCMY + Outf[3];
+
+    if (SumCMYK > bp ->MaxTAC) {
+
+        Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY);
+        if (Ratio < 0)
+            Ratio = 0;
+    }
+    else
+       Ratio = 1.0;
+
+    Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0);     // C
+    Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0);     // M
+    Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0);     // Y
+    Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0);
+
+    // Estimate the error (this goes 16 bits to Lab DBL)
+    cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1);
+    Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab);
+    if (Error > bp -> MaxError)
+        bp->MaxError = Error;
+
+    return TRUE;
+}
+
+// This is the entry for black-plane preserving, which are non-ICC
+static
+cmsPipeline* BlackPreservingKPlaneIntents(cmsContext     ContextID,
+                                          cmsUInt32Number nProfiles,
+                                          cmsUInt32Number TheIntents[],
+                                          cmsHPROFILE     hProfiles[],
+                                          cmsBool         BPC[],
+                                          cmsFloat64Number AdaptationStates[],
+                                          cmsUInt32Number dwFlags)
+{
+    PreserveKPlaneParams bp;
+    cmsPipeline*    Result = NULL;
+    cmsUInt32Number ICCIntents[256];
+    cmsStage*         CLUT;
+    cmsUInt32Number i, nGridPoints;
+    cmsHPROFILE hLab;
+
+    // Sanity check
+    if (nProfiles < 1 || nProfiles > 255) return NULL;
+
+    // Translate black-preserving intents to ICC ones
+    for (i=0; i < nProfiles; i++)
+        ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]);
+
+    // Check for non-cmyk profiles
+    if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+        cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData)
+           return  DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
+
+    // Allocate an empty LUT for holding the result
+    Result = cmsPipelineAlloc(ContextID, 4, 4);
+    if (Result == NULL) return NULL;
+
+
+    memset(&bp, 0, sizeof(bp));
+
+    // We need the input LUT of the last profile, assuming this one is responsible of
+    // black generation. This LUT will be seached in inverse order.
+    bp.LabK2cmyk = _cmsReadInputLUT(hProfiles[nProfiles-1], INTENT_RELATIVE_COLORIMETRIC);
+    if (bp.LabK2cmyk == NULL) goto Cleanup;
+
+    // Get total area coverage (in 0..1 domain)
+    bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0;
+
+    // Create a LUT holding normal ICC transform
+    bp.cmyk2cmyk = DefaultICCintents(ContextID,
+                                         nProfiles,
+                                         ICCIntents,
+                                         hProfiles,
+                                         BPC,
+                                         AdaptationStates,
+                                         dwFlags);
+
+    // Now the tone curve
+    bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles,
+                                   ICCIntents,
+                                   hProfiles,
+                                   BPC,
+                                   AdaptationStates,
+                                   dwFlags);
+
+
+    // To measure the output, Last profile to Lab
+    hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+    bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
+                                         CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL,
+                                         INTENT_RELATIVE_COLORIMETRIC,
+                                         cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
+
+    // Same as anterior, but lab in the 0..1 range
+    bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
+                                         FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab,
+                                         FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4),
+                                         INTENT_RELATIVE_COLORIMETRIC,
+                                         cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
+    cmsCloseProfile(hLab);
+
+    // Error estimation (for debug only)
+    bp.MaxError = 0;
+
+    // How many gridpoints are we going to use?
+    nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags);
+
+
+    CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL);
+    if (CLUT == NULL) goto Cleanup;
+
+    cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT);
+
+    cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0);
+
+Cleanup:
+
+    if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk);
+    if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab);
+    if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput);
+
+    if (bp.KTone) cmsFreeToneCurve(bp.KTone);
+    if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk);
+
+    return Result;
+}
+
+// Link routines ------------------------------------------------------------------------------------------------------
+
+// Chain several profiles into a single LUT. It just checks the parameters and then calls the handler
+// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the
+// rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable.
+cmsPipeline* _cmsLinkProfiles(cmsContext     ContextID,
+                              cmsUInt32Number nProfiles,
+                              cmsUInt32Number TheIntents[],
+                              cmsHPROFILE     hProfiles[],
+                              cmsBool         BPC[],
+                              cmsFloat64Number AdaptationStates[],
+                              cmsUInt32Number dwFlags)
+{
+    cmsUInt32Number i;
+    cmsIntentsList* Intent;
+
+    // Make sure a reasonable number of profiles is provided
+    if (nProfiles <= 0 || nProfiles > 255) {
+         cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't link '%d' profiles", nProfiles);
+        return NULL;
+    }
+
+    for (i=0; i < nProfiles; i++) {
+
+        // Check if black point is really needed or allowed. Note that
+        // following Adobe's document:
+        // BPC does not apply to devicelink profiles, nor to abs colorimetric,
+        // and applies always on V4 perceptual and saturation.
+
+        if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC)
+            BPC[i] = FALSE;
+
+        if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) {
+
+            // Force BPC for V4 profiles in perceptual and saturation
+            if (cmsGetProfileVersion(hProfiles[i]) >= 4.0)
+                BPC[i] = TRUE;
+        }
+    }
+
+    // Search for a handler. The first intent in the chain defines the handler. That would
+    // prevent using multiple custom intents in a multiintent chain, but the behaviour of
+    // this case would present some issues if the custom intent tries to do things like
+    // preserve primaries. This solution is not perfect, but works well on most cases.
+
+    Intent = SearchIntent(TheIntents[0]);
+    if (Intent == NULL) {
+        cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]);
+        return NULL;
+    }
+
+    // Call the handler
+    return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// Get information about available intents. nMax is the maximum space for the supplied "Codes"
+// and "Descriptions" the function returns the total number of intents, which may be greater
+// than nMax, although the matrices are not populated beyond this level.
+cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
+{
+    cmsIntentsList* pt;
+    cmsUInt32Number nIntents;
+
+    for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next)
+    {
+        if (nIntents < nMax) {
+            if (Codes != NULL)
+                Codes[nIntents] = pt ->Intent;
+
+            if (Descriptions != NULL)
+                Descriptions[nIntents] = pt ->Description;
+        }
+
+        nIntents++;
+    }
+
+    return nIntents;
+}
+
+// The plug-in registration. User can add new intents or override default routines
+cmsBool  _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data)
+{
+    cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data;
+    cmsIntentsList* fl;
+
+    // Do we have to reset the intents?
+    if (Data == NULL) {
+
+       Intents = DefaultIntents;
+       return TRUE;
+    }
+
+    fl = SearchIntent(Plugin ->Intent);
+
+    if (fl == NULL) {
+        fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList));
+        if (fl == NULL) return FALSE;
+    }
+
+    fl ->Intent  = Plugin ->Intent;
+    strncpy(fl ->Description, Plugin ->Description, 255);
+    fl ->Description[255] = 0;
+
+    fl ->Link    = Plugin ->Link;
+
+    fl ->Next = Intents;
+    Intents = fl;
+
+    return TRUE;
+}
+
--- a/src/share/native/sun/java2d/cmm/lcms/cmserr.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmserr.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -48,92 +49,399 @@
 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
 
+#include "lcms2_internal.h"
 
-#include "lcms.h"
+// I am so tired about incompatibilities on those functions that here are some replacements
+// that hopefully would be fully portable.
 
+// compare two strings ignoring case
+int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)
+{
+         register const unsigned char *us1 = (const unsigned char *)s1,
+                                      *us2 = (const unsigned char *)s2;
 
-// As a rule, only the functions visible from API can signal
-// errors.
-
-void cdecl cmsSignalError(int ErrorCode, const char *ErrorText, ...);
-
-int  LCMSEXPORT cmsErrorAction(int lAbort);
-void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn);
-
-
-// ******************************************************************
-
-static int nDoAbort = LCMS_ERROR_ABORT;
-static cmsErrorHandlerFunction UserErrorHandler = (cmsErrorHandlerFunction) NULL;
-
-
-int LCMSEXPORT cmsErrorAction(int nAction)
-{
-       int nOld = nDoAbort;
-       nDoAbort = nAction;
-
-       return nOld;
+        while (toupper(*us1) == toupper(*us2++))
+                if (*us1++ == '\0')
+                        return (0);
+        return (toupper(*us1) - toupper(*--us2));
 }
 
-void LCMSEXPORT cmsSetErrorHandler(cmsErrorHandlerFunction Fn)
+// long int because C99 specifies ftell in such way (7.19.9.2)
+long int CMSEXPORT cmsfilelength(FILE* f)
 {
-       UserErrorHandler = Fn;
+    long int n;
+
+    if (fseek(f, 0, SEEK_END) != 0) {
+        return -1;
+    }
+    n = ftell(f);
+    fseek(f, 0, SEEK_SET);
+
+    return n;
 }
 
+// Memory handling ------------------------------------------------------------------
+//
+// This is the interface to low-level memory management routines. By default a simple
+// wrapping to malloc/free/realloc is provided, although there is a limit on the max
+// amount of memoy that can be reclaimed. This is mostly as a safety feature to
+// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms
+// would never need.
 
-// Default error handler
+#define MAX_MEMORY_FOR_ALLOC  ((cmsUInt32Number)(1024U*1024U*512U))
 
+// User may override this behaviour by using a memory plug-in, which basically replaces
+// the default memory management functions. In this case, no check is performed and it
+// is up to the plug-in writter to keep in the safe side. There are only three functions
+// required to be implemented: malloc, realloc and free, although the user may want to
+// replace the optional mallocZero, calloc and dup as well.
 
-void cmsSignalError(int ErrorCode, const char *ErrorText, ...)
+cmsBool   _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
+
+// *********************************************************************************
+
+// This is the default memory allocation function. It does a very coarse
+// check of amout of memory, just to prevent exploits
+static
+void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
 {
-       va_list args;
+    if (size > MAX_MEMORY_FOR_ALLOC) return NULL;  // Never allow over maximum
 
-       if (nDoAbort == LCMS_ERROR_IGNORE) return;
+    return (void*) malloc(size);
 
-        va_start(args, ErrorText);
+    cmsUNUSED_PARAMETER(ContextID);
+}
 
-        if (UserErrorHandler != NULL) {
+// Generic allocate & zero
+static
+void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size)
+{
+    void *pt = _cmsMalloc(ContextID, size);
+    if (pt == NULL) return NULL;
 
-            char Buffer[1024];
+    memset(pt, 0, size);
+    return pt;
+}
 
-            vsnprintf(Buffer, 1023, ErrorText, args);
-            va_end(args);
 
-            if (UserErrorHandler(ErrorCode, Buffer)) {
+// The default free function. The only check proformed is against NULL pointers
+static
+void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)
+{
+    // free(NULL) is defined a no-op by C99, therefore it is safe to
+    // avoid the check, but it is here just in case...
 
-                return;
-                }
-         }
+    if (Ptr) free(Ptr);
 
-#if defined( __CONSOLE__ ) || defined( NON_WINDOWS )
+    cmsUNUSED_PARAMETER(ContextID);
+}
 
-              fprintf(stderr, "lcms: Error #%d; ", ErrorCode);
-              vfprintf(stderr, ErrorText, args);
-              fprintf(stderr, "\n");
-              va_end(args);
+// The default realloc function. Again it check for exploits. If Ptr is NULL,
+// realloc behaves the same way as malloc and allocates a new block of size bytes.
+static
+void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
+{
 
-              if (nDoAbort == LCMS_ERROR_ABORT) exit(1);
-#else
-              {
-              char Buffer1[1024];
-              char Buffer2[256];
+    if (size > MAX_MEMORY_FOR_ALLOC) return NULL;  // Never realloc over 512Mb
 
-              snprintf(Buffer1,  767, "Error #%x; ", ErrorCode);
-              vsnprintf(Buffer2, 255, ErrorText, args);
-              strcat(Buffer1, Buffer2);
-              MessageBox(NULL, Buffer1, "Little cms",
-                                          MB_OK|MB_ICONSTOP|MB_TASKMODAL);
-              va_end(args);
+    return realloc(Ptr, size);
 
-              if (nDoAbort == LCMS_ERROR_ABORT) {
+    cmsUNUSED_PARAMETER(ContextID);
+}
 
-#ifdef __BORLANDC__
-                    _cexit();
-#endif
 
-                  FatalAppExit(0, "lcms is terminating application");
-              }
-              }
-#endif
+// The default calloc function. Allocates an array of num elements, each one of size bytes
+// all memory is initialized to zero.
+static
+void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
+{
+    cmsUInt32Number Total = num * size;
+
+    // Check for overflow
+    if (Total < num || Total < size) {
+        return NULL;
+    }
+
+    if (Total > MAX_MEMORY_FOR_ALLOC) return NULL;  // Never alloc over 512Mb
+
+    return _cmsMallocZero(ContextID, Total);
 }
+
+// Generic block duplication
+static
+void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size)
+{
+    void* mem;
+
+    if (size > MAX_MEMORY_FOR_ALLOC) return NULL;  // Never dup over 512Mb
+
+    mem = _cmsMalloc(ContextID, size);
+
+    if (mem != NULL && Org != NULL)
+        memmove(mem, Org, size);
+
+    return mem;
+}
+
+// Pointers to malloc and _cmsFree functions in current environment
+static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size)                     = _cmsMallocDefaultFn;
+static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size)                 = _cmsMallocZeroDefaultFn;
+static void   (* FreePtr)(cmsContext ContextID, void *Ptr)                                  = _cmsFreeDefaultFn;
+static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize)      = _cmsReallocDefaultFn;
+static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn;
+static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size)       = _cmsDupDefaultFn;
+
+// Plug-in replacement entry
+cmsBool  _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data)
+{
+    cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;
+
+    // NULL forces to reset to defaults
+    if (Data == NULL) {
+
+        MallocPtr    = _cmsMallocDefaultFn;
+        MallocZeroPtr= _cmsMallocZeroDefaultFn;
+        FreePtr      = _cmsFreeDefaultFn;
+        ReallocPtr   = _cmsReallocDefaultFn;
+        CallocPtr    = _cmsCallocDefaultFn;
+        DupPtr       = _cmsDupDefaultFn;
+        return TRUE;
+    }
+
+    // Check for required callbacks
+    if (Plugin -> MallocPtr == NULL ||
+        Plugin -> FreePtr == NULL ||
+        Plugin -> ReallocPtr == NULL) return FALSE;
+
+    // Set replacement functions
+    MallocPtr  = Plugin -> MallocPtr;
+    FreePtr    = Plugin -> FreePtr;
+    ReallocPtr = Plugin -> ReallocPtr;
+
+    if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr;
+    if (Plugin ->CallocPtr != NULL)     CallocPtr     = Plugin -> CallocPtr;
+    if (Plugin ->DupPtr != NULL)        DupPtr        = Plugin -> DupPtr;
+
+    return TRUE;
+}
+
+// Generic allocate
+void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)
+{
+    return MallocPtr(ContextID, size);
+}
+
+// Generic allocate & zero
+void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)
+{
+    return MallocZeroPtr(ContextID, size);
+}
+
+// Generic calloc
+void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
+{
+    return CallocPtr(ContextID, num, size);
+}
+
+// Generic reallocate
+void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
+{
+    return ReallocPtr(ContextID, Ptr, size);
+}
+
+// Generic free memory
+void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr)
+{
+    if (Ptr != NULL) FreePtr(ContextID, Ptr);
+}
+
+// Generic block duplication
+void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)
+{
+    return DupPtr(ContextID, Org, size);
+}
+
+// ********************************************************************************************
+
+// Sub allocation takes care of many pointers of small size. The memory allocated in
+// this way have be freed at once. Next function allocates a single chunk for linked list
+// I prefer this method over realloc due to the big inpact on xput realloc may have if
+// memory is being swapped to disk. This approach is safer (although thats not true on any platform)
+static
+_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
+{
+    _cmsSubAllocator_chunk* chunk;
+
+    // Create the container
+    chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk));
+    if (chunk == NULL) return NULL;
+
+    // Initialize values
+    chunk ->Block     = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial);
+    if (chunk ->Block == NULL) {
+
+        // Something went wrong
+        _cmsFree(ContextID, chunk);
+        return NULL;
+    }
+
+    // 20K by default
+    if (Initial == 0)
+        Initial = 20*1024;
+
+    chunk ->BlockSize = Initial;
+    chunk ->Used      = 0;
+    chunk ->next      = NULL;
+
+    return chunk;
+}
+
+// The suballocated is nothing but a pointer to the first element in the list. We also keep
+// the thread ID in this structure.
+_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial)
+{
+    _cmsSubAllocator* sub;
+
+    // Create the container
+    sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator));
+    if (sub == NULL) return NULL;
+
+    sub ->ContextID = ContextID;
+
+    sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial);
+    if (sub ->h == NULL) {
+        _cmsFree(ContextID, sub);
+        return NULL;
+    }
+
+    return sub;
+}
+
+
+// Get rid of whole linked list
+void _cmsSubAllocDestroy(_cmsSubAllocator* sub)
+{
+    _cmsSubAllocator_chunk *chunk, *n;
+
+    for (chunk = sub ->h; chunk != NULL; chunk = n) {
+
+        n = chunk->next;
+        if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block);
+        _cmsFree(sub ->ContextID, chunk);
+    }
+
+    // Free the header
+    _cmsFree(sub ->ContextID, sub);
+}
+
+
+// Get a pointer to small memory block.
+void*  _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)
+{
+    cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used;
+    cmsUInt8Number* ptr;
+
+    size = _cmsALIGNLONG(size);
+
+    // Check for memory. If there is no room, allocate a new chunk of double memory size.
+    if (size > Free) {
+
+        _cmsSubAllocator_chunk* chunk;
+        cmsUInt32Number newSize;
+
+        newSize = sub -> h ->BlockSize * 2;
+        if (newSize < size) newSize = size;
+
+        chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize);
+        if (chunk == NULL) return NULL;
+
+        // Link list
+        chunk ->next = sub ->h;
+        sub ->h    = chunk;
+
+    }
+
+    ptr =  sub -> h ->Block + sub -> h ->Used;
+    sub -> h -> Used += size;
+
+    return (void*) ptr;
+}
+
+// Error logging ******************************************************************
+
+// There is no error handling at all. When a funtion fails, it returns proper value.
+// For example, all create functions does return NULL on failure. Other return FALSE
+// It may be interesting, for the developer, to know why the function is failing.
+// for that reason, lcms2 does offer a logging function. This function does recive
+// a ENGLISH string with some clues on what is going wrong. You can show this
+// info to the end user, or just create some sort of log.
+// The logging function should NOT terminate the program, as this obviously can leave
+// resources. It is the programmer's responsability to check each function return code
+// to make sure it didn't fail.
+
+// Error messages are limited to MAX_ERROR_MESSAGE_LEN
+
+#define MAX_ERROR_MESSAGE_LEN   1024
+
+// ---------------------------------------------------------------------------------------------------------
+
+// This is our default log error
+static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
+
+// The current handler in actual environment
+static cmsLogErrorHandlerFunction LogErrorHandler   = DefaultLogErrorHandlerFunction;
+
+// The default error logger does nothing.
+static
+void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
+{
+    // fprintf(stderr, "[lcms]: %s\n", Text);
+    // fflush(stderr);
+
+     cmsUNUSED_PARAMETER(ContextID);
+     cmsUNUSED_PARAMETER(ErrorCode);
+     cmsUNUSED_PARAMETER(Text);
+}
+
+// Change log error
+void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn)
+{
+    if (Fn == NULL)
+        LogErrorHandler = DefaultLogErrorHandlerFunction;
+    else
+        LogErrorHandler = Fn;
+}
+
+// Log an error
+// ErrorText is a text holding an english description of error.
+void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...)
+{
+    va_list args;
+    char Buffer[MAX_ERROR_MESSAGE_LEN];
+
+    va_start(args, ErrorText);
+    vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);
+    va_end(args);
+
+    // Call handler
+    LogErrorHandler(ContextID, ErrorCode, Buffer);
+}
+
+// Utility function to print signatures
+void _cmsTagSignature2String(char String[5], cmsTagSignature sig)
+{
+    cmsUInt32Number be;
+
+    // Convert to big endian
+    be = _cmsAdjustEndianess32((cmsUInt32Number) sig);
+
+    // Move chars
+    memmove(String, &be, 4);
+
+    // Make sure of terminator
+    String[4] = 0;
+}
+
--- a/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -48,447 +49,850 @@
 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+#include "lcms2_internal.h"
 
+// Tone curves are powerful constructs that can contain curves specified in diverse ways.
+// The curve is stored in segments, where each segment can be sampled or specified by parameters.
+// a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation,
+// each segment is evaluated separately. Plug-ins may be used to define new parametric schemes,
+// each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function,
+// the plug-in should provide the type id, how many parameters each type has, and a pointer to
+// a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will
+// be called with the type id as a negative value, and a sampled version of the reversed curve
+// will be built.
 
-#include "lcms.h"
+// ----------------------------------------------------------------- Implementation
+// Maxim number of nodes
+#define MAX_NODES_IN_CURVE   4097
+#define MINUS_INF            (-1E22F)
+#define PLUS_INF             (+1E22F)
 
-// Gamma handling.
+// The list of supported parametric curves
+typedef struct _cmsParametricCurvesCollection_st {
 
-LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries);
-void         LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma);
-void         LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3]);
-LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma);
-LPGAMMATABLE LCMSEXPORT cmsDupGamma(LPGAMMATABLE Src);
-LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma);
-LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[]);
-LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma);
-LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma, LPGAMMATABLE OutGamma, int nPoints);
-LCMSBOOL         LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda);
+    int nFunctions;                                     // Number of supported functions in this chunk
+    int FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN];        // The identification types
+    int ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN];       // Number of parameters for each function
+    cmsParametricCurveEvaluator    Evaluator;           // The evaluator
 
-LCMSBOOL         cdecl _cmsSmoothEndpoints(LPWORD Table, int nPoints);
+    struct _cmsParametricCurvesCollection_st* Next; // Next in list
 
+} _cmsParametricCurvesCollection;
 
-// Sampled curves
 
-LPSAMPLEDCURVE cdecl cmsAllocSampledCurve(int nItems);
-void           cdecl cmsFreeSampledCurve(LPSAMPLEDCURVE p);
-void           cdecl cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max);
-void           cdecl cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max);
-LCMSBOOL       cdecl cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double SmoothingLambda);
-void           cdecl cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints);
+// This is the default (built-in) evaluator
+static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R);
 
-LPSAMPLEDCURVE cdecl cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints);
+// The built-in list
+static _cmsParametricCurvesCollection DefaultCurves = {
+    9,                                  // # of curve types
+    { 1, 2, 3, 4, 5, 6, 7, 8, 108 },    // Parametric curve ID
+    { 1, 3, 4, 5, 7, 4, 5, 5, 1 },      // Parameters by type
+    DefaultEvalParametricFn,            // Evaluator
+    NULL                                // Next in chain
+};
 
-double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t);
-double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double Thereshold);
+// The linked list head
+static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves;
 
-// ----------------------------------------------------------------------------------------
+// As a way to install new parametric curves
+cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data)
+{
+    cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data;
+    _cmsParametricCurvesCollection* fl;
 
+    if (Data == NULL) {
 
-#define MAX_KNOTS   4096
-typedef float vec[MAX_KNOTS+1];
+          ParametricCurves =  &DefaultCurves;
+          return TRUE;
+    }
 
+    fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(sizeof(_cmsParametricCurvesCollection));
+    if (fl == NULL) return FALSE;
 
-// Ciclic-redundant-check for assuring table is a true representation of parametric curve
+    // Copy the parameters
+    fl ->Evaluator  = Plugin ->Evaluator;
+    fl ->nFunctions = Plugin ->nFunctions;
 
-// The usual polynomial, which is used for AAL5, FDDI, and probably Ethernet
-#define QUOTIENT 0x04c11db7
+    // Make sure no mem overwrites
+    if (fl ->nFunctions > MAX_TYPES_IN_LCMS_PLUGIN)
+        fl ->nFunctions = MAX_TYPES_IN_LCMS_PLUGIN;
 
+    // Copy the data
+    memmove(fl->FunctionTypes,  Plugin ->FunctionTypes,   fl->nFunctions * sizeof(cmsUInt32Number));
+    memmove(fl->ParameterCount, Plugin ->ParameterCount,  fl->nFunctions * sizeof(cmsUInt32Number));
+
+    // Keep linked list
+    fl ->Next = ParametricCurves;
+    ParametricCurves = fl;
+
+    // All is ok
+    return TRUE;
+}
+
+
+// Search in type list, return position or -1 if not found
 static
-unsigned int Crc32(unsigned int result, LPVOID ptr, int len)
+int IsInSet(int Type, _cmsParametricCurvesCollection* c)
 {
-    int          i,j;
-    BYTE         octet;
-    LPBYTE       data = (LPBYTE) ptr;
+    int i;
 
-    for (i=0; i < len; i++) {
+    for (i=0; i < c ->nFunctions; i++)
+        if (abs(Type) == c ->FunctionTypes[i]) return i;
 
-        octet = *data++;
+    return -1;
+}
 
-        for (j=0; j < 8; j++) {
 
-            if (result & 0x80000000) {
+// Search for the collection which contains a specific type
+static
+_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index)
+{
+    _cmsParametricCurvesCollection* c;
+    int Position;
 
-                result = (result << 1) ^ QUOTIENT ^ (octet >> 7);
-            }
-            else
-            {
-                result = (result << 1) ^ (octet >> 7);
-            }
-            octet <<= 1;
+    for (c = ParametricCurves; c != NULL; c = c ->Next) {
+
+        Position = IsInSet(Type, c);
+
+        if (Position != -1) {
+            if (index != NULL)
+                *index = Position;
+            return c;
         }
     }
 
-    return result;
+    return NULL;
 }
 
-// Get CRC of gamma table
+// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case
+// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the
+// optimization curve is given. Both features simultaneously is an error
+static
+cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries,
+                                      cmsInt32Number nSegments, const cmsCurveSegment* Segments,
+                                      const cmsUInt16Number* Values)
+{
+    cmsToneCurve* p;
+    int i;
 
-unsigned int _cmsCrc32OfGammaTable(LPGAMMATABLE Table)
-{
-    unsigned int crc = ~0U;
+    // We allow huge tables, which are then restricted for smoothing operations
+    if (nEntries > 65530 || nEntries < 0) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries");
+        return NULL;
+    }
 
-    crc = Crc32(crc, &Table -> Seed.Type,  sizeof(int));
-    crc = Crc32(crc, Table ->Seed.Params,  sizeof(double)*10);
-    crc = Crc32(crc, &Table ->nEntries,    sizeof(int));
-    crc = Crc32(crc, Table ->GammaTable,   sizeof(WORD) * Table -> nEntries);
+    if (nEntries <= 0 && nSegments <= 0) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table");
+        return NULL;
+    }
 
-    return ~crc;
+    // Allocate all required pointers, etc.
+    p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve));
+    if (!p) return NULL;
 
+    // In this case, there are no segments
+    if (nSegments <= 0) {
+        p ->Segments = NULL;
+        p ->Evals = NULL;
+    }
+    else {
+        p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment));
+        if (p ->Segments == NULL) goto Error;
+
+        p ->Evals    = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator));
+        if (p ->Evals == NULL) goto Error;
+    }
+
+    p -> nSegments = nSegments;
+
+    // This 16-bit table contains a limited precision representation of the whole curve and is kept for
+    // increasing xput on certain operations.
+    if (nEntries <= 0) {
+        p ->Table16 = NULL;
+    }
+    else {
+       p ->Table16 = (cmsUInt16Number*)  _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number));
+       if (p ->Table16 == NULL) goto Error;
+    }
+
+    p -> nEntries  = nEntries;
+
+    // Initialize members if requested
+    if (Values != NULL && (nEntries > 0)) {
+
+        for (i=0; i < nEntries; i++)
+            p ->Table16[i] = Values[i];
+    }
+
+    // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it
+    // is placed in advance to maximize performance.
+    if (Segments != NULL && (nSegments > 0)) {
+
+        _cmsParametricCurvesCollection *c;
+
+        p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*));
+        if (p ->SegInterp == NULL) goto Error;
+
+        for (i=0; i< nSegments; i++) {
+
+            // Type 0 is a special marker for table-based curves
+            if (Segments[i].Type == 0)
+                p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT);
+
+            memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment));
+
+            if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL)
+                p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints);
+            else
+                p ->Segments[i].SampledPoints = NULL;
+
+
+            c = GetParametricCurveByType(Segments[i].Type, NULL);
+            if (c != NULL)
+                    p ->Evals[i] = c ->Evaluator;
+        }
+    }
+
+    p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS);
+    return p;
+
+Error:
+    if (p -> Segments) _cmsFree(ContextID, p ->Segments);
+    if (p -> Evals) _cmsFree(ContextID, p -> Evals);
+    if (p ->Table16) _cmsFree(ContextID, p ->Table16);
+    _cmsFree(ContextID, p);
+    return NULL;
 }
 
 
-LPGAMMATABLE LCMSEXPORT cmsAllocGamma(int nEntries)
+// Parametric Fn using floating point
+static
+cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R)
 {
-       LPGAMMATABLE p;
-       size_t size;
+    cmsFloat64Number e, Val, disc;
 
-       if (nEntries > 65530 || nEntries <= 0) {
-                cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't create gammatable of more than 65530 entries");
-                return NULL;
-       }
+    switch (Type) {
 
-       size = sizeof(GAMMATABLE) + (sizeof(WORD) * (nEntries-1));
+    // X = Y ^ Gamma
+    case 1:
+        if (R < 0)
+            Val = 0;
+        else
+            Val = pow(R, Params[0]);
+        break;
 
-       p = (LPGAMMATABLE) _cmsMalloc(size);
-       if (!p) return NULL;
+    // Type 1 Reversed: X = Y ^1/gamma
+    case -1:
+        if (R < 0)
+            Val = 0;
+        else
+            Val = pow(R, 1/Params[0]);
+        break;
 
-       ZeroMemory(p, size);
+    // CIE 122-1966
+    // Y = (aX + b)^Gamma  | X >= -b/a
+    // Y = 0               | else
+    case 2:
+        disc = -Params[2] / Params[1];
 
-       p -> Seed.Type     = 0;
-       p -> nEntries = nEntries;
+        if (R >= disc ) {
 
-       return p;
+            e = Params[1]*R + Params[2];
+
+            if (e > 0)
+                Val = pow(e, Params[0]);
+            else
+                Val = 0;
+        }
+        else
+            Val = 0;
+        break;
+
+     // Type 2 Reversed
+     // X = (Y ^1/g  - b) / a
+     case -2:
+         if (R < 0)
+             Val = 0;
+         else
+             Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
+
+         if (Val < 0)
+              Val = 0;
+         break;
+
+
+    // IEC 61966-3
+    // Y = (aX + b)^Gamma | X <= -b/a
+    // Y = c              | else
+    case 3:
+        disc = -Params[2] / Params[1];
+        if (disc < 0)
+            disc = 0;
+
+        if (R >= disc) {
+
+            e = Params[1]*R + Params[2];
+
+            if (e > 0)
+                Val = pow(e, Params[0]) + Params[3];
+            else
+                Val = 0;
+        }
+        else
+            Val = Params[3];
+        break;
+
+
+    // Type 3 reversed
+    // X=((Y-c)^1/g - b)/a      | (Y>=c)
+    // X=-b/a                   | (Y<c)
+    case -3:
+        if (R >= Params[3])  {
+
+            e = R - Params[3];
+
+            if (e > 0)
+                Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1];
+            else
+                Val = 0;
+        }
+        else {
+            Val = -Params[2] / Params[1];
+        }
+        break;
+
+
+    // IEC 61966-2.1 (sRGB)
+    // Y = (aX + b)^Gamma | X >= d
+    // Y = cX             | X < d
+    case 4:
+        if (R >= Params[4]) {
+
+            e = Params[1]*R + Params[2];
+
+            if (e > 0)
+                Val = pow(e, Params[0]);
+            else
+                Val = 0;
+        }
+        else
+            Val = R * Params[3];
+        break;
+
+    // Type 4 reversed
+    // X=((Y^1/g-b)/a)    | Y >= (ad+b)^g
+    // X=Y/c              | Y< (ad+b)^g
+    case -4:
+        e = Params[1] * Params[4] + Params[2];
+        if (e < 0)
+            disc = 0;
+        else
+            disc = pow(e, Params[0]);
+
+        if (R >= disc) {
+
+            Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
+        }
+        else {
+            Val = R / Params[3];
+        }
+        break;
+
+
+    // Y = (aX + b)^Gamma + e | X >= d
+    // Y = cX + f             | X < d
+    case 5:
+        if (R >= Params[4]) {
+
+            e = Params[1]*R + Params[2];
+
+            if (e > 0)
+                Val = pow(e, Params[0]) + Params[5];
+            else
+                Val = 0;
+        }
+        else
+            Val = R*Params[3] + Params[6];
+        break;
+
+
+    // Reversed type 5
+    // X=((Y-e)1/g-b)/a   | Y >=(ad+b)^g+e), cd+f
+    // X=(Y-f)/c          | else
+    case -5:
+
+        disc = Params[3] * Params[4] + Params[6];
+        if (R >= disc) {
+
+            e = R - Params[5];
+            if (e < 0)
+                Val = 0;
+            else
+                Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1];
+        }
+        else {
+            Val = (R - Params[6]) / Params[3];
+        }
+        break;
+
+
+    // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf
+    // Type 6 is basically identical to type 5 without d
+
+    // Y = (a * X + b) ^ Gamma + c
+    case 6:
+        e = Params[1]*R + Params[2];
+
+        if (e < 0)
+            Val = 0;
+        else
+            Val = pow(e, Params[0]) + Params[3];
+        break;
+
+    // ((Y - c) ^1/Gamma - b) / a
+    case -6:
+        e = R - Params[3];
+        if (e < 0)
+            Val = 0;
+        else
+        Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1];
+        break;
+
+
+    // Y = a * log (b * X^Gamma + c) + d
+    case 7:
+
+       e = Params[2] * pow(R, Params[0]) + Params[3];
+       if (e <= 0)
+           Val = 0;
+       else
+           Val = Params[1]*log10(e) + Params[4];
+       break;
+
+    // (Y - d) / a = log(b * X ^Gamma + c)
+    // pow(10, (Y-d) / a) = b * X ^Gamma + c
+    // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X
+    case -7:
+       Val = pow((pow(10.0, (R-Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]);
+       break;
+
+
+   //Y = a * b^(c*X+d) + e
+   case 8:
+       Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]);
+       break;
+
+
+   // Y = (log((y-e) / a) / log(b) - d ) / c
+   // a=0, b=1, c=2, d=3, e=4,
+   case -8:
+
+       disc = R - Params[4];
+       if (disc < 0) Val = 0;
+       else
+           Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2];
+       break;
+
+   // S-Shaped: (1 - (1-x)^1/g)^1/g
+   case 108:
+      Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]);
+      break;
+
+    // y = (1 - (1-x)^1/g)^1/g
+    // y^g = (1 - (1-x)^1/g)
+    // 1 - y^g = (1-x)^1/g
+    // (1 - y^g)^g = 1 - x
+    // 1 - (1 - y^g)^g
+    case -108:
+        Val = 1 - pow(1 - pow(R, Params[0]), Params[0]);
+        break;
+
+    default:
+        // Unsupported parametric curve. Should never reach here
+        return 0;
+    }
+
+    return Val;
 }
 
-void LCMSEXPORT cmsFreeGamma(LPGAMMATABLE Gamma)
+// Evaluate a segmented funtion for a single value. Return -1 if no valid segment found .
+// If fn type is 0, perform an interpolation on the table
+static
+cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
 {
-       if (Gamma)  _cmsFree(Gamma);
+    int i;
+
+    for (i = g ->nSegments-1; i >= 0 ; --i) {
+
+        // Check for domain
+        if ((R > g ->Segments[i].x0) && (R <= g ->Segments[i].x1)) {
+
+            // Type == 0 means segment is sampled
+            if (g ->Segments[i].Type == 0) {
+
+                cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0);
+                cmsFloat32Number Out;
+
+                // Setup the table (TODO: clean that)
+                g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints;
+
+                g ->SegInterp[i] -> Interpolation.LerpFloat(&R1, &Out, g ->SegInterp[i]);
+
+                return Out;
+            }
+            else
+                return g ->Evals[i](g->Segments[i].Type, g ->Segments[i].Params, R);
+        }
+    }
+
+    return MINUS_INF;
 }
 
 
-
-void LCMSEXPORT cmsFreeGammaTriple(LPGAMMATABLE Gamma[3])
+// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
+// floating point description empty.
+cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number Values[])
 {
-    cmsFreeGamma(Gamma[0]);
-    cmsFreeGamma(Gamma[1]);
-    cmsFreeGamma(Gamma[2]);
-    Gamma[0] = Gamma[1] = Gamma[2] = NULL;
+    return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values);
 }
 
-
-
-// Duplicate a gamma table
-
-LPGAMMATABLE  LCMSEXPORT cmsDupGamma(LPGAMMATABLE In)
+static
+int EntriesByGamma(cmsFloat64Number Gamma)
 {
-       LPGAMMATABLE Ptr;
-       size_t size;
-
-       Ptr = cmsAllocGamma(In -> nEntries);
-       if (Ptr == NULL) return NULL;
-
-       size = sizeof(GAMMATABLE) + (sizeof(WORD) * (In -> nEntries-1));
-
-       CopyMemory(Ptr, In, size);
-       return Ptr;
+    if (fabs(Gamma - 1.0) < 0.001) return 2;
+    return 4096;
 }
 
 
-// Handle gamma using interpolation tables. The resulting curves can become
-// very stange, but are pleasent to eye.
+// Create a segmented gamma, fill the table
+cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
+                                                   cmsInt32Number nSegments, const cmsCurveSegment Segments[])
+{
+    int i;
+    cmsFloat64Number R, Val;
+    cmsToneCurve* g;
+    int nGridPoints = 4096;
 
-LPGAMMATABLE LCMSEXPORT cmsJoinGamma(LPGAMMATABLE InGamma,
-                          LPGAMMATABLE OutGamma)
-{
-       register int i;
-       L16PARAMS L16In, L16Out;
-       LPWORD InPtr, OutPtr;
-       LPGAMMATABLE p;
+    _cmsAssert(Segments != NULL);
 
-       p = cmsAllocGamma(256);
-       if (!p) return NULL;
+    // Optimizatin for identity curves.
+    if (nSegments == 1 && Segments[0].Type == 1) {
 
-       cmsCalcL16Params(InGamma -> nEntries, &L16In);
-       InPtr  = InGamma -> GammaTable;
+        nGridPoints = EntriesByGamma(Segments[0].Params[0]);
+    }
 
-       cmsCalcL16Params(OutGamma -> nEntries, &L16Out);
-       OutPtr = OutGamma-> GammaTable;
+    g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL);
+    if (g == NULL) return NULL;
 
-       for (i=0; i < 256; i++)
-       {
-              WORD wValIn, wValOut;
+    // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries
+    // for performance reasons. This table would normally not be used except on 8/16 bits transforms.
+    for (i=0; i < nGridPoints; i++) {
 
-              wValIn  = cmsLinearInterpLUT16(RGB_8_TO_16(i), InPtr, &L16In);
-              wValOut = cmsReverseLinearInterpLUT16(wValIn, OutPtr, &L16Out);
+        R   = (cmsFloat64Number) i / (nGridPoints-1);
 
-              p -> GammaTable[i] = wValOut;
-       }
+        Val = EvalSegmentedFn(g, R);
 
-       return p;
+        // Round and saturate
+        g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0);
+    }
+
+    return g;
 }
 
+// Use a segmented curve to store the floating point table
+cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[])
+{
+    cmsCurveSegment Seg[2];
 
+    // Initialize segmented curve part up to 0
+    Seg[0].x0 = -1;
+    Seg[0].x1 = 0;
+    Seg[0].Type = 6;
 
-// New method, using smoothed parametric curves. This works FAR better.
-// We want to get
-//
-//      y = f(g^-1(x))      ; f = ingamma, g = outgamma
-//
-// And this can be parametrized as
-//
-//      y = f(t)
-//      x = g(t)
+    Seg[0].Params[0] = 1;
+    Seg[0].Params[1] = 0;
+    Seg[0].Params[2] = 0;
+    Seg[0].Params[3] = 0;
+    Seg[0].Params[4] = 0;
 
+    // From zero to any
+    Seg[1].x0 = 0;
+    Seg[1].x1 = 1.0;
+    Seg[1].Type = 0;
 
-LPGAMMATABLE LCMSEXPORT cmsJoinGammaEx(LPGAMMATABLE InGamma,
-                                       LPGAMMATABLE OutGamma, int nPoints)
-{
+    Seg[1].nGridPoints = nEntries;
+    Seg[1].SampledPoints = (cmsFloat32Number*) values;
 
-    LPSAMPLEDCURVE x, y, r;
-    LPGAMMATABLE res;
-
-    x = cmsConvertGammaToSampledCurve(InGamma,  nPoints);
-    y = cmsConvertGammaToSampledCurve(OutGamma, nPoints);
-    r = cmsJoinSampledCurves(y, x, nPoints);
-
-    // Does clean "hair"
-    cmsSmoothSampledCurve(r, 0.001);
-
-    cmsClampSampledCurve(r, 0.0, 65535.0);
-
-    cmsFreeSampledCurve(x);
-    cmsFreeSampledCurve(y);
-
-    res = cmsConvertSampledCurveToGamma(r, 65535.0);
-    cmsFreeSampledCurve(r);
-
-    return res;
+    return cmsBuildSegmentedToneCurve(ContextID, 2, Seg);
 }
 
-
-
-// Reverse a gamma table
-
-LPGAMMATABLE LCMSEXPORT cmsReverseGamma(int nResultSamples, LPGAMMATABLE InGamma)
-{
-       register int i;
-       L16PARAMS L16In;
-       LPWORD InPtr;
-       LPGAMMATABLE p;
-
-       // Try to reverse it analytically whatever possible
-       if (InGamma -> Seed.Type > 0 && InGamma -> Seed.Type <= 5 &&
-            _cmsCrc32OfGammaTable(InGamma) == InGamma -> Seed.Crc32) {
-
-                return cmsBuildParametricGamma(nResultSamples, -(InGamma -> Seed.Type), InGamma ->Seed.Params);
-       }
-
-
-       // Nope, reverse the table
-       p = cmsAllocGamma(nResultSamples);
-       if (!p) return NULL;
-
-       cmsCalcL16Params(InGamma -> nEntries, &L16In);
-       InPtr  = InGamma -> GammaTable;
-
-       for (i=0; i < nResultSamples; i++)
-       {
-              WORD wValIn, wValOut;
-
-              wValIn = _cmsQuantizeVal(i, nResultSamples);
-              wValOut = cmsReverseLinearInterpLUT16(wValIn, InPtr, &L16In);
-              p -> GammaTable[i] = wValOut;
-       }
-
-
-       return p;
-}
-
-
-
 // Parametric curves
 //
-// Parameters goes as: Gamma, a, b, c, d, e, f
+// Parameters goes as: Curve, a, b, c, d, e, f
 // Type is the ICC type +1
 // if type is negative, then the curve is analyticaly inverted
+cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[])
+{
+    cmsCurveSegment Seg0;
+    int Pos = 0;
+    cmsUInt32Number size;
+    _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos);
 
-LPGAMMATABLE LCMSEXPORT cmsBuildParametricGamma(int nEntries, int Type, double Params[])
+    _cmsAssert(Params != NULL);
+
+    if (c == NULL) {
+         cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
+        return NULL;
+    }
+
+    memset(&Seg0, 0, sizeof(Seg0));
+
+    Seg0.x0   = MINUS_INF;
+    Seg0.x1   = PLUS_INF;
+    Seg0.Type = Type;
+
+    size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number);
+    memmove(Seg0.Params, Params, size);
+
+    return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0);
+}
+
+
+
+// Build a gamma table based on gamma constant
+cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma)
 {
-        LPGAMMATABLE Table;
-        double R, Val, dval, e;
-        int i;
-        int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
+    return cmsBuildParametricToneCurve(ContextID, 1, &Gamma);
+}
 
-        Table = cmsAllocGamma(nEntries);
-        if (NULL == Table) return NULL;
 
-        Table -> Seed.Type = Type;
+// Free all memory taken by the gamma curve
+void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve)
+{
+    cmsContext ContextID;
 
-        CopyMemory(Table ->Seed.Params, Params, ParamsByType[abs(Type)] * sizeof(double));
+    if (Curve == NULL) return;
 
+    ContextID = Curve ->InterpParams->ContextID;
 
-        for (i=0; i < nEntries; i++) {
+    _cmsFreeInterpParams(Curve ->InterpParams);
 
-                R   = (double) i / (nEntries-1);
+    if (Curve -> Table16)
+        _cmsFree(ContextID, Curve ->Table16);
 
-                switch (Type) {
+    if (Curve ->Segments) {
 
-                // X = Y ^ Gamma
-                case 1:
-                      Val = pow(R, Params[0]);
-                      break;
+        cmsUInt32Number i;
 
-                // Type 1 Reversed: X = Y ^1/gamma
-                case -1:
-                      Val = pow(R, 1/Params[0]);
-                      break;
+        for (i=0; i < Curve ->nSegments; i++) {
 
-                // CIE 122-1966
-                // Y = (aX + b)^Gamma  | X >= -b/a
-                // Y = 0               | else
-                case 2:
-                    if (R >= -Params[2] / Params[1]) {
+            if (Curve ->Segments[i].SampledPoints) {
+                _cmsFree(ContextID, Curve ->Segments[i].SampledPoints);
+            }
 
-                              e = Params[1]*R + Params[2];
-
-                              if (e > 0)
-                                Val = pow(e, Params[0]);
-                              else
-                                Val = 0;
-                    }
-                    else
-                              Val = 0;
-                      break;
-
-                // Type 2 Reversed
-                // X = (Y ^1/g  - b) / a
-                case -2:
-
-                    Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
-                    if (Val < 0)
-                            Val = 0;
-                    break;
-
-
-                // IEC 61966-3
-                // Y = (aX + b)^Gamma | X <= -b/a
-                // Y = c              | else
-                case 3:
-                    if (R >= -Params[2] / Params[1]) {
-
-                      e = Params[1]*R + Params[2];
-                      Val = pow(e, Params[0]) + Params[3];
-                    }
-                    else
-                      Val = Params[3];
-                    break;
-
-
-                // Type 3 reversed
-                // X=((Y-c)^1/g - b)/a      | (Y>=c)
-                // X=-b/a                   | (Y<c)
-
-                case -3:
-                    if (R >= Params[3])  {
-                        e = R - Params[3];
-                        Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1];
-                        if (Val < 0) Val = 0;
-                    }
-                    else {
-                        Val = -Params[2] / Params[1];
-                    }
-                    break;
-
-
-                // IEC 61966-2.1 (sRGB)
-                // Y = (aX + b)^Gamma | X >= d
-                // Y = cX             | X < d
-                case 4:
-                    if (R >= Params[4]) {
-
-                              e = Params[1]*R + Params[2];
-                              if (e > 0)
-                                Val = pow(e, Params[0]);
-                              else
-                                Val = 0;
-                    }
-                      else
-                              Val = R * Params[3];
-                      break;
-
-                // Type 4 reversed
-                // X=((Y^1/g-b)/a)    | Y >= (ad+b)^g
-                // X=Y/c              | Y< (ad+b)^g
-
-                case -4:
-                    if (R >= pow(Params[1] * Params[4] + Params[2], Params[0])) {
-
-                        Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
-                    }
-                    else {
-                        Val = R / Params[3];
-                    }
-                    break;
-
-
-
-                // Y = (aX + b)^Gamma + e | X <= d
-                // Y = cX + f             | else
-                case 5:
-                    if (R >= Params[4]) {
-
-                        e = Params[1]*R + Params[2];
-                        Val = pow(e, Params[0]) + Params[5];
-                    }
-                    else
-                        Val = R*Params[3] + Params[6];
-                    break;
-
-
-                // Reversed type 5
-                // X=((Y-e)1/g-b)/a   | Y >=(ad+b)^g+e)
-                // X=(Y-f)/c          | else
-                case -5:
-
-                if (R >= pow(Params[1] * Params[4], Params[0]) + Params[5]) {
-
-                    Val = pow(R - Params[5], 1/Params[0]) - Params[2] / Params[1];
-                }
-                else {
-                    Val = (R - Params[6]) / Params[3];
-                }
-                break;
-
-                default:
-                        cmsSignalError(LCMS_ERRC_ABORTED, "Unsupported parametric curve type=%d", abs(Type)-1);
-                        cmsFreeGamma(Table);
-                        return NULL;
-                }
-
-
-        // Saturate
-
-        dval = Val * 65535.0 + .5;
-        if (dval > 65535.) dval = 65535.0;
-        if (dval < 0) dval = 0;
-
-        Table->GammaTable[i] = (WORD) floor(dval);
+            if (Curve ->SegInterp[i] != 0)
+                _cmsFreeInterpParams(Curve->SegInterp[i]);
         }
 
-        Table -> Seed.Crc32 = _cmsCrc32OfGammaTable(Table);
+        _cmsFree(ContextID, Curve ->Segments);
+        _cmsFree(ContextID, Curve ->SegInterp);
+    }
 
-        return Table;
+    if (Curve -> Evals)
+        _cmsFree(ContextID, Curve -> Evals);
+
+    if (Curve) _cmsFree(ContextID, Curve);
 }
 
-// Build a gamma table based on gamma constant
+// Utility function, free 3 gamma tables
+void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3])
+{
 
-LPGAMMATABLE LCMSEXPORT cmsBuildGamma(int nEntries, double Gamma)
-{
-    return cmsBuildParametricGamma(nEntries, 1, &Gamma);
+    _cmsAssert(Curve != NULL);
+
+    if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]);
+    if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]);
+    if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]);
+
+    Curve[0] = Curve[1] = Curve[2] = NULL;
 }
 
 
+// Duplicate a gamma table
+cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In)
+{
+    if (In == NULL) return NULL;
+
+    return  AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16);
+}
+
+// Joins two curves for X and Y. Curves should be monotonic.
+// We want to get
+//
+//      y = Y^-1(X(t))
+//
+cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID,
+                                      const cmsToneCurve* X,
+                                      const cmsToneCurve* Y, cmsUInt32Number nResultingPoints)
+{
+    cmsToneCurve* out = NULL;
+    cmsToneCurve* Yreversed = NULL;
+    cmsFloat32Number t, x;
+    cmsFloat32Number* Res = NULL;
+    cmsUInt32Number i;
+
+
+    _cmsAssert(X != NULL);
+    _cmsAssert(Y != NULL);
+
+    Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y);
+    if (Yreversed == NULL) goto Error;
+
+    Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number));
+    if (Res == NULL) goto Error;
+
+    //Iterate
+    for (i=0; i <  nResultingPoints; i++) {
+
+        t = (cmsFloat32Number) i / (nResultingPoints-1);
+        x = cmsEvalToneCurveFloat(X,  t);
+        Res[i] = cmsEvalToneCurveFloat(Yreversed, x);
+    }
+
+    // Allocate space for output
+    out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res);
+
+Error:
+
+    if (Res != NULL) _cmsFree(ContextID, Res);
+    if (Yreversed != NULL) cmsFreeToneCurve(Yreversed);
+
+    return out;
+}
+
+
+
+// Get the surrounding nodes. This is tricky on non-monotonic tables
+static
+int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p)
+{
+    int i;
+    int y0, y1;
+
+    // A 1 point table is not allowed
+    if (p -> Domain[0] < 1) return -1;
+
+    // Let's see if ascending or descending.
+    if (LutTable[0] < LutTable[p ->Domain[0]]) {
+
+        // Table is overall ascending
+        for (i=p->Domain[0]-1; i >=0; --i) {
+
+            y0 = LutTable[i];
+            y1 = LutTable[i+1];
+
+            if (y0 <= y1) { // Increasing
+                if (In >= y0 && In <= y1) return i;
+            }
+            else
+                if (y1 < y0) { // Decreasing
+                    if (In >= y1 && In <= y0) return i;
+                }
+        }
+    }
+    else {
+        // Table is overall descending
+        for (i=0; i < (int) p -> Domain[0]; i++) {
+
+            y0 = LutTable[i];
+            y1 = LutTable[i+1];
+
+            if (y0 <= y1) { // Increasing
+                if (In >= y0 && In <= y1) return i;
+            }
+            else
+                if (y1 < y0) { // Decreasing
+                    if (In >= y1 && In <= y0) return i;
+                }
+        }
+    }
+
+    return -1;
+}
+
+// Reverse a gamma table
+cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve)
+{
+    cmsToneCurve *out;
+    cmsFloat64Number a = 1, b = 0, y, x1, y1, x2, y2;
+    int i, j;
+    int Ascending;
+
+    _cmsAssert(InCurve != NULL);
+
+    // Try to reverse it analytically whatever possible
+    if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) {
+
+        return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID,
+                                       -(InCurve -> Segments[0].Type),
+                                       InCurve -> Segments[0].Params);
+    }
+
+    // Nope, reverse the table.
+    out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL);
+    if (out == NULL)
+        return NULL;
+
+    // We want to know if this is an ascending or descending table
+    Ascending = !cmsIsToneCurveDescending(InCurve);
+
+    // Iterate across Y axis
+    for (i=0; i <  nResultSamples; i++) {
+
+        y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1);
+
+        // Find interval in which y is within.
+        j = GetInterval(y, InCurve->Table16, InCurve->InterpParams);
+        if (j >= 0) {
+
+            // Get limits of interval
+            x1 = InCurve ->Table16[j];
+            x2 = InCurve ->Table16[j+1];
+
+            y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1);
+            y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1);
+
+            // If collapsed, then use any
+            if (x1 == x2) {
+
+                out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1);
+                continue;
+
+            } else {
+
+                // Interpolate
+                a = (y2 - y1) / (x2 - x1);
+                b = y2 - a * x2;
+            }
+        }
+
+        out ->Table16[i] = _cmsQuickSaturateWord(a* y + b);
+    }
+
+    return out;
+}
+
+// Reverse a gamma table
+cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma)
+{
+    _cmsAssert(InGamma != NULL);
+
+    return cmsReverseToneCurveEx(InGamma -> nEntries, InGamma);
+}
 
 // From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite
 // differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press.
@@ -499,485 +903,264 @@
 //   Input:  smoothing parameter (lambda), length (m).
 //   Output: smoothed vector (z): vector from 1 to m.
 
+static
+cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[], cmsFloat32Number z[], cmsFloat32Number lambda, int m)
+{
+    int i, i1, i2;
+    cmsFloat32Number *c, *d, *e;
+    cmsBool st;
 
-static
-void smooth2(vec w, vec y, vec z, float lambda, int m)
-{
-  int i, i1, i2;
-  vec c, d, e;
-  d[1] = w[1] + lambda;
-  c[1] = -2 * lambda / d[1];
-  e[1] = lambda /d[1];
-  z[1] = w[1] * y[1];
-  d[2] = w[2] + 5 * lambda - d[1] * c[1] *  c[1];
-  c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2];
-  e[2] = lambda / d[2];
-  z[2] = w[2] * y[2] - c[1] * z[1];
-  for (i = 3; i < m - 1; i++) {
-    i1 = i - 1; i2 = i - 2;
-    d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
-    c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i];
-    e[i] = lambda / d[i];
-    z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2];
-  }
-  i1 = m - 2; i2 = m - 3;
-  d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
-  c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1];
-  z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2];
-  i1 = m - 1; i2 = m - 2;
-  d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
-  z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m];
-  z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m];
-  for (i = m - 2; 1<= i; i--)
-     z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2];
+
+    c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
+    d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
+    e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
+
+    if (c != NULL && d != NULL && e != NULL) {
+
+
+    d[1] = w[1] + lambda;
+    c[1] = -2 * lambda / d[1];
+    e[1] = lambda /d[1];
+    z[1] = w[1] * y[1];
+    d[2] = w[2] + 5 * lambda - d[1] * c[1] *  c[1];
+    c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2];
+    e[2] = lambda / d[2];
+    z[2] = w[2] * y[2] - c[1] * z[1];
+
+    for (i = 3; i < m - 1; i++) {
+        i1 = i - 1; i2 = i - 2;
+        d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
+        c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i];
+        e[i] = lambda / d[i];
+        z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2];
+    }
+
+    i1 = m - 2; i2 = m - 3;
+
+    d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
+    c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1];
+    z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2];
+    i1 = m - 1; i2 = m - 2;
+
+    d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
+    z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m];
+    z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m];
+
+    for (i = m - 2; 1<= i; i--)
+        z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2];
+
+      st = TRUE;
+    }
+    else st = FALSE;
+
+    if (c != NULL) _cmsFree(ContextID, c);
+    if (d != NULL) _cmsFree(ContextID, d);
+    if (e != NULL) _cmsFree(ContextID, e);
+
+    return st;
 }
 
-
-
-// Smooths a curve sampled at regular intervals
-
-LCMSBOOL LCMSEXPORT cmsSmoothGamma(LPGAMMATABLE Tab, double lambda)
-
+// Smooths a curve sampled at regular intervals.
+cmsBool  CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda)
 {
-    vec w, y, z;
+    cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE];
     int i, nItems, Zeros, Poles;
 
+    if (Tab == NULL) return FALSE;
 
-    if (cmsIsLinear(Tab->GammaTable, Tab->nEntries)) return FALSE; // Nothing to do
+    if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do
 
     nItems = Tab -> nEntries;
 
-    if (nItems > MAX_KNOTS) {
-                cmsSignalError(LCMS_ERRC_ABORTED, "cmsSmoothGamma: too many points.");
-                return FALSE;
-                }
+    if (nItems >= MAX_NODES_IN_CURVE) {
+        cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: too many points.");
+        return FALSE;
+    }
 
-    ZeroMemory(w, nItems * sizeof(float));
-    ZeroMemory(y, nItems * sizeof(float));
-    ZeroMemory(z, nItems * sizeof(float));
+    memset(w, 0, nItems * sizeof(cmsFloat32Number));
+    memset(y, 0, nItems * sizeof(cmsFloat32Number));
+    memset(z, 0, nItems * sizeof(cmsFloat32Number));
 
     for (i=0; i < nItems; i++)
     {
-        y[i+1] = (float) Tab -> GammaTable[i];
+        y[i+1] = (cmsFloat32Number) Tab -> Table16[i];
         w[i+1] = 1.0;
     }
 
-    smooth2(w, y, z, (float) lambda, nItems);
+    if (!smooth2(Tab ->InterpParams->ContextID, w, y, z, (cmsFloat32Number) lambda, nItems)) return FALSE;
 
     // Do some reality - checking...
     Zeros = Poles = 0;
     for (i=nItems; i > 1; --i) {
 
-            if (z[i] == 0.) Zeros++;
-            if (z[i] >= 65535.) Poles++;
-            if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
+        if (z[i] == 0.) Zeros++;
+        if (z[i] >= 65535.) Poles++;
+        if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
     }
 
     if (Zeros > (nItems / 3)) return FALSE;  // Degenerated, mostly zeros
     if (Poles > (nItems / 3)) return FALSE;  // Degenerated, mostly poles
 
     // Seems ok
-
     for (i=0; i < nItems; i++) {
 
-        // Clamp to WORD
-
-        float v = z[i+1];
-
-        if (v < 0) v = 0;
-        if (v > 65535.) v = 65535.;
-
-        Tab -> GammaTable[i] = (WORD) floor(v + .5);
-        }
+        // Clamp to cmsUInt16Number
+        Tab -> Table16[i] = _cmsQuickSaturateWord(z[i+1]);
+    }
 
     return TRUE;
 }
 
+// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting
+// in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases.
+cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
+{
+    cmsUInt32Number i;
+    int diff;
 
-// Check if curve is exponential, return gamma if so.
+    _cmsAssert(Curve != NULL);
 
-double LCMSEXPORT cmsEstimateGammaEx(LPWORD GammaTable, int nEntries, double Thereshold)
+    for (i=0; i < Curve ->nEntries; i++) {
+
+        diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries));
+        if (diff > 0x0f)
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+// Same, but for monotonicity
+cmsBool  CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
 {
-    double gamma, sum, sum2;
-    double n, x, y, Std;
-    int i;
+    int n;
+    int i, last;
+
+    _cmsAssert(t != NULL);
+
+    n    = t ->nEntries;
+    last = t ->Table16[n-1];
+
+    for (i = n-2; i >= 0; --i) {
+
+        if (t ->Table16[i] > last)
+
+            return FALSE;
+        else
+            last = t ->Table16[i];
+
+    }
+
+    return TRUE;
+}
+
+// Same, but for descending tables
+cmsBool  CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t)
+{
+    _cmsAssert(t != NULL);
+
+    return t ->Table16[0] > t ->Table16[t ->nEntries-1];
+}
+
+
+// Another info fn: is out gamma table multisegment?
+cmsBool  CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t)
+{
+    _cmsAssert(t != NULL);
+
+    return t -> nSegments > 1;
+}
+
+cmsInt32Number  CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t)
+{
+    _cmsAssert(t != NULL);
+
+    if (t -> nSegments != 1) return 0;
+    return t ->Segments[0].Type;
+}
+
+// We need accuracy this time
+cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v)
+{
+    _cmsAssert(Curve != NULL);
+
+    // Check for 16 bits table. If so, this is a limited-precision tone curve
+    if (Curve ->nSegments == 0) {
+
+        cmsUInt16Number In, Out;
+
+        In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0);
+        Out = cmsEvalToneCurve16(Curve, In);
+
+        return (cmsFloat32Number) (Out / 65535.0);
+    }
+
+    return (cmsFloat32Number) EvalSegmentedFn(Curve, v);
+}
+
+// We need xput over here
+cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v)
+{
+    cmsUInt16Number out;
+
+    _cmsAssert(Curve != NULL);
+
+    Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams);
+    return out;
+}
+
+
+// Least squares fitting.
+// A mathematical procedure for finding the best-fitting curve to a given set of points by
+// minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve.
+// The sum of the squares of the offsets is used instead of the offset absolute values because
+// this allows the residuals to be treated as a continuous differentiable quantity.
+//
+// y = f(x) = x ^ g
+//
+// R  = (yi - (xi^g))
+// R2 = (yi - (xi^g))2
+// SUM R2 = SUM (yi - (xi^g))2
+//
+// dR2/dg = -2 SUM x^g log(x)(y - x^g)
+// solving for dR2/dg = 0
+//
+// g = 1/n * SUM(log(y) / log(x))
+
+cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision)
+{
+    cmsFloat64Number gamma, sum, sum2;
+    cmsFloat64Number n, x, y, Std;
+    cmsUInt32Number i;
+
+    _cmsAssert(t != NULL);
 
     sum = sum2 = n = 0;
 
-    // Does exclude endpoints
-    for (i=1; i < nEntries - 1; i++) {
+    // Excluding endpoints
+    for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) {
 
-            x = (double) i / (nEntries - 1);
-            y = (double) GammaTable[i] / 65535.;
+        x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1);
+        y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x);
 
-            // Avoid 7% on lower part to prevent
-            // artifacts due to linear ramps
+        // Avoid 7% on lower part to prevent
+        // artifacts due to linear ramps
 
-            if (y > 0. && y < 1. && x > 0.07) {
+        if (y > 0. && y < 1. && x > 0.07) {
 
             gamma = log(y) / log(x);
             sum  += gamma;
             sum2 += gamma * gamma;
             n++;
-            }
-
+        }
     }
 
     // Take a look on SD to see if gamma isn't exponential at all
     Std = sqrt((n * sum2 - sum * sum) / (n*(n-1)));
 
-
-    if (Std > Thereshold)
+    if (Std > Precision)
         return -1.0;
 
     return (sum / n);   // The mean
 }
 
-
-double LCMSEXPORT cmsEstimateGamma(LPGAMMATABLE t)
-{
-        return cmsEstimateGammaEx(t->GammaTable, t->nEntries, 0.7);
-}
-
-
-// -----------------------------------------------------------------Sampled curves
-
-// Allocate a empty curve
-
-LPSAMPLEDCURVE cmsAllocSampledCurve(int nItems)
-{
-    LPSAMPLEDCURVE pOut;
-
-    pOut = (LPSAMPLEDCURVE) _cmsMalloc(sizeof(SAMPLEDCURVE));
-    if (pOut == NULL)
-            return NULL;
-
-    if((pOut->Values = (double *) _cmsMalloc(nItems * sizeof(double))) == NULL)
-    {
-         _cmsFree(pOut);
-        return NULL;
-    }
-
-    pOut->nItems = nItems;
-    ZeroMemory(pOut->Values, nItems * sizeof(double));
-
-    return pOut;
-}
-
-
-void cmsFreeSampledCurve(LPSAMPLEDCURVE p)
-{
-     _cmsFree((LPVOID) p -> Values);
-     _cmsFree((LPVOID) p);
-}
-
-
-
-// Does duplicate a sampled curve
-
-LPSAMPLEDCURVE cmsDupSampledCurve(LPSAMPLEDCURVE p)
-{
-    LPSAMPLEDCURVE out;
-
-    out = cmsAllocSampledCurve(p -> nItems);
-    if (!out) return NULL;
-
-    CopyMemory(out ->Values, p ->Values, p->nItems * sizeof(double));
-
-    return out;
-}
-
-
-// Take min, max of curve
-
-void cmsEndpointsOfSampledCurve(LPSAMPLEDCURVE p, double* Min, double* Max)
-{
-        int i;
-
-        *Min = 65536.;
-        *Max = 0.;
-
-        for (i=0; i < p -> nItems; i++) {
-
-                double v = p -> Values[i];
-
-                if (v < *Min)
-                        *Min = v;
-
-                if (v > *Max)
-                        *Max = v;
-        }
-
-        if (*Min < 0) *Min = 0;
-        if (*Max > 65535.0) *Max = 65535.0;
-}
-
-// Clamps to Min, Max
-
-void cmsClampSampledCurve(LPSAMPLEDCURVE p, double Min, double Max)
-{
-
-        int i;
-
-        for (i=0; i < p -> nItems; i++) {
-
-                double v = p -> Values[i];
-
-                if (v < Min)
-                        v = Min;
-
-                if (v > Max)
-                        v = Max;
-
-                p -> Values[i] = v;
-
-        }
-
-}
-
-
-
-// Smooths a curve sampled at regular intervals
-
-LCMSBOOL cmsSmoothSampledCurve(LPSAMPLEDCURVE Tab, double lambda)
-{
-    vec w, y, z;
-    int i, nItems;
-
-    nItems = Tab -> nItems;
-
-    if (nItems > MAX_KNOTS) {
-                cmsSignalError(LCMS_ERRC_ABORTED, "cmsSmoothSampledCurve: too many points.");
-                return FALSE;
-                }
-
-    ZeroMemory(w, nItems * sizeof(float));
-    ZeroMemory(y, nItems * sizeof(float));
-    ZeroMemory(z, nItems * sizeof(float));
-
-    for (i=0; i < nItems; i++)
-    {
-        float value = (float) Tab -> Values[i];
-
-        y[i+1] = value;
-        w[i+1] = (float) ((value < 0.0) ?  0 : 1);
-    }
-
-
-    smooth2(w, y, z, (float) lambda, nItems);
-
-    for (i=0; i < nItems; i++) {
-
-        Tab -> Values[i] = z[i+1];;
-     }
-
-    return TRUE;
-
-}
-
-
-// Scale a value v, within domain Min .. Max
-// to a domain 0..(nPoints-1)
-
-static
-double ScaleVal(double v, double Min, double Max, int nPoints)
-{
-
-        double a, b;
-
-        if (v <= Min) return 0;
-        if (v >= Max) return (nPoints-1);
-
-        a = (double) (nPoints - 1) / (Max - Min);
-        b = a * Min;
-
-        return (a * v) - b;
-
-}
-
-
-// Does rescale a sampled curve to fit in a 0..(nPoints-1) domain
-
-void cmsRescaleSampledCurve(LPSAMPLEDCURVE p, double Min, double Max, int nPoints)
-{
-
-        int i;
-
-        for (i=0; i < p -> nItems; i++) {
-
-                double v = p -> Values[i];
-
-                p -> Values[i] = ScaleVal(v, Min, Max, nPoints);
-        }
-
-}
-
-
-// Joins two sampled curves for X and Y. Curves should be sorted.
-
-LPSAMPLEDCURVE cmsJoinSampledCurves(LPSAMPLEDCURVE X, LPSAMPLEDCURVE Y, int nResultingPoints)
-{
-    int i, j;
-    LPSAMPLEDCURVE out;
-    double MinX, MinY, MaxX, MaxY;
-    double x, y, x1, y1, x2, y2, a, b;
-
-    out = cmsAllocSampledCurve(nResultingPoints);
-    if (out == NULL)
-        return NULL;
-
-    if (X -> nItems != Y -> nItems) {
-
-        cmsSignalError(LCMS_ERRC_ABORTED, "cmsJoinSampledCurves: invalid curve.");
-        cmsFreeSampledCurve(out);
-        return NULL;
-    }
-
-    // Get endpoints of sampled curves
-    cmsEndpointsOfSampledCurve(X, &MinX, &MaxX);
-    cmsEndpointsOfSampledCurve(Y, &MinY, &MaxY);
-
-
-    // Set our points
-    out ->Values[0] = MinY;
-    for (i=1; i < nResultingPoints; i++) {
-
-        // Scale t to x domain
-        x = (i * (MaxX - MinX) / (nResultingPoints-1)) + MinX;
-
-        // Find interval in which j is within (always up,
-        // since fn should be monotonic at all)
-
-        j = 1;
-        while ((j < X ->nItems - 1) && X ->Values[j] < x)
-            j++;
-
-        // Now x is within X[j-1], X[j]
-        x1 = X ->Values[j-1]; x2 = X ->Values[j];
-        y1 = Y ->Values[j-1]; y2 = Y ->Values[j];
-
-        // Interpolate  the value
-        a = (y1 - y2) / (x1 - x2);
-        b = y1 - a * x1;
-        y = a* x + b;
-
-        out ->Values[i] = y;
-    }
-
-
-    cmsClampSampledCurve(out, MinY, MaxY);
-    return out;
-}
-
-
-
-// Convert between curve types
-
-LPGAMMATABLE cmsConvertSampledCurveToGamma(LPSAMPLEDCURVE Sampled, double Max)
-{
-    LPGAMMATABLE Gamma;
-    int i, nPoints;
-
-
-    nPoints = Sampled ->nItems;
-
-    Gamma = cmsAllocGamma(nPoints);
-    for (i=0; i < nPoints; i++) {
-
-        Gamma->GammaTable[i] = (WORD) floor(ScaleVal(Sampled ->Values[i], 0, Max, 65536) + .5);
-    }
-
-    return Gamma;
-
-}
-
-// Inverse of anterior
-
-LPSAMPLEDCURVE cmsConvertGammaToSampledCurve(LPGAMMATABLE Gamma, int nPoints)
-{
-    LPSAMPLEDCURVE Sampled;
-    L16PARAMS L16;
-    int i;
-    WORD wQuant, wValIn;
-
-    if (nPoints > 4096) {
-
-        cmsSignalError(LCMS_ERRC_ABORTED, "cmsConvertGammaToSampledCurve: too many points (max=4096)");
-        return NULL;
-    }
-
-    cmsCalcL16Params(Gamma -> nEntries, &L16);
-
-    Sampled = cmsAllocSampledCurve(nPoints);
-    for (i=0; i < nPoints; i++) {
-            wQuant  = _cmsQuantizeVal(i, nPoints);
-            wValIn  = cmsLinearInterpLUT16(wQuant, Gamma ->GammaTable, &L16);
-            Sampled ->Values[i] = (float) wValIn;
-    }
-
-    return Sampled;
-}
-
-
-
-
-// Smooth endpoints (used in Black/White compensation)
-
-LCMSBOOL _cmsSmoothEndpoints(LPWORD Table, int nEntries)
-{
-    vec w, y, z;
-    int i, Zeros, Poles;
-
-
-
-    if (cmsIsLinear(Table, nEntries)) return FALSE; // Nothing to do
-
-
-    if (nEntries > MAX_KNOTS) {
-                cmsSignalError(LCMS_ERRC_ABORTED, "_cmsSmoothEndpoints: too many points.");
-                return FALSE;
-                }
-
-    ZeroMemory(w, nEntries * sizeof(float));
-    ZeroMemory(y, nEntries * sizeof(float));
-    ZeroMemory(z, nEntries * sizeof(float));
-
-    for (i=0; i < nEntries; i++)
-    {
-        y[i+1] = (float) Table[i];
-        w[i+1] = 1.0;
-    }
-
-    w[1]        = 65535.0;
-    w[nEntries] = 65535.0;
-
-    smooth2(w, y, z, (float) nEntries, nEntries);
-
-    // Do some reality - checking...
-    Zeros = Poles = 0;
-    for (i=nEntries; i > 1; --i) {
-
-            if (z[i] == 0.) Zeros++;
-            if (z[i] >= 65535.) Poles++;
-            if (z[i] < z[i-1]) return FALSE; // Non-Monotonic
-    }
-
-    if (Zeros > (nEntries / 3)) return FALSE;  // Degenerated, mostly zeros
-    if (Poles > (nEntries / 3)) return FALSE;    // Degenerated, mostly poles
-
-    // Seems ok
-
-    for (i=0; i < nEntries; i++) {
-
-        // Clamp to WORD
-
-        float v = z[i+1];
-
-        if (v < 0) v = 0;
-        if (v > 65535.) v = 65535.;
-
-        Table[i] = (WORD) floor(v + .5);
-        }
-
-    return TRUE;
-}
--- a/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -48,871 +49,383 @@
 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
 
+#include "lcms2_internal.h"
 
-#include "lcms.h"
 
-/*
-Gamut check by default is a catching of 0xFFFF/0xFFFF/0xFFFF PCS values, used
-internally by lcms to hold invalid values. Matrix LUT's, operates in a way that
-unencodeable values are marked as this combination, if PCS is XYZ, this is a very
-high value since encoding is a 1.15 fixed point, something like 1.9997, 1.9997, 1.9997
-not a very common color after all. Lab PCS is not to be a problem, since L>100 are truely
-undefined. There is a posibility than ICC comitee defines L>100 as a valid means
-to use highlights, then it will be lost.
+// Auxiliar: append a Lab identity after the given sequence of profiles
+// and return the transform. Lab profile is closed, rest of profiles are kept open.
+cmsHTRANSFORM _cmsChain2Lab(cmsContext            ContextID,
+                            cmsUInt32Number        nProfiles,
+                            cmsUInt32Number        InputFormat,
+                            cmsUInt32Number        OutputFormat,
+                            const cmsUInt32Number  Intents[],
+                            const cmsHPROFILE      hProfiles[],
+                            const cmsBool          BPC[],
+                            const cmsFloat64Number AdaptationStates[],
+                            cmsUInt32Number        dwFlags)
+{
+    cmsHTRANSFORM xform;
+    cmsHPROFILE   hLab;
+    cmsHPROFILE   ProfileList[256];
+    cmsBool       BPCList[256];
+    cmsFloat64Number AdaptationList[256];
+    cmsUInt32Number IntentList[256];
+    cmsUInt32Number i;
 
-(1.10 - Actually ICC did it, so this should be checked for full ICC 4.0 support)
+    // This is a rather big number and there is no need of dynamic memory
+    // since we are adding a profile, 254 + 1 = 255 and this is the limit
+    if (nProfiles > 254) return NULL;
 
-*/
+    // The output space
+    hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+    if (hLab == NULL) return NULL;
 
+    // Create a copy of parameters
+    for (i=0; i < nProfiles; i++) {
 
-LCMSBOOL _cmsEndPointsBySpace(icColorSpaceSignature Space, WORD **White, WORD **Black,
-                            int *nOutputs)
-{
-       // Only most common spaces
+        ProfileList[i]    = hProfiles[i];
+        BPCList[i]        = BPC[i];
+        AdaptationList[i] = AdaptationStates[i];
+        IntentList[i]     = Intents[i];
+    }
 
-       static WORD RGBblack[4]  = { 0, 0, 0 };
-       static WORD RGBwhite[4]  = { 0xffff, 0xffff, 0xffff };
-       static WORD CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff };   // 400% of ink
-       static WORD CMYKwhite[4] = { 0, 0, 0, 0 };
-       static WORD LABblack[4]  = { 0, 0x8000, 0x8000 };
-       static WORD LABwhite[4]  = { 0xFF00, 0x8000, 0x8000 };
-       static WORD CMYblack[4]  = { 0xffff, 0xffff, 0xffff };
-       static WORD CMYwhite[4]  = { 0, 0, 0 };
-       static WORD Grayblack[4] = { 0 };
-       static WORD GrayWhite[4] = { 0xffff };
+    // Place Lab identity at chain's end.
+    ProfileList[nProfiles]    = hLab;
+    BPCList[nProfiles]        = 0;
+    AdaptationList[nProfiles] = 1.0;
+    IntentList[nProfiles]     = INTENT_RELATIVE_COLORIMETRIC;
 
-       switch (Space) {
+    // Create the transform
+    xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList,
+                                       BPCList,
+                                       IntentList,
+                                       AdaptationList,
+                                       NULL, 0,
+                                       InputFormat,
+                                       OutputFormat,
+                                       dwFlags);
 
-       case icSigGrayData: if (White)    *White = GrayWhite;
-                           if (Black)    *Black = Grayblack;
-                           if (nOutputs) *nOutputs = 1;
-                           return TRUE;
+    cmsCloseProfile(hLab);
 
-       case icSigRgbData:  if (White)    *White = RGBwhite;
-                           if (Black)    *Black = RGBblack;
-                           if (nOutputs) *nOutputs = 3;
-                           return TRUE;
-
-       case icSigLabData:  if (White)    *White = LABwhite;
-                           if (Black)    *Black = LABblack;
-                           if (nOutputs) *nOutputs = 3;
-                           return TRUE;
-
-       case icSigCmykData: if (White)    *White = CMYKwhite;
-                           if (Black)    *Black = CMYKblack;
-                           if (nOutputs) *nOutputs = 4;
-                           return TRUE;
-
-       case icSigCmyData:  if (White)    *White = CMYwhite;
-                           if (Black)    *Black = CMYblack;
-                           if (nOutputs) *nOutputs = 3;
-                           return TRUE;
-
-       default:;
-       }
-
-  return FALSE;
+    return xform;
 }
 
 
-WORD *_cmsWhiteBySpace(icColorSpaceSignature Space)
+// Compute K -> L* relationship. Flags may include black point compensation. In this case,
+// the relationship is assumed from the profile with BPC to a black point zero.
+static
+cmsToneCurve* ComputeKToLstar(cmsContext            ContextID,
+                               cmsUInt32Number       nPoints,
+                               cmsUInt32Number       nProfiles,
+                               const cmsUInt32Number Intents[],
+                               const cmsHPROFILE     hProfiles[],
+                               const cmsBool         BPC[],
+                               const cmsFloat64Number AdaptationStates[],
+                               cmsUInt32Number dwFlags)
 {
-       WORD *White= NULL, *Black = NULL;
-       int Dummy;
-       static WORD Default[MAXCHANNELS];
+    cmsToneCurve* out = NULL;
+    cmsUInt32Number i;
+    cmsHTRANSFORM xform;
+    cmsCIELab Lab;
+    cmsFloat32Number cmyk[4];
+    cmsFloat32Number* SampledPoints;
 
-       if (_cmsEndPointsBySpace(Space, &White, &Black, &Dummy))
-              return White;
+    xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+    if (xform == NULL) return NULL;
 
-       return Default;
+    SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number));
+    if (SampledPoints  == NULL) goto Error;
 
+    for (i=0; i < nPoints; i++) {
+
+        cmyk[0] = 0;
+        cmyk[1] = 0;
+        cmyk[2] = 0;
+        cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1));
+
+        cmsDoTransform(xform, cmyk, &Lab, 1);
+        SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation
+    }
+
+    out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints);
+
+Error:
+
+    cmsDeleteTransform(xform);
+    if (SampledPoints) _cmsFree(ContextID, SampledPoints);
+
+    return out;
 }
 
 
+// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
+// using the proof direction on both profiles to find K->L* relationship
+// then joining both curves. dwFlags may include black point compensation.
+cmsToneCurve* _cmsBuildKToneCurve(cmsContext        ContextID,
+                                   cmsUInt32Number   nPoints,
+                                   cmsUInt32Number   nProfiles,
+                                   const cmsUInt32Number Intents[],
+                                   const cmsHPROFILE hProfiles[],
+                                   const cmsBool     BPC[],
+                                   const cmsFloat64Number AdaptationStates[],
+                                   cmsUInt32Number   dwFlags)
+{
+    cmsToneCurve *in, *out, *KTone;
 
+    // Make sure CMYK -> CMYK
+    if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+        cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL;
 
-WORD Clamp_L(Fixed32 in)
-{
-       if (in == 0xFFFF) return 0xFFFFU;  // Marker
 
-       if (in > 0xFF00) return 0xFF00U;  // L* = 100.0
-       return (WORD) in;
+    // Make sure last is an output profile
+    if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL;
+
+    // Create individual curves. BPC works also as each K to L* is
+    // computed as a BPC to zero black point in case of L*
+    in  = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+    if (in == NULL) return NULL;
+
+    out = ComputeKToLstar(ContextID, nPoints, 1,
+                            Intents + (nProfiles - 1),
+                            hProfiles + (nProfiles - 1),
+                            BPC + (nProfiles - 1),
+                            AdaptationStates + (nProfiles - 1),
+                            dwFlags);
+    if (out == NULL) {
+        cmsFreeToneCurve(in);
+        return NULL;
+    }
+
+    // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but
+    // since this is used on black-preserving LUTs, we are not loosing  accuracy in any case
+    KTone = cmsJoinToneCurve(ContextID, in, out, nPoints);
+
+    // Get rid of components
+    cmsFreeToneCurve(in); cmsFreeToneCurve(out);
+
+    // Something went wrong...
+    if (KTone == NULL) return NULL;
+
+    // Make sure it is monotonic
+    if (!cmsIsToneCurveMonotonic(KTone)) {
+
+        cmsFreeToneCurve(KTone);
+        return NULL;
+    }
+
+    return KTone;
 }
 
 
-#define ENCODE_AB(x) (WORD) (((x) + 128.0) * 256.0 + 0.5)
-
-WORD Clamp_ab(Fixed32 in)
-{
-       if (in == 0xFFFF) return 0xFFFFU;             // Marker
-
-       if (in < 0) return ENCODE_AB(-128.0);         // Max negative number
-       if (in > 0xFFFF) return ENCODE_AB(+127.9961); // Max positive number
-       return (WORD) in;
-}
-
-
-
-// Returns dE on two Lab values
-
-double LCMSEXPORT cmsDeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
-        double dL, da, db;
-
-        if (Lab1 -> L < 0 ||
-            Lab2 -> L < 0) return 65536.;
-
-        if (Lab1 -> a < -200 || Lab1 -> a > 200) return 65536.;
-        if (Lab1 -> b < -200 || Lab1 -> b > 200) return 65536.;
-
-        if (Lab2 -> a < -200 || Lab2 -> a > 200) return 65536.;
-        if (Lab2 -> b < -200 || Lab2 -> b > 200) return 65536.;
-
-        if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
-        dL = fabs(Lab1 -> L - Lab2 -> L);
-        da = fabs(Lab1 -> a - Lab2 -> a);
-        db = fabs(Lab1 -> b - Lab2 -> b);
-
-        return pow(dL*dL + da * da + db * db, 0.5);
-
-}
-
-
-// Square
-static
-double Sqr(double v)
-{
-    return v *  v;
-}
-
-// Return the CIE94 Delta E
-double LCMSEXPORT cmsCIE94DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
-    cmsCIELCh LCh1, LCh2;
-    double dE, dL, dC, dh, dhsq;
-    double c12, sc, sh;
-
-    if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
-    dL = fabs(Lab1 ->L - Lab2 ->L);
-
-    cmsLab2LCh(&LCh1, Lab1);
-    cmsLab2LCh(&LCh2, Lab2);
-
-    dC  = fabs(LCh1.C - LCh2.C);
-    dE  = cmsDeltaE(Lab1, Lab2);
-
-    dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC);
-    if (dhsq < 0)
-        dh = 0;
-    else
-        dh = pow(dhsq, 0.5);
-
-    c12 = sqrt(LCh1.C * LCh2.C);
-
-    sc = 1.0 + (0.048 * c12);
-    sh = 1.0 + (0.014 * c12);
-
-    return sqrt(Sqr(dL)  + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh));
-}
-
-
-// Auxiliary
-
-static
-double ComputeLBFD(LPcmsCIELab Lab)
-{
-  double yt;
-
-  if (Lab->L > 7.996969)
-        yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100;
-  else
-        yt = 100 * (Lab->L / 903.3);
-
-  return (54.6 * (LOGE * (log(yt + 1.5))) - 9.6);
-}
-
-
-
-// bfd - gets BFD(1:1) difference between Lab1, Lab2
-double LCMSEXPORT cmsBFDdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
-    double lbfd1,lbfd2,AveC,Aveh,dE,deltaL,
-        deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd;
-    cmsCIELCh LCh1, LCh2;
-
-
-    if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
-    lbfd1 = ComputeLBFD(Lab1);
-    lbfd2 = ComputeLBFD(Lab2);
-    deltaL = lbfd2 - lbfd1;
-
-    cmsLab2LCh(&LCh1, Lab1);
-    cmsLab2LCh(&LCh2, Lab2);
-
-    deltaC = LCh2.C - LCh1.C;
-    AveC = (LCh1.C+LCh2.C)/2;
-    Aveh = (LCh1.h+LCh2.h)/2;
-
-    dE = cmsDeltaE(Lab1, Lab2);
-
-    if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC)))
-        deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC));
-    else
-        deltah =0;
-
-
-    dc   = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521;
-    g    = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000));
-    t    = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))-
-        0.040*cos((2*Aveh-136)/(180/M_PI))+
-        0.070*cos((3*Aveh-31)/(180/M_PI))+
-        0.049*cos((4*Aveh+114)/(180/M_PI))-
-        0.015*cos((5*Aveh-103)/(180/M_PI)));
-
-    dh    = dc*(g*t+1-g);
-    rh    = -0.260*cos((Aveh-308)/(180/M_PI))-
-        0.379*cos((2*Aveh-160)/(180/M_PI))-
-        0.636*cos((3*Aveh+254)/(180/M_PI))+
-        0.226*cos((4*Aveh+140)/(180/M_PI))-
-        0.194*cos((5*Aveh+280)/(180/M_PI));
-
-    rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000));
-    rt = rh*rc;
-
-    bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh)));
-
-    return bfd;
-}
-
-
-//  cmc - CMC(1:1) difference between Lab1, Lab2
-double LCMSEXPORT cmsCMCdeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2)
-{
-  double dE,dL,dC,dh,sl,sc,sh,t,f,cmc;
-  cmsCIELCh LCh1, LCh2;
-
-  if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
-
-  cmsLab2LCh(&LCh1, Lab1);
-  cmsLab2LCh(&LCh2, Lab2);
-
-
-  dL = Lab2->L-Lab1->L;
-  dC = LCh2.C-LCh1.C;
-
-  dE = cmsDeltaE(Lab1, Lab2);
-  if (Sqr(dE)>(Sqr(dL)+Sqr(dC)))
-            dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC));
-  else
-            dh =0;
-
-  if ((LCh1.h > 164) && (LCh1.h<345))
-      t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI))));
-  else
-      t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI))));
-
-   sc  = 0.0638   * LCh1.C / (1 + 0.0131  * LCh1.C) + 0.638;
-   sl  = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L);
-
-   if (Lab1->L<16)
-         sl = 0.511;
-
-   f   = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900));
-   sh  = sc*(t*f+1-f);
-   cmc = sqrt(Sqr(dL/sl)+Sqr(dC/sc)+Sqr(dh/sh));
-
-   return cmc;
-}
-
-
-
-static
-double atan2deg(double b, double a)
-{
-   double h;
-
-   if (a == 0 && b == 0)
-            h   = 0;
-    else
-            h = atan2(a, b);
-
-    h *= (180. / M_PI);
-
-    while (h > 360.)
-        h -= 360.;
-
-    while ( h < 0)
-        h += 360.;
-
-    return h;
-
-}
-
-
-static
-double RADIANES(double deg)
-{
-    return (deg * M_PI) / 180.;
-}
-
-
-// dE2000 The weightings KL, KC and KH can be modified to reflect the relative
-// importance of lightness, chroma and hue in different industrial applications
-
-double LCMSEXPORT cmsCIE2000DeltaE(LPcmsCIELab Lab1, LPcmsCIELab Lab2,
-                                  double Kl, double Kc, double Kh)
-{
-    double L1  = Lab1->L;
-    double a1  = Lab1->a;
-    double b1  = Lab1->b;
-    double C   = sqrt( Sqr(a1) + Sqr(b1) );
-
-    double Ls = Lab2 ->L;
-    double as = Lab2 ->a;
-    double bs = Lab2 ->b;
-    double Cs = sqrt( Sqr(as) + Sqr(bs) );
-
-    double G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) ));
-
-    double a_p = (1 + G ) * a1;
-    double b_p = b1;
-    double C_p = sqrt( Sqr(a_p) + Sqr(b_p));
-    double h_p = atan2deg(a_p, b_p);
-
-
-    double a_ps = (1 + G) * as;
-    double b_ps = bs;
-    double C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps));
-    double h_ps = atan2deg(a_ps, b_ps);
-
-    double meanC_p =(C_p + C_ps) / 2;
-
-    double hps_plus_hp  = h_ps + h_p;
-    double hps_minus_hp = h_ps - h_p;
-
-    double meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 :
-                            (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 :
-                                                 (hps_plus_hp - 360)/2;
-
-    double delta_h = (hps_minus_hp) <= -180.000001 ?  (hps_minus_hp + 360) :
-                            (hps_minus_hp) > 180 ? (hps_minus_hp - 360) :
-                                                    (hps_minus_hp);
-    double delta_L = (Ls - L1);
-    double delta_C = (C_ps - C_p );
-
-
-    double delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANES(delta_h) / 2);
-
-    double T = 1 - 0.17 * cos(RADIANES(meanh_p-30))
-                 + 0.24 * cos(RADIANES(2*meanh_p))
-                 + 0.32 * cos(RADIANES(3*meanh_p + 6))
-                 - 0.2  * cos(RADIANES(4*meanh_p - 63));
-
-    double Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) );
-
-    double Sc = 1 + 0.045 * (C_p + C_ps)/2;
-    double Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T;
-
-    double delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25)));
-
-    double Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0)));
-
-    double Rt = -sin(2 * RADIANES(delta_ro)) * Rc;
-
-    double deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) +
-                            Sqr(delta_C/(Sc * Kc))  +
-                            Sqr(delta_H/(Sh * Kh))  +
-                            Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh)));
-
-    return deltaE00;
-}
-
-
-
-// Carefully,  clamp on CIELab space.
-
-void LCMSEXPORT cmsClampLab(LPcmsCIELab Lab, double amax, double amin,
-                                   double bmax, double bmin)
-{
-
-            // Whole Luma surface to zero
-
-        if (Lab -> L < 0) {
-
-                Lab-> L = Lab->a = Lab-> b = 0.0;
-                return;
-            }
-
-            // Clamp white, DISCARD HIGHLIGHTS. This is done
-            // in such way because icc spec doesn't allow the
-            // use of L>100 as a highlight means.
-
-            if (Lab->L > 100)
-                        Lab -> L = 100;
-
-            // Check out gamut prism, on a, b faces
-
-            if (Lab -> a < amin || Lab->a > amax||
-                Lab -> b < bmin || Lab->b > bmax) {
-
-                 cmsCIELCh LCh;
-                 double h, slope;
-
-                 // Falls outside a, b limits. Transports to LCh space,
-                 // and then do the clipping
-
-
-                 if (Lab -> a == 0.0) { // Is hue exactly 90?
-
-                        // atan will not work, so clamp here
-                        Lab -> b = Lab->b < 0 ? bmin : bmax;
-                        return;
-                 }
-
-                 cmsLab2LCh(&LCh, Lab);
-
-                 slope = Lab -> b / Lab -> a;
-                 h = LCh.h;
-
-                 // There are 4 zones
-
-                 if ((h >= 0. && h < 45.) ||
-                     (h >= 315 && h <= 360.)) {
-
-                     // clip by amax
-                     Lab -> a = amax;
-                     Lab -> b = amax * slope;
-                 }
-                 else
-                 if (h >= 45. && h < 135)
-                 {
-                        // clip by bmax
-                        Lab -> b = bmax;
-                        Lab -> a = bmax / slope;
-                 }
-                 else
-                 if (h >= 135 && h < 225) {
-                        // clip by amin
-                        Lab -> a = amin;
-                        Lab -> b = amin * slope;
-
-                 }
-                 else
-                 if (h >= 225 && h < 315) {
-                        // clip by bmin
-                        Lab -> b = bmin;
-                        Lab -> a = bmin / slope;
-                 }
-                 else
-                        cmsSignalError(LCMS_ERRC_ABORTED, "Invalid angle");
-
-        }
-}
-
-// Several utilities -------------------------------------------------------
-
-// Translate from our colorspace to ICC representation
-
-icColorSpaceSignature LCMSEXPORT _cmsICCcolorSpace(int OurNotation)
-{
-       switch (OurNotation) {
-
-       case 1:
-       case PT_GRAY: return  icSigGrayData;
-
-       case 2:
-       case PT_RGB:  return  icSigRgbData;
-
-       case PT_CMY:  return  icSigCmyData;
-       case PT_CMYK: return  icSigCmykData;
-       case PT_YCbCr:return  icSigYCbCrData;
-       case PT_YUV:  return  icSigLuvData;
-       case PT_XYZ:  return  icSigXYZData;
-       case PT_Lab:  return  icSigLabData;
-       case PT_YUVK: return  icSigLuvKData;
-       case PT_HSV:  return  icSigHsvData;
-       case PT_HLS:  return  icSigHlsData;
-       case PT_Yxy:  return  icSigYxyData;
-       case PT_HiFi: return  icSigHexachromeData;
-       case PT_HiFi7: return icSigHeptachromeData;
-       case PT_HiFi8: return icSigOctachromeData;
-
-       case PT_HiFi9:  return icSigMCH9Data;
-       case PT_HiFi10: return icSigMCHAData;
-       case PT_HiFi11: return icSigMCHBData;
-       case PT_HiFi12: return icSigMCHCData;
-       case PT_HiFi13: return icSigMCHDData;
-       case PT_HiFi14: return icSigMCHEData;
-       case PT_HiFi15: return icSigMCHFData;
-
-       default:  return icMaxEnumData;
-       }
-}
-
-
-int LCMSEXPORT _cmsLCMScolorSpace(icColorSpaceSignature ProfileSpace)
-{
-    switch (ProfileSpace) {
-
-    case icSigGrayData: return  PT_GRAY;
-    case icSigRgbData:  return  PT_RGB;
-    case icSigCmyData:  return  PT_CMY;
-    case icSigCmykData: return  PT_CMYK;
-    case icSigYCbCrData:return  PT_YCbCr;
-    case icSigLuvData:  return  PT_YUV;
-    case icSigXYZData:  return  PT_XYZ;
-    case icSigLabData:  return  PT_Lab;
-    case icSigLuvKData: return  PT_YUVK;
-    case icSigHsvData:  return  PT_HSV;
-    case icSigHlsData:  return  PT_HLS;
-    case icSigYxyData:  return  PT_Yxy;
-
-    case icSig6colorData:
-    case icSigHexachromeData: return PT_HiFi;
-
-    case icSigHeptachromeData:
-    case icSig7colorData:     return PT_HiFi7;
-
-    case icSigOctachromeData:
-    case icSig8colorData:     return PT_HiFi8;
-
-    case icSigMCH9Data:
-    case icSig9colorData:     return PT_HiFi9;
-
-    case icSigMCHAData:
-    case icSig10colorData:     return PT_HiFi10;
-
-    case icSigMCHBData:
-    case icSig11colorData:     return PT_HiFi11;
-
-    case icSigMCHCData:
-    case icSig12colorData:     return PT_HiFi12;
-
-    case icSigMCHDData:
-    case icSig13colorData:     return PT_HiFi13;
-
-    case icSigMCHEData:
-    case icSig14colorData:     return PT_HiFi14;
-
-    case icSigMCHFData:
-    case icSig15colorData:     return PT_HiFi15;
-
-    default:  return icMaxEnumData;
-    }
-}
-
-
-int LCMSEXPORT _cmsChannelsOf(icColorSpaceSignature ColorSpace)
-{
-
-    switch (ColorSpace) {
-
-    case icSigGrayData: return 1;
-
-    case icSig2colorData:  return 2;
-
-    case icSigXYZData:
-    case icSigLabData:
-    case icSigLuvData:
-    case icSigYCbCrData:
-    case icSigYxyData:
-    case icSigRgbData:
-    case icSigHsvData:
-    case icSigHlsData:
-    case icSigCmyData:
-    case icSig3colorData:  return 3;
-
-    case icSigLuvKData:
-    case icSigCmykData:
-    case icSig4colorData:  return 4;
-
-    case icSigMCH5Data:
-    case icSig5colorData:  return 5;
-
-    case icSigHexachromeData:
-    case icSig6colorData:  return 6;
-
-    case icSigHeptachromeData:
-    case icSig7colorData:  return  7;
-
-    case icSigOctachromeData:
-    case icSig8colorData:  return  8;
-
-    case icSigMCH9Data:
-    case icSig9colorData:  return  9;
-
-    case icSigMCHAData:
-    case icSig10colorData: return 10;
-
-    case icSigMCHBData:
-    case icSig11colorData: return 11;
-
-    case icSigMCHCData:
-    case icSig12colorData: return 12;
-
-    case icSigMCHDData:
-    case icSig13colorData: return 13;
-
-    case icSigMCHEData:
-    case icSig14colorData: return 14;
-
-    case icSigMCHFData:
-    case icSig15colorData: return 15;
-
-    default: return 3;
-    }
-
-}
-
-
-// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable
-// number of gridpoints that would make exact match. However, a
-// prelinearization of 258 entries, would map 0xFF00 on entry 257.
-// This is almost what we need, unfortunately, the rest of entries
-// should be scaled by (255*257/256) and this is not exact.
-//
-// An intermediate solution would be to use 257 entries. This does not
-// map 0xFF00 exactly on a node, but so close that the dE induced is
-// negligible. AND the rest of curve is exact.
-
-static
-void CreateLabPrelinearization(LPGAMMATABLE LabTable[])
-{
-    int i;
-
-    LabTable[0] = cmsAllocGamma(257);
-    LabTable[1] = cmsBuildGamma(257, 1.0);
-    LabTable[2] = cmsBuildGamma(257, 1.0);
-
-    // L* uses 257 entries. Entry 256 holds 0xFFFF, so, the effective range
-    // is 0..0xFF00. Last entry (257) is also collapsed to 0xFFFF
-
-    // From 0 to 0xFF00
-    for (i=0; i < 256; i++)
-        LabTable[0]->GammaTable[i] = RGB_8_TO_16(i);
-
-    // Repeat last for 0xFFFF
-    LabTable[0] ->GammaTable[256] = 0xFFFF;
-}
-
+// Gamut LUT Creation -----------------------------------------------------------------------------------------
 
 // Used by gamut & softproofing
 
 typedef struct {
 
-    cmsHTRANSFORM hInput;               // From whatever input color space. NULL for Lab
+    cmsHTRANSFORM hInput;               // From whatever input color space. 16 bits to DBL
     cmsHTRANSFORM hForward, hReverse;   // Transforms going from Lab to colorant and back
-    double Thereshold;                  // The thereshold after which is considered out of gamut
+    cmsFloat64Number Thereshold;        // The thereshold after which is considered out of gamut
 
-    } GAMUTCHAIN,FAR* LPGAMUTCHAIN;
+    } GAMUTCHAIN;
 
 // This sampler does compute gamut boundaries by comparing original
 // values with a transform going back and forth. Values above ERR_THERESHOLD
 // of maximum are considered out of gamut.
 
-
 #define ERR_THERESHOLD      5
 
 
 static
-int GamutSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
 {
-    LPGAMUTCHAIN t = (LPGAMUTCHAIN) Cargo;
-    WORD Proof[MAXCHANNELS], Check[MAXCHANNELS];
-    WORD Proof2[MAXCHANNELS], Check2[MAXCHANNELS];
+    GAMUTCHAIN*  t = (GAMUTCHAIN* ) Cargo;
     cmsCIELab LabIn1, LabOut1;
     cmsCIELab LabIn2, LabOut2;
-    double dE1, dE2, ErrorRatio;
+    cmsFloat32Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
+    cmsFloat64Number dE1, dE2, ErrorRatio;
 
     // Assume in-gamut by default.
     dE1 = 0.;
     dE2 = 0;
     ErrorRatio = 1.0;
 
-
-    // Any input space? I can use In[] no matter channels
-    // because is just one pixel
-
-    if (t -> hInput != NULL) cmsDoTransform(t -> hInput, In, In, 1);
+    // Convert input to Lab
+    if (t -> hInput != NULL)
+        cmsDoTransform(t -> hInput, In, &LabIn1, 1);
 
     // converts from PCS to colorant. This always
     // does return in-gamut values,
-    cmsDoTransform(t -> hForward, In, Proof, 1);
+    cmsDoTransform(t -> hForward, &LabIn1, Proof, 1);
 
     // Now, do the inverse, from colorant to PCS.
-    cmsDoTransform(t -> hReverse, Proof, Check, 1);
+    cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1);
 
+    memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
 
     // Try again, but this time taking Check as input
-    cmsDoTransform(t -> hForward, Check, Proof2,  1);
-    cmsDoTransform(t -> hReverse, Proof2, Check2, 1);
+    cmsDoTransform(t -> hForward, &LabOut1, Proof2,  1);
+    cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
 
+    // Take difference of direct value
+    dE1 = cmsDeltaE(&LabIn1, &LabOut1);
 
+    // Take difference of converted value
+    dE2 = cmsDeltaE(&LabIn2, &LabOut2);
 
-    // Does the transform returns out-of-gamut?
-    if (Check[0] == 0xFFFF &&
-        Check[1] == 0xFFFF &&
-        Check[2] == 0xFFFF)
 
-        Out[0] = 0xFF00;            // Out of gamut!
+    // if dE1 is small and dE2 is small, value is likely to be in gamut
+    if (dE1 < t->Thereshold && dE2 < t->Thereshold)
+        Out[0] = 0;
     else {
 
-        // Transport encoded values
-        cmsLabEncoded2Float(&LabIn1,  In);
-        cmsLabEncoded2Float(&LabOut1, Check);
-
-        // Take difference of direct value
-        dE1 = cmsDeltaE(&LabIn1, &LabOut1);
-
-        cmsLabEncoded2Float(&LabIn2,  Check);
-        cmsLabEncoded2Float(&LabOut2, Check2);
-
-        // Take difference of converted value
-        dE2 = cmsDeltaE(&LabIn2, &LabOut2);
-
-
-        // if dE1 is small and dE2 is small, value is likely to be in gamut
-        if (dE1 < t->Thereshold && dE2 < t->Thereshold)
+        // if dE1 is small and dE2 is big, undefined. Assume in gamut
+        if (dE1 < t->Thereshold && dE2 > t->Thereshold)
             Out[0] = 0;
         else
-            // if dE1 is small and dE2 is big, undefined. Assume in gamut
-            if (dE1 < t->Thereshold && dE2 > t->Thereshold)
-                Out[0] = 0;
-            else
-                // dE1 is big and dE2 is small, clearly out of gamut
-                if (dE1 > t->Thereshold && dE2 < t->Thereshold)
-                    Out[0] = (WORD) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
-                else  {
+            // dE1 is big and dE2 is small, clearly out of gamut
+            if (dE1 > t->Thereshold && dE2 < t->Thereshold)
+                Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
+            else  {
 
-                    // dE1 is big and dE2 is also big, could be due to perceptual mapping
-                    // so take error ratio
-                    if (dE2 == 0.0)
-                        ErrorRatio = dE1;
-                    else
-                        ErrorRatio = dE1 / dE2;
+                // dE1 is big and dE2 is also big, could be due to perceptual mapping
+                // so take error ratio
+                if (dE2 == 0.0)
+                    ErrorRatio = dE1;
+                else
+                    ErrorRatio = dE1 / dE2;
 
-                    if (ErrorRatio > t->Thereshold)
-                        Out[0] = (WORD)  _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
-                    else
-                        Out[0] = 0;
-                }
+                if (ErrorRatio > t->Thereshold)
+                    Out[0] = (cmsUInt16Number)  _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
+                else
+                    Out[0] = 0;
+            }
+    }
 
-    }
 
     return TRUE;
 }
 
+// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs
+// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE
+// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well.
+//
+// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors,
+// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should.
 
-// Does compute a gamut LUT going back and forth across
-// pcs -> relativ. colorimetric intent -> pcs
-// the dE obtained is then annotated on the LUT.
-// values truely out of gamut, are clipped to dE = 0xFFFE
-// and values changed are supposed to be handled by
-// any gamut remapping, so, are out of gamut as well.
-//
-// **WARNING: This algorithm does assume that gamut
-// remapping algorithms does NOT move in-gamut colors,
-// of course, many perceptual and saturation intents does
-// not work in such way, but relativ. ones should.
-
-static
-LPLUT ComputeGamutWithInput(cmsHPROFILE hInput, cmsHPROFILE hProfile, int Intent)
+cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
+                                          cmsHPROFILE hProfiles[],
+                                          cmsBool  BPC[],
+                                          cmsUInt32Number Intents[],
+                                          cmsFloat64Number AdaptationStates[],
+                                          cmsUInt32Number nGamutPCSposition,
+                                          cmsHPROFILE hGamut)
 {
     cmsHPROFILE hLab;
-    LPLUT Gamut;
-    DWORD dwFormat;
+    cmsPipeline* Gamut;
+    cmsStage* CLUT;
+    cmsUInt32Number dwFormat;
     GAMUTCHAIN Chain;
-    int nErrState, nChannels, nGridpoints;
-    LPGAMMATABLE Trans[3];
-    icColorSpaceSignature ColorSpace;
+    int nChannels, nGridpoints;
+    cmsColorSpaceSignature ColorSpace;
+    cmsUInt32Number i;
+    cmsHPROFILE ProfileList[256];
+    cmsBool     BPCList[256];
+    cmsFloat64Number AdaptationList[256];
+    cmsUInt32Number IntentList[256];
 
+    memset(&Chain, 0, sizeof(GAMUTCHAIN));
 
-    ZeroMemory(&Chain, sizeof(GAMUTCHAIN));
 
-    hLab = cmsCreateLabProfile(NULL);
+    if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition);
+        return NULL;
+    }
 
-    // Safeguard against early abortion
-    nErrState = cmsErrorAction(LCMS_ERROR_IGNORE);
+    hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+    if (hLab == NULL) return NULL;
+
 
     // The figure of merit. On matrix-shaper profiles, should be almost zero as
     // the conversion is pretty exact. On LUT based profiles, different resolutions
     // of input and output CLUT may result in differences.
 
-    if (!cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) &&
-        !cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_OUTPUT))
+    if (cmsIsMatrixShaper(hGamut)) {
 
         Chain.Thereshold = 1.0;
-    else
+    }
+    else {
         Chain.Thereshold = ERR_THERESHOLD;
-
-    ColorSpace  = cmsGetColorSpace(hProfile);
-
-    // If input profile specified, create a transform from such profile to Lab
-    if (hInput != NULL) {
-
-        nChannels   = _cmsChannelsOf(ColorSpace);
-        nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
-        dwFormat    = (CHANNELS_SH(nChannels)|BYTES_SH(2));
-
-        Chain.hInput = cmsCreateTransform(hInput, dwFormat,
-                                          hLab,   TYPE_Lab_16,
-                                          Intent,
-                                          cmsFLAGS_NOTPRECALC);
-    }
-    else  {
-        // Input transform=NULL (Lab) Used to compute the gamut tag
-        // This table will take 53 points to give some accurancy,
-        // 53 * 53 * 53 * 2 = 291K
-
-        nChannels    = 3;      // For Lab
-        nGridpoints  = 53;
-        Chain.hInput = NULL;
-        dwFormat = (CHANNELS_SH(_cmsChannelsOf(ColorSpace))|BYTES_SH(2));
     }
 
 
-    // Does create the forward step
-    Chain.hForward = cmsCreateTransform(hLab, TYPE_Lab_16,
-                                        hProfile, dwFormat,
-                                        INTENT_RELATIVE_COLORIMETRIC,
-                                        cmsFLAGS_NOTPRECALC);
+    // Create a copy of parameters
+    for (i=0; i < nGamutPCSposition; i++) {
+        ProfileList[i]    = hProfiles[i];
+        BPCList[i]        = BPC[i];
+        AdaptationList[i] = AdaptationStates[i];
+        IntentList[i]     = Intents[i];
+    }
+
+    // Fill Lab identity
+    ProfileList[nGamutPCSposition] = hLab;
+    BPCList[nGamutPCSposition] = 0;
+    AdaptationList[nGamutPCSposition] = 1.0;
+    Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
+
+
+    ColorSpace  = cmsGetColorSpace(hGamut);
+
+    nChannels   = cmsChannelsOf(ColorSpace);
+    nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
+    dwFormat    = (CHANNELS_SH(nChannels)|BYTES_SH(2));
+
+    // 16 bits to Lab double
+    Chain.hInput = cmsCreateExtendedTransform(ContextID,
+                                              nGamutPCSposition + 1,
+                                              ProfileList,
+                                              BPCList,
+                                              Intents,
+                                              AdaptationList,
+                                              NULL, 0,
+                                              dwFormat, TYPE_Lab_DBL,
+                                              cmsFLAGS_NOCACHE);
+
+
+    // Does create the forward step. Lab double to cmsFloat32Number
+    dwFormat    = (FLOAT_SH(1)|CHANNELS_SH(nChannels)|BYTES_SH(4));
+    Chain.hForward = cmsCreateTransformTHR(ContextID,
+                                           hLab, TYPE_Lab_DBL,
+                                           hGamut, dwFormat,
+                                           INTENT_RELATIVE_COLORIMETRIC,
+                                           cmsFLAGS_NOCACHE);
 
     // Does create the backwards step
-    Chain.hReverse = cmsCreateTransform(hProfile, dwFormat,
-                                        hLab, TYPE_Lab_16,
-                                        INTENT_RELATIVE_COLORIMETRIC,
-                                        cmsFLAGS_NOTPRECALC);
-
-    // Restores error handler previous state
-    cmsErrorAction(nErrState);
+    Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat,
+                                           hLab, TYPE_Lab_DBL,
+                                           INTENT_RELATIVE_COLORIMETRIC,
+                                           cmsFLAGS_NOCACHE);
 
 
     // All ok?
     if (Chain.hForward && Chain.hReverse) {
 
-    // Go on, try to compute gamut LUT from PCS.
-    // This consist on a single channel containing
-    // dE when doing a transform back and forth on
-    // the colorimetric intent.
+        // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing
+        // dE when doing a transform back and forth on the colorimetric intent.
 
-    Gamut = cmsAllocLUT();
-    Gamut = cmsAlloc3DGrid(Gamut, nGridpoints, nChannels, 1);
+        Gamut = cmsPipelineAlloc(ContextID, 3, 1);
 
-    // If no input, then this is a gamut tag operated by Lab,
-    // so include pertinent prelinearization
-    if (hInput == NULL) {
+        if (Gamut != NULL) {
 
-        CreateLabPrelinearization(Trans);
-        cmsAllocLinearTable(Gamut, Trans, 1);
-        cmsFreeGammaTriple(Trans);
-    }
+            CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
+            cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT);
 
-
-    cmsSample3DGrid(Gamut, GamutSampler, (LPVOID) &Chain, Gamut ->wFlags);
+            cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
+        }
     }
     else
         Gamut = NULL;   // Didn't work...
@@ -921,352 +434,187 @@
     if (Chain.hInput)   cmsDeleteTransform(Chain.hInput);
     if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
     if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
-
-    cmsCloseProfile(hLab);
+    if (hLab) cmsCloseProfile(hLab);
 
     // And return computed hull
     return Gamut;
 }
 
+// Total Area Coverage estimation ----------------------------------------------------------------
 
-// Wrapper
+typedef struct {
+    cmsUInt32Number  nOutputChans;
+    cmsHTRANSFORM    hRoundTrip;
+    cmsFloat32Number MaxTAC;
+    cmsFloat32Number MaxInput[cmsMAXCHANNELS];
 
-LPLUT _cmsComputeGamutLUT(cmsHPROFILE hProfile, int Intent)
+} cmsTACestimator;
+
+
+// This callback just accounts the maximum ink dropped in the given node. It does not populate any
+// memory, as the destination table is NULL. Its only purpose it to know the global maximum.
+static
+int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo)
 {
-    return ComputeGamutWithInput(NULL, hProfile, Intent);
+    cmsTACestimator* bp = (cmsTACestimator*) Cargo;
+    cmsFloat32Number RoundTrip[cmsMAXCHANNELS];
+    cmsUInt32Number i;
+    cmsFloat32Number Sum;
+
+
+    // Evaluate the xform
+    cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1);
+
+    // All all amounts of ink
+    for (Sum=0, i=0; i < bp ->nOutputChans; i++)
+            Sum += RoundTrip[i];
+
+    // If above maximum, keep track of input values
+    if (Sum > bp ->MaxTAC) {
+
+            bp ->MaxTAC = Sum;
+
+            for (i=0; i < bp ->nOutputChans; i++) {
+                bp ->MaxInput[i] = In[i];
+            }
+    }
+
+    return TRUE;
+
+    cmsUNUSED_PARAMETER(Out);
 }
 
 
-// This routine does compute the gamut check CLUT. This CLUT goes from whatever
-// input space to the 0 or != 0 gamut check.
+// Detect Total area coverage of the profile
+cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile)
+{
+    cmsTACestimator bp;
+    cmsUInt32Number dwFormatter;
+    cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS];
+    cmsHPROFILE hLab;
+    cmsContext ContextID = cmsGetProfileContextID(hProfile);
 
-LPLUT _cmsPrecalculateGamutCheck(cmsHTRANSFORM h)
-{
-       _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) h;
+    // TAC only works on output profiles
+    if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) {
+        return 0;
+    }
 
-       return ComputeGamutWithInput(p->InputProfile, p ->PreviewProfile, p->Intent);
+    // Create a fake formatter for result
+    dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE);
+
+    bp.nOutputChans = T_CHANNELS(dwFormatter);
+    bp.MaxTAC = 0;    // Initial TAC is 0
+
+    //  for safety
+    if (bp.nOutputChans >= cmsMAXCHANNELS) return 0;
+
+    hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+    if (hLab == NULL) return 0;
+    // Setup a roundtrip on perceptual intent in output profile for TAC estimation
+    bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16,
+                                          hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
+
+    cmsCloseProfile(hLab);
+    if (bp.hRoundTrip == NULL) return 0;
+
+    // For L* we only need black and white. For C* we need many points
+    GridPoints[0] = 6;
+    GridPoints[1] = 74;
+    GridPoints[2] = 74;
+
+
+    if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
+        bp.MaxTAC = 0;
+    }
+
+    cmsDeleteTransform(bp.hRoundTrip);
+
+    // Results in %
+    return bp.MaxTAC;
 }
 
 
-// SoftProofing. Convert from Lab to device, then back to Lab,
-// any gamut remapping is applied
+// Carefully,  clamp on CIELab space.
 
-static
-int SoftProofSampler(register WORD In[], register WORD Out[], register LPVOID Cargo)
+cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
+                                   double amax, double amin,
+                                   double bmax, double bmin)
 {
-        LPGAMUTCHAIN t = (LPGAMUTCHAIN) Cargo;
-        WORD Colorant[MAXCHANNELS];
 
-        // From pcs to colorant
-        cmsDoTransform(t -> hForward, In, Colorant, 1);
+    // Whole Luma surface to zero
 
-        // Now, do the inverse, from colorant to pcs.
-        cmsDoTransform(t -> hReverse, Colorant, Out, 1);
+    if (Lab -> L < 0) {
 
-        return TRUE;
-}
+        Lab-> L = Lab->a = Lab-> b = 0.0;
+        return FALSE;
+    }
 
-// Does return Softproofing LUT on desired intent
+    // Clamp white, DISCARD HIGHLIGHTS. This is done
+    // in such way because icc spec doesn't allow the
+    // use of L>100 as a highlight means.
 
-LPLUT _cmsComputeSoftProofLUT(cmsHPROFILE hProfile, int nIntent)
-{
-    cmsHPROFILE hLab;
-    LPLUT SoftProof;
-    DWORD dwFormat;
-    GAMUTCHAIN Chain;
-    int nErrState;
-    LPGAMMATABLE Trans[3];
+    if (Lab->L > 100)
+        Lab -> L = 100;
 
+    // Check out gamut prism, on a, b faces
 
-    // LUTs are never abs. colorimetric, is the transform who
-    // is responsible of generating white point displacement
-    if (nIntent == INTENT_ABSOLUTE_COLORIMETRIC)
-        nIntent = INTENT_RELATIVE_COLORIMETRIC;
+    if (Lab -> a < amin || Lab->a > amax||
+        Lab -> b < bmin || Lab->b > bmax) {
 
-    ZeroMemory(&Chain, sizeof(GAMUTCHAIN));
+            cmsCIELCh LCh;
+            double h, slope;
 
-    hLab = cmsCreateLabProfile(NULL);
+            // Falls outside a, b limits. Transports to LCh space,
+            // and then do the clipping
 
-    // ONLY 4 channels
-    dwFormat = (CHANNELS_SH(4)|BYTES_SH(2));
 
-    // Safeguard against early abortion
-    nErrState = cmsErrorAction(LCMS_ERROR_IGNORE);
+            if (Lab -> a == 0.0) { // Is hue exactly 90?
 
-    // Does create the first step
-    Chain.hForward = cmsCreateTransform(hLab, TYPE_Lab_16,
-                                        hProfile, dwFormat,
-                                        nIntent,
-                                        cmsFLAGS_NOTPRECALC);
+                // atan will not work, so clamp here
+                Lab -> b = Lab->b < 0 ? bmin : bmax;
+                return TRUE;
+            }
 
-    // Does create the last step
-    Chain.hReverse = cmsCreateTransform(hProfile, dwFormat,
-                                        hLab, TYPE_Lab_16,
-                                        INTENT_RELATIVE_COLORIMETRIC,
-                                        cmsFLAGS_NOTPRECALC);
+            cmsLab2LCh(&LCh, Lab);
 
-    // Restores error handler previous state
-    cmsErrorAction(nErrState);
+            slope = Lab -> b / Lab -> a;
+            h = LCh.h;
 
-    // All ok?
-    if (Chain.hForward && Chain.hReverse) {
+            // There are 4 zones
 
-    // This is Lab -> Lab, so 33 point should hold anything
-    SoftProof = cmsAllocLUT();
-    SoftProof = cmsAlloc3DGrid(SoftProof, 33, 3, 3);
+            if ((h >= 0. && h < 45.) ||
+                (h >= 315 && h <= 360.)) {
 
-    CreateLabPrelinearization(Trans);
-    cmsAllocLinearTable(SoftProof, Trans, 1);
-    cmsFreeGammaTriple(Trans);
+                    // clip by amax
+                    Lab -> a = amax;
+                    Lab -> b = amax * slope;
+            }
+            else
+                if (h >= 45. && h < 135.)
+                {
+                    // clip by bmax
+                    Lab -> b = bmax;
+                    Lab -> a = bmax / slope;
+                }
+                else
+                    if (h >= 135. && h < 225.) {
+                        // clip by amin
+                        Lab -> a = amin;
+                        Lab -> b = amin * slope;
 
-    cmsSample3DGrid(SoftProof, SoftProofSampler, (LPVOID) &Chain, SoftProof->wFlags);
-    }
-    else
-        SoftProof = NULL;   // Didn't work...
-
-    // Free all needed stuff.
-    if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
-    if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
-
-    cmsCloseProfile(hLab);
-
-    return SoftProof;
-}
-
-
-static
-int MostlyLinear(WORD Table[], int nEntries)
-{
-       register int i;
-       int diff;
-
-       for (i=5; i < nEntries; i++) {
-
-           diff = abs((int) Table[i] - (int) _cmsQuantizeVal(i, nEntries));
-           if (diff > 0x0300)
-                     return 0;
-       }
-
-       return 1;
-}
-
-
-static
-void SlopeLimiting(WORD Table[], int nEntries)
-{
-    int At = (int) floor((double) nEntries * 0.02 + 0.5);   // Cutoff at 2%
-    double Val, Slope;
-    int i;
-
-    Val   = Table[At];
-    Slope = Val / At;
-
-    for (i=0; i < At; i++)
-        Table[i] = (WORD) floor(i * Slope + 0.5);
-
-}
-
-
-// Check for monotonicity.
-
-static
-LCMSBOOL IsMonotonic(LPGAMMATABLE t)
-{
-    int n = t -> nEntries;
-    int i, last;
-
-    last = t ->GammaTable[n-1];
-
-    for (i = n-2; i >= 0; --i) {
-
-        if (t ->GammaTable[i] > last)
-
-               return FALSE;
-        else
-                last = t ->GammaTable[i];
+                    }
+                    else
+                        if (h >= 225. && h < 315.) {
+                            // clip by bmin
+                            Lab -> b = bmin;
+                            Lab -> a = bmin / slope;
+                        }
+                        else  {
+                            cmsSignalError(0, cmsERROR_RANGE, "Invalid angle");
+                            return FALSE;
+                        }
 
     }
 
     return TRUE;
 }
-
-// Check for endpoints
-
-static
-LCMSBOOL HasProperEndpoints(LPGAMMATABLE t)
-{
-    if (t ->GammaTable[0] != 0) return FALSE;
-    if (t ->GammaTable[t ->nEntries-1] != 0xFFFF) return FALSE;
-
-    return TRUE;
-}
-
-
-
-#define PRELINEARIZATION_POINTS 4096
-
-// Fixes the gamma balancing of transform. Thanks to Mike Chaney
-// for pointing this subtle bug.
-
-void _cmsComputePrelinearizationTablesFromXFORM(cmsHTRANSFORM h[], int nTransforms, LPLUT Grid)
-{
-    LPGAMMATABLE Trans[MAXCHANNELS];
-    unsigned int t, i, v;
-    int j;
-    WORD In[MAXCHANNELS], Out[MAXCHANNELS];
-    LCMSBOOL lIsSuitable;
-    _LPcmsTRANSFORM InputXForm   = (_LPcmsTRANSFORM) h[0];
-    _LPcmsTRANSFORM OutputXForm  = (_LPcmsTRANSFORM) h[nTransforms-1];
-
-
-    // First space is *Lab, use our specialized curves for v2 Lab
-
-    if (InputXForm ->EntryColorSpace == icSigLabData &&
-        OutputXForm->ExitColorSpace != icSigLabData) {
-
-                CreateLabPrelinearization(Trans);
-                cmsAllocLinearTable(Grid, Trans, 1);
-                cmsFreeGammaTriple(Trans);
-                return;
-    }
-
-
-    // Do nothing on all but Gray/RGB to Gray/RGB transforms
-
-    if (((InputXForm ->EntryColorSpace != icSigRgbData) && (InputXForm ->EntryColorSpace != icSigGrayData)) ||
-        ((OutputXForm->ExitColorSpace  != icSigRgbData) && (OutputXForm->ExitColorSpace  != icSigGrayData))) return;
-
-
-    for (t = 0; t < Grid -> InputChan; t++)
-            Trans[t] = cmsAllocGamma(PRELINEARIZATION_POINTS);
-
-    for (i=0; i < PRELINEARIZATION_POINTS; i++) {
-
-                v = _cmsQuantizeVal(i, PRELINEARIZATION_POINTS);
-
-                for (t=0; t < Grid -> InputChan; t++)
-                        In[t] = (WORD) v;
-
-                cmsDoTransform(h[0], In, Out, 1);
-                for (j=1; j < nTransforms; j++)
-                        cmsDoTransform(h[j], Out, Out, 1);
-
-                for (t=0; t < Grid -> InputChan; t++)
-                        Trans[t] ->GammaTable[i] = Out[t];
-
-    }
-
-
-    // Check transfer curves
-    lIsSuitable = TRUE;
-    for (t=0; (lIsSuitable && (t < Grid->InputChan)); t++) {
-
-
-        // Exclude if already linear
-        if (MostlyLinear(Trans[t]->GammaTable, PRELINEARIZATION_POINTS))
-                    lIsSuitable = FALSE;
-
-        // Exclude if non-monotonic
-        if (!IsMonotonic(Trans[t]))
-                    lIsSuitable = FALSE;
-
-        // Exclude if weird endpoints
-        if (!HasProperEndpoints(Trans[t]))
-                    lIsSuitable = FALSE;
-
-        /*
-        // Exclude if transfer function is not smooth enough
-        // to be modelled as a gamma function, or the gamma is reversed
-
-        if (cmsEstimateGamma(Trans[t]) < 1.0)
-                    lIsSuitable = FALSE;
-        */
-
-    }
-
-    if (lIsSuitable) {
-
-            for (t = 0; t < Grid ->InputChan; t++)
-                SlopeLimiting(Trans[t]->GammaTable, Trans[t]->nEntries);
-    }
-
-    if (lIsSuitable) cmsAllocLinearTable(Grid, Trans, 1);
-
-
-    for (t = 0; t < Grid ->InputChan; t++)
-                        cmsFreeGamma(Trans[t]);
-
-
-}
-
-
-// Compute K -> L* relationship. Flags may include black point compensation. In this case,
-// the relationship is assumed from the profile with BPC to a black point zero.
-static
-LPGAMMATABLE ComputeKToLstar(cmsHPROFILE hProfile, int nPoints, int Intent, DWORD dwFlags)
-{
-    LPGAMMATABLE out;
-    int i;
-    WORD cmyk[4], wLab[3];
-    cmsHPROFILE   hLab  = cmsCreateLabProfile(NULL);
-    cmsHTRANSFORM xform = cmsCreateTransform(hProfile, TYPE_CMYK_16,
-                                             hLab, TYPE_Lab_16,
-                                             Intent, (dwFlags|cmsFLAGS_NOTPRECALC));
-
-
-    out = cmsAllocGamma(nPoints);
-    for (i=0; i < nPoints; i++) {
-
-        cmyk[0] = 0;
-        cmyk[1] = 0;
-        cmyk[2] = 0;
-        cmyk[3] = _cmsQuantizeVal(i, nPoints);
-
-        cmsDoTransform(xform, cmyk, wLab, 1);
-        out->GammaTable[i] = (WORD) (0xFFFF - wLab[0]);
-    }
-
-    cmsDeleteTransform(xform);
-    cmsCloseProfile(hLab);
-
-    return out;
-}
-
-
-
-// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
-// using the proof direction on both profiles to find K->L* relationship
-// then joining both curves. dwFlags may include black point compensation.
-
-LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints)
-{
-    LPGAMMATABLE in, out;
-    LPGAMMATABLE KTone;
-    _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) hCMYK2CMYK;
-
-
-    // Make sure CMYK -> CMYK
-    if (p -> EntryColorSpace != icSigCmykData ||
-        p -> ExitColorSpace  != icSigCmykData) return NULL;
-
-    // Create individual curves. BPC works also as each K to L* is
-    // computed as a BPC to zero black point in case of L*
-    in  = ComputeKToLstar(p ->InputProfile,  nPoints, p->Intent, p -> dwOriginalFlags);
-    out = ComputeKToLstar(p ->OutputProfile, nPoints, p->Intent, p -> dwOriginalFlags);
-
-    // Build the relationship
-    KTone = cmsJoinGamma(in, out);
-
-    cmsFreeGamma(in); cmsFreeGamma(out);
-
-    // Make sure it is monotonic
-
-    if (!IsMonotonic(KTone)) {
-
-        cmsFreeGamma(KTone);
-        return NULL;
-    }
-
-
-    return KTone;
-}
--- a/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c	Tue Sep 07 16:54:39 2010 +0400
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c	Thu Sep 09 16:20:55 2010 +0400
@@ -27,9 +27,10 @@
 // However, the following notice accompanied the original version of this
 // file:
 //
+//---------------------------------------------------------------------------------
 //
-//  Little cms
-//  Copyright (C) 1998-2007 Marti Maria
+//  Little Color Management System
+//  Copyright (c) 1998-2010 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -48,731 +49,318 @@
 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
 
-// Interpolation
+#include "lcms2_internal.h"
 
-#include "lcms.h"
+// This module incorporates several interpolation routines, for 1, 3, 4, 5, 6, 7 and 8 channels on input and
+// up to 65535 channels on output. The user may change those by using the interpolation plug-in
 
-void cmsCalcL16Params(int nSamples, LPL16PARAMS p)
+// Interpolation routines by default
+static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
+
+// This is the default factory
+static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory;
+
+
+// Main plug-in entry
+cmsBool  _cmsRegisterInterpPlugin(cmsPluginBase* Data)
 {
-       p -> nSamples = nSamples;
-       p -> Domain   = (WORD) (nSamples - 1);
-       p -> nInputs = p -> nOutputs = 1;
+    cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
 
+    if (Data == NULL) {
+
+        Interpolators = DefaultInterpolatorsFactory;
+        return TRUE;
+    }
+
+    // Set replacement functions
+    Interpolators = Plugin ->InterpolatorsFactory;
+    return TRUE;
 }
 
 
+// Set the interpolation method
+static
+cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
+{
+    // Invoke factory, possibly in the Plug-in
+    p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
 
-// Eval gray LUT having only one input channel
+    // If unsupported by the plug-in, go for the LittleCMS default.
+    // If happens only if an extern plug-in is being used
+    if (p ->Interpolation.Lerp16 == NULL)
+        p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);
 
-static
-void Eval1Input(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
-       Fixed32 fk;
-       Fixed32 k0, k1, rk, K0, K1;
-       int OutChan;
-
-       fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
-       k0 = FIXED_TO_INT(fk);
-       rk = (WORD) FIXED_REST_TO_INT(fk);
-
-       k1 = k0 + (StageABC[0] != 0xFFFFU ? 1 : 0);
-
-       K0 = p16 -> opta1 * k0;
-       K1 = p16 -> opta1 * k1;
-
-       for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
-
-           StageLMN[OutChan] = (WORD) FixedLERP(rk, LutTable[K0+OutChan],
-                                                    LutTable[K1+OutChan]);
-       }
+    // Check for valid interpolator (we just check one member of the union)
+    if (p ->Interpolation.Lerp16 == NULL) {
+            return FALSE;
+    }
+    return TRUE;
 }
 
 
+// This function precalculates as many parameters as possible to speed up the interpolation.
+cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
+                                           const cmsUInt32Number nSamples[],
+                                           int InputChan, int OutputChan,
+                                           const void *Table,
+                                           cmsUInt32Number dwFlags)
+{
+    cmsInterpParams* p;
+    int i;
 
-// For more that 3 inputs (i.e., CMYK)
-// evaluate two 3-dimensional interpolations and then linearly interpolate between them.
+    // Check for maximum inputs
+    if (InputChan > MAX_INPUT_DIMENSIONS) {
+             cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS);
+            return NULL;
+    }
+
+    // Creates an empty object
+    p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));
+    if (p == NULL) return NULL;
+
+    // Keep original parameters
+    p -> dwFlags  = dwFlags;
+    p -> nInputs  = InputChan;
+    p -> nOutputs = OutputChan;
+    p ->Table     = Table;
+    p ->ContextID  = ContextID;
+
+    // Fill samples per input direction and domain (which is number of nodes minus one)
+    for (i=0; i < InputChan; i++) {
+
+        p -> nSamples[i] = nSamples[i];
+        p -> Domain[i]   = nSamples[i] - 1;
+    }
+
+    // Compute factors to apply to each component to index the grid array
+    p -> opta[0] = p -> nOutputs;
+    for (i=1; i < InputChan; i++)
+        p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
+
+
+    if (!_cmsSetInterpolationRoutine(p)) {
+         cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
+        _cmsFree(ContextID, p);
+        return NULL;
+    }
+
+    // All seems ok
+    return p;
+}
+
+
+// This one is a wrapper on the anterior, but assuming all directions have same number of nodes
+cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags)
+{
+    int i;
+    cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
+
+    // Fill the auxiliar array
+    for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
+        Samples[i] = nSamples;
+
+    // Call the extended function
+    return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
+}
+
+
+// Free all associated memory
+void _cmsFreeInterpParams(cmsInterpParams* p)
+{
+    if (p != NULL) _cmsFree(p ->ContextID, p);
+}
+
+
+// Inline fixed point interpolation
+cmsINLINE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
+{
+    cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
+    dif = (dif >> 16) + l;
+    return (cmsUInt16Number) (dif);
+}
+
+
+//  Linear interpolation (Fixed-point optimized)
 static
-void Eval4Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
+void LinLerp1D(register const cmsUInt16Number Value[],
+               register cmsUInt16Number Output[],
+               register const cmsInterpParams* p)
 {
-       Fixed32 fk;
-       Fixed32 k0, rk;
-       int K0, K1;
-       LPWORD T;
-       int i;
-       WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
+    cmsUInt16Number y1, y0;
+    int cell0, rest;
+    int val3;
+    const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
 
+    // if last value...
+    if (Value[0] == 0xffff) {
 
-       fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
+        Output[0] = LutTable[p -> Domain[0]];
+        return;
+    }
 
-       K0 = p16 -> opta4 * k0;
-       K1 = p16 -> opta4 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
+    val3 = p -> Domain[0] * Value[0];
+    val3 = _cmsToFixedDomain(val3);    // To fixed 15.16
 
-       p16 -> nInputs = 3;
+    cell0 = FIXED_TO_INT(val3);             // Cell is 16 MSB bits
+    rest  = FIXED_REST_TO_INT(val3);        // Rest is 16 LSB bits
 
-       T = LutTable + K0;
+    y0 = LutTable[cell0];
+    y1 = LutTable[cell0+1];
 
-       cmsTetrahedralInterp16(StageABC + 1,  Tmp1, T, p16);
 
+    Output[0] = LinearInterp(rest, y0, y1);
+}
 
-       T = LutTable + K1;
 
-       cmsTetrahedralInterp16(StageABC + 1,  Tmp2, T, p16);
+// Floating-point version of 1D interpolation
+static
+void LinLerp1Dfloat(const cmsFloat32Number Value[],
+                    cmsFloat32Number Output[],
+                    const cmsInterpParams* p)
+{
+       cmsFloat32Number y1, y0;
+       cmsFloat32Number val2, rest;
+       int cell0, cell1;
+       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
 
-
-       p16 -> nInputs = 4;
-       for (i=0; i < p16 -> nOutputs; i++)
-       {
-              StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
-
+       // if last value...
+       if (Value[0] == 1.0) {
+           Output[0] = LutTable[p -> Domain[0]];
+           return;
        }
 
-}
-
-
-static
-void Eval5Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
-       Fixed32 fk;
-       Fixed32 k0, rk;
-       int K0, K1;
-       LPWORD T;
-       int i;
-       WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
-       fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta5 * k0;
-       K1 = p16 -> opta5 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
-       p16 -> nInputs = 4;
-
-       T = LutTable + K0;
-
-       Eval4Inputs(StageABC + 1, Tmp1, T, p16);
-
-       T = LutTable + K1;
-
-       Eval4Inputs(StageABC + 1, Tmp2, T, p16);
-
-       p16 -> nInputs = 5;
-       for (i=0; i < p16 -> nOutputs; i++)
-       {
-              StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
-
-       }
-
-}
-
-
-static
-void Eval6Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
-       Fixed32 fk;
-       Fixed32 k0, rk;
-       int K0, K1;
-       LPWORD T;
-       int i;
-       WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
-       fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta6 * k0;
-       K1 = p16 -> opta6 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
-       p16 -> nInputs = 5;
-
-       T = LutTable + K0;
-
-       Eval5Inputs(StageABC + 1, Tmp1, T, p16);
-
-       T = LutTable + K1;
-
-       Eval5Inputs(StageABC + 1, Tmp2, T, p16);
-
-       p16 -> nInputs = 6;
-       for (i=0; i < p16 -> nOutputs; i++)
-       {
-              StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
-       }
-
-}
-
-static
-void Eval7Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
-       Fixed32 fk;
-       Fixed32 k0, rk;
-       int K0, K1;
-       LPWORD T;
-       int i;
-       WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
-       fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta7 * k0;
-       K1 = p16 -> opta7 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
-       p16 -> nInputs = 6;
-
-       T = LutTable + K0;
-
-       Eval6Inputs(StageABC + 1, Tmp1, T, p16);
-
-       T = LutTable + K1;
-
-       Eval6Inputs(StageABC + 1, Tmp2, T, p16);
-
-       p16 -> nInputs = 7;
-       for (i=0; i < p16 -> nOutputs; i++)
-       {
-              StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
-       }
-
-}
-
-static
-void Eval8Inputs(WORD StageABC[], WORD StageLMN[], WORD LutTable[], LPL16PARAMS p16)
-{
-       Fixed32 fk;
-       Fixed32 k0, rk;
-       int K0, K1;
-       LPWORD T;
-       int i;
-       WORD Tmp1[MAXCHANNELS], Tmp2[MAXCHANNELS];
-
-
-       fk = ToFixedDomain((Fixed32) StageABC[0] * p16 -> Domain);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta8 * k0;
-       K1 = p16 -> opta8 * (k0 + (StageABC[0] != 0xFFFFU ? 1 : 0));
-
-       p16 -> nInputs = 7;
-
-       T = LutTable + K0;
-
-       Eval7Inputs(StageABC + 1, Tmp1, T, p16);
-
-       T = LutTable + K1;
-
-       Eval7Inputs(StageABC + 1, Tmp2, T, p16);
-
-       p16 -> nInputs = 8;
-       for (i=0; i < p16 -> nOutputs; i++)
-       {
-              StageLMN[i] = (WORD) FixedLERP(rk, Tmp1[i], Tmp2[i]);
-       }
-
-}
-
-
-// Fills optimization parameters
-
-void cmsCalcCLUT16ParamsEx(int nSamples, int InputChan, int OutputChan,
-                                            LCMSBOOL lUseTetrahedral, LPL16PARAMS p)
-{
-       int clutPoints;
-
-       cmsCalcL16Params(nSamples, p);
-
-       p -> nInputs  = InputChan;
-       p -> nOutputs = OutputChan;
-
-       clutPoints = p -> Domain + 1;
-
-       p -> opta1 = p -> nOutputs;              // Z
-       p -> opta2 = p -> opta1 * clutPoints;    // Y
-       p -> opta3 = p -> opta2 * clutPoints;    // X
-       p -> opta4 = p -> opta3 * clutPoints;    // Used only in 4 inputs LUT
-       p -> opta5 = p -> opta4 * clutPoints;    // Used only in 5 inputs LUT
-       p -> opta6 = p -> opta5 * clutPoints;    // Used only on 6 inputs LUT
-       p -> opta7 = p -> opta6 * clutPoints;    // Used only on 7 inputs LUT
-       p -> opta8 = p -> opta7 * clutPoints;    // Used only on 8 inputs LUT
-
-
-       switch (InputChan) {
-
-
-           case 1: // Gray LUT
-
-               p ->Interp3D = Eval1Input;
-               break;
-
-           case 3:  // RGB et al
-               if (lUseTetrahedral) {
-                   p ->Interp3D = cmsTetrahedralInterp16;
-               }
-               else
-                   p ->Interp3D = cmsTrilinearInterp16;
-               break;
-
-           case 4:  // CMYK LUT
-                p ->Interp3D = Eval4Inputs;
-                break;
-
-           case 5: // 5 Inks
-                p ->Interp3D = Eval5Inputs;
-                break;
-
-           case 6: // 6 Inks
-                p -> Interp3D = Eval6Inputs;
-                break;
-
-            case 7: // 7 inks
-                p ->Interp3D = Eval7Inputs;
-                break;
-
-           case 8: // 8 inks
-                p ->Interp3D = Eval8Inputs;
-                break;
-
-           default:
-                cmsSignalError(LCMS_ERRC_ABORTED, "Unsupported restoration (%d channels)", InputChan);
-           }
-
-}
-
-
-void cmsCalcCLUT16Params(int nSamples, int InputChan, int OutputChan, LPL16PARAMS p)
-{
-    cmsCalcCLUT16ParamsEx(nSamples, InputChan, OutputChan, FALSE, p);
-}
-
-
-
-#ifdef USE_FLOAT
-
-
-// Floating-point version
-
-WORD cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p)
-{
-       double y1, y0;
-       double y;
-       double val2, rest;
-       int cell0, cell1;
-
-       // if last value...
-
-       if (Value == 0xffff) return LutTable[p -> Domain];
-
-       val2 = p -> Domain * ((double) Value / 65535.0);
+       val2 = p -> Domain[0] * Value[0];
 
        cell0 = (int) floor(val2);
        cell1 = (int) ceil(val2);
 
        // Rest is 16 LSB bits
-
        rest = val2 - cell0;
 
        y0 = LutTable[cell0] ;
        y1 = LutTable[cell1] ;
 
-       y = y0 + (y1 - y0) * rest;
-
-
-       return (WORD) floor(y+.5);
+       Output[0] = y0 + (y1 - y0) * rest;
 }
 
-#endif
 
 
-//
-//  Linear interpolation (Fixed-point optimized, but C source)
-//
+// Eval gray LUT having only one input channel
+static
+void Eval1Input(register const cmsUInt16Number Input[],
+                register cmsUInt16Number Output[],
+                register const cmsInterpParams* p16)
+{
+       cmsS15Fixed16Number fk;
+       cmsS15Fixed16Number k0, k1, rk, K0, K1;
+       int v;
+       cmsUInt32Number OutChan;
+       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
 
+       v = Input[0] * p16 -> Domain[0];
+       fk = _cmsToFixedDomain(v);
 
-#ifdef USE_C
+       k0 = FIXED_TO_INT(fk);
+       rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
 
-WORD cmsLinearInterpLUT16(WORD Value1, WORD LutTable[], LPL16PARAMS p)
+       k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
+
+       K0 = p16 -> opta[0] * k0;
+       K1 = p16 -> opta[0] * k1;
+
+       for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
+
+           Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
+       }
+}
+
+
+
+// Eval gray LUT having only one input channel
+static
+void Eval1InputFloat(const cmsFloat32Number Value[],
+                     cmsFloat32Number Output[],
+                     const cmsInterpParams* p)
 {
-       WORD y1, y0;
-       WORD y;
-       int dif, a1;
-       int cell0, rest;
-       int val3, Value;
+    cmsFloat32Number y1, y0;
+    cmsFloat32Number val2, rest;
+    int cell0, cell1;
+    cmsUInt32Number OutChan;
+    const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
 
-       // if last value...
-
-
-       Value = Value1;
-       if (Value == 0xffff) return LutTable[p -> Domain];
-
-       val3 = p -> Domain * Value;
-       val3 = ToFixedDomain(val3);              // To fixed 15.16
-
-       cell0 = FIXED_TO_INT(val3);             // Cell is 16 MSB bits
-       rest  = FIXED_REST_TO_INT(val3);        // Rest is 16 LSB bits
-
-       y0 = LutTable[cell0] ;
-       y1 = LutTable[cell0+1] ;
-
-       dif = (int) y1 - y0;        // dif is in domain -ffff ... ffff
-
-       if (dif >= 0)
-       {
-       a1 = ToFixedDomain(dif * rest);
-       a1 += 0x8000;
-       }
-       else
-       {
-              a1 = ToFixedDomain((- dif) * rest);
-              a1 -= 0x8000;
-              a1 = -a1;
+        // if last value...
+       if (Value[0] == 1.0) {
+           Output[0] = LutTable[p -> Domain[0]];
+           return;
        }
 
-       y = (WORD) (y0 + FIXED_TO_INT(a1));
+       val2 = p -> Domain[0] * Value[0];
 
-       return y;
+       cell0 = (int) floor(val2);
+       cell1 = (int) ceil(val2);
+
+       // Rest is 16 LSB bits
+       rest = val2 - cell0;
+
+       cell0 *= p -> opta[0];
+       cell1 *= p -> opta[0];
+
+       for (OutChan=0; OutChan < p->nOutputs; OutChan++) {
+
+            y0 = LutTable[cell0 + OutChan] ;
+            y1 = LutTable[cell1 + OutChan] ;
+
+            Output[OutChan] = y0 + (y1 - y0) * rest;
+       }
 }
 
-#endif
 
-// Linear interpolation (asm by hand optimized)
 
-#ifdef USE_ASSEMBLER
-
-#ifdef _MSC_VER
-#pragma warning(disable : 4033)
-#pragma warning(disable : 4035)
-#endif
-
-WORD cmsLinearInterpLUT16(WORD Value, WORD LutTable[], LPL16PARAMS p)
-{
-       int xDomain = p -> Domain;
-
-
-       if (Value == 0xffff) return LutTable[p -> Domain];
-       else
-       ASM {
-              xor       eax, eax
-              mov       ax, word ptr ss:Value
-              mov       edx, ss:xDomain
-              mul       edx                         //  val3 = p -> Domain * Value;
-              shld      edx, eax, 16                // Convert it to fixed 15.16
-              shl       eax, 16                     // * 65536 / 65535
-              mov       ebx, 0x0000ffff
-              div       ebx
-              mov       ecx, eax
-              sar       ecx, 16                        // ecx = cell0
-              mov       edx, eax                       // rest = (val2 & 0xFFFFU)
-              and       edx, 0x0000ffff                // edx = rest
-              mov       ebx, ss:LutTable
-              lea       eax, dword ptr [ebx+2*ecx]     // Ptr to LUT
-              xor       ebx, ebx
-              mov        bx, word  ptr [eax]           // EBX = y0
-              movzx     eax, word  ptr [eax+2]         // EAX = y1
-              sub       eax, ebx                       // EAX = y1-y0
-              js        IsNegative
-              mul       edx                            // EAX = EAX * rest
-              shld      edx, eax, 16                   // Pass it to fixed
-              sal       eax, 16                        // * 65536 / 65535
-              mov       ecx, 0x0000ffff
-              div       ecx
-              add       eax, 0x8000                    // Rounding
-              sar       eax, 16
-              add       eax, ebx                       // Done!
-              }
-
-              RET((WORD) _EAX);
-
-       IsNegative:
-
-              ASM {
-              neg       eax
-              mul       edx                            // EAX = EAX * rest
-              shld      edx, eax, 16                   // Pass it to fixed
-              sal       eax, 16                        // * 65536 / 65535
-              mov       ecx, 0x0000ffff
-              div       ecx
-              sub       eax, 0x8000
-              neg       eax
-              sar       eax, 16
-